5

ho sviluppato un codice che riceve in ingresso una grande immagine 2-D (fino a 64MPixels) e:Interpretazione di uscita perf stat

  • applica un filtro su ogni riga
  • traspone l'immagine (serve blocco per evitare un sacco di cache miss)
  • applica un filtro sulle colonne (ora a righe) dell'immagine
  • traspone l'immagine filtrata di nuovo a continuare con altri calcoli

Anche se non cambia qualcosa, per completezza della mia domanda, il filtraggio applica una trasformata wavelet discreta e il codice è scritto in C.

Il mio obiettivo finale è quello di eseguire questa corsa veloce come possibile. Le accelerazioni che ho finora sono più di 10 volte l'uso della trasposizione matrice, trasposizione, multithreading, codice compilatore ecc.

Venendo alla mia domanda: le ultime statistiche di profilazione del codice che ho (usando perf stat -e) mi hanno turbato.

 76,321,873 cache-references            
    8,647,026,694 cycles     # 0.000 GHz      
    7,050,257,995 instructions    # 0.82 insns per cycle   
     49,739,417 cache-misses    # 65.171 % of all cache refs  

     0.910437338 seconds time elapsed 

Il (# di cache-misses)/(# istruzioni) è basso intorno a ~ 0,7%. Here si dice che questo numero è una buona cosa da avere in mente per verificare l'efficienza della memoria.

D'altra parte, la percentuale di cache-misses nei riferimenti alla cache è significativamente alta (65%!) Che, come vedo, potrebbe indicare che qualcosa non funziona nell'esecuzione in termini di efficienza della cache.

Lo stat dettagliate dai perf stat -d è:

2711.191150 task-clock    # 2.978 CPUs utilized   
     1,421 context-switches   # 0.524 K/sec     
      50 cpu-migrations   # 0.018 K/sec     
     362,533 page-faults    # 0.134 M/sec     
8,518,897,738 cycles     # 3.142 GHz      [40.13%] 
6,089,067,266 stalled-cycles-frontend # 71.48% frontend cycles idle [39.76%] 
4,419,565,197 stalled-cycles-backend # 51.88% backend cycles idle [39.37%] 
7,095,514,317 instructions    # 0.83 insns per cycle   
             # 0.86 stalled cycles per insn [49.66%] 
    858,812,708 branches     # 316.766 M/sec     [49.77%] 
    3,282,725 branch-misses    # 0.38% of all branches   [50.19%] 
1,899,797,603 L1-dcache-loads   # 700.724 M/sec     [50.66%] 
    153,927,756 L1-dcache-load-misses  # 8.10% of all L1-dcache hits [50.94%] 
    45,287,408 LLC-loads     # 16.704 M/sec     [40.70%] 
    26,011,069 LLC-load-misses   # 57.44% of all LL-cache hits [40.45%] 

    0.910380914 seconds time elapsed 

Qui cicli di frontend e backend in fase di stallo sono anche alti e le cache di livello inferiore sembrano soffrire di un alto tasso di perdere del 57,5%.

Quale metrica è la più appropriata per questo scenario? Un'idea che stavo pensando è che potrebbe essere il caso che il carico di lavoro non richieda più "contatto" delle cache LL dopo il caricamento iniziale dell'immagine (carica i valori una volta e dopo che è stato eseguito - il carico di lavoro è più legato alla CPU di legato alla memoria essendo un algoritmo di filtraggio delle immagini).

La macchina su cui sto eseguendo è una Xeon E5-2680 (20 M di cache intelligente, di cui 256 KB di cache L2 per core, 8 core).

+0

koukouviou, 'perf stat -d' potrebbe essere impreciso, può essere utile eseguirlo di nuovo più volte con 4-5 eventi per esecuzione,' perf stat -e L1-dcache-load, L1-dcache-load-misses , LLC-carichi, LLC carichi-semincidenti. Se le tue fasi possono essere separate, puoi misurare ogni fase per scoprire quale di esse genera mancanze. Oppure puoi eseguire 'perf record -e cache-misses' per ottenere il profilo del codice che ha più problemi (come raccomandato nel ["Qui"] (http://developerblog.redhat.com/2014/03/10/ determinare-se-un'applicazione-ha-scarsa-cache-prestazioni-2 /) è stato collegato). – osgx

+0

@osgx Ho fatto i test che hai citato ma il post era già lungo, quindi l'ho tenuto il più breve possibile. Anche se le statistiche cambiano un po ', rimangono statisticamente simili con errori di cache alti%. Ho eseguito perf record/report/annotate e le miss sono attribuite in gran parte a kernel-kallsyms, ma non so cosa fare di questo ... – koukouviou

