====== Installation de Par4All sous Debian Wheezy ======
Cette page présente l'installation de par4all pour les versions 1.4 de Par4All.
===== Contexte =====
Comment facilement paralléliser les codes que nous avons à disposition pour exploiter les derniers développements matériels à notre disposition (multi-coeurs, GPU) ?
Par4All exploite un outil déjà vieux (et éprouvé) analysant le code et le transformant pour permettre d'effectuer pour nous ce travail de portage : PIPS.
Ses avantages sont nombreux :
* il est Open Source
* il est simple à installer
* il est simple à utiliser
* il est français (voire breton)
===== Installation =====
==== Préparation du système ====
apt-get install libncurses5 libreadline6 python ipython cproto indent flex bison automake libtool autoconf libreadline6-dev python-dev swig python-ply libgmp3-dev libmpfr-dev gfortran subversion git wget libmpfr4 python-docutils tex4ht
==== Récupération, compilation et installation ====
Voici les quelques commandes pour installer **Par4All** dans ''/opt'' à partir des sources.
Récupération et expansion de l'archive :
cd /tmp
wget http://download.par4all.org/development/ubuntu/x86_64/2012/11/2012-11-29/par4all-1.4.3-e2355ae_src.tar.gz
tar xzf /tmp/par4all-1.4.3-e2355ae_src.tar.gz
cd /tmp/par4all-1.4.3_src/
Compilation & Installation dans ''/opt''
src/simple_tools/p4a_setup.py --prefix=/opt/par4all-1.4.3 -v --jobs=4
Paramétrage du lien :
cd /opt
[ -d /opt/par4all ] && mv /opt/par4all /opt/par4all-$(date '+%Y%m%d')
cd /opt
ln -sf par4all-1.4.3 par4all
===== Utilisation =====
Je conseille très **fortement** de toujours disposer d'exécutables "//témoins//" pour vérifier les sorties des autres implémentations ! Nous pouvons voir que le programme ci-dessus présente en sortie les éléments de la diagonale de la matrice, éléments qui peuvent être utilisés pour une vérification //a minima// des résultats.
==== Le code source ====
Ensuite, il faut disposer d'un code très simple et que nous savons aisément parallélisable : un produit de matrices par exemple. Le code source le plus élémentaire que nous puissions trouver est le suivant :
#include
#define SIZE 2048
#define FTYPE double
int main(void)
{
FTYPE a[SIZE][SIZE];
FTYPE b[SIZE][SIZE];
FTYPE c[SIZE][SIZE];
FTYPE trace=0.;
for (unsigned int i = 0; i < SIZE; ++i) {
for (unsigned int j = 0; j < SIZE; ++j) {
a[i][j] = (FTYPE)(i + j);
b[i][j] = (FTYPE)(i - j);
c[i][j] = 0.0f;
}
}
for (unsigned int i = 0; i < SIZE; ++i) {
for (unsigned int j = 0; j < SIZE; ++j) {
for (unsigned int k = 0; k < SIZE; ++k) {
c[i][j] += a[i][k] * b[k][j];
}
}
}
for (unsigned int i = 0; i < SIZE; ++i) {
trace+=c[i][i];
}
printf("La trace de la matrice est %.2f\n",trace);
return 0;
}
==== Compilation standard & Exécution ====
Si nous appelons ce code ''matrix.c'', pour le compiler simplement avec GCC, nous avons :
gcc -std=c99 -o matrix matrix.c
En exécutant directement **matrix** par ''/usr/bin/time ./matrix'', nous obtenons un superbe ''Segmentation fault''.
Command terminated by signal 11
0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 376maxresident)k
0inputs+0outputs (0major+134minor)pagefaults 0swaps
Pour y remédier, nous étendons la taille de la pile (//stack// en langue de Shakespeare) à l'infini :
# Pour eviter les Segmentation Fault
ulimit -s unlimited
L'exécution précédente de **matrix** par la commande ''/usr/bin/time ./matrix'' donne alors :
La trace de la matrice est 18428734073246580736.00
152.60user 0.02system 2:32.91elapsed 99%CPU (0avgtext+0avgdata 98796maxresident)k
0inputs+0outputs (0major+24740minor)pagefaults 0swaps
Le programme s'est exécuté en 2 minutes et 32 secondes et donne une trace de 18428734073246580736.
==== Compilation optimisée & Exécution ====
Nous avons plusieurs [[http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html|niveaux d'optimisation intégré à GCC]].
Si nous voulons optimiser un peu la compilation, nous utilisons les options ''-O2'', ''-mtune=native'' :
gcc -std=c99 -O2 -mtune=native -o matrix-O2 matrix.c
La trace de la matrice est 18428734073246580736.00
75.10user 0.02system 1:15.26elapsed 99%CPU (0avgtext+0avgdata 98796maxresident)k
0inputs+0outputs (0major+24740minor)pagefaults 0swaps
Si nous voulons optimiser un peu la compilation, nous utilisons les options ''-O3'', ''-mtune=native'' :
gcc -std=c99 -O3 -mtune=native -o matrix-O3 matrix.c
L'exécution précédente de **matrix** par la commande ''/usr/bin/time ./matrix-O3'' donne alors :
La trace de la matrice est 18428734073246580736.00
39.61user 0.01system 0:39.70elapsed 99%CPU (0avgtext+0avgdata 98796maxresident)k
0inputs+0outputs (0major+24740minor)pagefaults 0swaps
==== Pour utiliser P4A en mode analyse ====
La première étape consiste à charger les variables d'environnements pour ensuite utiliser la commande "magique", ''p4a''
# Si vous utilisez ksh ou assimiles
source /opt/par4all/etc/par4all-rc.sh
# Si vous utilisez csh ou assimiles
source /opt/par4all/etc/par4all-rc.csh
Utilisation directe
p4a --simple -vv matrix.c -o matrix-simple
L'exécution précédente de matrix par la commande ''/usr/bin/time ./matrix-simple'' donne alors :
La trace de la matrice est 18428734073246580736.00
40.73user 0.03system 0:40.85elapsed 99%CPU (0avgtext+0avgdata 98796maxresident)k
0inputs+0outputs (0major+24740minor)pagefaults 0swaps
==== Pour utiliser P4A en mode OpenMP ====
Utilisation directe
p4a --openmp -vv matrix.c --fine -o matrix-OpenMP
Utilisation en 2 étapes
p4a --openmp -vv matrix.c
gcc -fopenmp -O3 -mtune=native -o matrix-OpenMP matrix.p4a.c
L'exécution précédente de matrix par la commande ''/usr/bin/time ./matrix-OpenMP'' donne alors :
La trace de la matrice est 18428734073246580736.00
182.20user 0.12system 0:23.39elapsed 779%CPU (0avgtext+0avgdata 99068maxresident)k
0inputs+0outputs (0major+24825minor)pagefaults 0swaps
Par défaut, le programme OpenMP se lance sur tous les coeurs disponibles (virtuels ou pas !). Pour limiter sur un certain nombre de coeurs ''N'', utilisons ''export OMP_NUM_THREADS=N'' :
N=1
while [ $N -ge 1 ]
do
echo "Lancement sur $N thread(s)"
export OMP_NUM_THREADS=$N
/usr/bin/time ./matrix-OpenMP
N=$(($N-1))
echo
done
Lancement sur 8 threads
187.95user 0.08system 0:24.13elapsed 779%CPU (0avgtext+0avgdata 99088maxresident)k
Lancement sur 7 threads
170.10user 0.04system 0:26.00elapsed 654%CPU (0avgtext+0avgdata 99076maxresident)k
Lancement sur 6 threads
151.38user 0.07system 0:27.95elapsed 541%CPU (0avgtext+0avgdata 99072maxresident)k
Lancement sur 5 threads
125.15user 0.06system 0:29.87elapsed 419%CPU (0avgtext+0avgdata 99064maxresident)k
Lancement sur 4 threads
104.46user 0.04system 0:26.33elapsed 396%CPU (0avgtext+0avgdata 99056maxresident)k
Lancement sur 3 threads
95.95user 0.02system 0:32.17elapsed 298%CPU (0avgtext+0avgdata 99048maxresident)k
Lancement sur 2 threads
87.65user 0.03system 0:43.94elapsed 199%CPU (0avgtext+0avgdata 99032maxresident)k
Lancement sur 1 threads
91.47user 0.02system 1:31.65elapsed 99%CPU (0avgtext+0avgdata 99012maxresident)k
==== Pour utiliser P4A en mode Cuda ====
Utilisation directe avec la commande suivante ne fonctionne pas avec la version 1.4 de par4all et le paquet Debian rétroporté du SDK CUDA version 5.5.
export CUDA_DIR=/usr/lib/nvidia-cuda-toolkit/
p4a --cuda -vv matrix.c --fine -o matrix-cuda
Nous allons explorer une autre solution :
Utilisation avec compilation séparée
# Appel de Par4all
p4a --fine --cuda -vv matrix.c
# Compilation des sources CUDA avec le compilateur Nvidia
nvcc --cuda -I/usr/include -DP4A_ACCEL_CUDA -I/opt/par4all/share/p4a_accel -o matrix.p4a.cpp matrix.p4a.cu
nvcc --cuda -I/usr/include -DP4A_ACCEL_CUDA -I/opt/par4all/share/p4a_accel -o p4a_accel.cpp /opt/par4all/share/p4a_accel/p4a_accel.cu
# Compilation des deux sources
g++ -c -I/usr/include -DP4A_ACCEL_CUDA -I/opt/par4all/share/p4a_accel -Wall -fno-strict-aliasing -fPIC -O3 -o matrix.p4a.o matrix.p4a.cpp
g++ -c -I/usr/include -DP4A_ACCEL_CUDA -I/opt/par4all/share/p4a_accel -Wall -fno-strict-aliasing -fPIC -O3 -o p4a_accel.o p4a_accel.cpp
# Compilation finale de l'executable
g++ -L/usr/lib/x86_64-linux-gnu -Bdynamic -lcudart -o matrix-CUDA matrix.p4a.o p4a_accel.o
# Effacement des fichiers intermédiaires inutiles
rm p4a_accel.o p4a_accel.cpp
En lançant la ''/usr/bin/time ./matrix-CUDA''
/usr/bin/time ./matrix-CUDA
La trace de la matrice est 18428734073246580736.00
2.81user 1.01system 0:03.84elapsed 99%CPU (0avgtext+0avgdata 122360maxresident)k
0inputs+88outputs (0major+27380minor)pagefaults 0swaps
==== Pour utiliser P4A en mode OpenCL ====
Utilisation simple passe
p4a --opencl -vvv matrix.c -o matrix-OpenCL
Son exécution donne ''/usr/bin/time ./matrix-OpenCL''
La trace de la matrice est 18428734073246580736.00
3.39user 3.22system 0:06.66elapsed 99%CPU (0avgtext+0avgdata 156856maxresident)k
32inputs+112outputs (0major+38185minor)pagefaults 0swaps
===== Analyse des résultats =====
--- //[[emmanuel.quemener@ens-lyon.fr|Emmanuel Quemener]] 2013/09/26 21:44//