c++ - g++ 4.7 中的 OpenMP(并行)不是很有效吗? 2.5 倍于 5 倍 CPU

标签 c++ openmp g++-4.7

我已经尝试将 OpenMP 与单个 #pragma omp parallel for 结合使用,这导致我的程序运行时间从 35 秒(99.6% CPU) 变为14 秒(500% CPU),在 Intel(R) Xeon(R) CPU E3-1240 v3 @ 3.40GHz 上运行.这就是使用 g++ -O3g++ -O3 -fopenmp 编译之间的区别,两者都使用 gcc (Debian 4.7.2-5) 4.7.2 在 Debian 7 上(喘不过气来)。

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

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

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

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

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

最佳答案

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

我假设 OpenMP 确实使用了 8 个线程(通过 export OMP_NUM_THREADS=8 验证)

  1. 500% CPU 意味着在障碍上花费了大量时间。这是由于负载平衡不好:不同的迭代花费不同的时间。因此默认(静态)循环调度效率低下,尝试不同的 kinds of loop scheduling ,例如动态

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

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

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

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

      using 5x resources

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

      现在考虑在 4 个内核上运行 5 个事件线程。 2 个线程,共享一个核心,只会以大约 50% 的速度运行,这会减慢一切。尝试将线程数减少到内核数(export OMP_NUM_THREADS=4)。

关于c++ - g++ 4.7 中的 OpenMP(并行)不是很有效吗? 2.5 倍于 5 倍 CPU,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36950532/

相关文章:

c++ - OpenMP:不要使用超线程内核(一半 `num_threads()` w/超线程)

c++ - 与 std::hash 的意外冲突

c++ - 理解这个递归函数

for-loop - 有没有办法控制 OpenMP parallel_for 构造的分区?

c++ - 创建 3D 网格时嵌套 for() 循环上的 OpenMP

c++ - g++ 4.7.2 用于类型别名的处理似乎被打破

c++ - 接收容器作为模板参数

c++ - 记分卡刽子手。 C++

c++ - C++中取消的数值问题

fortran - omp simd的多维数组对齐