HPC编程语言依赖于隐式向量化

die*_*gor 15 c hpc vectorization opencl

是否存在依赖于隐式向量化的编程语言或语言扩展?

对于标量C代码的单/双精度的SSE4.1,AVX,AVX2(有或没有FMA3/4),我需要做出积极的假设来生成良好的DLP /向量化代码.

在过去的10年里,我依靠英特尔的内在函数来编写我的HPC内核,并明确地进行了矢量化.与此同时,我经常对C/C++编译器(GCC,clang,LLVM等)生成的DLP代码的质量感到失望,如果你问,我可以发布具体的例子.

内在指南来看,很明显,为现代平台编写带有内在函数的"手动"HPC内核不再是一个可持续的选择,除非我有一大批程序员.太多版本和组合:SSE4.1,AVX,AVX2,AVX512 +口味,FMA,SP,DP,半精度?如果我的目标平台是2012年以来最普遍的平台,那就不可持续了.

我最近尝试过针对OpenCL(CPU)的英特尔离线编译器.我编写了内核"a la CUDA"(即标量代码,隐式向量化),令我惊讶的是生成的程序集非常好地矢量化了!(Skylake,SP中的AVX2 + FMA)我遇到的唯一限制是缺少内置的数据缩减/互通通信功能,而不依赖于共享内存(可转换为CPU水平添加或shuffle + min/max操作) .

正如clemens和sschuberth所指出的那样,离线编译器并不是真正的解决方案,除非我不完全接受OpenCL.或者我破解我的调用者代码以遵守生成的程序集的调用约定,其中包括我不需要的参数,例如ndrange.完全接受OpenCL对我来说也不是一个选择,因为对于TLP我依赖于OpenMP和Pthreads(对于ILP,我依赖于硬件).

更新

首先,值得回顾一下隐式矢量化和自动矢量化并不是一回事.事实上,我对自动向量化失去了希望(如上所述).不在隐式矢量化中.

下面的答案之一是要求一些代码示例. 这里我提供了一个内核的代码示例,该内核在三维结构块上实现NSE对流项的三阶逆风方案.值得一提的是,这代表了一个 简单的例子,因为不需要SIMD通道间合作/通信.

die*_*gor 11

英特尔SPMD程序编译器.

目前,最佳选择是英特尔SPMD程序编译器.ISPC是一个开源编译器,其编程模型依赖于隐式向量化(借用英特尔OpenCL SDK文档的术语)来输出向量化汇编代码.ISPC将源代码映射到SSE4.1,AVX,AVX2,KNC和KNL的SPX512指令.ISPC的后端是LLVM.

对于CFD内核,它只提供无与伦比的性能.对于必须是标量的代码部分,只需将"uniform"关键字添加到关联变量即可.有用于通道间通信的内置功能,如shuffle,broadcast和reduce_add等.

为什么ISPC与其他C++编译器相比如此之快?我的猜测是因为C/C++编译器假设没有任何东西可以被矢量化,除非有明确的相反证据.除非另有说明,否则ISPC假定所有SIMD通道都(独立地)执行每行代码.

我想知道为什么ISPC还没有被广泛接受.也许是因为他的少年阶段,但它已经在CG /科学可视化社区中展示了很强大的能力(Embree,OSPray).ISPC是编写HPC内核的一个很好的选择,因为它似乎很好地弥合了性能 - 生产力差距.

基准

对于问题中引用的简单内核示例,使用GCC 4.9.X和ISPC 1.8.2获得以下结果.根据每个周期的FLOP报告性能.

在此输入图像描述

此处未报告ICC结果(就可访问性而言,向ICC报告免费和开源编译器是否100%公平?).尽管如此,在这种情况下,ICC相对于GCC报告的最大增益约为4倍,因此不会影响ISPC的优势.

  • 我认为你不太了解我的答案.OpenMP 4.0`pragma omp simd`与线程无关,CilkPlus也不是pragma simd`或类似Fortran的数组符号.这些是使用SIMD指令实现的,而不是线程.关于用于矢量化的英特尔C/C++编译器的保守性质的断言是错误的,除非ISO C/C++缺乏明确的矢量化.我希望您的代码和数据显示ISPC比ICC更快,因为我与开发两者的人合作.您是否真的编写了与ISPC在语义上等效的C/C++代码? (2认同)

Jef*_*eff 7

请注意,如果没有数学或代码示例,很难知道这里的最佳答案是什么.如果您提供代码示例,我将尝试使用下面提到的一些方言来实现它.

Fortran 90

Fortran 90+冒号表示法是实现隐式向量化的一种很好的方法,虽然我怀疑如果你是C内在函数程序员,Fortran不是你愿意使用的东西.

关于这个主题的一个合理的信息来源是fortran90.org.

OpenMP 4.0

OpenMP 4.0引入了SIMD关键字,它强制编译器对代码进行矢量化.您应该将其作为内在函数的替代方案.

有大量的OpenMP 4.0 pragma omp simd在线示例,但非常简单的一个是使用OpenMP4.0在程序中启用SIMD.

显然,OpenMP的最终权限是最新的特性:OpenMP应用程序编程接口版本4.5.

CilkPlus

既然你已经表明,你愿意写低于ISO标准的代码,你可能愿意使用CilkPlus扩展到由英特尔编译器和GCC(以及可能锵/ LLVM支持C/C++,但还没不经过验证.

有关详细信息,请参阅使用英特尔®Cilk ™PlusCilkPlus主页的最佳实践.

OpenCL的

OpenCL在理论上是另一个不错的选择,但在实践中似乎不太引人注目.我自己不是OpenCL用户,但我与OpenCL编程指南的作者合作,我认为他是一个可靠的来源.

自动向量化

如果一切都失败了,英特尔16编译器一个不错的工作autovectorizing,但你必须阅读选择报告,使用restrict__assume_aligned在许多情况下.

尝试使用Intel C/C++实现自动向量化时,最好的起点是-qopt-report编译器选项.这通常会告诉你什么是矢量化而不是,为什么.您可能需要使用不同的分配器(为什么要用_mm_malloc?(而不是_aligned_malloc,alligned_alloc,或posix_memalign)列出了相关的选项),然后用__assume_aligned你的内核.如果您使用第二代英特尔至强核处理器(又名Knights Landing)或其他支持它们的产品,AVX-512CDI指令可能会有所帮助,那么矢量依赖性可能更难以缓解.

Cray编译器也可以自动进行自动向量化,但仅限于有权访问Cray超级计算机的用户.

对于那些好奇的人,我对这些编译器的乐观是基于NWChem内核获得的结果.使用Fortran 77,OpenMP 3/4以及使用其他编译器指令可以获得最佳结果,但至少在那里没有特定于处理器的代码.并且C99内核的矢量化足够好.

放弃

我在英特尔从事研究/寻路工作.我不使用任何软件产品,但我不时向编译器团队的专家学习.