并行化两个嵌套的for循环,我遇到了无法解释的行为。我在i7 860和xeon E5540上尝试了使用OpenMP的三种不同类型的并行化,我希望这些代码在两个平台上的行为大致相同,这意味着其中一个平台对于所有三种不同的情况应该更快我测试过了。但事实并非如此:
你知道可能导致这种情况的原因吗?
请说明何时需要更多信息或澄清!
为了进一步澄清,我的问题意味着更为笼统。如果我在i7和xeon系统上运行相同的代码,那么使用OpenMP不应该产生可比较的(比例)结果吗?
伪代码:
for 1:4
for 1:1000
vector_multiplication
end
end
案例:
案例1: 没有pramga omp没有并行化
案例2: 第一个for循环的pragma omp
案例3: 第二个for循环的pragma omp
结果
以下是time
命令的实际数字:
案例1
Time Xeon i7
real 11m14.120s 12m53.679s
user 11m14.030s 12m46.220s
sys 0m0.080s 0m0.176s
案例2
Time Xeon i7
real 8m57.144s 4m37.859s
user 71m10.530s 29m07.797s
sys 0m0.300s 0m00.128s
案例3
Time Xeon i7
real 2m00.234s 3m35.866s
user 11m52.870s 22m10.799s
sys 0m00.170s 0m00.136s
[更新]
感谢所有提示。我还在研究原因是什么。
答案 0 :(得分:2)
这里有很好的答案,关于编译效果的可能变化等,这是非常正确的;但是还有其他原因可以预期差异。像这样相当简单(例如,低算术强度)的计算往往对存储器带宽非常敏感;每个线程可用的内存带宽量取决于您运行的线程数。内存在两个系统上的设置方式是否相同?
看起来i7 860具有更高的时钟速度,但E5540具有更高的总内存带宽。由于情况2只能使用4个线程,而情况3可以使用更多,所以认为在4线程情况下时钟速度获胜但在8线程情况下增加的内存争用并不奇怪(试图拉入/推出值的8个线程)向更高波段的Xeon提示。
使这可能更复杂的事实是,它看起来像你正在运行8个线程 - 这些是双插槽系统还是你正在使用超线程?这使情况变得更加复杂,因为超线程实际上有助于通过在另一个线程等待内存时切换线程来隐藏一些内存争用。
如果你想尝试看看有限的内存带宽是否在这里发挥作用,你可以人为地为问题添加更多的计算(例如,乘以exp(sin(a))cos(b)* cos(b)或者什么)确保问题是计算限制的,当你试图找到问题时,消除一个变量。使用针对该特定计算机的优化(使用-march或-xHost或您拥有的内容)编译每个系统上的代码可以消除另一个变量。如果启用了超线程,则将其关闭(或者仅将OMP_NUM_THREADS设置为物理内核的数量)将删除另一个变量。一旦你理解了这个简化案例中发生了什么,一个接一个地放宽上面的限制应该可以帮助你更好地理解发生了什么。
答案 1 :(得分:0)
可以影响openMP效率的事情就是迭代边界的计算。确保这些是事先计算的,并且迭代变量尽可能是本地的。如果你有C99做类似的事情
#pragma omp parallel for
for (size_t i = start, is = stop; i < is; ++i) ...
确保在开头评估表达式start
和stop
。 (或使用_Pragma
,请参阅我的其他答案。)
然后,查看这是否真的成功的唯一方法是查看汇编代码(通常是选项-S
)。
如果没有查看其他编译器选项。 gcc
具有选项-march=native
,可以针对实际体系结构进行最佳编译。其他平台可能有类似的选择。首先,搜索案例1的最佳架构选项。
答案 2 :(得分:0)
这更多是评论而不是答案。
你所测量的并不完全清楚。为了更加确定,我想:
在我的代码中的点处插入时序语句以报告执行时间。这样我知道我在测量什么,比Linux时间命令给我更确定。
使用2个不同的编译器,以确保我正在测量一些关于OpenMP的内容而不是其中一个实现的方面。
除此之外,我倾向于同意您的初步结果需要进一步调查。
我建议您尝试的其中一项功能是折叠您的两个循环并让OpenMP调度4000循环而不是4或1000.