Top Banner
Programmation Parallèle sur CPU et GPU (GPU=Graphics Processing Unit) [email protected] www.labri.fr/perso/guenneba/pghp_IO16
39

Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

Sep 16, 2018

Download

Documents

nguyenkhue
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

Programmation Parallèlesur CPU et GPU

(GPU=Graphics Processing Unit)

[email protected]

www.labri.fr/perso/guenneba/pghp_IO16

Page 2: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

2

Plan du cours

• Motivations pour le parallélisme et les GPUs– single core → multi-core → many-core

• CPU– Architecture– Modèle de programmation en mémoire partagé

• OpenMP

• GPU (Graphics Processing Unit)– Architecture– Modèle de programmation many-core

• CUDA

Page 3: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

3

Objectifs

• Acquérir les bases pour

– éviter les erreurs de bases dans vos propres codes

• poursuivre en auto-formation au besoin

– échanger avec des spécialistes

– savoir comparer deux solutions matérielles

• savoir adapter le matériel aux besoins

Page 4: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

4

Motivations applicatives

• Toujours plus de performance...– plus rapide : de x10 à x100 ou plus !!– résoudre des problèmes plus gros– plus de précisions– rendre possible de nouvelles applications, nouveaux algorithmes– réduire la consommation– etc.

Page 5: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

5

Motivations applicatives

• Exemples :– Simu électromag, en un point : intégration 4D

• Code initial en (mauvais) MatLab : 20min

• Code optimisé / CPU : 0.5s !!

– Simu sur GPU via MatLab : a life changer !→ utilisation de CUDA en 3A-voie B (simu)

– 3A-voie A (instrumentation) :

• Embarqué– traitement/reconstruction efficace des données...

• Free-form optics

Page 6: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

6

Code optimisé et consommation énergétique

• Exemple sur un smartphone :

conso

nombre d'opérations (+,*,etc.)

Page 7: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

7

Comment augmenter les performances ?

→ Améliorer les algorithmes(voir autres cours)

→ Augmenter la puissance de calcul ?→ Comment ?→ Comment exploiter cette puissance ?

Page 8: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

8

Loi de Moore...

• Le nombre de transistors qui peut être intégré facilement dans un microprocesseur double tout les deux ans

Page 9: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

9

Motivations pour le multi-cores

• Finesse de gravure– 32nm en 2010, 22nm en 2012, 14nm en 2014, …– demain : 10nm

→ plus de transistors par circuit

• Leviers pour augmenter les performances– avec un seul processeur :

• augmenter la fréquence ?– difficile, consommation++, chaleur++

• augmenter la complexité des processeurs– opérations spécialisées, logique (ex. prédiction de branchement),

