我想学习使用 Intel 的 Haswell CPU 微架构进行并行编程。关于在 asm/C/C++/(任何其他语言)中使用 SIMD:SSE4.2、AVX2?。你能推荐书籍、教程、互联网资源、课程吗?
谢谢!
我想学习使用 Intel 的 Haswell CPU 微架构进行并行编程。关于在 asm/C/C++/(任何其他语言)中使用 SIMD:SSE4.2、AVX2?。你能推荐书籍、教程、互联网资源、课程吗?
谢谢!
在我看来,您通常需要了解 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 最常见的两个问题是竞争条件和错误共享。定期在 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)。还研究英特尔条带挖掘使用 SSE 计算矩阵乘积比使用直接算法慢得多
有关在光线追踪中实现 SIMD 的有趣方法,请参阅Ingo Wald 的博士论文。我对 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
FMA3 是自 Haswell 以来的新产品。它太新了,所以还没有太多关于它的讨论。但是这个答案(对我的问题)很好 How to use Fused Multiply-Add (FMA) instructions with SSE/AVX。FMA3 使峰值 FLOPS 翻倍,因此与 Ivy Bridge 相比,Haswell 上的矩阵乘法可能快两倍。
根据这个答案,FMA 最重要的方面不是它是一条指令而不是两条指令来进行乘法和加法,而是“(实际上)中间结果的无限精度”。例如,在没有 FMA 的情况下实现双倍乘法需要 6 次乘法和多次加法,而使用 FMA 只需两次操作。
指令级并行
Haswell 有 8 个端口,可以将 μ-ops 发送到这些端口(尽管并非每个端口都可以采用相同的 mirco-op;请参阅此AnandTech 评论)。这意味着 Haswell 可以同时执行两个 256 位加载、一个 256 位存储、两个 256 位 FMA 操作、一个标量加法和一个条件跳转(每个时钟周期六个 μ-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以及为什么转置 512x512 的矩阵比转置 513x513 的矩阵慢得多?
缓存的另一个非常有用的主题是循环阻塞或平铺。请参阅我的答案(得票最高的那个)在什么是用 C++ 转置矩阵的最快方法?例如。
在 IGP 上计算(使用 Iris Pro)。
所有 Haswell 消费者处理器(Haswell-E 尚未推出)都有 IGP。IGP 使用至少 30% 到超过 50% 的硅。这对于至少 2 个以上的 x86 内核来说已经足够了。对于大多数程序员来说,这是浪费的计算潜力。对 IGP 进行编程的唯一方法是使用 OpenCL。英特尔没有适用于 Linux 的 OpenCL Iris Pro 驱动程序,因此您只能使用 Windows(我不确定 Apple 对此的实现有多好)。 在没有 OpenCL 的情况下对 Intel IGP(例如 Iris Pro 5200)硬件进行编程。
与 Nvidia 和 AMD 相比,Iris Pro 的一个优势是双浮点速度仅为Iris Pro 单浮点速度的四分之一(但是 fp64 仅在 Direct Compute 中启用,而在 OpenCL 中不启用)。NVIDIA 和 AMD(最近)严重削弱了双浮点,以至于 GPGPU 双浮点计算在他们的消费卡上不是很有效。