我正在尝试使用用于计算永久物的数组来实现计算。
问题是我用C ++(串行)编写的循环比带有openMP的并行化版本快。
这是代码的一部分。
int t,k,j,i;
double result = 0;
#pragma omp parallel for private (t,k,j,i)
for (int t = 0; t < cols; ++t) {
double delta = 1;
#pragma omp parallel for reduction(*: delta)
for (int k = 0; k < m; ++k) {
delta *= trasposta[k][t];
}
double p = 1;
for (int j = 0; j < m; j++) {
double s = 0;
#pragma omp parallel for reduction(+: s)
for (int i = 0; i < m; i++) {
s += trasposta[i][t] * matr[i][j];
}
p *= s;
}
result += delta * p;
}
permanent = result / cols;
cout << permanent << endl;
带有openMP的执行时间并行版本:
real 0m0,334s
user 0m0,387s
sys 0m0,207s
执行时间序列号版本(没有所有的#pragma omp)
real 0m0,100s
user 0m0,095s
sys 0m0,005s
如何解决opeMP以获得更好的结果?
编辑:我使用以下命令编译了openMP版本:
g++ -fopenmp permanent.cpp -o permanent
答案 0 :(得分:0)
我建议您检查一下代码:
t
,k
,j
和i
被声明两次; 答案 1 :(得分:0)
不确定,它会完全回答您的问题,但是您的代码有很多问题。
关于并行化,您有几个嵌套的omp节。使用嵌套并行机制,每个线程在每个节中创建max_threads新线程。因此,如果max_threads = 10,具有3个嵌套级别,您最终将拥有1000个线程!如果没有嵌套并行机制(这似乎是您的情况),那么内部omp并行机制将被忽略。所以删除它们。
关于omp,内部减少涉及线程局部变量并且可以被抑制。但是result+=delta*p
呢?这是对全局变量的减少,应该这样处理。当前代码有错误。
也许代码中最糟糕的是访问数据的方式。您对矩阵进行的 All 访问均以不友好的缓存方式完成。也许更糟的是,它禁止编译器进行优化(例如simd矢量化)。最低要求是对矩阵进行转置(我做了什么),但是您可能会重新考虑算法,以使缓存更容易被忽略。如果您不知道这些问题,请查看what is a cache friendly code。
一些随机的评论。 tijk声明是没有用的。通过const分配双精度数时,它不应为int(对于结果,为delta,s)。
请勿使用time(1)来衡量执行时间。使用rdtsc,times(2)或clock(3)(我使用过)有更精确的度量。我怀疑您的代码非常快,一旦适当地进行了优化,并且为了得到公平的比较,您应该考虑几个循环。根据需要调整循环数。并运行几次您的程序。您将看到执行时间不是确定的。并删除异常值。
最后,但并非最不重要。您应该永远不要在不优化代码的情况下衡量性能。使用gcc -O2或-O3。
#include <time.h>
// transposed versions of matrices. To get efficient transpose code, look
// at https://stackoverflow.com/questions/5200338/a-cache-efficient-matrix-transpose-program
// it is a quick and dirty hack,
// but you should rethink your algorithms to use properly caches
double Tmatr[m][m];
double Ttrasposta[cols][m];
clock_t start, end;
start=clock(); //tic
#define NLOOPS 100
// to adjust
// run the code several times
for(int l=0; l<NLOOPS; l++)
{
double result = 0.0;
#pragma omp parallel for reduction(+:result)
for (int t = 0; t < cols; ++t) {
double delta = 1.0;
for (int k = 0; k < m; ++k) {
delta *= Ttrasposta[t][k];
}
double p = 1.0;
for (int j = 0; j < m; j++) {
double s = 0.0;
for (int i = 0; i < m; i++) {
s += Ttrasposta[t][i] * Tmatr[j][i];
}
p *= s;
}
result += delta * p;
}
permanent = result / cols;
}
end=clock();//toc
cout << permanent << endl;
cout << "Time: " << (double)(end-start) << endl ;
最后一句话。使用干净的代码,您现在可以尝试使用程序。我无法执行此操作,因为缺少重要数据:例如,矩阵的大小。 m = 4或100000吗?同上为cols。它可以严重改变并行化策略。这就是为什么您应该始终提供Minimum, Complete, Verifiable Example的原因。
根据这些值,也许最好collapse进行“并行运算”。