使用OpenMP比不使用OpenMP效率更低的例子(求double数组最小值)

bigbigknife 2008-12-08 11:38:24
加精
一、环境

Intel(R) Core(TM)2 CPU 6320,双核,超频到2.45G.
4G内存
Windows 2003 x64 操作系统
开发平台:Visual C++ 2008


二、代码

void TestMinOutput()
{
const long nSize = 1000000;
static vector <double> longVector(nSize);
FILE* fid = NULL;
fopen_s(&fid, "I:\\longVector.dat", "rb");
fread_s(&longVector[0], sizeof(double)*nSize, sizeof(double), nSize, fid);
fclose(fid);

double minVal[100], minValOmp[100];

DWORD tStart = GetTickCount();
for (long i=0; i<100; i++)
{
minVal[i] = MinOutput(longVector, 220000 + i*5000);
}
DWORD tMin = GetTickCount() - tStart;

tStart = GetTickCount();
for (long i=0; i<100; i++)
{
minValOmp[i] = MinOutputOMP(longVector, 220000 + i*5000);
}
DWORD tMinOmp = GetTickCount() - tStart;

char xxx[200];
sprintf_s(xxx, 200, " minVal = %le, tMin = %d\n minValOmp = %le, tMinOmp = %d",
minVal[0], tMin, minValOmp[0], tMinOmp);
AfxMessageBox(xxx);
}

double MinOutputOMP(const vector <double> &outputs, const long n)
{
static vector <double> ompDblValues(2);
ompDblValues.assign(2, FLT_MAX);
//const long n = (long)outputs.size(); //n=220000
#pragma omp parallel for
for (long i=0; i <n; i++)
{
long nThread = omp_get_thread_num();
ompDblValues[nThread] = (ompDblValues[nThread] < outputs[i]) ? ompDblValues[nThread] : outputs[i];
}
double minPositive= FLT_MAX;
for (long i=0; i <2; i++)
{
minPositive = (minPositive < ompDblValues[i]) ? minPositive : ompDblValues[i];
}
return minPositive;
}

double MinOutput(const vector <double> &outputs, const long n)
{
double minPositive= FLT_MAX;
//const long n = (long)outputs.size(); //n=220000
for (int i=0; i <n; i++)
{
minPositive = (minPositive < outputs[i]) ? minPositive : outputs[i];
}
return minPositive;
}

有人说,把omp_get_thread_num从循环中拿出来可以提高效率,因此MinOutputOMP可改为
double MinOutputOMP(const vector <double> &outputs, const long n)
{
static vector <double> ompDblValues(2);
ompDblValues.assign(2, FLT_MAX);
//const long n = (long)outputs.size(); //n=220000
#pragma omp parallel
{
long nThread = omp_get_thread_num();
#pragma omp for
for (long i=0; i <n; i++)
{
ompDblValues[nThread] = (ompDblValues[nThread] < outputs[i]) ? ompDblValues[nThread] : outputs[i];
}

}
double minPositive= FLT_MAX;
for (long i=0; i <2; i++)
{
minPositive = (minPositive < ompDblValues[i]) ? minPositive : ompDblValues[i];
}
return minPositive;
}

三、运行结果

1. 使用Intel10.1.029编译器
/GL /c /O3 /Og /Ob2 /Oi /Ot /GT /GA /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "_AFXDLL" /D "_MBCS" /FD /EHsc /MD /GS /Gy /GR /Yu"StdAfx.h" /Fp"x64|x64\Release/Test.pch" /Fo"x64|x64\Release/" /W3 /nologo /Zi /Qopenmp /QxT /Qparallel
不提出omp_get_thread_num
minVal = 1.085423e-005, tMin = 78
minValOmp = 1.085423e-005, tMin = 1156
提出omp_get_thread_num
minVal = 1.085423e-005, tMin = 78
minValOmp = 1.085423e-005, tMin = 1235


2. 使用VC++2008编译器
/O2 /Ob2 /Oi /Ot /Oy /GT /GL /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "_AFXDLL" /D "_MBCS" /FD /EHsc /MD /Gy /openmp /Yu"stdafx.h" /Fp"x64\Release\Test.pch" /Fo"x64\Release\\" /Fd"x64\Release\vc90.pdb" /W3 /nologo /c /Zi /TP /errorReport:prompt
不提出omp_get_thread_num
minVal = 1.085423e-005, tMin = 78
minValOmp = 1.085423e-005, tMin = 703
提出omp_get_thread_num
minVal = 1.085423e-005, tMin=78
minValOmp = 1.085423e-005, tMin=1141


四、结论
在这个例子中
(1) 使用OMP比不使用OMP效率要大大下降;
(2) 把omp_get_thread_num从循环中拿出来并不能提高效率;
(3) VC++2008编译的代码效率比Intel v10.1编译的代码效率高一些。
...全文
1617 62 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
62 条回复
切换为时间正序
请发表友善的回复…
发表回复
gzpyming 2010-03-11
  • 打赏
  • 举报
回复
五明!所以需要更加深入的学习
shiqicai 2009-04-23
  • 打赏
  • 举报
回复
受教了,顶礼膜拜。
谭建新 2009-04-20
  • 打赏
  • 举报
回复
今天测试了一下,效果不是很明显,继续学习
goldencode 2008-12-21
  • 打赏
  • 举报
