Hanya menggunakan ANSI C, adakah cara untuk mengukur waktu dengan presisi milidetik atau lebih? Saya sedang menjelajah time.h tetapi saya hanya menemukan fungsi presisi kedua.
c
portability
time-precision
corto
sumber
sumber
Jawaban:
Tidak ada fungsi ANSI C yang memberikan resolusi waktu lebih baik dari 1 detik, tetapi fungsi POSIX
gettimeofday
menyediakan resolusi mikrodetik. Fungsi jam hanya mengukur jumlah waktu yang dihabiskan suatu proses untuk dieksekusi dan tidak akurat pada banyak sistem.Anda dapat menggunakan fungsi ini seperti ini:
Ini mengembalikan
Time elapsed: 1.000870
mesin saya.sumber
timeval::tv_usec
selalu di bawah satu detik, itu berulang. Yaitu untuk mengambil perbedaan waktu lebih besar dari 1 detik, Anda harus:long usec_diff = (e.tv_sec - s.tv_sec)*1000000 + (e.tv_usec - s.tv_usec);
timersub
fungsi. Kita dapat menggunakantval_result
nilai (tv_sec dan tv_usec) apa adanya.sumber
CLOCKS_PER_SEC / 1000
mungkin tidak tepat yang dapat mempengaruhi hasil akhir (meskipun menurut pengalaman sayaCLOCKS_PER_SEC
selalu kelipatan 1000). Melakukan(1000 * clock()) / CLOCKS_PER_SEC
kurang rentan terhadap ketidaktepatan pembagian, tetapi di sisi lain lebih rentan terhadap luapan. Hanya beberapa masalah yang perlu dipertimbangkan.Saya selalu menggunakan fungsi clock_gettime (), mengembalikan waktu dari jam CLOCK_MONOTONIC. Waktu yang dikembalikan adalah jumlah waktu, dalam detik dan nanodetik, sejak beberapa titik yang tidak ditentukan di masa lalu, seperti permulaan sistem pada zaman tersebut.
sumber
clock_gettime(CLOCK_MONOTONIC, ...)
dan bahkan ada makro uji fitur_POSIX_MONOTONIC_CLOCK
.Menerapkan solusi portabel
Seperti yang telah disebutkan di sini bahwa tidak ada solusi ANSI yang tepat dengan ketepatan yang cukup untuk masalah pengukuran waktu, saya ingin menulis tentang cara mendapatkan portabel dan, jika mungkin, solusi pengukuran waktu resolusi tinggi.
Jam monotonik vs stempel waktu
Secara umum ada dua cara pengukuran waktu:
Yang pertama menggunakan penghitung jam monotonik (terkadang disebut penghitung tick) yang menghitung tick dengan frekuensi yang telah ditentukan, jadi jika Anda memiliki nilai tick dan frekuensinya diketahui, Anda dapat dengan mudah mengubah tick ke waktu yang telah berlalu. Sebenarnya tidak ada jaminan bahwa jam monotonik mencerminkan waktu sistem saat ini dengan cara apa pun, ia juga dapat menghitung kutu sejak sistem dinyalakan. Tapi itu menjamin bahwa jam selalu berjalan dengan cara yang meningkat terlepas dari status sistemnya. Biasanya frekuensi terikat ke sumber resolusi tinggi perangkat keras, itulah sebabnya ia memberikan akurasi tinggi (bergantung pada perangkat keras, tetapi sebagian besar perangkat keras modern tidak memiliki masalah dengan sumber jam resolusi tinggi).
Cara kedua memberikan nilai waktu (tanggal) berdasarkan nilai jam sistem saat ini. Ini mungkin juga memiliki resolusi tinggi, tetapi memiliki satu kelemahan utama: nilai waktu semacam ini dapat dipengaruhi oleh penyesuaian waktu sistem yang berbeda, yaitu perubahan zona waktu, perubahan waktu musim panas (DST), pembaruan server NTP, hibernasi sistem, dan sebagainya. di. Dalam beberapa situasi, Anda bisa mendapatkan nilai waktu berlalu yang negatif yang dapat menyebabkan perilaku yang tidak ditentukan. Sebenarnya sumber waktu semacam ini kurang dapat diandalkan dibandingkan yang pertama.
Jadi aturan pertama dalam pengukuran interval waktu adalah menggunakan jam monotonik jika memungkinkan. Biasanya memiliki presisi tinggi, dan desainnya dapat diandalkan.
Strategi fallback
Saat mengimplementasikan solusi portabel, ada baiknya untuk mempertimbangkan strategi fallback: gunakan jam monotonik jika tersedia dan fallback ke pendekatan stempel waktu jika tidak ada jam monotonik dalam sistem.
Windows
Ada artikel bagus berjudul Memperoleh stempel waktu resolusi tinggi di MSDN tentang pengukuran waktu di Windows yang menjelaskan semua detail yang mungkin perlu Anda ketahui tentang dukungan perangkat lunak dan perangkat keras. Untuk mendapatkan cap waktu presisi tinggi di Windows, Anda harus:
kueri frekuensi pengatur waktu (ticks per second) dengan QueryPerformanceFrequency :
Frekuensi pengatur waktu ditetapkan pada boot sistem sehingga Anda hanya perlu mendapatkannya sekali.
menanyakan nilai ticks saat ini dengan QueryPerformanceCounter :
skala tanda ke waktu yang telah berlalu, yaitu ke mikrodetik:
Menurut Microsoft, Anda seharusnya tidak mengalami masalah dengan pendekatan ini pada Windows XP dan versi yang lebih baru dalam banyak kasus. Tetapi Anda juga dapat menggunakan dua solusi fallback di Windows:
GetTickCount
, tetapi tersedia mulai dari Windows Vista dan yang lebih baru.OS X (macOS)
OS X (macOS) memiliki satuan waktu absolut Mach sendiri yang mewakili jam monotonik. Cara terbaik untuk memulai adalah artikel Apple Q&A Teknis QA1398: Mach Absolute Time Units yang menjelaskan (dengan contoh kode) bagaimana menggunakan API khusus Mach untuk mendapatkan tanda centang monoton. Ada juga pertanyaan lokal tentang itu yang disebut clock_gettime alternatif di Mac OS X yang pada akhirnya mungkin membuat Anda sedikit bingung apa yang harus dilakukan dengan kemungkinan overflow nilai karena frekuensi penghitung digunakan dalam bentuk pembilang dan penyebut. Jadi, contoh singkat bagaimana mendapatkan waktu yang berlalu:
dapatkan pembilang dan penyebut frekuensi clock:
Anda hanya perlu melakukannya sekali.
menanyakan nilai tick saat ini dengan
mach_absolute_time
:menskalakan tick ke waktu yang telah berlalu, yaitu ke mikrodetik, menggunakan pembilang dan penyebut yang ditanyakan sebelumnya:
Ide utama untuk mencegah overflow adalah dengan menurunkan tick ke akurasi yang diinginkan sebelum menggunakan pembilang dan penyebut. Karena resolusi pengatur waktu awal dalam nanodetik, kami membaginya
1000
untuk mendapatkan mikrodetik. Anda dapat menemukan pendekatan yang sama yang digunakan di time_mac.c Chromium . Jika Anda benar-benar membutuhkan akurasi nanodetik, pertimbangkan untuk membaca bagian Bagaimana cara menggunakan mach_absolute_time tanpa meluap? .Linux dan UNIX
The
clock_gettime
panggilan adalah cara Anda terbaik pada setiap sistem yang ramah POSIX. Itu dapat meminta waktu dari sumber jam yang berbeda, dan yang kita butuhkan adalahCLOCK_MONOTONIC
. Tidak semua sistemclock_gettime
mendukungCLOCK_MONOTONIC
, jadi hal pertama yang perlu Anda lakukan adalah memeriksa ketersediaannya:_POSIX_MONOTONIC_CLOCK
didefinisikan ke nilai>= 0
itu berartiCLOCK_MONOTONIC
tersedia;jika
_POSIX_MONOTONIC_CLOCK
didefinisikan untuk0
itu berarti Anda juga harus memeriksa apakah itu berfungsi saat runtime, saya sarankan untuk menggunakansysconf
:Penggunaannya
clock_gettime
cukup mudah:dapatkan nilai waktu:
Saya telah memperkecil waktu menjadi mikrodetik di sini.
menghitung selisih dengan nilai waktu sebelumnya diterima dengan cara yang sama:
Strategi fallback terbaik adalah menggunakan
gettimeofday
panggilan: ini tidak monotonik, tetapi memberikan resolusi yang cukup baik. Idenya sama dengan denganclock_gettime
, tetapi untuk mendapatkan nilai waktu Anda harus:Sekali lagi, nilai waktu diperkecil menjadi mikrodetik.
SGI IRIX
IRIX punya
clock_gettime
panggilan, tapi kurangCLOCK_MONOTONIC
. Sebaliknya ia memiliki sumber jam monotoniknya sendiri yang didefinisikan sebagaiCLOCK_SGI_CYCLE
yang harus Anda gunakan, bukanCLOCK_MONOTONIC
denganclock_gettime
.Solaris dan HP-UX
Solaris memiliki antarmuka
gethrtime
pengatur waktu resolusi tinggi yang mengembalikan nilai pengatur waktu saat ini dalam nanodetik. Meskipun versi Solaris yang lebih baru mungkin memilikiclock_gettime
, Anda dapat tetap menggunakannyagethrtime
jika Anda perlu mendukung versi Solaris yang lama.Penggunaannya sederhana:
HP-UX tidak memiliki kekurangan
clock_gettime
, tetapi mendukunggethrtime
yang harus Anda gunakan dengan cara yang sama seperti pada Solaris.BeOS
BeOS juga memiliki antarmuka
system_time
pengatur waktu resolusi tinggi yang mengembalikan jumlah mikrodetik yang telah berlalu sejak komputer di-boot.Contoh penggunaan:
OS / 2
OS / 2 memiliki API sendiri untuk mengambil stempel waktu presisi tinggi:
query frekuensi timer (ticks per unit) dengan
DosTmrQueryFreq
(untuk compiler GCC):menanyakan nilai ticks saat ini dengan
DosTmrQueryTime
:skala tanda ke waktu yang telah berlalu, yaitu ke mikrodetik:
Contoh implementasi
Anda dapat melihat pustaka plibsys yang mengimplementasikan semua strategi yang dijelaskan di atas (lihat ptimeprofiler * .c untuk detailnya).
sumber
timespec_get
: stackoverflow.com/a/36095407/895245timespec_get
tidak monotonik.timespec_get
dari C11Mengembalikan hingga nanodetik, dibulatkan ke resolusi penerapan.
Sepertinya penipuan ANSI dari POSIX '
clock_gettime
.Contoh: a
printf
dilakukan setiap 100ms di Ubuntu 15.10:The C11 N1570 standar rancangan 7.27.2.5 "Fungsi timespec_get mengatakan":
C ++ 11 juga mendapat
std::chrono::high_resolution_clock
: C ++ Cross-Platform High-Resolution Timerglibc 2.21
Dapat ditemukan di bawah
sysdeps/posix/timespec_get.c
sebagai:sangat jelas:
hanya
TIME_UTC
saat ini didukungitu meneruskan ke
__clock_gettime (CLOCK_REALTIME, ts)
, yang merupakan API POSIX: http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.htmlLinux x86-64 memiliki file
clock_gettime
panggilan sistem.Perhatikan bahwa ini bukan metode pembandingan mikro yang terbukti gagal karena:
man clock_gettime
mengatakan bahwa ukuran ini mungkin memiliki diskontinuitas jika Anda mengubah beberapa pengaturan waktu sistem saat program Anda berjalan. Ini harus menjadi peristiwa yang jarang terjadi, dan Anda mungkin bisa mengabaikannya.ini mengukur waktu dinding, jadi jika penjadwal memutuskan untuk melupakan tugas Anda, tugas itu akan tampak berjalan lebih lama.
Untuk alasan itu
getrusage()
mungkin alat pembandingan POSIX yang lebih baik, meskipun presisi maksimum mikrodetiknya lebih rendah.Informasi lebih lanjut di: Mengukur waktu di Linux - waktu vs jam vs getrusage vs clock_gettime vs gettimeofday vs timespec_get?
sumber
Presisi terbaik yang mungkin Anda peroleh adalah melalui penggunaan instruksi "rdtsc" hanya x86, yang dapat memberikan resolusi level-jam (tentu saja tidak harus memperhitungkan biaya panggilan rdtsc itu sendiri, yang dapat diukur dengan mudah di aplikasi startup).
Tangkapan utama di sini adalah mengukur jumlah jam per detik, yang seharusnya tidak terlalu sulit.
sumber
Jawaban yang diterima cukup bagus, tetapi solusi saya lebih sederhana, saya hanya menguji di Linux, gunakan gcc (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0.
Alse use
gettimeofday
, thetv_sec
adalah bagian dari detik, dantv_usec
adalah mikrodetik , bukan milidetik .Ini mencetak:
1522139691342 1522139692342
, tepat satu detik.sumber
Di bawah jendela:
sumber