我有一些代码,其中一个(通常是大的)数组的内容被添加到另一个相同大小的数组中:
for (long i = 0; i < len; i++)
data1[i] += data2[i];
看起来这应该很容易使用OpenMP并行化:
#pragma omp parallel for
for (long i = 0; i < len; i++)
data1[i] += data2[i];
然而,即使我有8个核心+8个超线程,加速也是最小的(可能是10%)。我试着微调了一下:
#pragma omp parallel for schedule(dynamic, 1000)
但没有效果。我看到所有内核和超线程都在并发工作,但只有10%或15%。
其他功能,例如在一个数组中找到最小值(这样你只需要读,而不是写),使用并行化可以轻松地运行5倍的速度。
这让我想到了一个假设,也许并行化没有多大帮助,因为写内存很慢,不能由不同的内核并发完成。这有道理吗我有很老的硬件:HP Z600工作站(2010),配有两个Xeon E5540 CPU,每个CPU为4个内核+ 4个超线程,并配有8 MB高速缓存。内存为1066 MHz的DDR3。
我的问题:
- 你认为这就是并行化做不了多少事情的原因吗?
- 我能做些什么来从并行化中获益更多?
2条答案
按热度按时间ulydmbyx1#
你的假设基本上是正确的,你的计算通常是“内存限制”的,也就是说,与从/到内存传输的数据量相比,计算太少了,瓶颈是CPU和内存之间的传输速率。因此,使用更多的核心并没有帮助。
在较新的CPU(特别是为服务器设计的CPU)上,您可能会观察到更高的速度提升,因为近年来内存带宽的增长速度超过了单核性能。
编辑:注意,在明显的内存限制计算的情况下,最好的性能并不总是在最大可能的线程数下获得,因为它们都在竞争访问内存。使用2个或4个线程可能比使用8个线程快(有点)。
编辑2:为了得到更完整的答案,我收集了在评论(@Homer512)和@JerryCoffin的回答中提到的其他可能的影响:
所有上述效果部分取决于您编写测试代码的方式。这就是为什么展示整个代码而不仅仅是一小部分代码是很重要的。还有:
ecfdbz9o2#
根据您编写代码的方式,创建线程以运行代码所花费的时间很容易出错。例如,考虑将片段扩展为完整程序的代码,并在各种大小的向量上运行代码:
当我运行它时,我得到这样的结果:
几乎不管我设置的起始大小如何,在第一次运行时,OpenMP代码都非常慢,但随后的运行速度要快得多。
虽然很难100%确定,但我猜这是(至少在很大程度上)创建线程池以并行运行代码的时候了。完成后,使用OpenMP的后续运行将显示更接近您希望的结果:OpenMP版本通常比没有的版本快3倍左右。
免责声明:当然,我使用的CPU与你的不同(E5-2680 V4),这意味着它的内存也不同(DDR4与因此,在您的机器上,即使使用相同的代码,您的结果也可能不会遵循相同的模式。我当然不会期望它具有完全相同的比率,但我猜如果有足够大的阵列,您将从OpenMP获得超过10%的改进。根据Peter Cordes的评论,它可能会被证明是相同水平的改进(很少有人像Peter一样了解x86微架构的细节--而这少数人中的大多数为英特尔/AMD工作,不能和我们这些凡人谈论它)。