[Visual C++ 2010] [PPL] Code Séquentiel versus Code Parallèle
Dans mon billet précèdent nous avions évalué rapidement la librairie TPL en C#. Cette fois nous regarderons le côté natif de Visual Studio 2010. Celui-ci arrive avec une nouvelle librairie « Parallel Pattern Library » (PPL) permettant de paralléliser des applications natives en adhérence avec le style de la Standard Template Librairie (STL) tout en tirant parti des nouvelles caractéristiques du standard C++0x comme par exemple les expressions lambda. Pour illustrer cette librairie je vous propose l’étude de cas d’une simple méthode : l’exemple naïf d’une multiplication de matrices, si facile à comprendre (certains penseront que je manque d'imagination :-))
void MatrixMult(int size, double** m1, double** m2, double** result)
{
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
double t = 0;
for (int k = 0; k < size; k++) {
t += m1[i][k] * m2[k][j];
}
result[i][j] = t;
}
}
}
Figure 1: code à adapter à l'aide de la librairie PPL
Pour évaluer les performances de cette première version, nous allons solliciter la méthode MatrixMult, avec une valeur de size de 1000 sur une machine quadri-cœurs.
printf("Starting execution ...\n");
start = GetTickCount();
MatrixMultSeq(SIZE, m1, m2, result);
end = GetTickCount();
printf("Elapsed time: %ds\n\n", (end-start)/1000);
Figure 2: Code pour mesurer le temps de traitement
On lance le programme en mode Release tout en observant le Task Manager pour constater l'occupation des cœurs.
Figure 3: Exécution du traitement en mode séquentiel
Nous constatons que le traitement occupe peu les cœurs disponibles avec un temps d'exécution de 9 secondes.
Pour profiter de tous les cœurs disponibles, modifions le code et ajoutons l'inclusion du fichier de la librairie Parallel Pattern Library (PPL) :
#include <ppl.h>
Puis nous altérons légèrement le code de la méthode MatrixMult afin de paralléliser le code. La méthode parallel_for prend en paramètres: un pas d'incrémentation, une taille de collection à itérer, une expression lambda contenant le corps du traitement.
void MatrixMult(int size, double* m1[], double* m2[], double* result[])
{
parallel_for(0, size, [&](int i) {
for (int j = 0; j < size; j++)
{
double t = 0;
for (int k = 0; k < size; k ++)
{
t += m1[i][k] * m2[k][j];
}
result[i][j] = t;
}
});
}
Figure 4: code adapté à l'aide de la libraire PPL
On remarque que le code reste lisible et sémantiquement compréhensible en comparaison au code de la figure 1 J
Figure 5: Exécution du traitement en mode parallèle
On relance le programme et on observe une nouvelle fois le Task Manager. Cette fois les cœurs sont pleinement exploités avec un temps d’exécution de 2 secondes.
Finalement avec très peu d'efforts nous avons divisé par 4,5 le temps d’exécution de notre petit programme :-)
A bientôt,
Bruno
Bruno Boucard (boucard.bruno@free.fr)
Comments
Anonymous
January 19, 2009
Les deux offres parallèles de Visual Studio 2010, native et .NET, reposent sur des socles techniquesAnonymous
January 20, 2009
Les deux offres parallèles de Visual Studio 2010, native et .NET, reposent sur des socles techniques