我尝试使用单个#pragma omp parallel for
使用OpenMP,这导致我的程序从 35s(99.6%CPU)的运行时转到 14s( 500%CPU),在Intel(R) Xeon(R) CPU E3-1240 v3 @ 3.40GHz上运行。这与使用g++ -O3
和g++ -O3 -fopenmp
进行编译的区别在于Debian 7上的gcc (Debian 4.7.2-5) 4.7.2
(wheezy)。
为什么它最多只使用500%的CPU,理论上的最大值是800%,因为CPU是4核/ 8线程?它不应该达到至少700s?
为什么我的总体时间只提高了2.5倍,但CPU使用成本是5倍?缓存捶打?
整个程序基于C ++ string
操作,具有递归处理(使用大量.substr(1)
和一些连接),其中所述字符串被连续插入到vector
{ {1}}。
换句话说,基本上,在单个并行for循环中完成大约2k循环迭代,在set
上运行,并且每个循环迭代可以对其自身执行两次递归调用w / some {{1} } vector
和string
连接,然后递归以单个字符串的.substr(1)
+ char
或两个字符串的串联终止,并且表示set
.insert
还会处理大量可能的重复项。
所有内容都在规范中正常运行,但我试图查看它是否可以更快地运行。 : - )
答案 0 :(得分:3)
根据您的描述,您可以得出以下结论:
我假设OpenMP确实使用8个线程(由export OMP_NUM_THREADS=8
验证)
500%的CPU意味着在障碍中花费了大量时间。这是由于负载平衡不良:不同的迭代需要不同的时间。因此,默认(静态)循环调度是低效的,尝试不同的kinds of loop scheduling,例如, dynamic
。强>
如果运行时间没有与线程数成比例地减少(例如,花费的总CPU时间增加),则存在充当瓶颈的共享资源或线程之间的影响。请注意,这也可能是短障碍(来自负载不平衡)的结果,它会执行忙等待而不是阻塞。
最常见的共享资源是内存带宽。这是否会影响您,取决于您的工作集是否适合本地缓存。考虑到现代系统中的许多内存层次结构和NUMA属性,这可能会变得非常复杂。对于重构数据访问以更有效地使用缓存(阻塞)而言,这是没有根据的。
虚假共享:如果多个线程写入&读取到相同的存储器位置(高速缓存行),相应的存储器访问变得慢得多。尝试将并行循环中的写入限制为私有变量。
HyperThreading - 核心是两个硬件线程之间的共享资源。
使用5x资源
这是一个根本的误解。额外的硬件线程为每个核心提供的额外资源很少。如果两个线程在同一个内核上运行,它们将共享计算资源和内存带宽,基本上唯一的优势就是隐藏的I / O延迟。尽管有2倍的CPU时间,但你永远不会看到2倍的加速。有时它会给你10%的加速,有时它会慢一些。
现在考虑在4个核心上运行5个活动线程。共享核心的2个线程将以~50%的速度运行,从而减慢所有速度。尝试将线程数减少到核心数(export OMP_NUM_THREADS=4
)。
答案 1 :(得分:1)
实现线性加速通常并非易事,而且拥有的核心越多越难。您可能需要查找以下几个方面:
shared
变量,也可能发生缓存共享。在这种情况下,请考虑使用private
或firstprivate
来避免同步。schedule()
指令更改调度策略。请考虑至少尝试dynamic
。