GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Erkennt, ob der Prozessor zur Kompilierzeit über RDTSCP verfügt

GCC definiert viele Makros, um zur Kompilierzeit zu bestimmen, ob eine bestimmte Funktion von der Mikroarchitektur unterstützt wird, die mit -march angegeben wird . Die vollständige Liste finden Sie im Quellcode hier. Es ist klar, dass GCC kein solches Makro für RDTSCP definiert (oder sogar RDTSC übrigens). Die Prozessoren, die RDTSCP unterstützen sind aufgeführt in:Was ist der gcc-CPU-Typ, der Unterstützung für RDTSCP beinhaltet?.

Sie können also Ihre eigene (möglicherweise unvollständige) Liste von Mikroarchitekturen erstellen, die RDTSCP unterstützen . Schreiben Sie dann ein Build-Skript, das das an -march übergebene Argument überprüft und sehen Sie, ob es in der Liste ist. Wenn dies der Fall ist, definieren Sie ein Makro wie __RDTSCP__ und verwenden Sie es in Ihrem Code. Ich nehme an, selbst wenn Ihre Liste unvollständig ist, sollte dies die Korrektheit Ihres Codes nicht beeinträchtigen.

Leider scheinen die Intel-Datenblätter nicht anzugeben, ob ein bestimmter Prozessor RDTSCP unterstützt obwohl sie andere Funktionen wie AVX2 diskutieren.

Ein potenzielles Problem dabei ist, dass es keine Garantie dafür gibt, dass jeder Ein einzelner Prozessor, der eine bestimmte Mikroarchitektur implementiert, wie z. B. Skylake, unterstützt RDTSCP . Solche Ausnahmen sind mir aber nicht bekannt.

Verwandte:Was ist der gcc-CPU-Typ, der Unterstützung für RDTSCP beinhaltet?.

Um die RDTSCP-Unterstützung zur Laufzeit zu bestimmen , kann der folgende Code auf Compilern verwendet werden, die GNU-Erweiterungen (GCC, clang, ICC) auf jedem x86-Betriebssystem unterstützen. cpuid.h kommt mit dem Compiler, nicht mit dem Betriebssystem.

#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;
    }
}

__get_cpuid() führt CPUID zweimal aus:einmal, um die maximale Stufe zu prüfen, einmal mit dem angegebenen Blattwert. Es gibt false zurück, wenn das angeforderte Level gar nicht verfügbar ist, deshalb ist es Teil eines && Ausdruck. Sie möchten dies wahrscheinlich nicht jedes Mal vor rdtscp verwenden, nur als Initialisierer für eine Variable, es sei denn, es handelt sich nur um ein einfaches einmaliges Programm. Siehe es im Godbolt-Compiler-Explorer.

Informationen zu MSVC finden Sie unter Wie erkennt man die rdtscp-Unterstützung in Visual C++? für Code mit seinem intrinsischen.

Für einige CPU-Funktionen, die GCC kennt, können Sie __builtin_cpu_supports verwenden um eine Feature-Bitmap zu überprüfen, die früh beim Start initialisiert wird.

// unfortunately no equivalent for RDTSCP
int sse42_supported() {
    return __builtin_cpu_supports("sse4.2");
}

Anmerkung des Herausgebers:https://gcc.gnu.org/wiki/DontUseInlineAsm . Diese Antwort war lange Zeit unsicher und wurde später so bearbeitet, dass sie nicht einmal kompiliert wird, während sie immer noch unsicher ist (RAX verstopfen, wodurch der "a" Constraint unerfüllbar, während immer noch Clobbers auf Registern fehlen, die CPUID schreibt). Verwenden Sie die Intrinsics in einer anderen Antwort. (Aber ich habe das Inline-Asm darin so korrigiert, dass es sicher und korrekt ist, falls jemand es kopiert/einfügt oder lernen möchte, wie man Einschränkungen und Clobbers richtig verwendet.)

Nachdem ich basierend auf den Vorschlägen von @Jason ein wenig mehr nachgeforscht habe, habe ich jetzt eine Laufzeitlösung (immer noch keine Kompilierungslösung), um festzustellen, ob RDTSCP existiert, indem das 28. Bit (siehe Ausgangsbitmap) des cpuid geprüft wird Anweisung mit 0x80000001 als Eingabe in EAX .

int if_rdtscp() {
    unsigned int edx;
    unsigned int eax = 0x80000001;
#ifdef __GNUC__              // GNU extended asm supported
    __asm__ (     // doesn't need to be volatile: same EAX input -> same outputs
     "CPUID\n\t"
    : "+a" (eax),         // CPUID writes EAX, but we can't declare a clobber on an input-only operand.
      "=d" (edx)
    : // no read-only inputs
    : "ecx", "ebx");      // CPUID writes E[ABCD]X, declare clobbers

    // a clobber on ECX covers the whole RCX, so this code is safe in 64-bit mode but is portable to either.

#else // Non-gcc/g++ compilers.
    // To-do when needed
#endif
    return (edx >> 27) & 0x1;
}

Wenn dies in 32-Bit-PIC-Code aufgrund des EBX-Clobbers nicht funktioniert, dann 1. hören Sie auf, 32-Bit-PIC zu verwenden, da es im Vergleich zu 64-Bit-PIC oder zu -fno-pie -no-pie ineffizient ist ausführbare Dateien. 2. Holen Sie sich einen neueren GCC, der EBX-Clobber sogar in 32-Bit-PIC-Code zulässt und zusätzliche Anweisungen zum Speichern/Wiederherstellen von EBX oder was auch immer benötigt wird, ausgibt. 3. Verwenden Sie die intrinsische Version (die dies für Sie umgehen sollte).

Im Moment bin ich mit GNU-Compilern zufrieden, aber wenn jemand dies unter MSVC tun muss, gibt es eine intrinsische Möglichkeit, dies zu überprüfen, wie hier erklärt.


Linux
  1. Wie erkennt man Bash>=4.0?

  2. Wie erkennt man einen Intel Grafikprozessor?

  3. Der beste Weg, einen Kernel für einen I7-Prozessor zu kompilieren?

  4. In C erkennen, wenn an ein Terminal ausgegeben wird

  5. Erkennung von 64-Bit-Kompilierung in C

Linux-Zeitbefehl

Letzter Befehl in Linux

Apricity OS wurde eingestellt!

Terminplanung mit cron &At

Zeitanzeige zeigt Datum/Uhrzeit nicht an?

Timen Sie die Ausführungszeit mehrerer Befehle