2016-12-23 1 views
0

J'ai quelques difficultés à convertir un code OpenMP en TBB. Est-ce que quelqu'un peut m'aider?Conversion d'OpenMP en TBB

J'ai le code suivant dans OpenMP, où les résultats sont assez bons

# pragma omp parallel \ 
shared (b, count, count_max, g, r, x_max, x_min, y_max, y_min) \ 
private (i, j, k, x, x1, x2, y, y1, y2) 
{ 
# pragma omp for 

for (i = 0; i < m; i++) 
{ 
for (j = 0; j < n; j++) 
{ 
//cout << omp_get_thread_num() << " thread\n"; 
    x = ((double) ( j - 1) * x_max 
     + (double) (m - j ) * x_min) 
    /(double) (m  - 1); 

    y = ((double) ( i - 1) * y_max 
     + (double) (n - i ) * y_min) 
    /(double) (n  - 1); 

    count[i][j] = 0; 

    x1 = x; 
    y1 = y; 

    for (k = 1; k <= count_max; k++) 
    { 
    x2 = x1 * x1 - y1 * y1 + x; 
    y2 = 2 * x1 * y1 + y; 

    if (x2 < -2.0 || 2.0 < x2 || y2 < -2.0 || 2.0 < y2) 
    { 
     count[i][j] = k; 
     break; 
    } 
    x1 = x2; 
    y1 = y2; 
    } 

    if ((count[i][j] % 2) == 1) 
    { 
    r[i][j] = 255; 
    g[i][j] = 255; 
    b[i][j] = 255; 
    } 
    else 
    { 
    c = (int) (255.0 * sqrt (sqrt (sqrt ( 
     ((double) (count[i][j])/(double) (count_max)))))); 
    r[i][j] = 3 * c/5; 
    g[i][j] = 3 * c/5; 
    b[i][j] = c; 
    } 
} 
} 
} 

Et la version TBB est 10 fois plus lent que OpenMP

le code de TBB est:

tbb::parallel_for (int(0), m, [&](int i) 
{ 
for (j = 0; j < n; j++) 
{ 
    x = ((double) ( j - 1) * x_max 
     + (double) (m - j ) * x_min) 
    /(double) (m  - 1); 

    y = ((double) ( i - 1) * y_max 
     + (double) (n - i ) * y_min) 
    /(double) (n  - 1); 

    count[i][j] = 0; 

    x1 = x; 
    y1 = y; 

    for (k = 1; k <= count_max; k++) 
    { 
    x2 = x1 * x1 - y1 * y1 + x; 
    y2 = 2 * x1 * y1 + y; 

    if (x2 < -2.0 || 2.0 < x2 || y2 < -2.0 || 2.0 < y2) 
    { 
     count[i][j] = k; 
     break; 
    } 
    x1 = x2; 
    y1 = y2; 
    } 

    if ((count[i][j] % 2) == 1) 
    { 
    r[i][j] = 255; 
    g[i][j] = 255; 
    b[i][j] = 255; 
    } 
    else 
    { 
    c = (int) (255.0 * sqrt (sqrt (sqrt ( 
     ((double) (count[i][j])/(double) (count_max)))))); 
    r[i][j] = 3 * c/5; 
    g[i][j] = 3 * c/5; 
    b[i][j] = c; 
    } 
} 
}); 
+0

Le partitionneur par défaut de TBB est 'auto_partitioner', qui effectue la subdivision de travail récursif à un niveau d'une itération de la boucle par fil, ce qui pourrait entraîner une tête énorme. La planification par défaut de la construction 'for' de partage de travail avec de nombreux compilateurs est' static', vous devez donc fournir l'algorithme 'parallel_for' avec l'instance singleton de' static_partitioner' pour avoir la même distribution de travail dans TBB que dans OpenMP. –

+0

J'ai changé le parallel_for avec –

+0

TBB :: parallel_for (TBB :: blocked_range2d (0, m, 0, n) \t, [&] (TBB :: blocked_range2d s, static_partitioner()) { \t pour (int i = s.rows(). begin(); i

Répondre

2

Faites attention à la clause private (i, j, k, x, x1, x2, y, y1, y2) dans la version OpenMP du code. Cette liste de variables spécifie une variable privée/locale dans le corps de la boucle parallèle. Cependant, dans la version TBB du code, beaucoup de ces variables sont capturées par lambda comme références ([&]), donc le code est incorrect. Il a des races et, à mon avis, le ralentissement est causé par l'accès à ces variables à partir de plusieurs threads (surcharge de cohérence du cache et désordre dans les indices de boucle). Donc, si vous voulez corriger le code, rendez ces variables locales, par ex.

tbb::parallel_for (int(0), m, [&](int i) 
{ 
double x, y, x1, x2, y1, y2; // !!!! 
int j, k;     // !!!! 
for (j = 0; j < n; j++) 
{ 
    x = ((double) ( j - 1) * x_max 
     + (double) (m - j ) * x_min) 
    /(double) (m  - 1); 
...