Saya ingin menghitung waktu yang dibutuhkan API untuk mengembalikan nilai. Waktu yang dibutuhkan untuk tindakan semacam itu berada dalam rentang nano detik. Karena API adalah kelas / fungsi C ++, saya menggunakan timer.h untuk menghitung hal yang sama:
#include <ctime>
#include <cstdio>
using namespace std;
int main(int argc, char** argv) {
clock_t start;
double diff;
start = clock();
diff = ( std::clock() - start ) / (double)CLOCKS_PER_SEC;
cout<<"printf: "<< diff <<'\n';
return 0;
}
Kode di atas memberikan waktu dalam hitungan detik. Bagaimana cara mendapatkan yang sama dalam nano detik dan dengan lebih presisi?
clock()
tidak secepat yang saya kira.Jawaban:
Apa yang diposting orang lain tentang menjalankan fungsi berulang kali dalam satu putaran adalah benar.
Untuk Linux (dan BSD) Anda ingin menggunakan clock_gettime () .
Untuk windows Anda ingin menggunakan QueryPerformanceCounter . Dan ini lebih banyak tentang QPC
Tampaknya ada masalah yang diketahui dengan QPC pada beberapa chipset, jadi Anda mungkin ingin memastikan bahwa Anda tidak memiliki chipset tersebut. Selain itu, beberapa AMD inti ganda juga dapat menyebabkan masalah . Lihat posting kedua oleh sebbbi, di mana dia menyatakan:
EDIT 2013/07/16:
Sepertinya ada beberapa kontroversi tentang keefektifan QPC dalam keadaan tertentu seperti yang dinyatakan di http://msdn.microsoft.com/en-us/library/windows/desktop/ee417693(v=vs.85).aspx
Namun jawaban StackOverflow ini https://stackoverflow.com/a/4588605/34329 menyatakan bahwa QPC harus bekerja dengan baik di MS OS apa pun setelah paket layanan Win XP 2.
Artikel ini menunjukkan bahwa Windows 7 dapat menentukan apakah prosesor memiliki TSC invarian dan kembali ke pengatur waktu eksternal jika tidak. http://performancebydesign.blogspot.com/2012/03/high-resolution-clocks-and-timers-for.html Sinkronisasi antar prosesor masih menjadi masalah.
Bacaan bagus lainnya terkait pengatur waktu:
Lihat komentar untuk lebih jelasnya.
sumber
CLOCK_MONOTONIC_RAW
, jika tersedia, agar waktu perangkat keras tidak disesuaikan dengan NTP.Jawaban baru ini menggunakan fasilitas C ++ 11
<chrono>
. Meskipun ada jawaban lain yang menunjukkan cara menggunakan<chrono>
, tidak satupun yang menunjukkan cara menggunakan<chrono>
denganRDTSC
fasilitas yang disebutkan dalam beberapa jawaban lain di sini. Jadi saya pikir saya akan menunjukkan cara menggunakanRDTSC
dengan<chrono>
. Selain itu, saya akan mendemonstrasikan bagaimana Anda dapat membuat template kode pengujian pada jam sehingga Anda dapat dengan cepat beralih di antaraRDTSC
dan fasilitas jam bawaan sistem Anda (yang kemungkinan akan didasarkan padaclock()
,clock_gettime()
dan / atauQueryPerformanceCounter
.Perhatikan bahwa
RDTSC
instruksinya khusus x86.QueryPerformanceCounter
hanya untuk Windows. Danclock_gettime()
hanya POSIX. Di bawah ini saya perkenalkan dua jam baru:std::chrono::high_resolution_clock
danstd::chrono::system_clock
, yang, jika Anda dapat mengasumsikan C ++ 11, sekarang bersifat lintas platform.Pertama, berikut adalah cara Anda membuat jam yang kompatibel dengan C ++ 11 dari
rdtsc
instruksi perakitan Intel . Saya akan menyebutnyax::clock
:Semua jam ini menghitung siklus CPU dan menyimpannya dalam integer 64-bit unsigned. Anda mungkin perlu mengubah sintaks bahasa assembly untuk kompiler Anda. Atau kompilator Anda mungkin menawarkan intrinsik yang dapat Anda gunakan sebagai gantinya (mis
now() {return __rdtsc();}
.).Untuk membuat jam, Anda harus memberikan representasi (tipe penyimpanan). Anda juga harus menyediakan periode jam, yang harus berupa konstanta waktu kompilasi, meskipun mesin Anda mungkin mengubah kecepatan jam dalam mode daya yang berbeda. Dan dari sana, Anda dapat dengan mudah menentukan durasi waktu "asli" jam dan titik waktu dalam kaitannya dengan dasar-dasar ini.
Jika yang ingin Anda lakukan hanyalah menampilkan jumlah detak jam, tidak masalah angka apa yang Anda berikan untuk periode jam tersebut. Konstanta ini hanya berperan jika Anda ingin mengubah jumlah jam menjadi beberapa unit waktu nyata seperti nanodetik. Dan dalam hal ini, semakin akurat Anda dapat memberikan kecepatan clock, semakin akurat konversi ke nanodetik, (milidetik, apa pun).
Di bawah ini adalah contoh kode yang menunjukkan cara menggunakan
x::clock
. Sebenarnya saya telah membuat template kode pada jam karena saya ingin menunjukkan bagaimana Anda dapat menggunakan banyak jam berbeda dengan sintaks yang sama persis. Tes khusus ini menunjukkan apa overhead perulangan saat menjalankan apa yang Anda inginkan untuk waktu di bawah satu loop:Hal pertama yang dilakukan kode ini adalah membuat unit "waktu nyata" untuk menampilkan hasilnya. Saya telah memilih picoseconds, tetapi Anda dapat memilih unit apa pun yang Anda suka, baik integral atau berbasis floating point. Sebagai contoh ada
std::chrono::nanoseconds
unit yang sudah jadi yang bisa saya gunakan.Sebagai contoh lain, saya ingin mencetak jumlah rata-rata siklus jam per iterasi sebagai floating point, jadi saya membuat durasi lain, berdasarkan ganda, yang memiliki unit yang sama dengan tick jam (disebut
Cycle
dalam kode).Loop diatur dengan panggilan ke
clock::now()
salah satu sisi. Jika Anda ingin memberi nama tipe yang dikembalikan dari fungsi ini:(seperti yang ditunjukkan dengan jelas dalam
x::clock
contoh, dan juga berlaku untuk jam yang dipasok sistem).Untuk mendapatkan durasi dalam hal jam floating point, seseorang hanya mengurangi dua titik waktu, dan untuk mendapatkan nilai per iterasi, bagi durasi itu dengan jumlah iterasi.
Anda bisa mendapatkan hitungan dalam durasi berapa pun dengan menggunakan
count()
fungsi anggota. Ini mengembalikan representasi internal. Akhirnya saya gunakanstd::chrono::duration_cast
untuk mengubah durasiCycle
menjadi durasipicoseconds
dan mencetaknya.Untuk menggunakan kode ini sederhana:
Di atas saya melakukan pengujian menggunakan buatan kami
x::clock
, dan membandingkan hasil tersebut dengan menggunakan dua jam yang dipasok sistem:std::chrono::high_resolution_clock
danstd::chrono::system_clock
. Bagi saya ini cetakannya:Ini menunjukkan bahwa setiap jam ini memiliki periode detak yang berbeda, karena detak per iterasi sangat berbeda untuk setiap jam. Namun, ketika dikonversi ke satuan waktu yang diketahui (misalnya pikodetik), saya mendapatkan hasil yang kira-kira sama untuk setiap jam (jarak tempuh Anda mungkin berbeda-beda).
Perhatikan bagaimana kode saya benar-benar bebas dari "konstanta konversi ajaib". Memang, hanya ada dua angka ajaib di seluruh contoh:
x::clock
.sumber
rdtsc
jam kemungkinan memiliki konversi yang tidak akurat ke unit lain. Sebaiknya setel pengukuran Anda sehingga Anda dapat dengan mudah mengubah dan membandingkan jam (seperti yang ditunjukkan dalam jawaban ini).Dengan tingkat akurasi tersebut, akan lebih baik untuk bernalar di centang CPU daripada di panggilan sistem seperti clock () . Dan jangan lupa bahwa jika diperlukan lebih dari satu nanodetik untuk menjalankan instruksi ... memiliki akurasi nanodetik hampir tidak mungkin.
Namun, hal seperti itu adalah permulaan:
Berikut adalah kode sebenarnya untuk mengambil nomor dari jam CPU 80x86 yang berlalu sejak CPU terakhir kali dijalankan. Ini akan bekerja pada Pentium dan di atasnya (386/486 tidak didukung). Kode ini sebenarnya spesifik untuk MS Visual C ++, tetapi mungkin dapat dengan mudah di-porting ke yang lain, selama mendukung perakitan inline.
Fungsi ini juga memiliki keuntungan karena sangat cepat - biasanya tidak lebih dari 50 siklus cpu untuk dijalankan.
Menggunakan Angka Waktu :
Jika Anda perlu menerjemahkan hitungan jam menjadi waktu berlalu yang sebenarnya, bagi hasil dengan kecepatan jam chip Anda. Ingatlah bahwa "terukur" GHz kemungkinan besar akan sedikit berbeda dari kecepatan sebenarnya dari chip Anda. Untuk memeriksa kecepatan sebenarnya dari chip Anda, Anda dapat menggunakan beberapa utilitas yang sangat bagus atau panggilan Win32, QueryPerformanceFrequency ().
sumber
Untuk melakukan ini dengan benar, Anda dapat menggunakan salah satu dari dua cara, pergi dengan
RDTSC
atau denganclock_gettime()
. Yang kedua kira-kira 2 kali lebih cepat dan memiliki keuntungan memberikan waktu absolut yang tepat. Perhatikan bahwaRDTSC
agar berfungsi dengan benar Anda perlu menggunakannya seperti yang ditunjukkan (komentar lain di halaman ini memiliki kesalahan, dan mungkin menghasilkan nilai waktu yang salah pada prosesor tertentu)dan untuk clock_gettime: (Saya memilih resolusi mikrodetik secara sewenang-wenang)
waktu dan nilai yang dihasilkan:
sumber
Saya menggunakan yang berikut ini untuk mendapatkan hasil yang diinginkan:
sumber
Untuk C ++ 11 , berikut ini pembungkus sederhana:
Atau untuk C ++ 03 di * nix,
Contoh penggunaan:
Dari https://gist.github.com/gongzhitaao/7062087
sumber
Secara umum, untuk menentukan waktu berapa lama untuk memanggil suatu fungsi, Anda ingin melakukannya lebih dari sekali. Jika Anda memanggil fungsi Anda hanya sekali dan itu membutuhkan waktu yang sangat singkat untuk dijalankan, Anda masih memiliki overhead untuk benar-benar memanggil fungsi pengatur waktu dan Anda tidak tahu berapa lama waktu yang dibutuhkan.
Misalnya, jika Anda memperkirakan fungsi Anda mungkin membutuhkan 800 ns untuk dijalankan, panggil dalam loop sepuluh juta kali (yang kemudian akan memakan waktu sekitar 8 detik). Bagilah total waktu dengan sepuluh juta untuk mendapatkan waktu setiap panggilan.
sumber
Anda dapat menggunakan fungsi berikut dengan gcc yang berjalan di bawah prosesor x86:
dengan Digital Mars C ++:
yang membaca pengatur waktu kinerja tinggi pada chip. Saya menggunakan ini saat melakukan pembuatan profil.
sumber
unsigned int
sebagai tipe internal.Jika Anda memerlukan ketepatan sub-detik, Anda perlu menggunakan ekstensi khusus sistem, dan harus memeriksa dengan dokumentasi untuk sistem operasi tersebut. POSIX mendukung hingga mikrodetik dengan gettimeofday , tetapi tidak ada yang lebih presisi karena komputer tidak memiliki frekuensi di atas 1GHz.
Jika Anda menggunakan Boost, Anda dapat memeriksa boost :: posix_time .
sumber
Saya menggunakan kode Borland di sini adalah kode ti_hund memberi saya beberapa kali angka negatif tetapi waktunya cukup baik.
sumber
Menggunakan metode Brock Adams, dengan kelas sederhana:
Contoh Penggunaan:
Hasil:
Tes memakan waktu: 0,0002 ms
Memiliki beberapa overhead panggilan fungsi, tetapi masih harus lebih dari cukup cepat :)
sumber
Anda dapat menggunakan Embedded Profiler (gratis untuk Windows dan Linux) yang memiliki antarmuka ke pengatur waktu multiplatform (dalam hitungan siklus prosesor) dan dapat memberi Anda sejumlah siklus per detik:
Penghitungan ulang hitungan siklus ke waktu mungkin merupakan operasi berbahaya dengan prosesor modern di mana frekuensi CPU dapat diubah secara dinamis. Oleh karena itu untuk memastikan bahwa waktu yang dikonversi benar, frekuensi prosesor harus diperbaiki sebelum membuat profil.
sumber
Jika ini untuk Linux, saya telah menggunakan fungsi "gettimeofday", yang mengembalikan struct yang memberikan detik dan mikrodetik sejak Epoch. Anda kemudian dapat menggunakan sub waktu untuk mengurangi keduanya untuk mendapatkan perbedaan waktu, dan mengubahnya menjadi ketepatan waktu yang Anda inginkan. Namun, Anda menentukan nanodetik, dan sepertinya fungsi clock_gettime () adalah yang Anda cari. Ini menempatkan waktu dalam hitungan detik dan nanodetik ke dalam struktur yang Anda lewati.
sumber
Apa pendapatmu tentang itu:
sumber
Berikut adalah pengatur waktu Boost yang berfungsi dengan baik:
sumber
Salin & tempel-struct minimalis + penggunaan malas
Jika idenya adalah memiliki struct minimalis yang dapat Anda gunakan untuk tes cepat, maka saya sarankan Anda cukup salin dan tempelkan di mana saja di file C ++ Anda tepat setelah
#include
itu. Ini adalah satu-satunya contoh di mana saya mengorbankan pemformatan gaya Allman.Anda dapat dengan mudah menyesuaikan presisi di baris pertama struct. Nilai yang mungkin adalah:
nanoseconds
,microseconds
,milliseconds
,seconds
,minutes
, atauhours
.Pemakaian
Hasil keluaran standar
Jika Anda ingin ringkasan setelah eksekusi
Jika Anda menginginkan laporan setelahnya, karena misalnya kode Anda di antaranya juga menulis ke output standar. Kemudian tambahkan fungsi berikut ke struct (tepat sebelum MeasureTime ()):
Jadi Anda bisa menggunakan:
Yang akan mencantumkan semua tanda seperti sebelumnya, tetapi kemudian setelah kode lain dijalankan. Perhatikan bahwa Anda tidak boleh menggunakan keduanya
m.s()
danm.t()
.sumber