3

Je viens d'écrire mon premier programme OpenMP qui parallélise une boucle simple. J'ai couru le code sur ma machine à deux cœurs et j'ai vu une accélération en passant de 1 thread à 2 threads. Cependant, j'ai couru le même code sur un serveur linux d'école et n'ai vu aucune accélération. Après avoir essayé différentes choses, je me suis finalement rendu compte que la suppression de certaines instructions printf inutiles entraînait une accélération significative du code. Ci-dessous la partie principale du code que je parallélisées:Pas d'accélération avec printf inutile utilisant OpenMP

#pragma omp parallel for private(i) 
for(i = 2; i <= n; i++) 
{ 
    printf("useless statement"); 
    prime[i-2] = is_prime(i); 
} 

Je suppose que la mise en œuvre de printf dispose d'une charge importante qui doit être OpenMP dédouble à chaque thread. Quelles sont les causes de ce surcoût et pourquoi OpenMP ne peut-il pas le surmonter?

+0

Impossible de résister; entendu parler du Prime Sieve? http://en.wikipedia.org/wiki/Generating_primes#Prime_sieves – Will

+0

Quel compilateur utilisez-vous? Quelle version? – osgx

Répondre

6

Spéculation, mais peut-être le stdout est-il protégé par un verrou?

En général, printf est une opération coûteuse car elle interagit avec d'autres ressources (telles que des fichiers, la console et autres). Mon expérience empirique est que printf est très lent sur une console Windows, comparativement beaucoup plus rapide sur la console Linux mais plus rapide s'il est redirigé vers un fichier ou/dev/null.

J'ai trouvé que le débogage printf peut sérieusement affecter les performances de mes applications, et je l'utilise avec parcimonie. Essayez d'exécuter votre application redirigée vers un fichier ou vers/dev/null pour voir si cela a un impact appréciable; cela aidera à affiner où le problème réside.

Bien sûr, si les printfs sont inutiles, pourquoi sont-ils dans la boucle?

+1

Les printf étaient là pour le débogage. – t2k32316

+1

Oui, la glibc protège les sorties stdout avec des verrous, car elle les tamponne. – osgx

3

Pour développer un peu @ réponse de Will ...

Je ne sais pas si stdout est gardée par une serrure, mais je suis assez sûr que l'écriture lui est sérialisé à un moment donné dans le logiciel empiler. Avec les instructions printf inclus OP est probablement chronométrer l'exécution d'un grand nombre d'écritures en série à stdout, pas l'exécution parallélisée de la boucle.

Je suggère OP modifie l'instruction printf pour inclure i, voir ce qui se passe. En ce qui concerne l'accélération apparente de la machine à deux noyaux, était-elle statistiquement significative?

+0

L'accélération apparente n'a pas été montrée d'une manière statistiquement forte. Je l'ai juste couru encore et ai eu plusieurs courses vont pendant environ 9 secondes avec 1 fil et 7 secondes avec 2 fils. Mais quand je l'ai exécuté sur les serveurs de mon école, il n'y avait aucune accélération apparente (jusqu'à ce que je me sois débarrassé des déclarations printf). Je suppose que ma question principale en ce moment est juste une question de curiosité: que se passe-t-il derrière les scènes avec printf qui empêcherait OMP de paralléliser une boucle for? Je suppose que c'est tout simplement comme vous l'avez dit: il doit être sérialisé par la suite ... – t2k32316

+1

+1; Will a raison de dire que printf() est une opération très coûteuse, mais cela aiderait à accélérer, toutes choses restant égales par ailleurs; Les tâches coûteuses et indépendantes se marient bien. La question cruciale est de savoir s'ils sont vraiment indépendants. Comme Mark l'indique, ils accèdent à une ressource partagée (stdout), donc à un certain niveau, finalement, le contenu doit être sérialisé et la sérialisation tue nécessairement les performances parallèles. –

0

Quels étaient vos horaires - était-ce beaucoup plus lent avec le printf? Dans certaines boucles serrées, le printf peut prendre une fraction importante du temps de calcul total; par exemple si is_prime() est assez rapide, et donc la performance est déterminée plus par le nombre d'appels à printf que par le nombre d'appels (parallélisés) à is_prime().

1

Vous avez ici une boucle parallèle, mais la planification n'est pas spécifiée.

#pragma omp parallel for private(i) 
for(i = 2; i <= n; i++) 

Certains types de planification sont définis dans la norme OpenMP 3.0.Ils peuvent être modifiés en réglant OMP_SCHEDULE variable d'environnement type[,chunk]

  • Type est l'un des statique, dynamique, guidé ou auto
  • morceau est une option positif nombre entier qui spécifie la taille du segment

Une autre façon de changer le type d'horaire est d'appeler la fonction openmp omp_set_schedule

La fonction is_prime peut être plutôt rapide./Je suggère/

prime[i-2] = is_prime(i); 

Ainsi, le problème peut provenait du mauvais mode de programmation, quand un petit nombre est exécuté avant que la barrière de la planification.

Et printf ont 2 parties à l'intérieur/je considérer glibc comme la mise en œuvre populaire Linux libc/

  1. Parse la chaîne de format et de mettre tous les paramètres dans le tampon
  2. tampon d'écriture au descripteur de fichier (au tampon FILE , en tant que sortie standard est tamponnée par glibc par défaut)

La première partie de printf peut se faire en parallèle, mais deuxième partie est une section critique et elle est verrouillée avec _IO_flockfile.