并行vs omp simd:什么时候使用每个?

OpenMP 4.0引入了一个名为“omp simd”的新构造。 使用这个构造比旧的“并行”有什么好处? 每个人什么时候比另一个更好呢?

编辑:这是一个有趣的文件相关的SIMD指令。

相关标准相对比较清楚(第13页,第19 + 20行)

当任何线程遇到simd构造时,与构造相关联的循环的迭代可以由线程可用的SIMD通道执行。

SIMD是一个子线程的东西。 为了使它更具体,在CPU上,你可以想象使用simd指令来专门请求单独属于相同线程的循环迭代块的vector化 。 它以独立于平台的方式展示了单个多核处理器中存在的多层并行性。 请参阅这篇英特尔博客文章中的讨论(以及加速器内容)。

所以基本上,你需要使用omp parallel将工作分配到不同的线程,然后可以迁移到多个核心。 你会想要使用omp simd来利用每个内核中的向量pipe道(比如说)。 通常omp parallel会在“外部”去处理工作的粗粒度的并行分配,而omp simd会围绕在那里的紧密循环来利用细粒度的并行性。

一个简单的答案:

OpenMP仅用于为多个核心利用多个线程。 这个新的simd扩展允许您在现代CPU上明确使用SIMD指令 ,比如Intel的AVX / SSE和ARM的NEON。

(请注意,SIMD指令是在单线程和单核上进行devise的,但是对于GPGPU来说SIMD的含义可以相当的扩展,但是我认为你不需要考虑OpenMP 4.0的GPGPU。 )

所以,一旦你知道SIMD指令,你可以使用这个新的结构。


在现代的CPU中,大致有三种types的并行:(1)指令级并行(ILP),(2)线程级并行(TLP)和(3)SIMD指令(我们可以说这是向量级或者)。

ILP由您的乱序CPU或编译器自动完成。 您可以使用OpenMP的parallel for和其他线程库来利用TLP。 那么,SIMD呢? 内在是一种使用它们的方式(以及编译器的自动vector化)。 OpenMP的simd是一种使用SIMD的新方法。

举一个非常简单的例子:

 for (int i = 0; i < N; ++i) A[i] = B[i] + C[i]; 

上面的代码计算两个N维向量的总和。 正如您可以很容易地看到的那样,数组A[]没有(循环携带的)数据依赖关系 。 这个循环是尴尬的平行 。

可能有多种方法来并行化这个循环。 例如,在OpenMP 4.0之前,只能使用parallel for构造。 每个线程将在多个核上执行N/#thread迭代。

然而,你可能会认为使用multithreading进行这种简单的添加会是一个矫枉过正的问题。 这就是为什么有vector化,这主要是由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 通道可以并行执行。

您可以同时使用线程级并行。 上面的例子可以进一步并行parallel for

(但是,我怀疑有多less个循环可以真正转换为SIMD循环,OpenMP 4.0规范似乎有点不清楚,所以真正的性能和实际限制将取决于实际编译器的实现。


总而言之, simd构造允许您使用SIMD指令,反过来,可以利用更多的并行性和线程级并行性。 不过,我认为实际的实施会很重要。

编译器不需要在存在simd子句的情况下在并行区域内进行simd优化。 我熟悉的编译器继续像以前一样支持嵌套循环,并行外部向量和内部向量。
过去,OpenMP指令通常用于防止涉及外部并行化循环(带有collapse子句的多个循环)的循环切换优化。 这在一些编译器中似乎已经改变了。 当设置omp parallel do [for] simd时,OpenMP 4开辟了新的可能性,包括通过一种条带挖掘优化具有不可vector化的内部循环的并行外部循环。 ifort有时会在没有simd子句的情况下将其报告为外部循环向量化。 它可能会比omp parallel do simd更less的线程优化,似乎需要比simdvector宽度还要多的线程。 这样的区别可能被推断出来,因为如果没有simd子句,隐式地要求编译器针对诸如100或300的循环计数进行优化,而simd子句要求无条件的simd优化。 当我有一个24核心平台时,gcc 4.9 omp并行simd看起来相当有效。