+0

koukouviou, Puoi ripetere le tue statistiche con tutti gli eventi limitati a user- spazio: 'perf stat -e event1: u, event2: u, ...' e confronta i risultati pubblicati (per impostazione predefinita vengono misurati sia l'utente che il kernel). kernel-kallsyms significa che alcune funzioni del kernel-space avevano questo evento ... Alcuni possibili problemi di simboli sconosciuti/non risolti sono elencati qui: http://www.brendangregg.com/blog/2014-06-22/perf-cpu -sample.html. Non posso darti consigli sulle metriche ... – osgx

risposta

3

La prima cosa che si desidera assicurarsi è che non sia in esecuzione nessun altro processo intensivo di calcolo sul proprio computer. Questa è una CPU del server, quindi ho pensato che potesse essere un problema.

Se si utilizza il multithreading nel programma e si distribuisce la stessa quantità di lavoro tra i thread, è possibile che si interessi che raccolga le metriche solo su una CPU.

Suggerisco disabilitare l'hyper-threading nella fase di ottimizzazione in quanto può creare confusione nell'interpretazione delle metriche di profilazione. (ad esempio, #cycles aumentati nel back-end). Inoltre, se distribuisci il lavoro su 3 thread, hai un'alta probabilità che 2 thread condividano le risorse di un core e il terzo abbia l'intero core per se stesso - e sarà più veloce.

Perf non è mai stato molto bravo a spiegare le metriche. A giudicare dall'ordine di grandezza, i riferimenti alla cache sono i miss L2 che colpiscono la LLC. Un numero di errori LLC elevato rispetto ai riferimenti LLC non è sempre una cosa negativa se il numero di riferimenti LLC/#Instructions è basso. Nel tuo caso, hai 0,018, quindi significa che la maggior parte dei tuoi dati viene utilizzata da L2. L'elevato indice di perdita di LLC indica che è ancora necessario recuperare i dati dalla RAM e riscriverli.

Riguardo a #Cycles BE e FE bound, sono un po 'preoccupato per i valori perché non sommano al 100% e al numero totale di cicli. Hai 8G ma sei cicli di 6G nei cicli FE e 4G in BE. Non sembra molto corretto.

Se i cicli FE sono elevati, significa che ci sono errori nella cache delle istruzioni o nella speculazione di ramo errato. Se i cicli BE sono alti, significa che aspetti i dati.

Ad ogni modo, riguardo alla tua domanda. La metrica più rilevante per valutare le prestazioni del tuo codice è Istruzioni/ciclo (IPC). La tua CPU può eseguire fino a 4 istruzioni/ciclo. Esegui solo 0.8. Ciò significa che le risorse sono sottoutilizzate, tranne nel caso in cui si abbiano molte istruzioni vettoriali. Dopo l'IPC è necessario controllare i fallimenti di ramo e le missioni L1 (dati e codice) perché questi generano la maggior parte delle penalità.

Un ultimo suggerimento: potresti essere interessato a provare l'amplificatore vTune di Intel. Fornisce una spiegazione molto migliore delle metriche e ti indirizza agli eventuali problemi nel codice.

+1

Le bancarelle VAndrei, BE e FE non sommeranno mai le istruzioni al 100% dei cicli, perché la maggior parte delle CPU Intel è superpollinata. Molte istruzioni possono essere in volo nella pipeline e alcune generano bancarelle; ma alcuni saranno giustiziati. Il 71% delle bancarelle FE è alto (hai molto codice che è complesso da decodificare?) E il 51% delle bancarelle di BE è piuttosto alto - quindi ci sono molti problemi ... koukouviou, puoi anche provare 'toplev.py' da [andikleen/pmu-tools (github)] (https://github.com/andikleen/pmu-tools) come palliativo gratuito per Vtune. – osgx

+0

koukouviou, 'toplev.py' descrizione dall'autore - http://halobates.de/blog/p/262 – osgx

+0

@osgx. Non ne sono così sicuro. Il limite FE significa che l'unità di prenotazione non è alimentata con istruzioni quindi nessuna porta di esecuzione ha lavoro da fare. Ciò è dovuto a errori di cache del codice, istruzioni complesse e cattiva speculazione. Se BE è alto, significa che le istruzioni mantengono attive le porte di esecuzione ma sono in attesa di risorse (dati o registri liberi) o hanno latenze elevate (ad esempio transcedentali). Ci dovrebbe essere un'altra metrica: # cicli di ritiro. Se guardi a vTune vedrai che FE + BE + Ritiro aggiunge sempre al 100%. – VAndrei