GNU/Linux >> Belajar Linux >  >> Linux

Mendeteksi apakah prosesor memiliki RDTSCP pada waktu kompilasi

GCC mendefinisikan banyak makro untuk menentukan pada waktu kompilasi apakah fitur tertentu didukung oleh mikroarsitektur yang ditentukan menggunakan -march . Anda dapat menemukan daftar lengkapnya di kode sumber di sini. Jelas bahwa GCC tidak mendefinisikan makro seperti itu untuk RDTSCP (atau bahkan RDTSC untuk masalah itu). Prosesor yang mendukung RDTSCP tercantum di:Apa jenis cpu gcc yang menyertakan dukungan untuk RDTSCP?.

Jadi, Anda dapat membuat mikroarsitektur daftar sendiri (mungkin tidak lengkap) yang mendukung RDTSCP . Kemudian tulis skrip build yang memeriksa argumen yang diteruskan ke -march dan lihat apakah itu ada dalam daftar. Jika ya, tentukan makro seperti __RDTSCP__ dan menggunakannya dalam kode Anda. Saya berasumsi bahwa meskipun daftar Anda tidak lengkap, hal ini tidak boleh mengganggu kebenaran kode Anda.

Sayangnya, lembar data Intel tampaknya tidak menentukan apakah prosesor tertentu mendukung RDTSCP meskipun mereka membahas fitur lain seperti AVX2.

Salah satu potensi masalah di sini adalah bahwa tidak ada jaminan bahwa setiap prosesor tunggal yang mengimplementasikan mikroarsitektur tertentu, seperti Skylake, mendukung RDTSCP . Saya tidak mengetahui pengecualian seperti itu.

Terkait:Apa jenis cpu gcc yang menyertakan dukungan untuk RDTSCP?.

Untuk menentukan dukungan RDTSCP saat run-time , kode berikut dapat digunakan pada kompiler yang mendukung ekstensi GNU (GCC, dentang, ICC), pada OS x86 apa pun. cpuid.h disertakan dengan kompiler, bukan OS.

#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() menjalankan CPUID dua kali:sekali untuk memeriksa level maksimal, sekali dengan nilai daun yang ditentukan. Mengembalikan false jika level yang diminta bahkan tidak tersedia, itu sebabnya ini adalah bagian dari && ekspresi. Anda mungkin tidak ingin menggunakan ini setiap kali sebelum rdtscp, hanya sebagai penginisialisasi variabel kecuali itu hanya program satu kali yang sederhana. Lihat di penjelajah kompiler Godbolt.

Untuk MSVC, lihat Bagaimana cara mendeteksi dukungan rdtscp di Visual C++? untuk kode menggunakan intrinsiknya.

Untuk beberapa fitur CPU yang diketahui GCC, Anda dapat menggunakan __builtin_cpu_supports untuk memeriksa bitmap fitur yang diinisialisasi di awal startup.

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

Catatan editor:https://gcc.gnu.org/wiki/DontUseInlineAsm . Jawaban ini untuk waktu yang lama tidak aman, dan kemudian diedit bahkan tidak dapat dikompilasi saat masih tidak aman (memukul RAX membuat "a" kendala tidak dapat dipenuhi, sementara masih ada clobbers yang hilang pada register yang ditulis CPUID). Gunakan intrinsik dalam jawaban lain. (Tapi saya telah memperbaiki inline asm agar aman dan benar, jika ada yang menyalin/menempelnya, atau ingin mempelajari cara menggunakan batasan dan clobbers dengan benar.)

Setelah menyelidiki lebih banyak berdasarkan saran yang dibuat oleh @Jason, saya sekarang memiliki solusi run-time (masih bukan waktu kompilasi) untuk menentukan apakah RDTSCP ada dengan memeriksa bit ke-28 (lihat output bitmap) dari cpuid instruksi dengan 0x80000001 sebagai input di 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;
}

Jika ini tidak berhasil dalam kode PIC 32-bit karena clobber EBX, maka 1. berhenti menggunakan PIC 32-bit karena tidak efisien vs. PIC 64-bit atau vs. -fno-pie -no-pie dapat dieksekusi. 2. dapatkan GCC yang lebih baru yang memungkinkan penghancuran EBX bahkan dalam kode PIC 32-bit, memancarkan instruksi tambahan untuk menyimpan/mengembalikan EBX atau apa pun yang diperlukan. 3. gunakan versi intrinsik (yang seharusnya mengatasi hal ini untuk Anda).

Untuk saat ini saya baik-baik saja dengan kompiler GNU, tetapi jika seseorang perlu melakukan ini di bawah MSVC, maka cara intrinsik untuk memeriksanya seperti yang dijelaskan di sini.


Linux
  1. Bagaimana Mengenalinya Rsync Untuk Mempertahankan Cap Waktu Pada File Ketika Pohon Sumber Memiliki Titik Terpasang?

  2. Cara Terbaik Untuk Mengkompilasi Kernel Untuk Prosesor I7?

  3. Deteksi di C jika mengeluarkan ke terminal

  1. Status Proses Linux

  2. Mendeteksi kompilasi 64bit di C

  3. Sudah berapa lama sistem Linux saya berjalan?

  1. Tidak pernah ada waktu yang lebih baik untuk bermain game di Linux

  2. Proses Yang Memiliki Pid 0?

  3. Apakah Mungkin Untuk Mendeteksi Saat File Telah Diunduh?