프로세서 돼지 추적
한 애플리케이션이 프로세서의 모든 주의를 끄는 경우 다른 프로세스는 "굶주리고" 실행할 수 없게 됩니다.
다음 절차에 따라 이러한 종류의 버그를 수정합니다.
모든 CPU 주기를 사용하는 애플리케이션 디버깅
이 문제를 일으키는 애플리케이션을 식별 합니다. 작업 관리자 또는 Perfmon 을 사용하여 프로세서 주기의 99% 또는 100%를 사용하는 프로세스를 찾습니다. 그러면 잘못된 스레드도 알려줄 수 있습니다.
이 프로세스에 WinDbg, KD 또는 CDB를 연결합니다.
문제를 일으키는 스레드를 식별합니다. 잘못된 애플리케이션에 침입합니다. !runaway 3 확장을 사용하여 모든 CPU 시간이 진행되는 위치의 "스냅샷"을 수행합니다. g(Go)를 사용하고 몇 초 정도 기다립니다. 그런 다음 침입하여 !Runaway 3을 다시 사용합니다.
0:002> !runaway 3 User Mode Time Thread Time 4e0 0:12:16.0312 268 0:00:00.0000 22c 0:00:00.0000 Kernel Mode Time Thread Time 4e0 0:00:05.0312 268 0:00:00.0000 22c 0:00:00.0000 0:002> g 0:001> !runaway 3 User Mode Time Thread Time 4e0 0:12:37.0609 3d4 0:00:00.0000 22c 0:00:00.0000 Kernel Mode Time Thread Time 4e0 0:00:07.0421 3d4 0:00:00.0000 22c 0:00:00.0000
두 숫자 집합을 비교하고 사용자 모드 시간 또는 커널 모드 시간이 가장 많이 증가한 스레드를 찾습니다. !Runaway는 CPU 시간을 내림차순으로 정렬하기 때문에 위반 스레드는 일반적으로 목록 맨 위에 있는 스레드입니다. 이 경우 스레드 0x4E0 문제가 발생합니다.
~ (스레드 상태) 및 ~s(현재 스레드 설정) 명령을 사용하여 이 스레드를 현재 스레드로 만듭니다.
0:001> ~ 0 Id: 3f4.3d4 Suspend: 1 Teb: 7ffde000 Unfrozen . 1 Id: 3f4.22c Suspend: 1 Teb: 7ffdd000 Unfrozen 2 Id: 3f4.4e0 Suspend: 1 Teb: 7ffdc000 Unfrozen 0:001> ~2s
kb(Display Stack Backtrace)를 사용하여 이 스레드의 스택 추적을 가져옵니다.
0:002> kb FramePtr RetAddr Param1 Param2 Param3 Function Name 0b4ffc74 77f6c600 000000c8.00000000 77fa5ad0 BuggyProgram!CreateMsgFile+0x1b 0b4ffce4 01836060 0184f440 00000001 0b4ffe20 BuggyProgram!OpenDestFileStream+0xb3 0b4ffd20 01843eba 02b5b920 00000102 02b1e0e0 BuggyProgram!SaveMsgToDestFolder+0xb3 0b4ffe20 01855924 0b4ffef0 00145970 0b4ffef0 BuggyProgram!DispatchToConn+0xa4 0b4ffe5c 77e112e6 01843e16 0b4ffef0 0b4fff34 RPCRT4!DispatchToStubInC+0x34 0b4ffeb0 77e11215 0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStubWorker@RPC_INTERFACE@@AAEJPAU_RPC_MESSAGE@@IPAJ@Z+0xb0 0b4ffed0 77e1a3b1 0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStub@RPC_INTERFACE@@QAEJPAU_RPC_MESSAGE@Z+0x41 0b4fff40 77e181e4 02b1e0b0 00000074 0b4fff90 RPCRT4!?ReceiveOriginalCall@OSF_SCONNECTION@Z+0x14b 0b4fff60 77e1a5df 02b1e0b0 00000074 00149210 RPCRT4!?DispatchPacket@OSF_SCONNECTION@+0x91 0b4fff90 77e1ac1c 77e15eaf 00149210 0b4fffec RPCRT4!?ReceiveLotsaCalls@OSF_ADDRESS@@QAEXXZ+0x76
현재 실행 중인 함수의 반환 주소에 중단점을 설정합니다. 이 경우 반환 주소는 첫 번째 줄에 0x77F6C600 표시됩니다. 반환 주소는 두 번째 줄에 표시된 함수 오프셋과 동일합니다(BuggyProgram! OpenDestFileStream+0xB3). 애플리케이션에 사용할 수 있는 기호가 없으면 함수 이름이 표시되지 않을 수 있습니다. 기호 또는 16진수 주소를 사용하여 이 반환 주소에 도달할 때까지 실행하려면 g(Go) 명령을 사용합니다.
0:002> g BuggyProgram!OpenDestFileStream+0xb3
이 중단점이 적중되면 프로세스를 반복합니다. 예를 들어 이 중단점이 적중된 경우를 가정해 보겠습니다. 다음 단계를 수행해야 합니다.
0:002> kb FramePtr RetAddr Param1 Param2 Param3 Function Name 0b4ffce4 01836060 0184f440 00000001 0b4ffe20 BuggyProgram!OpenDestFileStream+0xb3 0b4ffd20 01843eba 02b5b920 00000102 02b1e0e0 BuggyProgram!SaveMsgToDestFolder+0xb3 0b4ffe20 01855924 0b4ffef0 00145970 0b4ffef0 BuggyProgram!DispatchToConn+0xa4 0b4ffe5c 77e112e6 01843e16 0b4ffef0 0b4fff34 RPCRT4!DispatchToStubInC+0x34 0b4ffeb0 77e11215 0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStubWorker@RPC_INTERFACE@@AAEJPAU_RPC_MESSAGE@@IPAJ@Z+0xb0 0b4ffed0 77e1a3b1 0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStub@RPC_INTERFACE@@QAEJPAU_RPC_MESSAGE@Z+0x41 0b4fff40 77e181e4 02b1e0b0 00000074 0b4fff90 RPCRT4!?ReceiveOriginalCall@OSF_SCONNECTION@Z+0x14b 0b4fff60 77e1a5df 02b1e0b0 00000074 00149210 RPCRT4!?DispatchPacket@OSF_SCONNECTION@+0x91 0b4fff90 77e1ac1c 77e15eaf 00149210 0b4fffec RPCRT4!?ReceiveLotsaCalls@OSF_ADDRESS@@QAEXXZ+0x76 0:002> g BuggyProgram!SaveMsgToDestFolder+0xb3
이 문제가 발생하면 다음을 계속 진행합니다.
0:002> kb FramePtr RetAddr Param1 Param2 Param3 Function Name 0b4ffd20 01843eba 02b5b920 00000102 02b1e0e0 BuggyProgram!SaveMsgToDestFolder+0xb3 0b4ffe20 01855924 0b4ffef0 00145970 0b4ffef0 BuggyProgram!DispatchToConn+0xa4 0b4ffe5c 77e112e6 01843e16 0b4ffef0 0b4fff34 RPCRT4!DispatchToStubInC+0x34 0b4ffeb0 77e11215 0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStubWorker@RPC_INTERFACE@@AAEJPAU_RPC_MESSAGE@@IPAJ@Z+0xb0 0b4ffed0 77e1a3b1 0b4ffef0 00000000 0b4fff34 RPCRT4!?DispatchToStub@RPC_INTERFACE@@QAEJPAU_RPC_MESSAGE@Z+0x41 0b4fff40 77e181e4 02b1e0b0 00000074 0b4fff90 RPCRT4!?ReceiveOriginalCall@OSF_SCONNECTION@Z+0x14b 0b4fff60 77e1a5df 02b1e0b0 00000074 00149210 RPCRT4!?DispatchPacket@OSF_SCONNECTION@+0x91 0b4fff90 77e1ac1c 77e15eaf 00149210 0b4fffec RPCRT4!?ReceiveLotsaCalls@OSF_ADDRESS@@QAEXXZ+0x76 0:002> g BuggyProgram!DispatchToConn+0xa4
마지막으로 적중되지 않은 중단점을 찾을 수 있습니다. 이 경우 마지막 g 명령이 실행 중인 대상을 설정했으며 중단되지 않았다고 가정해야 합니다. 즉 , SaveMsgToDestFolder() 함수는 반환되지 않습니다.
스레드에 다시 침입하여 BuggyProgram에서 중단점을 설정합니다. SaveMsgToDestFolder+0xB3bp(중단점 설정) 명령을 사용합니다. 그런 다음 g 명령을 반복적으로 사용합니다. 대상을 실행한 횟수에 관계없이 이 중단점이 즉시 도달하면 위반 함수를 식별했을 가능성이 큽니다.
0:002> bp BuggyProgram!SaveMsgToDestFolder+0xb3 0:002> g 0:002> g
명령의 반복 시퀀스가 있는 위치를 식별할 때까지 p(단계) 명령을 사용하여 함수를 진행합니다. 그런 다음 애플리케이션의 소스 코드를 분석하여 회전 스레드의 원인을 식별할 수 있습니다. 원인은 일반적으로 잠시 동안, do-while, goto 또는 for 루프의 논리에서 문제가 되는 것으로 판명됩니다.