向量化,简单来说,就是优化算法,使其可以在处理器中使用 SIMD 指令。
AVX、AVX2 和 AVX512 是在一条指令中对多个数据执行相同操作的指令集 (intel)。例如。 AVX512 意味着您一次可以操作 16 个整数值(4 个字节)。这意味着如果你有 16 个整数的向量,并且你想在每个整数中将该值加倍,然后将 10 加到它上面。您可以将值加载到通用寄存器 [a,b,c] 16 次并执行相同的操作,或者您可以通过将所有 16 个值加载到 SIMD 寄存器 [xmm,ymm] 并执行一次操作来执行相同的操作。这可以加快矢量数据的计算速度。
在矢量化中,我们利用这一优势,通过重构我们的数据,以便我们可以对其执行 SIMD 操作并加速程序。
矢量化的唯一问题是处理条件。因为条件分支了执行流程。这可以通过掩蔽来处理。通过将条件建模为算术运算。例如。如果我们想在值大于 100 的情况下加 10。我们也可以。
if(x[i] > 100) x[i] += 10; // this will branch execution flow.
或者我们可以将条件建模为算术运算,创建一个条件向量 c,
c[i] = x[i] > 100; // storing the condition on masking vector
x[i] = x[i] + (c[i] & 10) // using mask
虽然这是一个非常简单的例子......因此,c 是我们的掩码向量,我们使用它来根据它的值执行二元运算。这避免了执行流程的分支并启用了矢量化。
向量化与并行化同样重要。因此,我们应该尽可能地利用它。所有现代处理器都具有用于繁重计算工作负载的 SIMD 指令。我们可以通过向量化优化我们的代码以使用这些 SIMD 指令,这类似于将我们的代码并行化以在现代处理器上可用的多个内核上运行。
我想谈谈 OpenMP,它可以让你使用 pragma 对代码进行矢量化。我认为这是一个很好的起点。 OpenACC 也可以这样说。