Seguimiento de un Hog de procesador
Si una aplicación consume ("hogging") toda la atención del procesador, otros procesos acabarán "en hambre" e incapaz de ejecutarse.
Use el procedimiento siguiente para corregir un error de este tipo.
Depuración de una aplicación que usa todos los ciclos de CPU
Identifique qué aplicación está causando este problema: Use el Administrador de tareas o Perfmon para buscar qué proceso usa el 99 % o el 100 % de los ciclos del procesador. Esto puede avisarle también el subproceso infractor.
Adjunte WinDbg, KD o CDB a este proceso.
Identifique qué subproceso está causando el problema: Interrumpa en la aplicación incorrecta. Use la extensión !runaway 3 para tomar una "instantánea" de donde va todo el tiempo de CPU. Use g (Go) y espere unos segundos. A continuación, rompa y use !runaway 3 de nuevo.
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
Compare los dos conjuntos de números y busque el subproceso cuyo tiempo de modo de usuario o tiempo del modo kernel ha aumentado más. Dado que !runaway se ordena por tiempo descendente de CPU, el subproceso infractor suele ser el que se encuentra en la parte superior de la lista. En este caso, el subproceso 0x4E0 está causando el problema.
Use los comandos ~ (Estado del subproceso) y ~s (Establecer subproceso actual) para que este sea el subproceso actual:
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
Use kb (Display Stack Backtrace) para obtener un seguimiento de pila de este subproceso:
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
Establezca un punto de interrupción en la dirección de retorno de la función que se está ejecutando actualmente. En este caso, la dirección de retorno se muestra en la primera línea como 0x77F6C600. La dirección de retorno es equivalente al desplazamiento de función que se muestra en la segunda línea (BuggyProgram! OpenDestFileStream+0xB3). Si no hay símbolos disponibles para la aplicación, es posible que el nombre de la función no aparezca. Use el comando g (Go) para ejecutarse hasta que se alcance esta dirección de retorno, mediante la dirección simbólica o hexadecimal:
0:002> g BuggyProgram!OpenDestFileStream+0xb3
Si se alcanza este punto de interrupción, repita el proceso. Por ejemplo, supongamos que se alcanza este punto de interrupción. Se deben realizar los pasos siguientes:
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
Si se alcanza, continúe con:
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
Por último, encontrará un punto de interrupción que no se alcanza. En este caso, debe suponer que el último comando g establece el destino en ejecución y no se interrumpa. Esto significa que la función SaveMsgToDestFolder() nunca devolverá.
¡Vuelva a entrar en el subproceso y establezca un punto de interrupción en BuggyProgram! SaveMsgToDestFolder+0xB3 con el comando bp (Establecer punto de interrupción). A continuación, use el comando g repetidamente. Si este punto de interrupción alcanza inmediatamente, independientemente de cuántas veces haya ejecutado el destino, es muy probable que haya identificado la función infractora:
0:002> bp BuggyProgram!SaveMsgToDestFolder+0xb3 0:002> g 0:002> g
Use el comando p (Paso) para continuar con la función hasta que identifique el lugar donde se encuentra la secuencia de bucles de instrucciones. A continuación, puede analizar el código fuente de la aplicación para identificar la causa del subproceso giratorio. La causa suele ser un problema en la lógica de un tiempo, un tiempo, un goto o un bucle for.