다음을 통해 공유


프로세서 돼지 추적

한 애플리케이션이 프로세서의 모든 주의를 끄는 경우 다른 프로세스는 "굶주리고" 실행할 수 없게 됩니다.

다음 절차에 따라 이러한 종류의 버그를 수정합니다.

모든 CPU 주기를 사용하는 애플리케이션 디버깅

  1. 이 문제를 일으키는 애플리케이션을 식별 합니다. 작업 관리자 또는 Perfmon 을 사용하여 프로세서 주기의 99% 또는 100%를 사용하는 프로세스를 찾습니다. 그러면 잘못된 스레드도 알려줄 수 있습니다.

  2. 이 프로세스에 WinDbg, KD 또는 CDB를 연결합니다.

  3. 문제를 일으키는 스레드를 식별합니다. 잘못된 애플리케이션에 침입합니다. !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 문제가 발생합니다.

  4. ~ (스레드 상태)~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
    
  5. 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
    
  6. 현재 실행 중인 함수의 반환 주소에 중단점을 설정합니다. 이 경우 반환 주소는 첫 번째 줄에 0x77F6C600 표시됩니다. 반환 주소는 두 번째 줄에 표시된 함수 오프셋과 동일합니다(BuggyProgram! OpenDestFileStream+0xB3). 애플리케이션에 사용할 수 있는 기호가 없으면 함수 이름이 표시되지 않을 수 있습니다. 기호 또는 16진수 주소를 사용하여 이 반환 주소에 도달할 때까지 실행하려면 g(Go) 명령을 사용합니다.

    0:002> g BuggyProgram!OpenDestFileStream+0xb3
    
  7. 이 중단점이 적중되면 프로세스를 반복합니다. 예를 들어 이 중단점이 적중된 경우를 가정해 보겠습니다. 다음 단계를 수행해야 합니다.

    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
    
  8. 마지막으로 적중되지 않은 중단점을 찾을 수 있습니다. 이 경우 마지막 g 명령이 실행 중인 대상을 설정했으며 중단되지 않았다고 가정해야 합니다. 즉 , SaveMsgToDestFolder() 함수는 반환되지 않습니다.

  9. 스레드에 다시 침입하여 BuggyProgram에서 중단점을 설정합니다. SaveMsgToDestFolder+0xB3bp(중단점 설정) 명령을 사용합니다. 그런 다음 g 명령을 반복적으로 사용합니다. 대상을 실행한 횟수에 관계없이 이 중단점이 즉시 도달하면 위반 함수를 식별했을 가능성이 큽니다.

    0:002> bp BuggyProgram!SaveMsgToDestFolder+0xb3
    
    0:002> g 
    
    0:002> g 
    
  10. 명령의 반복 시퀀스가 있는 위치를 식별할 때까지 p(단계) 명령을 사용하여 함수를 진행합니다. 그런 다음 애플리케이션의 소스 코드를 분석하여 회전 스레드의 원인을 식별할 수 있습니다. 원인은 일반적으로 잠시 동안, do-while, goto 또는 for 루프의 논리에서 문제가 되는 것으로 판명됩니다.