1

我曾尝试将OpenMP单个#pragma omp parallel for. @ 3.40GHz。这就是在 Debian 7 (wheezy) 上使用和编译的区别。g++ -O3g++ -O3 -fopenmpgcc (Debian 4.7.2-5) 4.7.2

  • 为什么它最多只使用 500% CPU,而理论最大值为 800%,因为 CPU 是 4 核 / 8 线程?它不应该至少达到700s吗?

  • 为什么我的总时间仅提高了 2.5 倍,而 CPU 使用成本却提高了 5 倍?缓存抖动?

整个程序基于 C++string操作,具有递归处理(使用大量的.substr(1)和一些连接),其中所述字符串连续插入到 a vectorof 中set

换句话说,基本上,在单个并行 for 循环中完成了大约 2k 次循环迭代,在 上操作vector,并且它们中的每一个都可以对自身进行两次递归调用 w/ somestring .substr(1)+ charconcatenation,然后递归终止于set .inserta单个字符串或两个字符串的串联,并且 saidset .insert还负责处理大量可能的重复项。

一切都在规范范围内正确运行,但我正在尝试看看它是否可以运行得更快。:-)

4

2 回答 2

3

根据您的描述,您可以得出以下结论:

我假设 OpenMP 真的使用 8 个线程(验证者export OMP_NUM_THREADS=8

  1. 500% CPU 意味着有大量时间花在屏障上。这是由于负载平衡不好:不同的迭代需要不同的时间。因此,默认(静态)循环调度效率低下,尝试不同类型的循环调度,例如dynamic

  2. 如果运行时间没有与线程数量成比例地减少(例如,所花费的总 CPU 时间增加),则要么存在充当瓶颈的共享资源,要么存在线程之间的影响。请注意,这也可能是短障碍(来自负载不平衡)的结果,它执行忙等待而不是阻塞。

    • 最常见的共享资源是内存带宽。这是否会影响您,取决于您的工作集是否适合本地缓存。考虑到现代系统中的许多内存层次结构和 NUMA 属性,这可能会变得非常难以理解。除了重组数据访问以更有效地使用缓存(阻塞)之外,您可以做任何基本的事情。

    • 错误共享:如果多个线程写入和读取相同的内存位置(缓存行),则相应的内存访问会变得慢得多。尝试将并行循环内的写入限制为私有变量。

    • 超线程——核心是两个硬件线程之间的共享资源。

      使用 5x 资源

      这是一个根本性的误解。额外的硬件线程为每个内核提供的额外资源很少。如果两个线程在同一个内核上运行,它们将共享计算资源和内存带宽,基本上唯一的优势是隐藏的 I/O 延迟。尽管 CPU 时间是 2 倍,但你永远不会看到 2 倍的加速。有时它会给你 10% 的加速,有时它会更慢。

      现在考虑在 4 个内核上运行的 5 个活动线程。2 个线程,共享一个内核,只能以约 50% 的速度运行,从而减慢一切。尝试将线程数减少到内核数 ( export OMP_NUM_THREADS=4)。

于 2016-04-30T08:16:59.560 回答
1

实现线性加速通常并非易事,拥有的内核越多,就越难。您可能需要寻找几个方面:

  1. 错误共享:如果数组没有被正确分片,缓存线可能会在两个内核之间争用,通常缓存线的两半被两个线程写入,导致缓存线从一个内核的二级缓存移动到其他。shared如果您使用大量变量,也会发生缓存共享。在这种情况下,请考虑使用privatefirstprivate避免同步。
  2. OpenMP 调度:如果未指定,OpenMP 将在系统中的线程之间以相等的方式分割循环的迭代,并为每个线程分配一个子范围。但是,如果每个索引的工作量不同,那么您最终可能会遇到这样一种情况,即大多数线程都完成了它们的工作,并且它们在并行区域末端的屏障处被阻塞,等待较慢的线程(有更多工作要做)。这取决于您在循环中实现的算法类型,但 OpenMP 让您有机会使用该schedule()指令更改调度策略。考虑dynamic至少尝试一下。
于 2016-04-30T04:41:55.540 回答