c++ - 与 omp simd : when to use each? 并行

标签 c++ c performance openmp simd

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/

相关文章:

c++ - 混合使用 C 和 C++ 时出现重复符号

c - 同时生成真正的随机整数?

ajax - 在我的 ASP.NET MVC 应用程序中将 JSON 数据检索到 jqGrid 时,我应该使用 POST 还是 GET?

python - 替换字符串中一组字符的最快方法

c++ - 在 x64 系统上从 32 位应用程序使用 IFilter

c++ - POSIX 计时器信号未在信号处理程序中被阻止

ios - printf 中的奇怪字符

mysql - 优化慢速 SELECT 查询

c++ - 在条件中使用 boost::tribool 时是编译器错误还是我的错误?

c++ - 如何获取 crtdbg.h 文件?