回复
对于多线程中的问题,INTEL的thread checker确实提供了强大的检查功能. 例如大家都知道的共享CACHE不当造成性能下降的问题,是很难在程序中直观地发现的, 而用INTEL THREAD CHECKER一检查就查出来了. 还有就是例如多线程死锁等问题也是众所周知的难以排查的问题, 用THREAD CHECKER就能帮助检查出来, 但需要运行到出问题的代码. 除了INTEL以外似乎还没有哪个公司推出这么有效的针对多线程的工具. 问题是对于个人来说INTEL的工具比较贵,很多人因此不愿意去体验了. 但对于公司来说还算便宜的.
goldencode 2008-12-21
  • 打赏
  • 举报
回复
楼主这个例子是有可能发生的,它说明一个事实,OpenMP是一种API,使用任何一种API都有可能使用不当,仅此而已.
yang19891117 2008-12-20
  • 打赏
  • 举报
回复
上面写错,应该是

for (long i=0; i <nThread; i++)
ompDblValues[i] = MinOutput2(outputs, n, i) ;
speme 2008-12-19
  • 打赏
  • 举报
回复
作个记号。
rpshi83 2008-12-19
  • 打赏
  • 举报
回复
不是吧,我刚想学openmp,看来的好好搞一搞阿
xzybd 2008-12-18
  • 打赏
  • 举报
回复
值得参考,收藏!
colin1006 2008-12-18
  • 打赏
  • 举报
回复
非常感谢,谢谢
zgmlh 2008-12-17
  • 打赏
  • 举报
回复
好,非常好。
正需要这个
xiaoweivsp1 2008-12-17
  • 打赏
  • 举报
回复
感觉还可以
chmdcr 2008-12-17
  • 打赏
  • 举报
回复
mark 飘
zhuyanzheng 2008-12-17
  • 打赏
  • 举报
回复
好好,非vhanghao
zhuyanzheng 2008-12-17
  • 打赏
  • 举报
回复
怎么实现啊
goldencode 2008-12-16
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 Guilty 的回复:]
其实楼主的困境也是软件开发人员共同的问题,问题看上去很简单,但发贴一个星期还没解决,可见双核优化是多么费力的事。
如果这么简单典型的一个循环还要这个那个工具分析,那软件公司都别开了,一行代码成本都上千块了。
[/Quote]
这个例子确实比较简单, 如果开发者对硬件体系架构比较熟的话那可能自己就能意识到问题所在,但也不能确定还要手工修改再实验, 但还有很多开发者不一定对处理器体系架构很熟悉啊, 你是否认为他们就应该放弃呢. 这个工具就是准确地把问题所在分析出来告诉开发者确切的原因供他们参考,"发现问题就解决了一半了". 难道帮助他们不对吗?
goldencode 2008-12-16
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 Guilty 的回复:]
其实楼主的困境也是软件开发人员共同的问题,问题看上去很简单,但发贴一个星期还没解决,可见双核优化是多么费力的事。
如果这么简单典型的一个循环还要这个那个工具分析,那软件公司都别开了,一行代码成本都上千块了。
[/Quote]
说实话我都没有去看这个代码, 因为标题就明显是想哗众取宠但又没有什么技术含量了, 稍微有点编程背景的都知道软件性能如何差距可以是非常大的主要决定于开发者. API只是为此给开发者提供各种程度的帮助, 例如有的API就是让开发者优化性能更方便用的,但如果一个人就是想写出性能更差的程序API不能阻止他难道就是API不好吗. 哈哈哈
szy41 2008-12-16
  • 打赏
  • 举报
回复
mark
goldencode 2008-12-16
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 Guilty 的回复:]
楼上的,共用变量修改才是问题,你不能说访问都不行, 读没影响。
你看看INTEL那些例子,都是让一个不大的循环并行的,起码是同一计数器被共同写的频率太高,数组问题就不说了。当然谁也没说过INTEL推荐共写CACHE LINE,但很容易造成这种后果。
我是觉得似乎INTEL想给人一个假象:OPENMP就是这么好用,一个#pragma解决问题,赶紧买INTEL编译器。实际上为多核优化相当复杂,重写原代码是不可避免的,需要考虑问题相当多。多核C…
[/Quote]
而且也不一定是共用变量修该才有这个问题,如果不是共用一个变量,但变量存在在一个CACHE LINE里也会有这个问题, 所以本质是共享的CACHE LINE的频繁修改造成性能问题.
goldencode 2008-12-16
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 Guilty 的回复:]
楼上的,共用变量修改才是问题,你不能说访问都不行, 读没影响。
你看看INTEL那些例子,都是让一个不大的循环并行的,起码是同一计数器被共同写的频率太高,数组问题就不说了。当然谁也没说过INTEL推荐共写CACHE LINE,但很容易造成这种后果。
我是觉得似乎INTEL想给人一个假象:OPENMP就是这么好用,一个#pragma解决问题,赶紧买INTEL编译器。实际上为多核优化相当复杂,重写原代码是不可避免的,需要考虑问题相当多。多核C…
[/Quote]
OPENMP确实好用不是假象,而且它也不是INTEL的编译器才支持的,是个公共的标准很多编译器都支持的. 实际上INTEL反复强调的是它提供了一个全面的平台,可以解决各种多线程的问题. 这个CACHE LINE共享错误的例子就是我在INTEL的一个视频上看到的, INTEL是把它当做一个常见的多线程问题来演示如何用INTEL THREAD CHECKER来检查错误的.
你说的很多INTEL的例子都有这个问题?能否发个具体的例子?
加载更多回复(37)

567

社区成员

发帖
与我相关
我的任务
社区描述
英特尔® 边缘计算,聚焦于边缘计算、AI、IoT等领域,为开发者提供丰富的开发资源、创新技术、解决方案与行业活动。
社区管理员
  • 英特尔技术社区
  • shere_lin
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