cache, etc.– x2 logic → x1.4 performance (Pollack's rule)

!! vidéo !!

Page 10: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

10

Motivations pour le multi-cores

• Leviers pour augmenter les performances (cont.)– multiplier le nombre d'unités de calcul :

• parallélisme au niveau des instructions – out-of-order execution, pipelining

→ difficile (beaucoup de logique) et limité

• parallélisme au niveau des données (SIMD)– une seule instruction appliquée sur plusieurs registres– unités vectorielles : SSE, AVX, NEON, Cell SPE, (GPU)– efficace pour certaines applications, mais relativement

difficile à exploiter et reste limité

• parallélisme au niveau des threads– mettre plusieurs processeurs cote-à-cote

sur un même chip○ multi-core, many-core (>100)

– multi-processor : plusieurs chip sur une mêmecarte mère

un seulcoeur

Page 11: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

11

Motivations pour le multi-cores

• Plusieurs processeurs par circuits, plusieurs circuits par carte– réels gains théoriques:

• 2 « petits » processeurs → x1.8 perf

• 1 processeur 2 fois plus gros → x1.4 perf– consommation et dissipation de chaleur réduite

• N processeurs légèrement plus lents consomment autant qu'un seul rapide

• activation individuelle des processeurs– accès mémoires

• plusieurs CPU peuvent accéder en même temps à la mémoire

• permet d'augmenter la bande passante– même sans en réduire la latence

– simplicité

• plus simple de concevoir et fabriquer pleins de « petits » CPU simples,qu'un seul gros et complexe

→ améliore également la robustesse et absence de pannes/bugs

Page 12: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

12

Motivations pour le multi-cores

→ multi-core everywhere– CPU– GPU– super-calculateur– systèmes embarqués– smart-phones

embarqué (ex. Jetson)(4 cœurs CPU

+ 200-300 cœurs GPU)[↔ supercalculateur en 2000]

carte graphique(GPU :1000-3000 coeurs)

co-processeur dédié(GPU ou centaine de CPUs)

serveur

Page 13: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

13

mais...

• Programmer est difficile...

• Programmer parallèle est encore plus difficile !– trouver des tâches pouvant être exécuter en même temps– coordination entre les tâches, éviter les surcoûts...

Page 14: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

Architecture des CPUs

Page 15: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

15

CPU – Hiérarchie mémoire

regs

Cache - L1

Cache - L2

ALU

RAM (NUMA)

x100 bigger (90x90 floats) ; 1-4 cycles

x100 bigger (900x900 floats) ; 40-100 cycles

x1000 bigger ; ~400 cycles

small (8x8 floats) ; 1 cycle

Page 16: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

16

CPU - Parallélisme

• 3 niveaux de parallélisme :

1 – parallélisme au niveau des instructions

2 – SIMD – Single Instruction Multiple Data

3 – multi/many-cores – multi-threading

→ mécanismes complémentaires

Page 17: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

17

CPU – Parallélisme 1/3

• parallélisme au niveau des instructions– pipelining

• une opération = une unité de calcul (ex : addition)

• opération décomposée en plusieurs sous-taches– une sous-unité par sous-tache– 1 cycle par sous-tache

→ plusieurs opérations peuvent s'enchainer sur une même unité→ requière des instructions non dépendantes !

1op = 4 mini ops = 4 cycles

4 ops in 7 cycles !

time

a = a * b;c = c * d;e = e * f;g = g * h;

[démo]

Page 18: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

18

CPU – Parallélisme 1/3In-order / Out-of-order

• In-order processors– instruction fetch– attendre que les opérandes soient prêtes

• dépendances avec les opérations précédentes ou temps d'accès mémoire/caches– exécuter l'instruction par l'unité respective

• Out-of-orders processors– instruction fetch– mettre l'instruction dans une file d'attente– dès que les opérandes d'une des instructions de la file d'attente sont prêtes,

exécuter l'instruction par l'unité respective– couplée à la prédiction de branchement...

→ réduit les temps où le processeur est en attente

→ simplifie le travail du développeur/compilateur :)

→ requière des instructions non dépendantes

Page 19: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

19

CPU – Parallélisme 2/3

• SIMD → Single Instruction Multiple Data– Principe : exécuter la même opération sur plusieurs données en même temps– Jeux d'instructions vectoriels, ex :

• SSE (x86) : registres 128 bits (4 float, 2 double, 4 int)

• AVX (x86) : registres 256 bits (8 float, 4 double, 8 int)

• NEON (ARM) : registres 128 bits (4 float, 4 int)

• ...

4

-1

-6

2

-3

5

-2

4

* →

-12

-5

12

8

reg0 reg1 reg2

Page 20: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

20

CPU – Parallélisme 2/3SIMD

• Mise en oeuvre pratique, 3 possibilités :– vectorisation explicite via des fonctions « intrinsics » (pour les experts)– utiliser des bibliothèques tierces et optimisées– believe in your compiler !

• Nombreuses limitations :– réaliser des opérations intra-registres est difficile et très couteux– les données doivent être stockées séquentiellement en mémoire

• (voir slide suivant)

Page 21: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

21

CPU – Parallélisme 2/3SIMD

mémoire

fast(aligned)

slower(not aligned) don't be silly!

Page 22: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

22

CPU – Parallélisme 2/3SIMD

• Exemple de stockage pour des points 3D:

– Array of Structure (AoS)struct Vec3 { float x, y, z;} ;Vec3 points[100] ;

→ not SIMD friendly

