Saya mem-porting game, yang aslinya ditulis untuk Win32 API, ke Linux (baik, port OS X dari port Win32 ke Linux).
Saya telah menerapkan QueryPerformanceCounter
dengan memberikan uSeconds sejak proses dimulai:
BOOL QueryPerformanceCounter(LARGE_INTEGER* performanceCount)
{
gettimeofday(¤tTimeVal, NULL);
performanceCount->QuadPart = (currentTimeVal.tv_sec - startTimeVal.tv_sec);
performanceCount->QuadPart *= (1000 * 1000);
performanceCount->QuadPart += (currentTimeVal.tv_usec - startTimeVal.tv_usec);
return true;
}
Ini, ditambah dengan QueryPerformanceFrequency()
memberikan 1000000 konstan sebagai frekuensi, bekerja dengan baik pada mesin saya , memberi saya variabel 64-bit yang berisi uSeconds
sejak program dimulai.
Jadi, apakah ini portabel? Saya tidak ingin menemukannya bekerja secara berbeda jika kernel dikompilasi dengan cara tertentu atau semacamnya. Saya baik-baik saja dengan itu menjadi non-portabel untuk sesuatu selain Linux.
Resolusi Tinggi, Waktu Overhead Rendah untuk Prosesor Intel
Jika Anda menggunakan perangkat keras Intel, berikut ini cara membaca penghitung instruksi waktu nyata CPU. Ini akan memberi tahu Anda jumlah siklus CPU yang dijalankan sejak prosesor di-boot. Ini mungkin counter terbaik yang bisa Anda dapatkan untuk pengukuran kinerja.
Perhatikan bahwa ini adalah jumlah siklus CPU. Di linux Anda bisa mendapatkan kecepatan CPU dari / proc / cpuinfo dan membagi untuk mendapatkan jumlah detik. Mengubah ini menjadi ganda cukup berguna.
Ketika saya menjalankan ini di kotak saya, saya mengerti
Berikut panduan pengembang Intel yang memberikan banyak detail.
sumber
CPUID
lagi setelahRDTSC
instruksi pertama dan sebelum menjalankan kode yang menjadi tolok ukur? Jika tidak, apa yang harus menghentikan kode benchmark yang dieksekusi sebelum / in-parallel-dengan yang pertamaRDTSC
, dan akibatnya kurang terwakili diRDTSC
delta?@Bandung:
Itu pertanyaan yang bagus ... Saya pikir kodenya oke. Dari sudut pandang praktis, kami menggunakannya di perusahaan saya setiap hari, dan kami menjalankannya pada beragam kotak, semuanya dari 2-8 core. Tentu saja, YMMV, dll, tetapi tampaknya menjadi metode waktu yang andal dan overhead rendah (karena tidak membuat pengalihan konteks ke ruang sistem).
Secara umum cara kerjanya adalah:
Catatan khusus:
Eksekusi out-of-order dapat menyebabkan hasil yang salah, jadi kami mengeksekusi instruksi "cpuid" yang selain memberi Anda beberapa informasi tentang cpu juga menyinkronkan eksekusi instruksi out-of-order.
Sebagian besar OS menyinkronkan penghitung pada CPU ketika mereka mulai, jadi jawabannya bagus dalam beberapa nano-detik.
Komentar yang berhibernasi mungkin benar, tetapi dalam praktiknya Anda mungkin tidak peduli dengan pengaturan waktu melintasi batas hibernasi.
mengenai speedstep: CPU Intel yang lebih baru mengimbangi perubahan kecepatan dan mengembalikan hitungan yang disesuaikan. Saya melakukan pemindaian cepat pada beberapa kotak di jaringan kami dan hanya menemukan satu kotak yang tidak memilikinya: Pentium 3 menjalankan beberapa server database lama. (ini adalah kotak linux, jadi saya memeriksanya dengan: grep constant_tsc / proc / cpuinfo)
Saya tidak yakin tentang CPU AMD, kami pada dasarnya adalah toko Intel, meskipun saya tahu beberapa ahli sistem tingkat rendah kami melakukan evaluasi AMD.
Semoga ini memuaskan rasa ingin tahu Anda, ini adalah bidang pemrograman yang menarik dan (IMHO) kurang dipelajari. Anda tahu ketika Jeff dan Joel membicarakan tentang apakah seorang programmer harus tahu C atau tidak? Saya meneriaki mereka, "hei, lupakan hal C tingkat tinggi ... assembler adalah yang harus Anda pelajari jika Anda ingin tahu apa yang dilakukan komputer!"
sumber
Anda mungkin tertarik dengan FAQ Linux untuk
clock_gettime(CLOCK_REALTIME)
sumber
Wine sebenarnya menggunakan gettimeofday () untuk mengimplementasikan QueryPerformanceCounter () dan diketahui membuat banyak game Windows berfungsi di Linux dan Mac.
Mulai http://source.winehq.org/source/dlls/kernel32/cpu.c#L312
mengarah ke http://source.winehq.org/source/dlls/ntdll/time.c#L448
sumber
Struktur data didefinisikan sebagai memiliki mikrodetik sebagai unit pengukuran, tetapi itu tidak berarti bahwa jam atau sistem operasi sebenarnya mampu mengukurnya dengan cermat.
Seperti yang disarankan orang lain,
gettimeofday()
itu buruk karena pengaturan waktu dapat menyebabkan jam miring dan membuang perhitungan Anda.clock_gettime(CLOCK_MONOTONIC)
adalah yang Anda inginkan, danclock_getres()
akan memberi tahu Anda ketepatan jam Anda.sumber
Saya memperoleh jawaban ini dari Pengukuran Waktu dan Pengatur Waktu Resolusi Tinggi, Bagian I
sumber
Jawaban ini menyebutkan masalah dengan jam yang sedang disesuaikan. Masalah Anda dalam menjamin unit centang dan masalah dengan waktu yang disesuaikan diselesaikan di C ++ 11 dengan
<chrono>
perpustakaan.Jam
std::chrono::steady_clock
dijamin tidak akan disesuaikan, dan selanjutnya akan maju dengan kecepatan konstan relatif terhadap waktu nyata, jadi teknologi seperti SpeedStep tidak boleh memengaruhinya.Anda bisa mendapatkan unit yang aman dengan mengonversinya ke salah satu
std::chrono::duration
spesialisasi, sepertistd::chrono::microseconds
. Dengan tipe ini tidak ada ambiguitas tentang unit yang digunakan oleh nilai tick. Namun, perlu diingat bahwa jam tidak selalu memiliki resolusi ini. Anda dapat mengubah durasi menjadi attoseconds tanpa benar-benar memiliki jam yang akurat.sumber
Dari pengalaman saya, dan dari apa yang saya baca di internet, jawabannya adalah "Tidak", itu tidak dijamin. Itu tergantung pada kecepatan CPU, sistem operasi, rasa Linux, dll.
sumber
Membaca RDTSC tidak dapat diandalkan dalam sistem SMP, karena setiap CPU memelihara penghitungnya sendiri dan setiap penghitung tidak dijamin oleh sinkronisasi sehubungan dengan CPU lain.
Saya mungkin menyarankan untuk mencoba
clock_gettime(CLOCK_REALTIME)
. Manual posix menunjukkan bahwa ini harus diterapkan pada semua sistem yang sesuai. Ini dapat memberikan hitungan nanodetik, tetapi Anda mungkin ingin memeriksaclock_getres(CLOCK_REALTIME)
sistem Anda untuk melihat apa resolusi sebenarnya.sumber
clock_getres(CLOCK_REALTIME)
tidak akan memberikan resolusi yang sebenarnya. Itu selalu mengembalikan "1 ns" (satu nanodetik) saat jam pengatur waktu tersedia, periksainclude/linux/hrtimer.h
file untukdefine HIGH_RES_NSEC 1
(selengkapnya di stackoverflow.com/a/23044075/196561 )