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

时间:2013-02-03 15:29:01

标签: c++ c performance openmp simd

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

编辑: 这是一个与SIMD指令相关的有趣paper

3 个答案:

答案 0 :(得分:41)

一个简单的答案:

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

(注意,SIMD指令是在单个线程和单个内核中执行的。但是,对于GPGPU,SIMD的含义可以大大扩展。但是,我认为你不需要考虑GPGPU OpenMP 4.0。)

因此,一旦您了解了SIMD指令,就可以使用这个新结构。


在现代CPU中,大致有三种类型的并行:(1)指令级并行(ILP),(2)线程级并行(TLP),以及(3)SIMD指令(我们可以说这是矢量级左右。)

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

举一个非常简单的例子:

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

上述代码计算两个N维向量的总和。您可以很容易地看到,数组A[]上没有(loop-carried) data dependency。这个循环是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指令意味着矢量中的8个项目可以在单个机器指令中执行。请注意,英特尔最新的AVX提供了这种8路(32位* 8 = 256位)向量指令。

在SIMD中,您仍然使用单核(再次,这仅适用于传统CPU,而不是GPU)。但是,您可以在硬件中使用隐藏的并行性。现代CPU将硬件资源专用于SIMD指令,其中每个SIMD lane 可以并行执行。

您可以同时使用线程级并行。上述示例可以通过parallel for进一步并行化。

(但是,我怀疑有多少循环可以真正转换为SIMDized循环.OpenMP 4.0规范似乎有点不清楚。因此,真正的性能和实际限制将取决于实际编译器的实现。)< / p>


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

答案 1 :(得分:39)

链接标准相对清晰(第13页,第19 + 20行)

  

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

SIMD是一个子线程的东西。为了使其更具体,在CPU上可以想象使用simd指令专门请求矢量化的循环迭代块,它们分别属于同一个线程。它以独立于平台的方式暴露单个多核处理器中存在的多级并行性。例如,参见intel blog post上的讨论(以及加速器内容)。

基本上,您希望使用omp parallel将工作分配到不同的线程,然后可以迁移到多个核心;并且您希望使用omp simd来使用每个核心内的矢量管道(比如说)。通常情况下,omp parallel会在&#34;外部&#34;处理粗粒度的并行工作分配和omp simd会绕过内部的紧密循环来利用细粒度的并行性。

答案 2 :(得分:1)

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