我想将代码编写为并行化:
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);
问题是它在英特尔CPU上的运行速度只有 50%,而在AMD上运行速度 300%更快。 我在三个Intel CPU(Nehalem 2core + HT,Sandy Bridge 2core + HT,Ivy Brigde 4core + HT)上运行它。 AMD处理器是Phenom II x2,解锁4核。在2核英特尔处理器上,4线程运行速度提高50%。在4核上,它在4个线程上运行速度提高了50%。我正在使用VS2012,Windows 7进行测试。
当我尝试使用8个线程时,它比英特尔上的串行环路慢8倍。我想这是由HT引起的。
你怎么看?这种行为的原因是什么?也许代码不正确?
答案 0 :(得分:5)
我怀疑虚假分享。当两个变量共享同一个缓存行时会发生这种情况。实际上,它们上的所有操作必须非常昂贵地同步即使它们不是同时访问的,因为缓存只能在特定大小的缓存行中运行,即使您的操作更精细-grained。我怀疑AMD硬件更具弹性或者有不同的硬件设计来应对这种情况。
要进行测试,请更改代码,以便每个内核仅适用于64字节倍数的块。这应该避免任何缓存行共享,因为Intel CPU只有64字节的缓存行。
答案 1 :(得分:2)
我想说你需要改变你的编译器设置,使所有编译的代码最小化分支数量。两种不同的CPU样式具有不同的操作前瞻设置。您需要更改编译器优化设置以匹配目标 CPU,而不是编译代码的CPU。
答案 2 :(得分:2)
你也应该是cpu缓存的一部分。 Here是关于此主题的好文章。
简短版本:hw缓存数据,但是如果你正在处理相同的内存(SomeArray),它必须在cpus的缓存之间一直同步,它甚至可能导致运行速度慢于单个内存线程方式。