OpenMP 4.0引入了一个名为“omp simd”的新结构。与旧的“parallel for”相比,使用此构造有什么好处?什么时候会比另一个更好?
编辑: 这是一个有趣的paper与 SIMD 指令相关。
最佳答案
一个简单的答案:
OpenMP 仅用于为多个内核利用多个线程。这个新的 simd
扩展允许您在现代 CPU 上显式使用 SIMD 指令,例如 Intel 的 AVX/SSE 和 ARM 的 NEON。
(请注意,SIMD 指令在设计上是在单线程和单核中执行的。但是,对于 GPGPU,SIMD 的含义可以相当扩展。但是,但我认为您不需要考虑 GPGPU OpenMP 4.0。)
因此,一旦您了解 SIMD 指令,就可以使用这个新结构。
在现代 CPU 中,大致有三种类型的并行:(1) 指令级并行 (ILP),(2) 线程级并行 (TLP),以及 (3) SIMD 指令(我们可以说这是 vector 级左右)。
ILP 由您的乱序 CPU 或编译器自动完成。您可以使用 OpenMP 的 parallel for
和其他线程库来利用 TLP。那么,SIMD 呢?内在函数是使用它们的一种方式(以及编译器的自动矢量化)。 OpenMP 的 simd
是一种使用 SIMD 的新方法。
举个很简单的例子:
for (int i = 0; i < N; ++i)
A[i] = B[i] + C[i];
上面的代码计算两个 N 维 vector 的和。如您所见,没有(loop-carried) data dependency在数组 A[]
上。这个循环是embarrassingly parallel .
可能有多种方法可以并行化此循环。例如,在 OpenMP 4.0 之前,这可以仅使用 parallel for
构造进行并行化。每个线程将在多个内核上执行 N/#thread
次迭代。
但是,您可能会认为使用多个线程来进行这种简单的加法操作有点过头了。这就是为什么会有向量化,这主要是通过 SIMD 指令实现的。
使用 SIMD 是这样的:
for (int i = 0; i < N/8; ++i)
VECTOR_ADD(A + i, B + i, C + i);
此代码假设 (1) SIMD 指令 (VECTOR_ADD
) 是 256 位或 8 路(8 * 32 位); (2) N
是 8 的倍数。
8 路 SIMD 指令意味着一个 vector 中的 8 个项目可以在一条机器指令中执行。请注意,英特尔最新的 AVX 提供了这样的 8 路(32 位 * 8 = 256 位) vector 指令。
在 SIMD 中,您仍然使用单核(同样,这仅适用于传统 CPU,不适用于 GPU)。但是,您可以在硬件中使用隐藏的并行性。现代 CPU 将硬件资源专用于 SIMD 指令,其中每个 SIMD lane 都可以并行执行。
您可以同时使用线程级并行。上面的例子可以通过parallel for
进一步并行化。
(但是,我怀疑有多少循环可以真正转换为 SIMDized 循环。OpenMP 4.0 规范对此似乎有点不清楚。因此,实际性能和实际限制将取决于实际编译器的实现。)
总而言之,simd
构造允许您使用 SIMD 指令,进而可以利用线程级并行性来利用更多并行性。但是,我认为实际的实现很重要。
关于c++ - 与 omp simd : when to use each? 并行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14674049/