OpenACC Tutorial - Profiling/fr: Difference between revisions
No edit summary |
No edit summary |
||
Line 67: | Line 67: | ||
Le NVIDIA Visual Profiler peut être employé avec les applications OpenACC. C'est un outil d'analyse multiplateforme pour les instructions OpenACC et CUDA C/C++. | Le NVIDIA Visual Profiler peut être employé avec les applications OpenACC. C'est un outil d'analyse multiplateforme pour les instructions OpenACC et CUDA C/C++. | ||
[[File:Nvvp-pic1.png|thumbnail|300px|Localisez l'exécutable à profiler|left]] | [[File:Nvvp-pic1.png|thumbnail|300px|Localisez l'exécutable à profiler|left]] | ||
<br /> | <br /> |
Revision as of 18:11, 12 May 2017
- comprendre ce qu'est un profileur
- savoir utiliser PGPROF
- comprendre la performance du code
- savoir concentrer vos efforts et réécrire les routines qui exigent beaucoup de temps
Profiler du code
Pourquoi auriez-vous besoin de profiler du code? Parce que c'est la seule façon de comprendre
- comment le temps est employé aux points critiques (hotspots),
- comprendre la performance du code,
- savoir comment mieux employer votre temps.
Pourquoi est-ce important de connaitre les points critiques dans le code? D'après la loi d'Amdahl, paralléliser les routines qui exigent le plus de temps d'exécution (les points critiques) produit le plus d'impact.
Préparer le code pour l'exercice
Pour notre exemple, nous utilisons du code provenant de ces dépôts. Téléchargez les fichiers et utilisez les répertoires cpp ou f90. Le but de l'exercice est de compiler et lier le code et d'obtenir un exécutable que nous profilerons.
En date de mai 2016, relativement peu de compilateurs offraient les fonctionnalités d'OpenACC. Les plus avancés en ce sens sont les compilateurs du Portland Group de NVidia et ceux de Cray. Pour ce est qui de GNU, l'implémentation d'OpenACC dans la version 5 était expérimentale et devrait être complète dans la version 6.
Dans ce tutoriel, nous utilisons la version 16.3 des compilateurs du Portland Group qui sont gratuits pour des fins de recherche universitaire.
[name@server ~]$ make
pgc++ -fast -c -o main.o main.cpp
"vector.h", line 30: warning: variable "vcoefs" was declared but never
referenced
double *vcoefs=v.coefs;
^
pgc++ main.o -o cg.x -fast
Une fois l'exécutable créé, nous allons profiler le code.
Dans ce tutoriel, nous utilisons plusieurs des profileurs suivants :
- PGPROF : outil simple mais puissant pour l'analyse de programmes parallèles écrits avec OpenMP, OpenACC ou CUDA; rappelons que PGPROF est gratuit pour des fins de recherche universitaire.
- NVVP (NVIDIA Visual Profiler) : outil d'analyse multiplateforme pour des programmes écrits avec OpenACC et CUDA C/C++.
- NVPROF : version ligne de commande du NVIDIA Visual Profiler.
PGPROF
Ouvrez d'abord une nouvelle session PGPROF.
Localisez ensuite le fichier exécutable du code que vous voulez profiler.
Enfin, sélectionnez les options; par exemple, pour profiler l'activité du processeur, cochez Profile execution of the CPU.
NVVP
Le NVIDIA Visual Profiler peut être employé avec les applications OpenACC. C'est un outil d'analyse multiplateforme pour les instructions OpenACC et CUDA C/C++.
NVPROF ligne de commande
La version ligne de commande de NVPROF est semblable à GPU prof.
[name@server ~]$ nvprof --cpu-profiling on ./cgi.x
<Program output >
======== CPU profiling result (bottom up):
84.25% matvec(matrix const &, vector const &, vector const &)
84.25% main
9.50% waxpby(double, vector const &, double, vector const &, vector const &)
3.37% dot(vector const &, vector const &)
2.76% allocate_3d_poisson_matrix(matrix&, int)
2.76% main
0.11% __c_mset8
0.03% munmap
0.03% free_matrix(matrix&)
0.03% main
======== Data collected at 100Hz frequency
Renseignements sur le compilateur
Avant de travailler sur la routine, nous devons comprendre ce que fait le compilateur; posons-nous les questions suivantes :
- Quelles sont les optimisations qui ont été appliquées?
- Qu'est-ce qui a empêché d'optimiser davantage?
- La performance serait-elle affectée par les petites modifications?
Le compilateur PGI offre l'indicateur -Minfo avec les options suivantes :
- accel – liste des opérations du compilateur relativement à l'accélérateur
- all – résultats en sortie du compilateur
- intensity – renseignements sur l'intensité de la boucle
- ccff – ajout de renseignements aux fichiers objet pour utilisation future
Obtenir les renseignements sur le compilateur
- Éditez le Makefile.
CXX=pgc++ CXXFLAGS=-fast -Minfo=all,intensity,ccff LDFLAGS=${CXXFLAGS}
- Effectuez un nouveau build.
[name@server ~]$ make
pgc++ CXXFLAGS=-fast -Minfo=all,intensity,ccff LDFLAGS=-fast -fast -c -o main.o main.cpp
"vector.h", line 30: warning: variable "vcoefs" was declared but never
referenced
double *vcoefs=v.coefs;
^
_Z17initialize_vectorR6vectord:
37, Intensity = 0.0
Memory set idiom, loop replaced by call to __c_mset8
_Z3dotRK6vectorS1_:
27, Intensity = 1.00
Generated 3 alternate versions of the loop
Generated vector sse code for the loop
Generated 2 prefetch instructions for the loop
_Z6waxpbydRK6vectordS1_S1_:
39, Intensity = 1.00
Loop not vectorized: data dependency
Loop unrolled 4 times
_Z26allocate_3d_poisson_matrixR6matrixi:
43, Intensity = 0.0
44, Intensity = 0.0
Loop not vectorized/parallelized: loop count too small
45, Intensity = 0.0
Loop unrolled 3 times (completely unrolled)
57, Intensity = 0.0
59, Intensity = 0.0
Loop not vectorized: data dependency
_Z6matvecRK6matrixRK6vectorS4_:
29, Intensity = (num_rows*((row_end-row_start)* 2))/(num_rows+(num_rows+(num_rows+((row_end-row_start)+(row_end-row_start)))))
33, Intensity = 1.00
Unrolled inner loop 4 times
Generated 2 prefetch instructions for the loop
main:
61, Intensity = 16.00
Loop not vectorized/parallelized: potential early exits
pgc++ CXXFLAGS=-fast -Minfo=all,intensity,ccff LDFLAGS=-fast main.o -o cg.x -fast
Intensité computationnelle
L'intensité computationnelle d'une boucle représente la quantité de travail accompli par la boucle en fonction des opérations effectuées en mémoire.
intensité computationnelle = opérations de calcul / opérations en mémoire
Une valeur de 1 ou plus indique que la boucle serait bien exécutée sur un processeur graphique (GPU).
Comprendre le code
Regardons attentivement le code suivant :
for(int i=0;i<num_rows;i++) {
double sum=0;
int row_start=row_offsets[i];
int row_end=row_offsets[i+1];
for(int j=row_start; j<row_end;j++) {
unsigned int Acol=cols[j];
double Acoef=Acoefs[j];
double xcoef=xcoefs[Acol];
sum+=Acoef*xcoef;
}
ycoefs[i]=sum;
}
On trouvera les dépendances de données en se posant les questions suivantes :
- Une itération en affecte-t-elle d'autres?
- Les itérations lisent-elles ou écrivent-elles à des endroits différents du même tableau?
- Est-ce que sum est une dépendance? Non, c'est une réduction.