C 如何在OpenMP中对此进行并行处理
我知道OpenMP的基础知识,我知道为了并行化一个应用程序,它的迭代不能依赖于以前的迭代。也可以使用约化,但它们只支持基本运算符,如+、-、/、*、&&&、| | 我怎样才能把它做成平行的C 如何在OpenMP中对此进行并行处理,c,matrix,parallel-processing,openmp,C,Matrix,Parallel Processing,Openmp,我知道OpenMP的基础知识,我知道为了并行化一个应用程序,它的迭代不能依赖于以前的迭代。也可以使用约化,但它们只支持基本运算符,如+、-、/、*、&&&、| | 我怎样才能把它做成平行的 for (i = 1; i < n; ++i) { for (j = 1; j < n; ++j) { // stanga if (res[i][j - 1] != res[i][j]) { cmin2[i][j][0] = min(
for (i = 1; i < n; ++i) {
for (j = 1; j < n; ++j) {
// stanga
if (res[i][j - 1] != res[i][j]) {
cmin2[i][j][0] = min(cmin2_res[i][j - 1][0] + 1, cmin[i][j][0]);
cmin2_res[i][j][0] = min(cmin2[i][j - 1][0] + 1, cmin_res[i][j][0]);
} else {
cmin2[i][j][0] = min(cmin2[i][j - 1][0] + 1, cmin[i][j][0]);
cmin2_res[i][j][0] = min(cmin2_res[i][j - 1][0] + 1, cmin_res[i][j][0]);
}
// sus
if (res[i - 1][j] != res[i][j]) {
cmin2[i][j][0] = min3(cmin2[i][j][0], cmin2_res[i - 1][j][0] + 1, cmin[i][j][1]);
cmin2_res[i][j][0] = min3(cmin2_res[i][j][0], cmin2[i - 1][j][0] + 1, cmin_res[i][j][1]);
} else {
cmin2[i][j][0] = min3(cmin2[i][j][0], cmin2[i - 1][j][0] + 1, cmin[i][j][1]);
cmin2_res[i][j][0] = min3(cmin2_res[i][j][0], cmin2_res[i - 1][j][0] + 1, cmin_res[i][j][1]);
}
}
}
(i=1;i{
对于(j=1;j
我的问题是如何将其分解,以便能够并行运行(如果可能的话,还可以使用缩减)
问题是,在每次迭代中,操作必须按照这个顺序进行,因为我还有3组类似的for
p.S.min和min3是宏。有一种蛮力方式来做你想做的事情,但是更好的并行化需要更多关于你想从例程中得到什么的输入
在i-j空间中,循环中的数据依赖项如下所示:
i →
..........
j .....1....
↓ ....12....
...123....
其中,点3处的值取决于点2s处的值,而点1处的值取决于点1处的值,等等。由于这种对角结构,您可以对循环进行重新排序,以对角方式穿过网格,例如,第一次迭代超过(0,1)、(1,0),然后超过(0,2)、(1,1)、(2,0),等等。问题的简化版本如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>
int **int2darray(int n, int m);
void free2darray(int **array);
void init2darray(int **array, int n, int m);
void tick(struct timeval *timer);
double tock(struct timeval *timer);
int main(int argc, char **argv) {
const int N=10000;
int **serialarr, **omparr;
struct timeval serialtimer, omptimer;
double serialtime, omptime;
serialarr = int2darray(N,N);
omparr = int2darray(N,N);
init2darray(serialarr, N, N);
init2darray(omparr, N, N);
/* serial calculation */
tick(&serialtimer);
for (int i=1; i<N; i++)
for (int j=1; j<N; j++)
serialarr[i][j] = serialarr[i-1][j] + serialarr[i][j-1];
serialtime = tock(&serialtimer);
/* omp */
tick(&omptimer);
#pragma omp parallel shared(omparr) default(none)
{
for (int ipj=1; ipj<=N; ipj++) {
#pragma omp for
for (int j=1; j<ipj; j++) {
int i = ipj - j;
omparr[i][j] = omparr[i-1][j] + omparr[i][j-1];
}
}
for (int ipj=N+1; ipj<2*N-1; ipj++) {
#pragma omp for
for (int j=ipj-N+1; j<N; j++) {
int i = ipj - j;
omparr[i][j] = omparr[i-1][j] + omparr[i][j-1];
}
}
}
omptime = tock(&omptimer);
/* compare results */
int abserr = 0;
for (int i=0; i<N; i++)
for (int j=0; j<N; j++)
abserr += abs(omparr[i][j] - serialarr[i][j]);
printf("Difference between serial and OMP array: %d\n", abserr);
printf("Serial time = %lf\n", serialtime);
printf("OMP time = %lf\n", omptime);
free2darray(omparr);
free2darray(serialarr);
return 0;
}
int **int2darray(int n, int m) {
int *data = malloc(n*m*sizeof(int));
int **array = malloc(n*sizeof(int*));
for (int i=0; i<n; i++)
array[i] = &(data[i*m]);
return array;
}
void free2darray(int **array) {
free(array[0]);
free(array);
}
void init2darray(int **array, int n, int m) {
for (int i=0; i<n; i++)
for (int j=0; j<m; j++)
array[i][j] = i*m+j;
}
void tick(struct timeval *timer) {
gettimeofday(timer, NULL);
}
double tock(struct timeval *timer) {
struct timeval now;
gettimeofday(&now, NULL);
return (now.tv_usec-timer->tv_usec)/1.0e6 + (now.tv_sec - timer->tv_sec);
}
您会注意到,即使使用较大的N,加速率也相当低,因为每次迭代的计算量很小,内部循环是并行的,我们以一种奇怪的、不利于缓存的顺序遍历内存
上面提到的一些问题可能是可以解决的,但如果你能更多地了解你想做的事情,那会有更多的帮助;例如,您关心cmin2_res阵列,还是它们只是中间产品?换句话说,你想计算什么?i处的结果,j取决于i-1和j-1处的结果。您可能需要更改算法以使其能够并行运行。试一试纸上的2x2案例,看看你不能计算(0,0),(0,1),。。在没有输入数据限制的情况下高效地并行处理值。我知道这一点,问题是如何打破for,以便并行处理。非常感谢!我现在正试着用这个。我还有3组这样的人。我保留cmin2和cmin2_res,因为对于矩阵中的每个元素,我必须从cmin2和cmin2_res计算最小值
$ gcc -fopenmp -Wall -O2 loops.c -o loops -std=c99
$ export OMP_NUM_THREADS=8
$ ./loops
Difference between serial and OMP array: 0
Serial time = 0.246649
OMP time = 0.174936