是否可以使用SIMD指令批处理相同的功能?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了是否可以使用SIMD指令批处理相同的功能?相关的知识,希望对你有一定的参考价值。

我有一个场景,许多完全相同的功能(为简单起见,我们只考虑C / C ++和python)将在我的机器上同时执行。直观地说,我只是使用多线程将函数的每个实例视为利用并行性的线程,它们不会争用相同的资源,但是它们会进行许多分支操作(例如,for循环)。但是,由于它们实际上是相同的功能,我正在考虑使用一些SIMD指令(例如AVX-512)对它们进行批处理。当然,它应该是自动的,以便用户不必修改他们的代码。

原因?因为每个线程/进程/容器/ VM占用资源,但AVX只需要一条指令。所以我可以使用相同的硬件来容纳更多用户。

我在网上找到的大多数文章都专注于在函数内部使用AVX指令,例如,加速流数据处理,或处理一些大型计算。他们都没有提到批处理相同功能的不同实例。

我知道存在一些挑战,例如由不同输入引起的不同执行路径,并且将正常功能自动转换为批量版本并不容易,但我认为这在技术上确实是可能的。

这是我的问题

  1. 是否很难(或可能)将正常功能自动更改为批量版本?
  2. 如果1为否,那么我应该对该功能施加什么限制才能实现?例如,如果函数只有一条路径而不管数据是什么?
  3. 还有其他技术可以更好地解决问题吗?我不认为GPU对我来说是一个不错的选择,因为GPU不能支持IO或分支指令,尽管它的SIMT非常适合我的目标。

谢谢!

答案

SSE / AVX基本上是一个向量单元,它允许一次对多个元素的数组进行简单的操作(如+ - * /和,或XOR等)。 AVX1和2具有256字节寄存器,因此您可以执行以下操作: 8个32位单声道,或4个双打。 AVX-512即将推出,但非常罕见。

因此,如果您的函数都是基本类型数组上的所有操作,那么这很自然。如果操作非常简单,使用AVX内在函数重写函数是可行的。复杂的东西(比如不匹配矢量宽度)或甚至在汇编程序中这样做都是一个挑战。

如果你的函数不是在向量上运行那么就变得困难了,而且可能性主要是理论上的。自动向量化编译器有时可以做到这一点,但它很少见且有限,而且非常复杂。

另一答案

有两种方法可以解决这个问题:矢量化(SIMD)和并行化(线程)。

如果内联函数,GCC已经可以进行所需的SIMD矢量化,并且类型和操作是兼容的(并且它会自动内联小函数而不需要它)。

EG

inline void func (int i) {
   somearray[i] = someotherarray[i] * athirdarray[i];
}

for (int i = 0; i < ABIGNUMBER; i++)
   func (i);

-O3启用了矢量化和内联。

如果函数太复杂,和/或GCC尚未对其进行矢量化,则可以使用OpenMP或OpenACC对其进行并行化。

OpenMP使用特殊标记来告诉编译器在哪里生成线程。

EG

#pragma omp parallel
#pragma omp for
for (int i = 0; i < ABIGNUMBER; i++)
    ....

是的,你也可以在GPU上做到这一点!您必须进行更多输入才能正确复制和复制数据。只有标记区域在GPU上运行。其他所有东西都在CPU上运行,因此I / O等不是问题。

#pragma omp target map(somearray,someotherarray,athirdarray)
#pragma omp parallel
#pragma omp for
for (int i = 0; i < ABIGNUMBER; i++)
    ....

OpenACC是一个类似的想法,但更专注于GPU。

您可以在许多地方找到OpenMP和OpenACC编译器。 GCC和LLVM都支持NVidia GPU。 LLVM对AMD GPU有一些支持,也有非官方的GCC版本(很快就会有官方支持)。

以上是关于是否可以使用SIMD指令批处理相同的功能?的主要内容,如果未能解决你的问题,请参考以下文章

使用 simd 指令时,32 位图像处理是不是比 24 位图像处理快?

使用 ARM SIMD 指令优化掩码功能

是否可以使用 SIMD 指令进行 3x3 矩阵求逆?

SSE3指令有啥功能?

使用 SIMD 指令的平滑样条曲线

使用 SIMD 指令将代码转换为代码