zr.*_*zr. 50 c c++ performance simd openmp
OpenMP 4.0引入了一个名为"omp 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指令,反过来,可以利用更多的并行性以及线程级并行性.但是,我认为实际的实施很重要.
Jon*_*rsi 40
链接标准相对清晰(第13页,第19 + 20行)
当任何线程遇到simd构造时,与构造相关联的循环的迭代可以由线程可用的SIMD通道执行.
SIMD是一个子线程的东西.为了使它更具体,在CPU上你可以想象使用simd指令来专门请求对单独属于同一线程的循环迭代块进行矢量化.它以独立于平台的方式揭示了单个多核处理器中存在的多级并行性.例如,请参阅此英特尔博客文章中的讨论(以及加速器内容).
所以基本上,你会想要将omp parallel工作分配到不同的线程,然后可以迁移到多个核心; 并且您将要使用omp simd在每个核心内使用矢量管道(比如说).通常情况下omp parallel会在"外部"处理粗粒度的并行分布工作,并且omp simd会绕过内部的紧密循环来利用细粒度的并行性.