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

zr.*_*zr. 50 c c++ performance simd openmp

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

编辑:这是一篇与SIMD指令相关的有趣论文.

min*_*ang 43

一个简单的答案:

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];
Run Code Online (Sandbox Code Playgroud)

上面的代码计算两个N维向量的总和.您可以很容易地看到,阵列上没有(循环传送的)数据依赖性A[].这个循环令人尴尬地平行.

可以有多种方法来并行化此循环.例如,在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);
Run Code Online (Sandbox Code Playgroud)

该代码假定(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 通道可以并行执行.

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

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


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

  • "但是,我认为你不需要考虑GPGPU用于OpenMP 4.0." 事实上,人们确实如此 - 在OpenMP 4.0中建议支持GPGPU(和其他类型的加速器),但它是在一个单独的[TR]中(http://www.openmp.org/mp-documents /TR1_167.pdf)而不是主要文本的一部分(认为他们这样做是因为文本不像所要求的那样精确,以便被包括在关于SC'12会议发生时间的主要审查文本中). (2认同)

Jon*_*rsi 40

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

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

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

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