2013-06-09 21 views
8

Quando si crea il codice di profilazione a livello di istruzioni di assemblaggio, cosa significa realmente la posizione del puntatore di istruzioni dato che le CPU moderne non eseguono le istruzioni in serie o in ordine? Ad esempio, si assuma il seguente codice assembly x64:Profilo livello di istruzione: il significato del puntatore di istruzioni?

mov RAX, [RBX];   // Assume a cache miss here. 
mov RSI, [RBX + RCX]; // Another cache miss.    
xor R8, R8;   
add RDX, RAX;   // Dependent on the load into RAX. 
add RDI, RSI;   // Dependent on the load into RSI. 

Quale istruzione trascorrerà la maggior parte del tempo sull'indicatore di istruzioni? Posso pensare di buoni argomenti per tutti loro:

  • mov RAX, [RBX] sta prendendo probabilmente 100s di cicli perché è un cache miss.
  • mov RSI, [RBX + RCX] richiede anche 100 s di cicli, ma probabilmente viene eseguito in parallelo con l'istruzione precedente. Cosa significa per il puntatore dell'istruzione essere su uno o l'altro di questi?
  • xor R8, R8 probabilmente si esegue fuori ordine e termina prima che i carichi di memoria finiscano, ma il puntatore di istruzioni potrebbe rimanere qui fino a quando tutte le precedenti istruzioni non sono state completate.
  • add RDX, RAX genera uno stallo della pipeline perché è l'istruzione in cui il valore di RAX viene effettivamente utilizzato dopo un carico di cache-miss lento in esso.
  • add RDI, RSI si blocca anche perché dipende dal carico in RSI.

risposta

6

Le CPU mantengono una finzione che ci sono solo i registri architettonici (RAX, RBX, ecc.) E c'è un puntatore di istruzioni specifico (IP). Programmatori e compilatori hanno come obiettivo questa finzione.

Tuttavia, come notato, le CPU moderne non vengono eseguite in serie o in ordine. Finché il programmatore/utente non richiede l'IP, è come Quantum Physics, l'IP è un'ondata di istruzioni che vengono eseguite; tutto in modo che il processore possa eseguire il programma il più velocemente possibile. Quando richiedi l'IP corrente (ad esempio, tramite un punto di interruzione del debugger o un interrupt del profiler), il processore deve ricreare la finzione che ti aspetti, quindi collassa questa forma d'onda (tutte le istruzioni "in volo"), riunisce i valori del registro in nomi architettonici e crea un contesto per l'esecuzione della routine del debugger, ecc.

In questo contesto, esiste un IP che indica l'istruzione in cui il processore deve riprendere l'esecuzione. Durante l'esecuzione fuori ordine, questa istruzione era l'istruzione più vecchia ancora da completare, anche se al momento dell'interruzione il processore stava forse recuperando le istruzioni ben oltre quel punto.

Ad esempio, forse l'interrupt indica mov RSI, [RBX + RCX]; come IP, ma lo xor era già stato eseguito e completato; tuttavia, quando il processore riprende l'esecuzione dopo l'interruzione, eseguirà di nuovo l'xor.

+1

Puoi spiegare come funzionano i contatori di monitoraggio delle prestazioni dell'hardware in tale contesto? Per esempio. Linux ha il sottosistema 'perf' che fornisce profili statistici basati su PMC. Il kernel sta solo generando un interrupt ad alta frequenza che poi - secondo la tua molto bella analogia - collassa la funzione wave IP e legge i PMC, e quindi assegnerebbe i valori correnti di quei PMC all'IP attualmente trovato (dopo l'onda funzione collasso)? E poi resettare le PMC e riprendere dall'interrupt? – oberstet