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 <stdio.h>

#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 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 2013/09/26 21:44

developpement/activites/integration/par4all4wheezy.txt · Dernière modification: 2015/01/07 10:04 (modification externe)