【问题标题】:Parallel programming using Haswell architecture [closed]使用 Haswell 架构进行并行编程
【发布时间】:2014-01-22 21:35:12
【问题描述】:

我想了解如何使用 Intel 的 Haswell CPU 微架构进行并行编程。 关于在 asm/C/C++/(任何其他语言)中使用 SIMD:SSE4.2、AVX2?。 你能推荐书籍、教程、互联网资源、课程吗?

谢谢!

【问题讨论】:

标签: sse cpu-architecture avx avx2


【解决方案1】:

在我看来,您一般需要了解 CPU 上的并行编程。大约 10 个月前,我在使用 SSE、OpenMP 或内部函数之前就开始研究这个问题,所以让我简要总结一下我学到的一些重要概念和一些有用的资源。

可以采用多种并行计算技术:MIMD、SIMD、指令级并行、多级 cahces 和 FMA。有了 Haswell,IGP 上也有计算。

我建议选择矩阵乘法或 Mandelbrot 集之类的主题。他们都可以从所有这些技术中受益。

MIMD

通过 MIMD,我指的是使用多个物理内核进行计算。我为此推荐 OpenMP。浏览本教程 http://bisqwit.iki.fi/story/howto/openmp/#Abstract 然后将此作为参考https://computing.llnl.gov/tutorials/openMP/。使用 MIMD 最常见的两个问题是 race conditionsfalse sharing。定期关注 SO 上的 OpenMP。

SIMD

许多编译器都可以进行自动矢量化,所以我会研究一下。 MSVC 的自动矢量化非常原始,但 GCC 的非常好。

学习内在函数。了解内在函数的最佳资源是http://software.intel.com/sites/landingpage/IntrinsicsGuide/

另一个很棒的资源是 Agner Fog 的vectorclass。 SSE/AVX上95%的SO问题可以通过查看vectorclass的源代码来回答。最重要的是,您可以将向量类用于大多数 SIMD,并且仍然可以获得全速并跳过内在函数。

很多人使用 SIMD 效率低下。阅读结构数组 (AOS) 和数组结构 (SOA) 和数组结构数组 (AOOSA)。也可以看看英特尔剥离挖矿Calculating matrix product is much slower with SSE than with straight-forward-algorithm

请参阅Ingo Wald's PhD thesis,了解在光线追踪中实现 SIMD 的有趣方式。我对 Mandelbrot 集使用了同样的想法,使用 SSE(AVX) 一次计算 4(8) 个像素。

还可以阅读 Wald http://www.cdl.uni-saarland.de/papers/leissa_vecimp_tr.pdf 的这篇论文“Extending a C-like Language for Portable SIMD Programming”,以更好地了解如何使用 SIMD。

FMA

自 Haswell 以来,FMA3 是新的。它太新了,所以还没有太多关于它的讨论。但是这个答案(对我的问题)很好 How to use Fused Multiply-Add (FMA) instructions with SSE/AVX。 FMA3 使峰值 FLOPS 翻倍,因此与 Ivy Bridge 相比,Haswell 上的矩阵乘法可能快两倍。

根据this answer,FMA 最重要的方面不是它是一条指令而不是两条指令来进行乘法和加法,而是“(实际上)中间结果的无限精度”。例如,在没有 FMA 的情况下实现双倍乘法需要 6 次乘法和多次加法,而使用 FMA 只需两次操作。

指令级并行度

Haswell 有 8 个端口,它可以将 μ-ops 发送到(尽管不是每个端口都可以采用相同的 mirco-op;请参阅AnandTech review)。这意味着 Haswell 可以做到,例如two 256-bit loads, one 256-bit store, two 256-bit FMA operations, one scalar addition, and a condition jump at the same time(每个时钟周期六个 μ-ops)。

在大多数情况下,您不必担心这一点,因为它是由 CPU 完成的。但是,在某些情况下,您的代码可能会限制潜在的指令级并行性。最常见的是循环携带依赖。下面的代码有一个循环携带的依赖

for(int i=0; i<n; i++) {
    sum += x(i)*y(i);
}

解决这个问题的方法是展开循环并进行部分求和

for(int i=0; i<n; i+=2) {
    sum1 += x(i)*y(i);
    sum2 += x(i+1)*y(i+1);
}
sum = sum1 + sum2;

多级缓存:

Haswell 有多达四级缓存。在我看来,编写代码以最佳地利用缓存是迄今为止最困难的挑战。这是我仍然最挣扎和最无知的主题,但在许多情况下,改进缓存使用可以提供比任何其他技术更好的性能。我对此没有太多建议。

您需要了解集合和缓存行(以及关键步幅)以及关于页面的 NUMA 系统。要了解有关集合和关键步幅的一些信息,请参阅 Agner Fog 的 http://www.agner.org/optimize/optimizing_cpp.pdf 和此 Why is transposing a matrix of 512x512 much slower than transposing a matrix of 513x513?

缓存的另一个非常有用的主题是循环阻塞或平铺。例如,请参阅What is the fastest way to transpose a matrix in C++? 我的答案(得票最高的那个)。

在 IGP 上计算(使用 Iris Pro)

所有 Haswell 消费者处理器(Haswell-E 尚未推出)都有 IGP。 IGP 使用至少 30% 到超过 50% 的硅。这对于至少 2 个以上的 x86 内核来说已经足够了。对于大多数程序员来说,这是浪费的计算潜力。对 IGP 进行编程的唯一方法是使用 OpenCL。英特尔没有适用于 Linux 的 OpenCL Iris Pro 驱动程序,因此您只能使用 Windows(我不确定 Apple 对此的实现有多好)。 Programming Intel IGP (e.g. Iris Pro 5200) hardware without OpenCL

与 Nvidia 和 AMD 相比,Iris Pro 的一个优势是双浮点只有 one quarter the speed of single floating point with the Iris Pro (however fp64 is only enabled in Direct Compute and not with OpenCL)。 NVIDIA 和 AMD(最近)严重削弱了双浮点,以至于 GPGPU 双浮点计算在他们的消费卡上不是很有效。

【讨论】:

  • 感谢您的精彩介绍!
  • 让我在这里做一个小修正。我说 Haswell 可以同时进行两个 128 位加载和一个 128 位存储。事实上,它可以同时进行两次 256 位加载和一次 256 位存储(在一个周期内)。另一方面,即使它有 8 个端口,它每个时钟周期也只能执行 4 条指令(5 条带融合)。
  • @Zboson:那就编辑你的帖子,为什么要评论?
  • @einpoklum,好的,我做了更新(在几件事上)。让我知道你的想法
  • 做了一个小的额外编辑。确实没有必要保留您想要更正的文本,即使有删除线也是如此。只需将其删除。没有人“记得”你以前版本的答案(或者更确切地说,你可以忽略也许有些人记得它的事实)。而且,因为我还没有这么说 - 很好的答案!我真的需要去阅读大部分这些东西! :-)
猜你喜欢
  • 1970-01-01
  • 2011-03-17
  • 1970-01-01
  • 1970-01-01
  • 2021-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多