我有一些图像处理算法,该算法在三个版本中实现:
每个优化步骤都会提高性能。但是,我需要在仅支持SSE的旧CPU上运行它(我在Visual Studio上使用x64平台,因此我所有的CPU都支持SSE)。
在Visual Studio中,有一个名为“启用增强指令集”的设置,必须将其设置为/arch:AVX2
,才能在较新的CPU上获得最佳性能。但是,使用此设置,可执行文件在我的旧CPU上崩溃。如果我将“启用增强指令集”设置为/arch:SSE2
,则我的可执行文件可以在较旧的CPU上运行,但是在较新的CPU上无法获得最佳性能。
我使用较新的CPU测量了编译器标志和指令集所有组合的执行速度。总结在下表中。
Instruction set || Compilation flags which I use || /arch:SSE /arch:AVX2 ----------------++------------------------------------ x64 || bad (4.6) bad (4.5) SSE || OK (1.9) bad (5.3) AVX2 || bad (3.2) good (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编译器哪些编译标志?
答案 0 :(得分:2)
英特尔这样做的方法是CPU调度(请检查英特尔编译器文档中的ax
标志)。 ax
标志特定于Intel编译器,并进行隐式CPU调度。它在VS上不可用,因此您必须手动进行。
在代码的开头,检查CPU功能并在某个位置设置一些全局标志。
然后,当您调用其中一个函数时,首先要检查标志状态以查看实际要调用的函数。
因此,您最终得到了不同的功能风格。为了解决这个问题,您可以将它们放在其他特定的命名空间中(例如libsimdpp进行命名),或者手动修改函数名(例如Intel编译器进行修改)。
此外,任何64位CPU都通过构造支持SSE2,因此情况1不存在。