– Structure of Arrays (SoA)struct Points { float x[100]; float y[100]; float z[100];};Points points;

[démo]

Page 23: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

23

CPU – Parallélisme 3/3

• multi/many-cores– Principe : chaque cœur exécute son propre flot d'instruction (=thread)

• thread = « processus léger »

• un thread par cœur à la fois

• assignation et ordonnancement par l'OS

• les threads communiquent via la mémoire partagée– mise en œuvre, ex :

• bibliothèques tierces

• via le compilateur et OpenMP(instrumentation du code)

– hyper-threading

• assigner deux threads sur unmême cœur

• exécution alternée au niveaudes instructions

• permet un meilleur tauxd'utilisation des unitées

• parfois contre-productifs !

PC

shared memory

CPU1 CPU2 CPUn...

Page 24: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

24

Peak performance

• Example : Intel i7 Quad CPU @ 2.6GHz (x86_64,AVX,FMA)

– pipelining/OOO → 2 * (mul + add) / cycle (cas idéal)– AVX → x 8 ops simple précision à la fois– multi-threading → x 4– fréquence → x 2.6G

→ peak performance: 332.8 GFlops

Page 25: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

26

Programmation multi-threadavec mémoire partagé

-

OpenMP

Page 26: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

27

Programmation multi-threads

• Très nombreuses approches, différents paradigmes– exemples de modèles :

• Google's « map-reduce » → divide and conquer

• Nvidia's data parallelism → big homogeneous array

• Erlang's fonctional programming → side-effect free

• OpenMP– intégré au compilateur– instrumentation manuelle du code

• en C/C++ via : #pragma omp ...– + ensembles de fonctions...– fournit différents outils et paradigmes

→ flexibilité

Page 27: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

28

OpenMP – premier exemple

• Exécuter un même bloc par plusieurs threads :

… et premières difficultés !– ici tous les threads accèdent de manière concurrentielle à la même ressource

(la sortie standard)– solution :

• autoriser un seul thread à la fois→ section critique via #pragma omp critical

#pragma omp parallel{ // on récupère le numéro du thread // (entre 0 et nombre_total_de_thread-1) int i = omp_get_thread_num();

cout << "Thread #" << i << " says hello!\n";}

[démo]

Page 28: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

29

OpenMP – 2ème exemple

• Paralléliser une boucle

– les m itérations de la boucles sont réparties entre les N threads

• une itération est exécutée une seule fois et par un seul thread

• un thread traite une seule itération à la fois– nombreuses stratégie d'affectation

• ex. : statique ou dynamique

• Exercice :– comment calculer le produit scalaire en un vecteur B et tous les éléments d'un

tableau

• ex, conversion d'une image RGB en Luminance, projection de m points sur un plan, etc.

→ quelles taches peuvent être effectuées en parallèle ?

#pragma omp parallel forfor(int i=0 ; i<m ; ++i){ ...}

[démo]

Page 29: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

30

OpenMP – 3ème exemple

• Exercice :– comment calculer la somme des éléments d'un tableau en parallèle ?

→ quelles taches peuvent être effectuées en parallèle ?

• Race condition

race condition(résultat différent en fonction

de l'ordre d'exécution)

correct behavior(critical section ou atomic)

Page 30: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

31

Atomic operations

• Principe– opération ou ensemble d'opérations s'exécutant sans pouvant être interrompues

• pour le reste du système : comme si son exécution était instantanée– nécessitent des mécanismes de synchronisation

misent en œuvre au niveau du matériel

• Exemples– Read-Write– Fetch-and-add

– Test-and-set

– Compare-and-swap

int test_and_set (int *val){ int old = *val; *val = 1; return old;}

x = x + a ;

Page 31: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

Comment paralléliserson code et ses algorithmes ?

• Dépend de nombreux facteurs– Nature du problème– Dimensions du problème– Matériel visé

→ Pas de solution universelle

→ Pas de solution automatique (compilateur)

• Acquérir de l'expérience– étudier des cas « simples »– retrouver des motifs connus au sein d'applications complexes

Page 32: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

Défis

• Trouver et exploiter la concurrence1 - identifier les taches indépendantes → approche hiérarchique2 - regrouper les taches → trouver la bonne granularité

