Profilazione del codice CFD con Callgrind


16

Sto usando Valgrind + Callgrind per profilare un solutore che ho scritto. Come afferma il manuale dell'utente di Valgrind, ho compilato il mio codice con le opzioni di debug per il compilatore:

"Senza informazioni di debug, i migliori strumenti di Valgrind saranno in grado di fare è indovinare a quale funzione appartiene un particolare pezzo di codice, il che rende quasi inutili sia i messaggi di errore che l'output del profilo. Con -g, otterrai messaggi che puntano direttamente a le righe del codice sorgente pertinenti. "

Manuale di Valgrind

Se compilati con l'opzione di debug, i codici funzionano molto più lentamente. Il codice CFD, diventa DAVVERO lento, anche per i piccoli casi quando compilato con flag di debug. Valgrind rende 40 volte più lento (vedere il manuale 1 ).

  1. Quali strumenti stai usando per la profilazione del codice (profilazione, non benchmarking)?

  2. Per quanto tempo si lascia il codice in esecuzione (statistiche: quanti passaggi temporali)?

  3. Quanto sono grandi i casi (se il caso si adatta alla cache, il risolutore è più veloce degli ordini di grandezza, ma poi mi mancheranno i processi relativi alla memoria)?


3
È possibile compilare il codice con entrambi i simboli di debug e l'ottimizzazione abilitati. Tuttavia, 40x attraverso valgrind (che simula tutto l'accesso alla memoria) non è irragionevole.
Aron Ahmadia,

Grazie, questo è anche quello che ho letto ... Quello che vorrei sapere sono informazioni sulle esperienze quotidiane nella profilazione (preferibilmente con valgrind): quanto tempo è normale attendere i report, quante iterazioni conta di cosa ho bisogno, cosa posso escludere ... ecc ...
Tmaric,

Anche la tua domanda è un po 'ampia. Ti consiglio di modificare la tua domanda in modo da concentrarti su Q2.1 e Q2.2, poiché Q1 è una domanda completamente diversa (sono felice che tu la faccia separatamente, è una buona domanda, ma la frase come "Quali strumenti vorresti usare per risolvere il problema X ", dove X è ben descritto!), mentre Q2 da solo è troppo generale.
Aron Ahmadia,

Si può modificare anche il nome callgrind, cachegrindo massif. Molte persone associano Valgrind solo allo strumento predefinito ( memcheck). Come sistema di profilazione basato sull'emulazione (piuttosto che sull'interruzione), non è necessario eseguire a lungo.
Jed Brown,

@Aron & Jed: grazie per i suggerimenti, ho modificato la domanda. :)
tmaric,

Risposte:


11

Q1: quali strumenti stai usando per la profilazione del codice (profiling, non benchmarking)?

Q2: per quanto tempo si lascia il codice in esecuzione (statistiche: quanti passaggi temporali)?

D3: Quanto sono grandi i casi (se il caso si adatta alla cache, il risolutore è più veloce degli ordini di grandezza, ma poi mi mancheranno i processi relativi alla memoria)?

Ecco un esempio di come lo faccio.

Separo il benchmarking (vedendo quanto tempo impiega) dalla profilazione (identificando come renderlo più veloce). Non è importante che il profiler sia veloce. È importante che ti dica cosa risolvere.

Non mi piace nemmeno la parola "profiling" perché evoca un'immagine simile a un istogramma, dove c'è una barra dei costi per ogni routine o "collo di bottiglia" perché implica che c'è solo un piccolo spazio nel codice che deve essere fisso. Entrambe queste cose implicano una sorta di tempistica e statistiche, per le quali si ritiene che la precisione sia importante. Non vale la pena rinunciare alla comprensione dell'accuratezza dei tempi.

L'utilizzo metodo che è pausa a caso, e c'è un caso di studio e slide-show completo qui . Parte della visione del mondo del collo di bottiglia del profiler è che se non trovi nulla, non c'è nulla da trovare, e se trovi qualcosa e ottieni una certa percentuale di accelerazione, dichiari la vittoria e esci. I fan del profiler non dicono quasi mai quanto accelerano e gli annunci mostrano solo problemi artificialmente concepiti per essere facili da trovare. La pausa casuale rileva i problemi, facili o difficili. Quindi risolvere un problema espone altri, in modo che il processo possa essere ripetuto, per ottenere una maggiore velocità.

Nella mia esperienza di numerosi esempi, ecco come procede: posso trovare un problema (facendo una pausa casuale) e risolverlo, ottenendo una velocità di alcuni percento, diciamo del 30% o 1,3x. Quindi posso farlo di nuovo, trovare un altro problema e risolverlo, ottenendo un altro aumento di velocità, forse meno del 30%, forse di più. Quindi posso farlo di nuovo, più volte fino a quando non riesco davvero a trovare nient'altro da risolvere. L'ultimo fattore di accelerazione è il prodotto corrente dei singoli fattori e può essere incredibilmente grande - in alcuni casi ordini di grandezza.

