Начиная с OpenMP 4.0 вы можете написать свое собственное сокращение .
Идея такова:
- в цикле
for
, вы указываете компилятору уменьшить место, которое вы изменяете в каждом цикле.
- , поскольку omp не знает, как уменьшить такой массив, вы должны написать свой собственный сумматор
my_add
, который просто сложит два массива.
- Вы говорите omp, как использовать его в своем редукторе (
myred
)
#include <stdio.h>
#include <stdlib.h>
#define LEN 40000
int someCalculations(int i, int j)
{
return i * j % 40000 ;
}
/* simple adder, just sum x+y in y */
long *my_add(long * x, long *y)
{
int i;
#pragma omp parallel for private(i)
for (i = 0; i < LEN; ++i)
{
x[i] += y[i];
}
free(y);
return x;
}
/* reduction declaration:
name
type
operation to be performed
initializer */
#pragma omp declare reduction(myred: long*:omp_out=my_add(omp_out,omp_in))\
initializer(omp_priv=calloc(LEN, sizeof(long)))
int main(void)
{
int i, j;
long *result = calloc(LEN, sizeof *result);
// tell omp how to use it
#pragma omp parallel for reduction(myred:result) private (i, j)
for (i = 0; i < LEN; i++) {
for (j = 0; j < i; j++) {
int idx = someCalculations(i, j);
result[idx] += 1;
}
}
// simple display, I store it in a file and compare
// result files with/without openmp to be sure it's correct...
for (i = 0; i < LEN; ++i) {
printf("%ld\n", result[i]);
}
return 0;
}
Без -fopenmp
: real 0m3.727s
С -fopenmp
: real 0m0.835s