2016-04-30 2 views
4

Dans Is OpenMP (parallel for) in g++ 4.7 not very efficient? 2.5x at 5x CPU, j'ai déterminé que les performances de mon programme varient entre 11s et 13s (la plupart du temps toujours au-dessus de 12s, et parfois aussi lent que 13.4 s) à environ 500% CPU en utilisant le #pragma omp parallel for par défaut, et l'accélération OpenMP est seulement 2,5x à 5x CPU w/g++-4.7 -O3 -fopenmp, sur un Xeon 8-thread à 4 cœurs. J'ai essayé d'utiliser schedule(static) num_threads(4), et j'ai remarqué que mon programme se termine toujours en 11.5s à 11.7s (toujours en dessous de 12s) à environ 320% CPU, par exemple, fonctionne plus régulièrement et utilise moins de ressources (même si la meilleure exécution est une demi-seconde plus lentement que la valeur aberrante rare avec hyperthreading).OpenMP: n'utilisez pas les cœurs hyperthreading (moitié `num_threads()` w/hyperthreading)

Y at-il OpenMP-moyen simple de détecter hyperthreading et réduire num_threads() au nombre réel de cœurs de processeur?

(Il y a une question similaire, Poor performance due to hyper-threading with OpenMP: how to bind threads to cores, mais dans mes tests, je l'ai trouvé qu'une simple réduction de 8 à 4 fils en quelque sorte déjà fait ce travail avec/g ++ - 4.7 sur Debian 7 sifflante et Xeon E3-1240v3 , donc, cette question est simplement de réduire num_threads() au nombre de cœurs.)

+3

Non, il n'y a pas de façon simple de le faire entièrement automatique. Mais il y a http://stackoverflow.com/q/2901694/620382 + 'omp_set_num_threads'. Encore une fois, je recommande de contrôler manuellement la configuration des threads sur chaque système, si possible. – Zulan

+0

Pourquoi cette question a-t-elle été dépréciée ?! – cnst

Répondre

2

Si vous étiez sous Linux [en supposant également une arche x86], vous pouvez regarder /proc/cpuinfo. Il y a deux champs cpu cores et siblings. Le premier est le nombre de cœurs [réels] et le dernier est le nombre d'hyperthreads. (Par exemple sur mon système ils sont 4 et 8 respectivement pour ma machine hyperthreaded à quatre cœurs). Comme Linux peut le détecter [et à partir du lien dans le commentaire de Zulan], l'information est également disponible à partir de l'instruction x86 cpuid.

De toute façon, il y a aussi une variable d'environnement pour cela: OMP_NUM_THREADS qui peut être plus facile à utiliser conjointement avec un lanceur/script wrapper

Une chose que vous voudrez peut-être considérer est qu'au-delà d'un certain nombre de fils , vous pouvez saturer le bus mémoire, et aucune augmentation des threads [ou des cœurs] n'améliorera les performances et, en fait, réduira les performances.

De cette question: Atomically increment two integers with CAS il y a un lien vers une conversation vidéo à partir CppCon 2015 qui est en deux parties: https://www.youtube.com/watch?v=lVBvHbJsg5Y et https://www.youtube.com/watch?v=1obZeHnAwz4

Ils sont environ 1,5 heures chacune, mais l'OMI, valent la peine. Dans le discours, l'orateur [qui a fait beaucoup d'optimisation multithread/multicore] dit que, d'après son expérience, le bus mémoire/système a tendance à être saturé après environ quatre threads. Hyper-Threading est la mise en œuvre d'Intel de simultaneous multithreading (SMT)

0

Les processeurs AMD actuels n'implémentent pas SMT (la famille de la microarchitecture Bulldozer a autre chose qu'AMD appelle le multithreading basé sur les clusters mais la microarchitecture Zen est supposée avoir SMT). OpenMP n'a pas de support intégré pour détecter SMT. Si vous souhaitez qu'une fonction générale détecte Hyper-Threading, vous devez prendre en charge différentes générations de processeurs et vous assurer que le processeur est un processeur Intel et non AMD. Il est préférable d'utiliser une bibliothèque pour cela.

Mais vous pouvez créer une fonction en utilisant OpenMP qui fonctionne pour de nombreux processeurs Intel modernes comme je l'ai décrit here.

Le code suivant comptera le nombre de cœurs physiques sur un processeur Intel moderne (il a fonctionné sur tous les processeurs Intel sur lesquels je l'ai essayé). Vous devez lier les threads pour que cela fonctionne. Avec GCC vous pouvez utiliser export OMP_PROC_BIND=true sinon vous pouvez bind with code (ce que je fais).

Notez que je ne suis pas sûr que cette méthode soit fiable avec VirtualBox. Avec VirtualBox sur un CPU à 4 processeurs/8 processeurs logiques avec Windows comme Host et Linux, le nombre de cœurs pour la VM étant de 4, ce code rapporte 2 cœurs et/proc/cpuinfo montre que deux des cœurs sont des processeurs logiques.

#include <stdio.h> 

//cpuid function defined in instrset_detect.cpp by Agner Fog (2014 GNU General Public License) 
//http://www.agner.org/optimize/vectorclass.zip 

// Define interface to cpuid instruction. 
// input: eax = functionnumber, ecx = 0 
// output: eax = output[0], ebx = output[1], ecx = output[2], edx = output[3] 
static inline void cpuid (int output[4], int functionnumber) { 
#if defined (_MSC_VER) || defined (__INTEL_COMPILER)  // Microsoft or Intel compiler, intrin.h included 

    __cpuidex(output, functionnumber, 0);     // intrinsic function for CPUID 

#elif defined(__GNUC__) || defined(__clang__)    // use inline assembly, Gnu/AT&T syntax 

    int a, b, c, d; 
    __asm("cpuid" : "=a"(a),"=b"(b),"=c"(c),"=d"(d) : "a"(functionnumber),"c"(0) :); 
    output[0] = a; 
    output[1] = b; 
    output[2] = c; 
    output[3] = d; 

#else              // unknown platform. try inline assembly with masm/intel syntax 

    __asm { 
    mov eax, functionnumber 
     xor ecx, ecx 
     cpuid; 
    mov esi, output 
     mov [esi], eax 
     mov [esi+4], ebx 
     mov [esi+8], ecx 
     mov [esi+12], edx 
     } 

    #endif 
} 

int getNumCores(void) { 
    //Assuming an Intel processor with CPUID leaf 11 
    int cores = 0; 
    #pragma omp parallel reduction(+:cores) 
    { 
    int regs[4]; 
    cpuid(regs,11); 
    if(!(regs[3]&1)) cores++; 
    } 
    return cores; 
} 

int main(void) { 
    printf("cores %d\n", getNumCores()); 
}