→ regarder le problème sous un autre angle• Computational thinking (J. Wing)

• nombreuses façons de découper un même problème en taches

• Identifier et gérer les dépendances– Dépend du découpage !– Coordination entre les tâches (avoid races and deadlocks)

• éviter les attentes

Page 33: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

Défis

• Autres facteurs de performance :– Contrôler les surcouts

• limiter les échanges de données

• limiter les calculs supplémentaires– Équilibrer la charge de chaque unité– Saturation des ressources (bande-passante mémoire)

• Avant toute optimisation :– avoir un code qui fonctionne !– identifier les taches couteuses ! (on peut avoir des surprises)– penser à la complexité algorithmique !

Page 34: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

Qques motifs de parallélisationMap & Reduce

• « Map »– appliquer la même fonction à chacun des éléments d'un tableau– parallélisme évident : chaque élément peut être traité par un thread différent

• surjection de l'ensemble des M éléments → l'ensemble des N threads

• scheduling static– 1 thread ↔ un bloc de M/N éléments– ou 1 thread ↔ les éléments d'indices i*N

• scheduling dynamic– dès qu'un thread est libre, l'associer au premier élément non traité

• « Reduce » ou « Reduction »– réduire un tableau (ou sous-tableau) à une seule valeur

• Exemples : somme, produit, min, max, etc. (moyenne, calcul intégral,etc.)

• Si faible nombre de threads N : découper le problème en N sous problèmes puis réduire les N valeurs en 1 de manière séquentielle.→ généralisation à une approche hiérarchique

Page 35: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

Exemple : sampling et histogramme

• Approche séquentielle

RandomNumber

Generator

CDF 2D

MainThread

DestinationImage

for i=1..M { (x,y) = cdf.inverse(random(),random()); img(x,y) += incr;}

Page 36: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

Exemple : sampling et histogramme

• Multi-threading naif

RandomNumber

Generator

CDF 2D

DestinationImage

#pragma omp parallel forfor i=1..M { (x,y) = cdf.inverse(random(),random()); img(x,y) += incr;}

#T

#1

#2

Read-write→ critical section (bad)

Read-only

Read-onlymais variable d'étatinterne RW→ critical section (bad)

...

Page 37: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

Exemple : sampling et histogramme

• Multi-threading V1

RNG[1]

CDF 2D

DestinationImage

#pragma omp parallel forfor i=1..M { (x,y)=cdf.inverse(rng[tid].val(),rng[tid].val()); #pragma omp atomic img(x,y) += incr;}

#T

#1

#2

Read-write→ ou atomic (~OK)

→ 1 RNG/thread

RNG[2]

RNG[T]

......

Page 38: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

Exemple : sampling et histogramme

• Multi-threading V2

RNG[1]

CDF 2D

#T

#1

#2

→ 1 RNG/thread

RNG[2]

RNG[T]

Img[1]

Img[T]

Img[2]

...... ...Destination

Image∑

Cout mémoire :

Seconde passe→ parallel for

→ O ( N 2TT )

N 2TO (M /T ) , M≈N 2

Page 39: Programmation Parallèle sur CPU et GPU - labri.fr · • en C/C++ via : #pragma omp ... ... (résultat différent en fonction de l'ordre d'exécution) correct behavior (critical

Exemple : sampling et histogramme

• Multi-threading optimisé :

RNG[1]

CDF Y

#T

#1

#2RNG[2]

RNG[T]

...... ...

DestinationImage

Cout mémoire :

Découper l'image par thread→ nombreuses variantes→ ex : remplir ligne par ligne → meilleure cohérence des caches :) → nombre d'échantillons par ligne variable → scheduling dynamic

O (M /T )N T≪N 2

cpt[1]

cpt[2]

cpt[T]

cpt

Passe 1 : générer le nombre de samples par ligne (et par thread)

Passe 2 : sommerles compteursO ((N T )/T )

RNG[1]

#T

#1

#2RNG[2]

RNG[T]

......CDF X

Passe 3 : remplirligne par ligne,1 thread par ligne

O (M /T )