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

标签 c++ visual-studio optimization simd

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

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

每个优化步骤都会提高性能。但是,我需要在旧CPU上运行它,它只支持SSE(我在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)

My vectorized code uses intrinsics, like so:

// 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 调度(查看英特尔编译器文档中的 ax 标志)。 ax 标志特定于 Intel 编译器并进行隐式 CPU 调度。它在 VS 上不可用,因此您必须手动执行。

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

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

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

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

关于c++ - 如何在新 CPU 上利用 AVX2,同时支持旧 CPU?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55570983/

相关文章:

c++ - 在 700,000 个 vector 元素处突然出现内存峰值

c++ - 为 OpenCV 编译 MATLAB 绑定(bind)

elasticsearch - 如何在 Elasticsearch 5 中强制合并段?

java - for 循环内的引用类型变量声明

c++ - 在c/c++中非阻塞写入文件

c++ - BitBlt 从剪贴板复制位图给出了错误的颜色

c# - Visual Studio 2017 + Entity Framework + 身份 + mysql 不工作

vis studio 2008 中的 c++ 调试,如何在变量变为零时中断

c# - 如何在 VS2010 中创建 .NET2 兼容的应用程序?

java - Apache Commons 数学优化