如何在新CPU上利用AVX2,同时支持旧CPU?

How to take advantage of AVX2 on new CPUs while also supporting old CPUs?

本文关键字:CPU 支持 AVX2      更新时间:2023-10-16

我有一些图像处理算法,我在三个版本中实现了它:

  1. 使用 x64 指令集(rax、rbx、...寄存器)
  2. 使用 SSE 指令集(xmm 寄存器)
  3. 使用 AVX2 指令集(ymm 寄存器)

每个优化步骤都会提高性能。但是,我需要在仅支持 SSE 的旧 CPU 上运行它(我在 Visual Studio 上使用 x64 平台,所以我所有的 CPU 都支持 SSE)。

在Visual Studio中,有一个名为"启用增强指令集"的设置,我必须将其设置为/arch:AVX2,以便在较新的CPU上获得最佳性能。但是,使用此设置,可执行文件在我的旧 CPU 上崩溃。如果我将"启用增强指令集"设置为/arch:SSE2,那么我的可执行文件可以在较旧的 CPU 上运行,但我在较新的 CPU 上无法获得最佳性能。

我使用较新的 CPU 测量了编译器标志和指令集的所有组合的执行速度。下表显示了摘要。

指令集 ||       编译标志 我用的||   /arch:SSE/arch:AVX2 ----------------++------------------------------------ x64 ||    不好 (4.6) 不好 (4.5) 上交所 ||    正常 (1.9) 差 (5.3) AVX2 ||    不好 (3.2) 好 (1.4)

我的矢量化代码使用内部函数,如下所示:

// AVX2 - conversion from 32-bit to 16-bit
temp = _mm256_packus_epi32(input[0], input[1]);
output = _mm256_permute4x64_epi64(temp, 0xd8);
// SSE - choosing one of two results using a mask
result = _mm_blendv_epi8(result0, result1, mask);

我猜如果Visual Studio获得/arch:AVX2编译标志,它会执行所有必要的AVX2特定优化,例如发出vzeroupper。所以我不明白如何使用相同的编译可执行文件在两种类型的 CPU 上获得最佳性能。

这可能吗?如果是,我需要向Visual Studio编译器提供哪些编译标志?

英特尔这样做的方式是 CPU 调度(查看英特尔编译器文档中的ax标志)。ax标志特定于英特尔编译器,并进行隐式 CPU 调度。它在VS上不可用,因此您必须手动执行此操作。

在代码开始时,检查 CPU 功能并在某处设置一些全局标志。

然后,当您调用其中一个函数时,首先检查标志状态以查看您实际要调用的函数。

因此,您最终会得到不同风格的函数。为了解决这个问题,您可以将它们放在不同的特定命名空间中(如 libsimdpp 所做的),或者手动修改函数名称(如英特尔编译器所做的)。

此外,任何 64 位的 CPU 都通过构造支持 SSE2,因此情况 1 不存在。