【发布时间】:2019-08-29 11:00:21
【问题描述】:
我有一些图像处理算法,我实现了三个版本:
- 使用 x64 指令集(rax、rbx、...寄存器)
- 使用 SSE 指令集(xmm 寄存器)
- 使用 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 特定优化,例如 emitting vzeroupper。所以我不知道如何在两种类型的 CPU 上使用相同的编译可执行文件获得最佳性能。
这可能吗?如果是,我需要将哪些编译标志提供给 Visual Studio 编译器?
【问题讨论】:
-
英特尔性能基元对每个 CPU 系列使用单独的二进制实现,在运行时从 DLL 中选择和加载,因此您可能不得不这样做。我很惊讶 AVX2 CPU 运行 SSE 代码的速度很慢。
-
Visual Studio 不会自动复制代码,它们会根据实际 CPU 使用适当的版本,因此您必须自己处理。最终,您需要提供多个代码路径,具体如何执行取决于您。当您想利用
/arch优化时,您很可能希望构建同一个 DLL 的多个版本,并在检测到实际 CPU 功能后加载最合适的版本。 -
SSE2 是 x86-64 的基线,而不仅仅是 SSE。
-
@RomanR.:不过,其他编译器可以对使用不同目标选项编译的克隆进行运行时调度。 ICC 只为未修改的源提供了选项,而 GCC 将使用
ifunc的东西。
标签: c++ visual-studio optimization simd