web-dev-qa-db-fra.com

Parallèle pour vs omp simd: quand les utiliser?

OpenMP 4. introduit une nouvelle construction appelée "omp simd". Quel est l'avantage d'utiliser cette construction par rapport à l'ancien "parallèle pour"? Quand est-ce que chacun serait un meilleur choix par rapport à l'autre?

EDIT: Voici un intéressant papier lié à la directive SIMD.

50
zr.

La norme liée à est relativement claire (p 13, lignes 19 + 20)

Lorsqu'un thread rencontre une construction simd, les itérations de la boucle associée à la construction peuvent être exécutées par les voies SIMD disponibles pour le thread.

SIMD est une chose sous-thread. Pour le rendre plus concret, sur un CPU, vous pouvez imaginer utiliser des directives simd pour demander spécifiquement la vectorisation de morceaux d'itérations de boucle qui appartiennent individuellement sur le même thread . Il expose les multiples niveaux de parallélisme qui existent dans un seul processeur multicœur, d'une manière indépendante de la plate-forme. Voir par exemple la discussion (avec l'accélérateur) sur ce intel blog post .

Donc, en gros, vous voudrez utiliser omp parallel pour distribuer le travail sur différents threads, qui peuvent ensuite migrer vers plusieurs cœurs; et vous voudrez utiliser omp simd pour utiliser des pipelines vectoriels (par exemple) dans chaque noyau. Normalement omp parallel irait "à l'extérieur" pour gérer une distribution parallèle plus grossière du travail et omp simd ferait le tour de boucles serrées à l'intérieur de celui-ci pour exploiter le parallélisme à grain fin.

40
Jonathan Dursi

Une réponse simple:

OpenMP n'est utilisé que pour exploiter plusieurs threads pour plusieurs cœurs. Cette nouvelle extension simd vous permet d'utiliser explicitement les instructions SIMD sur les processeurs modernes, tels que AVX/SSE d'Intel et NEON d'ARM.

(Notez qu'une instruction SIMD est exécutée dans un seul thread et un seul noyau, par conception. Cependant, la signification de SIMD peut être assez étendue pour GPGPU. Mais, mais je ne pense pas que vous ayez besoin de considérer GPGPU pour OpenMP 4.0. )

Ainsi, une fois que vous connaissez les instructions SIMD, vous pouvez utiliser cette nouvelle construction.


Dans un processeur moderne, il existe à peu près trois types de parallélisme: (1) le parallélisme au niveau de l'instruction (ILP), (2) le parallélisme au niveau du thread (TLP) et (3) les instructions SIMD (on pourrait dire que c'est au niveau du vecteur) ou alors).

ILP est effectué automatiquement par vos CPU ou compilateurs hors service. Vous pouvez exploiter TLP en utilisant parallel for Et d'autres bibliothèques de threads d'OpenMP. Alors, qu'en est-il de SIMD? Les intrinsèques étaient un moyen de les utiliser (ainsi que la vectorisation automatique des compilateurs). simd d'OpenMP est une nouvelle façon d'utiliser SIMD.

Prenons un exemple très simple:

for (int i = 0; i < N; ++i)
  A[i] = B[i] + C[i];

Le code ci-dessus calcule une somme de deux vecteurs à N dimensions. Comme vous pouvez facilement le voir, il n'y a pas de (boucle-transportée) dépendance des données sur le tableau A[]. Cette boucle est parallèle embarrassante .

Il pourrait y avoir plusieurs façons de paralléliser cette boucle. Par exemple, jusqu'à OpenMP 4.0, cela peut être parallélisé en utilisant uniquement la construction parallel for. Chaque thread exécutera N/#thread Itérations sur plusieurs cœurs.

Cependant, vous pourriez penser que l'utilisation de plusieurs threads pour un ajout aussi simple serait une exagération. C'est pourquoi il y a la vectorisation, qui est principalement implémentée par les instructions SIMD.

Utiliser un SIMD serait comme ceci:

for (int i = 0; i < N/8; ++i)
  VECTOR_ADD(A + i, B + i, C + i);

Ce code suppose que (1) l'instruction SIMD (VECTOR_ADD) Est de 256 bits ou 8 voies (8 * 32 bits); et (2) N est un multiple de 8.

Une instruction SIMD à 8 voies signifie que 8 éléments d'un vecteur peuvent être exécutés dans une seule instruction machine. Notez que le dernier AVX d'Intel fournit de telles instructions vectorielles à 8 voies (32 bits * 8 = 256 bits).

Dans SIMD, vous utilisez toujours un seul cœur (encore une fois, ce n'est que pour les processeurs conventionnels, pas GPU). Mais, vous pouvez utiliser un parallélisme caché dans le matériel. Les processeurs modernes consacrent des ressources matérielles aux instructions SIMD, où chaque SIMD lane peut être exécuté en parallèle.

Vous pouvez utiliser le parallélisme au niveau du thread en même temps. L'exemple ci-dessus peut être davantage parallélisé par parallel for.

(Cependant, j'ai un doute sur le nombre de boucles qui peuvent être réellement transformées en boucles SIMDized. La spécification OpenMP 4.0 semble un peu floue à ce sujet. Ainsi, les performances réelles et les restrictions pratiques dépendraient des implémentations réelles des compilateurs.)


Pour résumer, la construction simd vous permet d'utiliser des instructions SIMD, à son tour, plus de parallélisme peut être exploité avec le parallélisme au niveau du thread. Cependant, je pense que les implémentations réelles importent.

42
minjang

Les compilateurs ne sont pas tenus de rendre l'optimisation simd dans une région parallèle conditionnelle à la présence de la clause simd. Les compilateurs que je connais continuent de prendre en charge les boucles imbriquées, parallèles externes, vectorielles internes, de la même manière qu'auparavant.
Dans le passé, les directives OpenMP étaient généralement utilisées pour empêcher les optimisations de commutation de boucle impliquant la boucle parallélisée externe (plusieurs boucles avec clause de repli). Cela semble avoir changé dans quelques compilateurs. OpenMP 4 ouvre de nouvelles possibilités, y compris l'optimisation d'une boucle externe parallèle avec une boucle interne non vectorisable, par une sorte d'exploration de bande, lorsque omp parallel do [for] simd est défini. ifort la signale parfois comme vectorisation de boucle externe lorsqu'elle est effectuée sans la clause simd. Il peut alors être optimisé pour un plus petit nombre de threads que le parallèle omp do simd, qui semble avoir besoin de plus de threads que la largeur du vecteur simd pour payer. Une telle distinction pourrait être inférée, car, sans la clause simd, le compilateur est implicitement invité à optimiser pour un nombre de boucles tel que 100 ou 300, tandis que la clause simd demande une optimisation simd inconditionnelle. gcc 4.9 omp parallel pour simd avait l'air assez efficace quand j'avais une plateforme à 24 cœurs.

1
tim18