Sto sviluppando un codice di moltiplicazione della matrice denso di grandi dimensioni. Quando registro il codice, a volte ottiene circa il 75% dei picchi del mio sistema a quattro core e altre volte il 36% circa. L'efficienza non cambia tra le esecuzioni del codice. Inizia al 75% e continua con quell'efficienza o inizia al 36% e continua con quell'efficienza.Prestazioni scarse a causa di hyper-threading con OpenMP: come eseguire il binding dei thread ai core
Ho tracciato il problema fino all'hyper-threading e il fatto che ho impostato il numero di thread su quattro invece che su quello predefinito. Quando disattivo l'hyper-threading nel BIOS ottengo un'efficienza del 75% costante (o almeno non vedo mai il drastico calo del 36%).
Prima di chiamare qualsiasi codice parallelo faccio omp_set_num_threads(4)
. Ho anche provato export OMP_NUM_THREADS=4
prima di eseguire il mio codice ma sembra essere equivalente.
Non voglio disabilitare l'hyper-threading nel BIOS. Penso di aver bisogno di legare i quattro fili ai quattro core. Ho testato alcuni casi diversi di GOMP_CPU_AFFINITY
ma finora ho ancora il problema che l'efficienza è del 36% a volte. Che cos'è il mapping con hyper-threading e core? Es. thread 0 e thread 1 corrispondono allo stesso core e thread 2 e thread 3 a un altro core?
Come si possono associare i thread a ciascun core senza migrazione di thread in modo da non dover disabilitare l'hyper-threading nel BIOS? Forse ho bisogno di esaminare usando sched_setaffinity?
Alcuni dettagli del mio sistema attuale: kernel Linux 3.13, GCC 4.8, Intel Xeon E5-1620 (quattro core fisici, otto hyper-thread).
Edit: Questo sembra funzionare bene finora
export GOMP_CPU_AFFINITY="0 1 2 3 4 5 6 7"
o
export GOMP_CPU_AFFINITY="0-7"
Edit: Questo sembra anche funzionare bene
export OMP_PROC_BIND=true
Edit: These options funziona anche bene (gemm è il nome della mia eseguibile)
numactl -C 0,1,2,3 ./gemm
e
taskset -c 0,1,2,3 ./gemm
Poiché export GOMP_CPU_AFFINITY = "0 1 2 3 4 5 6 7" dà buoni risultati, suppongo che significhi che il thread 0 e 4 sono core 0, thread 1 e 5 core2, ... cioè i thread sono assegnati come elettroni in orbitali. Prima riempie ogni core (thread 0-3) e quando tutti i core hanno un thread torna indietro e assegna i thread rimanenti allo stesso core (thread 4-7). –
Entrambi 'hwloc-ls' dalla libreria hwloc o' cpuinfo' da Intel MPI forniscono informazioni di topologia essenziali sulla macchina, ad es. mappatura dei numeri logici della CPU in core/thread fisici. La numerazione dipende dal BIOS, ma nella mia esperienza la maggior parte dei casi ha riguardato il fatto che gli hyperthread sono ciclicati in un "ciclo esterno". Inoltre, puoi usare la notazione di stenografia '" 0-7 "'. –
@HristoIliev, per la portabilità sembra il modo giusto per farlo è utilizzare OMP_PLACES, ad es. 'Esporta OMP_PLACES = core da OpenMP4.0. Sui sistemi AMD ogni modulo ha solo una FPU ma ottiene due thread e penso che sia assegnato linearmente https://stackoverflow.com/questions/19780554/what-limits-scaling-in-this-simple-openmp-program/19871592#19871592 così facendo GOMP_CPU_AFFINITY = "0-7" non funzionerà, penso. In realtà, OMP_PROC_BIND = true potrebbe andare bene anche allora. Forse è la soluzione migliore. –