我试图理解为什么OpenMP在下面的示例中的工作方式。
#include <omp.h>
#include <iostream>
#include <vector>
#include <stdlib.h>
void AddVectors (std::vector< double >& v1,
std::vector< double >& v2) {
size_t i;
#pragma omp parallel for private(i)
for (i = 0; i < v1.size(); i++) v1[i] += v2[i];
}
int main (int argc, char** argv) {
size_t N1 = atoi(argv[1]);
std::vector< double > v1(N1,1);
std::vector< double > v2(N1,2);
for (size_t i = 0; i < N1; i++) AddVectors(v1,v2);
return 0;
}
我首先在不启用OpenMP的情况下编译上面的代码(通过在编译标志上省略-fopenmp)。 N1 = 10000的执行时间为0.1秒。启用OpenMP会使执行时间超过1 分钟。我在它完成之前就已经停止了(厌倦了等待......)。
我正在编译代码如下:
g ++ -std = c ++ 0x -O3 -funroll-loops -march = core2 -fomit-frame-pointer -Wall -fno-strict-aliasing -o main.o -c main.cpp
g ++ main.o -o main
并非所有这些标志都是必需的,但我在项目中使用它们我试图并行化并在那里使用那些标志。这就是为什么我决定把它们留在这里的原因。另外,我添加-fopenmp以在编译时启用OpenMP。
有人知道出了什么问题吗?谢谢!
答案 0 :(得分:2)
我在Visual Studio 2008上尝试了相同的示例。 我对您的代码示例进行了两次修改,使用OpenMP的速度比没有OpenMP快大约3倍。
无法在GCC上确认它,问题可能是在主循环中调用函数AddVectors,并且每次必须执行“fork”操作时,这将花费一些可测量的时间。因此,如果你有N1 = 10000,它必须产生10000个“fork”操作。
我已经修改了您自己的代码片段,只是为了让它在Visual Studio下工作, 我最后添加了一个print语句,以避免编译器删除所有代码。
#include <omp.h>
#include <iostream>
#include <vector>
#include <stdlib.h>
void AddVectors (std::vector< double >& v1,
std::vector< double >& v2) {
#pragma omp parallel for
for (int i = 0; i < static_cast<int>(v1.size()); i++) v1[i] += v2[i];
}
int main (int argc, char** argv) {
size_t N1 = atoi(argv[1]);
std::vector< double > v1(N1,1);
std::vector< double > v2(N1,2);
for (size_t i = 0; i < N1; i++) AddVectors(v1,v2);
printf("%g\n",v1[0]);
return 0;
}
答案 1 :(得分:1)
可以对整个AddVectors调用进行g ++优化吗?尝试返回最后一个v1元素并将其存储在volatile变量中。
答案 2 :(得分:1)
问题在于您使用的数组类型。
矢量是一个容器。它是一种存储大小,开始,结束等信息的结构;并且有几个内置函数,其中 operator [] 是用于访问数据的其中一个。因此,倾向于加载的缓存行表示向量 V 的索引“i”,加载元素 V [i] 和一些未使用的信息在代码中。
相反,如果使用经典数组(动态/静态),则运算符[]导致仅加载数据元素。因此,高速缓存行(通常为64字节长)将加载此双数组的8个元素(大小为double = 8字节)。
请参阅_mm_malloc和malloc之间的区别以增强数据对齐。
@Mr Fooz 我不确定。让我们比较两种情况的效果结果:
i7处理器上的4个线程
阵列时间:0.122007 |重复:4 | MFlops:327.85
矢量时间:0.101006 |重复:2 | MFlops:188.669
我强制运行时间超过0.1秒,因此代码会自行重复。主循环:
const int N = 10000000;
timing(&wcs);
for(; runtime < 0.1; repeat*=2)
{
for(int r = 0; r < repeat; r++)
{
#pragma omp parallel for
for(int i = 0; i < N; i++)
{
A[i] += B[i];
}
if(A[0]==0) dummy(A[0]);
}
timing(&wce);
runtime = wce-wcs;
}
MFLops :((N *重复)/运行时)/ 1000000