【问题标题】:Multithreading on Intel much slower than on AMDIntel 上的多线程比 AMD 慢得多
【发布时间】:2012-12-12 19:49:36
【问题描述】:

我想让下面的代码并行化:

for(int c=0; c<n; ++c) {
    Work(someArray, c);
}

我是这样做的:

#include <thread>
#include <vector>

auto iterationsPerCore = n/numCPU;
std::vector<std::future<void>> futures;

for(auto th = 0; th < numCPU; ++th) {
    for(auto n = th * iterationsPerCore; n < (th+1) * iterationsPerCore; ++n) {
        auto ftr = std::async( std::launch::deferred | std::launch::async,
            [n, iterationsPerCore, someArray]()
            {
                for(auto m = n; m < n + iterationsPerCore; ++m)
                    Work(someArray, m);
            }
        );
        futures.push_back(std::move(ftr));
    }

    for(auto& ftr : futures)
        ftr.wait();
}

// rest of iterations: n%iterationsPerCore
for(auto r = numCPU * iterationsPerCore; r < n; ++r)
    Work(someArray, r);

问题是它在 Intel CPU 上的运行速度仅快 50%,而在 AMD 上却快 300%。 我在三个 Intel CPU(Nehalem 2core+HT、Sandy Bridge 2core+HT、Ivy Brigde 4core+HT)上运行它。 AMD 处理器是 4 核解锁的 Phenom II x2。在 2 核 Intel 处理器上,4 线程运行速度提高 50%。在 4 核上,它在 4 个线程上的运行速度也提高了 50%。我正在使用 VS2012、Windows 7 进行测试。

当我尝试使用 8 个线程时,它比 Intel 上的串行循环慢 8 倍。我想这是由 HT 引起的。

你怎么看?这种行为的原因是什么?也许代码不正确?

【问题讨论】:

  • 超线程使某些工作负载在开启时运行速度变慢。这可能是其中之一。在关闭 HT 的情况下进行测试,这样您就可以只使用实际内核。
  • 你在哪个平台上使用了哪个编译器?
  • @Donnie 在 2 核 Intel 处理器上,它在 4 个线程下运行速度提高了 50%。在 4 核上,它在 4 个线程上的运行速度也提高了 50%。当我尝试使用 8 个线程时,它比串行循环慢 8 倍。明天我将关闭 HT 并检查结果。目前我无法使用 Intel CPU 的计算机。
  • @bamboon VS2012,Windows 7。
  • 有关平台的具体信息(具体使用了哪些处理器、什么编译器、您生成的工作项数量以及每个平台上的计算时间可能对回答问题有很大帮助,所以您真的应该将这些信息编辑到您的问题中

标签: c++ multithreading concurrency c++11


【解决方案1】:

我怀疑 虚假分享。当两个变量共享同一个缓存行时,就会发生这种情况。实际上,对它们的所有操作都必须非常昂贵地同步即使它们不是同时访问的,因为缓存只能根据一定大小的缓存行进行操作,即使您的操作更精细- 细化。我怀疑 AMD 硬件只是更有弹性,或者有不同的硬件设计来应对这个问题。

要进行测试,请更改代码,使每个核心仅适用于 64 字节的倍数的块。这应该避免任何缓存行共享,因为 Intel CPU 只有一个 64 字节的缓存行。

【讨论】:

  • 这也是我最初的怀疑。但是再看一眼就会发现 Intel 和 AMD 机器的缓存线大小是一样的。无论如何 +1。
  • 不仅仅是缓存大小,还有L2和L3缓存是否在内核之间共享,也可能是包含与独占缓存,这在AMD和Intel之间有所不同
  • 是的 - 虚假共享中发生的不仅仅是缓存行。
【解决方案2】:

我会说您需要更改编译器设置以使所有编译的代码最小化分支数量。两种不同的 CPU 样式具有不同的操作前瞻设置。您需要更改编译器优化设置以匹配 目标 CPU,而不是编译代码的 CPU。

【讨论】:

  • 我该怎么做?你能给我推荐一些关于它的资源吗?
  • 首先,我会使用 GCC 而不是 VS2012。但是,这里有一些文档选项的链接msdn.microsoft.com/en-us/library/19z1t1wy.aspx 您可以查看 /MT /favor /Gr 之类的选项
  • 糟糕的顺序优化如何损害并行加速?
  • 最糟糕的可能是编译器对前瞻分支优化的计划。所以编译器认为代码总是会沿着一个特定的分支继续下去,但是并行进程在执行期间会改变环境,导致采用不同的路径,并导致所有前瞻代码被转储。这实际上是 volatile 关键字的原因。它使编译器无法根据该变量计算值进行优化。
【解决方案3】:

您也应该对 cpu 缓存感到敬畏。 Here 是一篇关于这个主题的好文章。

简短的版本:硬件缓存数据,但如果你在同一个内存(SomeArray)上工作,它必须在 cpu 的缓存之间一直同步,它甚至会导致运行速度比单个运行慢螺纹方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-13
    • 2012-01-24
    • 2013-09-29
    • 1970-01-01
    • 1970-01-01
    • 2012-09-05
    • 1970-01-01
    相关资源
    最近更新 更多