提问人:Norgannon 提问时间:11/7/2023 最后编辑:phuclvNorgannon 更新时间:11/8/2023 访问量:312
如何在运行时区分 C++ 中的英特尔 CPU 代系?
How to differentiate between Intel CPU generations in C++ at runtime?
问:
过去,SIMD 在 Intel CPU 上产生了初始化成本。因此,我正在寻找一种方法来区分在 C++ 运行时运行我的程序的一代 Intel CPU。
有没有一种简单的方法可以区分所有比 Ice Lake 更旧的 Intel CPU?
注意:检测运行的 CPU 是否是 Intel CPU 相当简单,但遗憾的是,对于这个用例来说还不够。
答:
2赞
Henrique Bucher
11/8/2023
#1
您可以让编译器在加载时使用编译器目标属性(或GCC调用的函数多版本控制)为您确定cpu属性,而不是在运行时手动检查cpu属性。
不幸的是,即使在“三大”编译器之间,它也不是标准功能,但 clang 和 gcc 至少都提供了类似的实现。
这里有一个教程,讨论了几种边缘情况的解决方法,但总的来说,这应该是相当透明的。
您可以在 Github 上查看此代码,但基本上有两种方法可以做到这一点。
首先,您可以手动实现每个体系结构的版本target
namespace detail {
inline Vector multiply(const Matrix& m, const Vector& v) {
Vector r;
r[0] = v[0] * m[0] + v[1] * m[2];
r[1] = v[0] * m[1] + v[1] * m[3];
return r;
}
} // namespace detail
__attribute__((target("default"))) Vector multiply(const Matrix& m, const Vector& v) {
printf("default\n");
return detail::multiply(m, v);
}
__attribute__((target("arch=core2"))) Vector multiply(const Matrix& m, const Vector& v) {
printf("core2\n");
return detail::multiply(m, v);
}
__attribute__((target("arch=sandybridge"))) Vector multiply(const Matrix& m, const Vector& v) {
printf("sandybridge\n");
return detail::multiply(m, v);
}
其次,如果所有实现在代码中都相似,则在选择所有可能的体系结构进行版本控制时,使用会更方便。target_clones
__attribute__((target_clones("default", "arch=core2", "arch=sandybridge", "arch=haswell", "arch=cascadelake",
"arch=znver1", "arch=znver2"))) Vector
multiply(const Matrix& m, const Vector& v) {
Vector r;
r[0] = v[0] * m[0] + v[1] * m[2];
r[1] = v[0] * m[1] + v[1] * m[3];
return r;
})
运行后,链接的代码将自动为目标计算机选择正确的实现。
阅读更多:文档
评论
1赞
Norgannon
11/9/2023
这是一个有趣的选择,知道存在!我肯定必须多读一些关于它的信息。谢谢!您知道 MSVC 是否也具有此功能的实现吗?我找不到它,所以假设它没有,但我可能没有使用正确的关键字。
1赞
Soonts
11/9/2023
@Norgannon 据我所知,事实并非如此。(1) 不支持多版本控制 (2) VC++ 编译器在编译时也不会区分这些代。它只有启用/禁用 AVX1/AVX2/AVX512 的开关,但没有专门针对 Skylake/Zen3/等进行优化的开关。
0赞
Soonts
11/9/2023
如果你真的需要在Visual Studio中,我相信不久前Microsoft发布了一个clang分支作为IDE的可选功能。您可以尝试将编译器从 MSVC 切换到那个编译器,但我没有这方面的实践经验。
0赞
Norgannon
11/9/2023
@Soonts 有趣!从 MSVC 完全切换到 Clang 很可能会比这里更麻烦。我可能只是依靠正在实施的 GFNI 来识别 MSVC 上的 Ice Lake+ Intel CPU。我也在研究 GCC/Clang 兼容性,所以......使用这种更可靠的解决方案很诱人,但混合使用这两种解决方案可能是一个糟糕的决定。我会考虑的。也许从长远来看,这将是解决方案,除非问题变得太老了,而那些较旧的CPU在这一点上无处可寻。
评论
/proc/cpuinfo
cpuid