我的任务是并行化这个函数并使其比顺序运行时间更快,但是我尝试过的#pragma omp parallel for语句似乎没有产生实质性的效果。
此代码的顺序版本本质上是相同的,除了#pragma 语句之外。我意识到代码写得非常糟糕,它是作业的一部分,其目标是实现 8 倍的加速。代码运行的 Linux 机器是具有超线程的 8 核系统。
测试运行时间的方法是通过以下代码行的输出:
clock_gettime(CLOCK_MONOTONIC, &start);
work_it_par(original, new);
clock_gettime(CLOCK_MONOTONIC, &finish);
类似的代码调用同一函数的顺序版本,然后通过顺序时间/并行时间计算加速比。然而,我的结果似乎非常不一致,并且我似乎无法并行化超过 1.5。
void work_it_par(long *old, long *new) {
int i, j, k;
int u, v, w;
long compute_it;
long aggregate=1.0;
long weNeedTheFunc = we_need_the_func();
long gimmieTheFunc = gimmie_the_func();
int marker = DIM-1;
#pragma omp parallel for private(i, j, k, compute_it)
for (i=1; i<marker; i++) {
for (j=1; j<marker; j++) {
for (k=1; k<marker; k++) {
compute_it = old[i*DIM*DIM+j*DIM+k] * weNeedTheFunc;
aggregate+= compute_it / gimmieTheFunc;
}
}
}
printf("AGGR:%ld\n",aggregate);
//#pragma omp parallel for private(i, j, u, v)
for (i=1; i<marker; i++) {
#pragma omp parallel for private(k)
for (j=1; j<marker; j++) {
for (k=1; k<marker; k++){
new[i*DIM*DIM+j*DIM+k]=0;
for (u=-1; u<=1; u++) {
for (v=-1; v<=1; v++) {
for (w=-1; w<=1; w++) {
new[i*DIM*DIM+j*DIM+k]+=old[(i+u)*DIM*DIM+(j+v)*DIM+(k+w)];
}
}
}
new[i*DIM*DIM+j*DIM+k]/=27;
}
}
}
#pragma omp parallel for private(i, j)
for (i=1; i<marker; i++) {
//#pragma omp parallel for private(k)
for (j=1; j<marker; j++) {
for (k=1; k<marker; k++) {
u=(new[i*DIM*DIM+j*DIM+k]/100);
if (u<=0) u=0;
if (u>=9) u=9;
histogrammy[u]++;
}
}
}
}
最佳答案
首先,您的代码在许多地方都是错误的。我乍一看有 7 个竞争条件。
我建议使用以下一般规则:
声明变量尽可能本地化。这比试图找出哪个变量需要私有(private)更容易。它还可以帮助将变量声明为 const 以确保它们可以安全地共享。
如果在并行循环中对变量求和,请使用归约子句。
将这些原则应用于第一个循环如下所示:
#pragma omp parallel for reduction(+:aggregate)
for (int i=1; i<marker; i++) {
for (int j=1; j<marker; j++) {
for (int k=1; k<marker; k++) {
long compute_it = old[i*DIM*DIM+j*DIM+k] * weNeedTheFunc;
aggregate+= compute_it / gimmieTheFunc;
}
}
}
对于直方图,您还可以从 OpenMP 4.5 开始使用
reduction(+:histogrammy[:10])
,或者在增量操作。哪一个更好取决于大小 - 数组缩减会产生每线程内存成本,原子
更新会产生争用惩罚。通常,在安全的情况下并行化最外层循环。对于嵌套循环,应用
collapse
子句可能会很有帮助,其中包括工作共享中的多个循环。这是否有帮助,取决于线程数量、循环大小和平衡。通常它不会造成伤害。
例如
#pragma omp parallel for collapse(3)
for (int i=1; i < marker; i++) {
for (int j=1; j < marker; j++) {
for (int k=1; k < marker; k++) {
如果您已确保代码正确并且想要查看性能,请考虑以下事项:使用了解 OpenMP/线程的性能分析工具。如果您想讨论 StackOverflow 上的实际性能,您必须
- 包括 reproducible example - 包括如何构建它
- 描述您的具体绩效衡量方法
- 包含您的具体绩效衡量结果
- 描述您的系统(CPU、编译器版本)
关于c - 当使用 openMP 并行化代码时,哪些变量应该是私有(private)的和/或firstprivate,什么时候合适?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56472915/