#include <iostream>
#include <chrono>
using namespace std;
class MyTimer {
private:
std::chrono::time_point<std::chrono::steady_clock> starter;
std::chrono::time_point<std::chrono::steady_clock> ender;
public:
void startCounter() {
starter = std::chrono::steady_clock::now();
}
double getCounter() {
ender = std::chrono::steady_clock::now();
return double(std::chrono::duration_cast<std::chrono::nanoseconds>(ender - starter).count()) /
1000000; // millisecond output
}
// timer need to have nanosecond precision
int64_t getCounterNs() {
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - starter).count();
}
};
MyTimer timer1, timer2, timerMain;
volatile int64_t dummy = 0, res1 = 0, res2 = 0;
// time run without any time measure
void func0() {
dummy ;
}
// we're trying to measure the cost of startCounter() and getCounterNs(), not "dummy "
void func1() {
timer1.startCounter();
dummy ;
res1 = timer1.getCounterNs();
}
void func2() {
// start your counter here
dummy ;
// res2 = end your counter here
}
int main()
{
int i, ntest = 1000 * 1000 * 100;
int64_t runtime0, runtime1, runtime2;
timerMain.startCounter();
for (i=1; i<=ntest; i ) func0();
runtime0 = timerMain.getCounter();
cout << "Time0 = " << runtime0 << "ms\n";
timerMain.startCounter();
for (i=1; i<=ntest; i ) func1();
runtime1 = timerMain.getCounter();
cout << "Time1 = " << runtime1 << "ms\n";
timerMain.startCounter();
for (i=1; i<=ntest; i ) func2();
runtime2 = timerMain.getCounter();
cout << "Time2 = " << runtime2 << "ms\n";
return 0;
}
我正在嘗試分析一個程式,其中某些關鍵部分的執行時間以 < 50 納秒為單位。我發現我使用的計時器類std::chrono太昂貴了(帶計時的代碼比不帶計時的代碼多花 40% 的時間)。如何制作更快的計時器課程?
我認為一些特定于作業系統的系統呼叫將是最快的解決方案。平臺是Linux Ubuntu。
編輯:所有代碼都是用 -O3 編譯的。確保每個計時器只初始化一次,因此測量的成本僅歸因于 startMeasure/stopMeasure 函式。我不做任何文本列印。
編輯 2:接受的答案不包括將周期數實際轉換為納秒的方法。如果有人能做到這一點,那將非常有幫助。
uj5u.com熱心網友回復:
您想要的稱為“微基準測驗”。它會變得非常復雜。我假設您在 x86_64 上使用 Ubuntu Linux。這對 ARM、ARM64 或任何其他平臺無效。
std::chrono 在 Linux 上的 libstdc (gcc) 和 libc (clang) 中實作,作為 GLIBC(C 庫)的簡單包裝器,它完成了所有繁重的作業。如果您查看 std::chrono::steady_clock::now() ,您將看到對 clock_gettime() 的呼叫。
clock_gettime() 是一個 VDSO,即它是在用戶空間中運行的內核代碼。它應該非常快,但有時它可能需要做一些內務處理,并且每次第 n 次呼叫都需要很長時間。所以我不建議進行微基準測驗。
幾乎每個平臺都有一個回圈計數器,x86 有匯編指令rdtsc。可以通過精心設計asm呼叫或使用特定于編譯器的內置函式 __builtin_ia32_rdtsc() 或 __rdtsc()將此指令插入到您的代碼中。
這些呼叫將回傳一個 64 位整數,表示自機器啟動以來的時鐘數。rdtsc 非常快,大約需要
不能保證在所有平臺上這個計數器對于每個核心都是相同的,所以當行程從一個核心移動到另一個核心時要小心。在現代系統中,這應該不是問題。
rdtsc 的另一個問題是,如果編譯器發現指令沒有副作用,它們通常會重新排序指令,不幸的是 rdtsc 就是其中之一。因此,如果您發現編譯器在欺騙您,您必須在這些計數器讀取周圍使用假障礙 - 查看生成的程式集。
還有一個大問題是 cpu 亂序執行本身。不僅編譯器可以改變執行順序,CPU 也可以。由于 x86 486 英特爾 CPU 是流水線的,因此可以同時執行多條指令 - 粗略地說。因此,您最終可能會測量虛假執行。
我建議您熟悉微基準測驗的類似量子的問題。這并不簡單。
請注意, rdtsc() 將回傳周期數。您必須使用時間戳計數器頻率轉換為納秒。
這是一個例子:
#include <iostream>
#include <cstdio>
void dosomething() {
// yada yada
}
int main() {
double sum = 0;
const uint32_t numloops = 100000000;
for ( uint32_t j=0; j<numloops; j ) {
uint64_t t0 = __builtin_ia32_rdtsc();
dosomething();
uint64_t t1 = __builtin_ia32_rdtsc();
uint64_t elapsed = t1-t0;
sum = elapsed;
}
std::cout << "Average:" << sum/numloops << std::endl;
}
這篇論文有點過時(2010 年),但它是最新的,可以很好地介紹微基準測驗:
如何在英特爾? IA-32 和 IA-64 指令集架構上對代碼執行時間進行基準測驗
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/389795.html
上一篇:Mysql查詢修改以獲得最佳性能
