C++ 在这种情况下,为什么OpenMP速度慢?
我试图理解为什么OpenMP会像下面的示例中那样工作C++ 在这种情况下,为什么OpenMP速度慢?,c++,openmp,C++,Openmp,我试图理解为什么OpenMP会像下面的示例中那样工作 #include <omp.h> #include <iostream> #include <vector> #include <stdlib.h> void AddVectors (std::vector< double >& v1, std::vector< double >& v2) { size_t i
#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;
}
#包括
#包括
#包括
#包括
void AddVectors(标准::vector&v1,
标准::向量&v2){
尺寸i;
#pragma omp并行专用(i)
对于(i=0;iv1(N1,1);
std::vectorv2(N1,2);
对于(size_t i=0;i
我首先编译了上面的代码,但没有启用OpenMP(通过在编译标志上省略-fopenmp)。N1=10000的执行时间为0.1s。启用OpenMP使执行时间超过1分钟。我在完成之前就停止了(厌倦了等待…)
我将代码编译如下:
g++-std=c++0x-O3-funroll循环-march=core2-fomit帧指针-Wall-fno严格别名-o main.o-c main.cpp
g++main.o-o main
这里并不是所有这些标志都是必需的,但我正在尝试并行化的项目中使用它们,我在那里使用这些标志。这就是为什么我决定把它们留在这里。此外,我还添加了-fopenmp以在编译时启用OpenMP
有人知道出了什么问题吗?谢谢大家! g++是否可以优化整个AddVectors调用?尝试返回最后一个v1元素并将其存储在volatile变量中。我在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;
}
#包括
#包括
#包括
#包括
void AddVectors(标准::vector&v1,
标准::向量&v2){
#pragma-omp并行
对于(inti=0;iv1(N1,1);
std::vectorv2(N1,2);
对于(size_t i=0;i
问题在于您使用的数组类型
向量是一个容器。它是一个存储多个信息的结构,如大小、开始、结束等;并且具有多个内置功能,其中操作符[]是用于访问数据的其中一个。因此,倾向于加载向量V的索引“i”的缓存线加载元素V[i]和代码中未使用的一些信息
#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;
}
相反,如果使用经典数组(动态/静态),运算符[]只会导致加载数据元素。因此,缓存线(通常64字节长)将加载此双数组的8个元素(大小为double=8字节)
请参见_mm_malloc和malloc之间的差异,以增强数据对齐
@福兹先生
我对此不确定。让我们比较两种情况下的性能结果:
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;
}
const int N=10000000;
定时(wcs和wcs);
对于(;运行时<0.1;重复*=2)
{
for(int r=0;r
MFLops:((N*repeat)/runtime)/1000000只是猜测,但是:您是否尝试过在循环之前将循环最大值(
v1.size()
)存储在临时变量中,并在for循环子句中使用该变量?也许编译器看不到size()的返回值由于某种原因没有改变。您的代码现在看起来很奇怪。N1表示向量的长度和循环的运行次数?这是故意的吗?无法复制,在这里工作正常(N1=100000,没有openmp时为17秒,使用Core2 Quad时为4.7秒)。你有什么版本的GCC?什么类型的CPURonny:我以前有一个bug——我将N1和N2设置为atoi(argv[1]),所以我放弃了N2。看起来很奇怪,但并没有改变我的结果。不相关:C++有一个<代码> <代码>标题,我认为它比