8 votes

Les threads OpenMP s'exécutent sur le même cœur de processeur.

Je suis actuellement en train de paralléliser un programme en utilisant openmp sur un phenom2 à 4 cœurs. Cependant, j'ai remarqué que ma parallélisation ne fait rien pour les performances. Naturellement, j'ai supposé que j'avais manqué quelque chose (falsesharing, sérialisation par les verrous, ...), mais je n'ai rien trouvé de tel. De plus, d'après l'utilisation du CPU, il semble que le programme ait été exécuté sur un seul cœur. D'après ce que j'ai trouvé sched_getcpu() devrait me donner l'Id du noyau sur lequel le thread exécutant l'appel est actuellement planifié. J'ai donc écrit le programme de test suivant :

#include <iostream>
#include <sstream>
#include <omp.h>
#include <utmpx.h>
#include <random>
int main(){
    #pragma omp parallel
    {
        std::default_random_engine rand;
        int num = 0;
    #pragma omp for
        for(size_t i = 0; i < 1000000000; ++i) num += rand();
    auto cpu = sched_getcpu();
    std::ostringstream os;
        os<<"\nThread "<<omp_get_thread_num()<<" on cpu "<<sched_getcpu()<<std::endl;
        std::cout<<os.str()<<std::flush;
    std::cout<<num;
    }
}

Sur ma machine, cela donne le résultat suivant (les nombres aléatoires varient bien sûr) :

Thread 2 on cpu 0 num 127392776
Thread 0 on cpu 0 num 1980891664
Thread 3 on cpu 0 num 431821313
Thread 1 on cpu 0 num -1976497224

A partir de là, je suppose que tous les threads s'exécutent sur le même noyau (celui qui a l'id 0). Pour être plus sûr, j'ai également essayé l'approche de cette réponse . Les résultats ont été les mêmes. De plus, en utilisant #pragma omp parallel num_threads(1) n'a pas rendu l'exécution plus lente (légèrement plus rapide en fait), ce qui donne de la crédibilité à la théorie selon laquelle tous les threads utilisent le même cpu, cependant le fait que le cpu soit toujours affiché comme 0 me rend un peu suspicieux. De plus, j'ai vérifié GOMP_CPU_AFFINITY qui n'était pas défini initialement, j'ai donc essayé de le définir sur 0 1 2 3 ce qui devrait lier chaque fil à un noyau différent d'après ce que je comprends. Cependant, cela n'a pas fait de différence.

Comme je développe sur un système Windows, j'utilise linux en virtualbox pour mon développement. J'ai donc pensé que le système virtuel ne pouvait peut-être pas accéder à tous les cœurs. Cependant, en vérifiant les paramètres de virtualbox, j'ai constaté que la machine virtuelle devait avoir accès aux 4 cœurs et l'exécution de mon programme de test 4 fois en même temps semble utiliser les 4 cœurs à en juger par l'utilisation du processeur (et le fait que le système devenait très peu réactif).

Ma question est donc de savoir ce qui se passe exactement ici. Plus précisément : Ma déduction selon laquelle tous les threads utilisent le même noyau est-elle correcte ? Si c'est le cas, quelles pourraient être les raisons de ce comportement ?

6voto

Grizzly Points 11329

Après quelques expériences, j'ai découvert que le problème venait du fait que je démarrais mon programme à partir de l'IDE d'Eclipse, ce qui semblait régler l'affinité pour n'utiliser qu'un seul cœur. Je pensais avoir les mêmes problèmes en démarrant à partir de l'extérieur de l'IDE, mais un test répété a montré que le programme fonctionne très bien, lorsqu'il est lancé à partir du terminal au lieu de l'intérieur de l'IDE.

2voto

baol Points 2291

J'ai compilé votre programme en utilisant g++ 4.6 sous Linux.

g++ --std=c++0x -fopenmp test.cc -o test

Le résultat était, sans surprise :

Thread 2 on cpu 2

Thread 3 on cpu 1
910270973
Thread 1 on cpu 3
910270973
Thread 0 on cpu 0
910270973910270973

Le fait que 4 threads soient lancés (si vous n'avez pas défini le nombre de threads d'une quelconque manière, par exemple en utilisant OMP_NUM_THREADS) devrait impliquer que le programme est capable de voir 4 CPU utilisables. Je ne peux pas deviner pourquoi il ne les utilise pas, mais je soupçonne un problème dans les paramètres de votre matériel/logiciel, dans une variable d'environnement ou dans les options du compilateur.

0voto

Nav Points 3105

Vous devez utiliser #pragma omp parallel for
Et oui, vous avez raison de ne pas avoir besoin de OMP_NUM_THREADS. omp_set_num_threads(4); aurait également fait l'affaire.

0voto

Krishnaraj Points 421

Si vous êtes sous Windows, essayez ceci :

c : \windows\system32\cmd.exe /C start /affinity F path \to\your\program.exe

/affinité 1 utilise CPU0

/affinity 2 utilise CPU1

/affinité 3 utilise CPU0 et CPU1

/affinity 4 utilise le CPU2

/affinité F utilise les 4 cœurs

Convertissez le nombre en hexadécimal, et voyez les bits de droite qui sont les cœurs à utiliser.

vous pouvez vérifier l'affinité pendant qu'il fonctionne en utilisant le gestionnaire de tâches.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X