Condividi tramite


Rilevamento di un hog processore

Se un'applicazione sta consumando ("hogging") tutta l'attenzione del processore, gli altri processi finiranno per "fame" e non potranno essere eseguiti.

Utilizzare la procedura seguente per correggere un bug di questo ordinamento.

Debug di un'applicazione che usa tutti i cicli della CPU

  1. Identificare l'applicazione che causa questo problema: Usare Gestione attività o Perfmon per trovare il processo che usa il 99% o il 100% dei cicli del processore. Questo può indicare anche il thread che causa l'offesa.

  2. Collegare WinDbg, KD o CDB a questo processo.

  3. Identificare il thread che causa il problema: Entrare nell'applicazione che causa l'offesa. Usare l'estensione !runaway 3 per creare uno "snapshot" di dove sta andando tutto il tempo della CPU. Usare g (Go) e attendere alcuni secondi. Quindi interrompere e usare di nuovo !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
    

    Confrontare i due set di numeri e cercare il thread il cui tempo in modalità utente o il tempo in modalità kernel è aumentato di più. Poiché !runaway ordina in base al tempo di CPU decrescente, il thread che causa l'errore è in genere quello nella parte superiore dell'elenco. In questo caso, il thread 0x4E0 causa il problema.

  4. Usare i comandi ~ (Stato thread) e ~s (Imposta thread corrente) per impostare il thread corrente:

    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. Usare kb (Display Stack Backtrace) per ottenere un'analisi dello stack di questo 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. Impostare un punto di interruzione sull'indirizzo restituito della funzione attualmente in esecuzione. In questo caso, l'indirizzo restituito viene visualizzato nella prima riga come 0x77F6C600. L'indirizzo restituito equivale all'offset della funzione visualizzato sulla seconda riga (BuggyProgram! OpenDestFileStream+0xB3). Se non sono disponibili simboli per l'applicazione, è possibile che il nome della funzione non venga visualizzato. Usare il comando g (Go) per eseguire fino a quando non viene raggiunto questo indirizzo restituito, usando l'indirizzo simbolico o esadecimale:

    0:002> g BuggyProgram!OpenDestFileStream+0xb3
    
  7. Se viene raggiunto questo punto di interruzione, ripetere il processo. Si supponga, ad esempio, che questo punto di interruzione venga raggiunto. È necessario eseguire i passaggi seguenti:

    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
    

    Se viene raggiunto, continuare 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
    
  8. Infine, troverai un punto di interruzione che non viene raggiunto. In questo caso, è consigliabile presupporre che l'ultimo comando g imposti la destinazione in esecuzione e che non si sia interrotto. Ciò significa che la funzione SaveMsgToDestFolder() non restituirà mai.

  9. Entrare di nuovo nel thread e impostare un punto di interruzione in BuggyProgram. SaveMsgToDestFolder+0xB3 con il comando bp (Imposta punto di interruzione). Usare quindi ripetutamente il comando g . Se questo punto di interruzione raggiunge immediatamente, indipendentemente dal numero di volte in cui è stata eseguita la destinazione, è molto probabile che sia stata identificata la funzione che causa l'errore:

    0:002> bp BuggyProgram!SaveMsgToDestFolder+0xb3
    
    0:002> g 
    
    0:002> g 
    
  10. Usare il comando p (passaggio) per procedere con la funzione fino a quando non si identifica la posizione in cui si trova la sequenza di istruzioni a ciclo. È quindi possibile analizzare il codice sorgente dell'applicazione per identificare la causa del thread rotante. La causa in genere si rivelerà un problema nella logica di un po', do-while, goto o ciclo for .