检测处理器在编译时是否具有RDTSCP

Jun*_*aid 6 c c++ linux x86 intel

一些新的英特尔处理器既有RDTSCRDTSCP指令,而最年长的处理器只有RDTSC指令.

在C/C++中编码时,如何在编译时检测所使用的体系结构是否有RDTSCP指令?

我知道我们可以通过浏览CPU信息(例如,cat/proc/cpuinfo)然后调整我们的代码来手动检查.但是在编译时获取此信息(作为宏或标志值)将真正省略手动检查和编辑代码的需要.

Had*_*ais 5

GCC 定义了许多宏来在编译时确定使用-march. 您可以在此处的源代码中找到完整列表。很明显,GCC 没有为RDTSCP(或什至RDTSC为此)定义这样的宏。支持的处理器RDTSCP列在:什么是包含对 RDTSCP 支持的 gcc cpu 类型?.

因此,您可以制作自己的(可能不完整的)列表微体系结构支持RDTSCP. 然后编写一个构建脚本来检查传递给的参数-march并查看它是否在列表中。如果是,则定义一个宏,例如__RDTSCP__并在您的代码中使用它。我认为即使您的列表不完整,也不应该损害您代码的正确性。

不幸的是,RDTSCP尽管英特尔数据表讨论了 AVX2 等其他功能,但它们似乎并未指定特定处理器是否支持。

这里的一个潜在问题是,无法保证实现特定微体系结构(例如 Skylake)的每个处理器都支持RDTSCP. 我不知道这样的例外。

相关:包含对 RDTSCP 支持的 gcc cpu 类型是什么?.


要在运行时确定 RDTSCP 支持,可以在任何 x86 操作系统上支持 GNU 扩展(GCC、clang、ICC)的编译器上使用以下代码。 cpuid.h带有编译器,而不是操作系统。

#include <cpuid.h>

int rdtscp_supported(void) {
    unsigned a, b, c, d;
    if (__get_cpuid(0x80000001, &a, &b, &c, &d) && (d & (1<<27)))
    {
        // RDTSCP is supported.
        return 1;
    }
    else
    {
        // RDTSCP is not supported.
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

__get_cpuid()运行 CPUID 两次:一次检查最大级别,一次使用指定的叶值。如果请求的级别甚至不可用,它就会返回 false,这就是为什么它是&&表达式的一部分。您可能不想每次都在 rdtscp 之前使用它,只是作为变量的初始化程序,除非它只是一个简单的一次性程序。在 Godbolt 编译器浏览器上查看。

对于 MSVC,请参阅如何检测 Visual C++ 中的 rdtscp 支持?对于使用其内在的代码。


对于 GCC 知道的某些 CPU 功能,您可以使用__builtin_cpu_supports检查在启动早期初始化的功能位图。

// unfortunately no equivalent for RDTSCP
int sse42_supported() {
    return __builtin_cpu_supports("sse4.2");
}
Run Code Online (Sandbox Code Playgroud)