Partager via


Suivi d’un porc de processeur

Si une application consomme (« hogging ») toute l’attention du processeur, d’autres processus finissent par être « affamés » et incapables de s’exécuter.

Utilisez la procédure suivante pour corriger un bogue de ce type.

Débogage d’une application qui utilise tous les cycles du processeur

  1. Identifiez l’application à l’origine de ce problème : Utilisez le Gestionnaire des tâches ou Perfmon pour déterminer quel processus utilise 99 % ou 100 % des cycles du processeur. Cela peut également vous indiquer le thread incriminé.

  2. Attachez WinDbg, KD ou CDB à ce processus.

  3. Identifiez le thread à l’origine du problème : S’introduire dans l’application incriminant. Utilisez l’extension !runaway 3 pour prendre un « instantané » de tout le temps processeur. Utilisez g (Go) et attendez quelques secondes. Ensuite, faites une pause et utilisez à nouveau !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
    

    Comparez les deux ensembles de nombres et recherchez le thread dont le temps en mode utilisateur ou en mode noyau a le plus augmenté. Étant donné que !runaway trie en décroissant le temps processeur, le thread incriminé est généralement celui en haut de la liste. Dans ce cas, le thread 0x4E0 est à l’origine du problème.

  4. Utilisez les commandes ~ (État du thread) et ~s (Définir le thread actuel) pour en faire le thread actuel :

    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. Utilisez kb (Display Stack Backtrace) pour obtenir une trace de pile de ce thread :

    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. Définissez un point d’arrêt sur l’adresse de retour de la fonction en cours d’exécution. Dans ce cas, l’adresse de retour est affichée sur la première ligne en tant que 0x77F6C600. L’adresse de retour est équivalente au décalage de fonction affiché sur la deuxième ligne (BuggyProgram ! OpenDestFileStream+0xB3). Si aucun symbole n’est disponible pour l’application, le nom de la fonction peut ne pas apparaître. Utilisez la commande g (Go) pour exécuter jusqu’à ce que cette adresse de retour soit atteinte, en utilisant l’adresse symbolique ou hexadécimale :

    0:002> g BuggyProgram!OpenDestFileStream+0xb3
    
  7. Si ce point d’arrêt est atteint, répétez le processus. Par exemple, supposons que ce point d’arrêt soit atteint. Les étapes suivantes doivent être effectuées :

    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 cette option est atteinte, continuez avec :

    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. Enfin, vous trouverez un point d’arrêt qui n’est pas atteint. Dans ce cas, vous devez supposer que la dernière commande g a défini la cible en cours d’exécution et qu’elle ne s’est pas rompue. Cela signifie que la fonction SaveMsgToDestFolder() ne retournera jamais.

  9. Arrêtez à nouveau le thread et définissez un point d’arrêt sur BuggyProgram ! SaveMsgToDestFolder+0xB3 avec la commande bp (Définir le point d’arrêt). Utilisez ensuite la commande g à plusieurs reprises. Si ce point d’arrêt atteint immédiatement, quel que soit le nombre de fois où vous avez exécuté la cible, il est très probable que vous ayez identifié la fonction incriminée :

    0:002> bp BuggyProgram!SaveMsgToDestFolder+0xb3
    
    0:002> g 
    
    0:002> g 
    
  10. Utilisez la commande p (Étape) pour parcourir la fonction jusqu’à ce que vous identifiez l’emplacement où se trouve la séquence d’instructions en boucle. Vous pouvez ensuite analyser le code source de l’application pour identifier la cause du thread en rotation. La cause s’avère généralement être un problème dans la logique d’une boucle while, do-while, goto ou for .