INSERITO: Giusto per illustrare quest'ultimo punto. C'è un esempio dettagliato qui , con slide show e tutti i file, che mostra come è stata raggiunta una velocità di 730x in una serie di rimozioni di problemi. La prima versione impiegava 2700 microsecondi per unità di lavoro. Il problema A è stato rimosso, portando il tempo a 1800 e aumentando le percentuali di problemi rimanenti di 1,5x (2700/1800). Quindi B è stato rimosso. Questo processo è proseguito attraverso sei iterazioni, determinando una velocità di quasi 3 ordini di grandezza. Ma la tecnica di profilazione deve essere davvero efficace, perché se uno di questi problemi non viene rilevato, ovvero se si raggiunge un punto in cui si ritiene erroneamente che non si possa fare più nulla, il processo si blocca.

Descrizione della rimozione di più problemi per ottenere una maggiore velocità

INSERITO: Per dirla in altro modo, ecco un grafico del fattore di accelerazione totale man mano che vengono rimossi problemi successivi:

inserisci qui la descrizione dell'immagine

Quindi per Q1, per il benchmarking è sufficiente un semplice timer. Per la "profilazione" uso una pausa casuale.

D2: Gli do un carico di lavoro sufficiente (o semplicemente ci giro attorno) in modo che funzioni abbastanza a lungo da mettere in pausa.

D3: Assicura un carico di lavoro realisticamente elevato in modo da non perdere i problemi di cache. Questi verranno visualizzati come esempi nel codice che esegue il recupero della memoria.


Mike, hai una preferenza su come fare una pausa casuale in assenza di un IDE visivo? Questo processo può essere automatizzato in qualche modo?
Matthew Emmett,

@Matthew: Capisco che ci sono strumenti come pstacke lsstack, ma lo considero davvero un processo più simile al debugging. Quindi, anche se il miglior debugger che posso mettere in pratica è gdb, fa il suo lavoro. Con un debugger puoi esaminare i dati e questo può fare la differenza quando lo stack da solo non ti dice abbastanza.
Mike Dunlavey,

9

Il profiler del povero è fondamentalmente uno gdbscript che campiona lo stack di chiamate. Sarà comunque necessario disporre di simboli di debug. È ancora lento, ma poiché non implementa una macchina virtuale per eseguire il codice su di esso è spesso più veloce callgrinde adeguato all'attività.

Mi sono imbattuto in analizzatori di fisica delle particelle con un successo modesto (cioè ho dimostrato che il codice non aveva punti caldi orribili e l'ottimizzazione avrebbe richiesto un algoritmo migliore).


1
+ L'assenza di prove non è una prova di assenza :) Ciò che il profiler di quel poveretto dovrebbe fare è prendere meno tracce e non farle crollare, ma farle vedere. L'occhio umano è molto più bravo nel rilevare modelli utili rispetto alle semplici stime del tempo di funzionamento e se vedi qualcosa che potresti migliorare su appena 2 campioni, ti aiuterà in modo significativo. La frazione X che salverà è una distribuzione beta con modalità 2 / N, in cui N è il numero di tracce esaminate e il fattore di accelerazione sarà 1 / (1-X), che può essere grande.
Mike Dunlavey,

2

Per aggiungere alle grandi risposte disponibili, c'è uno strumento sviluppato in Rice che automatizza il campionamento dello stack e quindi ha un sovraccarico minimo:

http://hpctoolkit.org/


Sembra carino, anche se (mi dispiace) ho messo il mio cappello di fiamma qui. Non mi sintonizzo sul codice ottimizzato per il compilatore perché è difficile vedere cosa sta succedendo nel codice alterato. Le cose che sto potando non sono cose che l'ottimizzatore potrebbe affrontare, come chiamare ripetutamente expe logcon gli stessi argomenti ripetutamente o operazioni a matrice che impiegano tutto il loro tempo a decodificare. Sintonizzo il più possibile, quindi accendo -O3.
Mike Dunlavey,

Gli strumenti sono strumenti e sono utili solo se l'utente conosce e comprende i propri limiti. Non penso che ci sarà mai un "profiler perfetto" che rimuoverà l'utente dall'equazione del tutto per quanto riguarda la comprensione del suo output e il saper usare le informazioni.
Reid.Atcheson,

1

Allinea MAP è un profiler di campionamento sviluppato e supportato commercialmente e quindi - come suggerito da HPC Toolkit in una risposta precedente - può essere eseguito su lavori di dimensioni di produzione se lo si desidera.

Questo tipo di strumento indica colli di bottiglia della CPU o scarsa comunicazione MPI, ma anche la completa supervisione della profilazione dell'intero lavoro può essere impagabile nel trovare problemi a sorpresa.

Ci sono spesso frutti con prestazioni ridotte che si trovano al di fuori del nucleo del kernel di un codice CFD, in aree che non erano previste. Il campionamento casuale dello stack è, se fatto manualmente con GDB o con strumenti come HPC Toolkit e Allinea MAP, il modo migliore per trovarli. Se qualcosa è importante per le prestazioni, verrà visualizzato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.