SIMD 过去在 Intel CPU 上有初始化成本。因此,我正在寻找一种方法来在 C++ 运行时区分哪一代 Intel CPU 正在运行我的程序。
有没有一种简单的方法来区分所有早于Ice Lake的Intel CPU?
注意:检测运行的 CPU 是否为 Intel CPU 相当简单,但遗憾的是对于此用例来说还不够。
您可以让编译器在加载时使用编译器目标属性(或 GCC 所说的函数多版本控制)来计算出它,而不是在运行时手动检查 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;
})
运行后,链接的代码将自动为您的目标机器选择正确的实现。
阅读更多:文档