直接呼叫 timeGetTime/GetTickCount 精度有限 (毫秒級),且在模組前後插入計時代碼導致程式碼混亂。本文封裝高精度計時器,支援巢狀計時、迴圈累加、結果自動輸出檔案。
QueryPerformanceFrequency:取得硬體計數器頻率QueryPerformanceCounter:取得當前計數值#define BENCHMARK_MAX_COUNT 20
double gStarts[BENCHMARK_MAX_COUNT];
double gEnds[BENCHMARK_MAX_COUNT];
double gCounters[BENCHMARK_MAX_COUNT];
double dfFreq = 1.0;
void InitBenchmark() {
ResetBenchmarkCounters(); // 陣列歸零
GetClockFrequent(); // QueryPerformanceFrequency(&dfFreq)
}
void BMTimerStart(int iModel) {
LARGE_INTEGER li; QueryPerformanceCounter(&li);
gStarts[iModel] = li.QuadPart;
}
#define BM_START(t) BMTimerStart(t)
void BMTimerEnd(int iModel) {
LARGE_INTEGER li; QueryPerformanceCounter(&li);
gEnds[iModel] = li.QuadPart;
gCounters[iModel] += ((gEnds[iModel] - gStarts[iModel]) / dfFreq) * 1000000.0; // 累加 μs
}
#define BM_END(t) BMTimerEnd(t)
關鍵點:使用 += 而非 =,支援同一模組多次呼叫累加 (如迴圈內)。
void WriteData() {
// 將 gCounters 所有值寫入文字檔 (如 D:\log.txt)
}
BM_START(0); // 外層
BM_START(1); // 內層模組 A
// ... code ...
BM_END(1);
BM_START(2); // 內層模組 B
// ... code ...
BM_END(2);
BM_END(0);
for (int i=1; i<=20; i++) {
BM_START(0);
double result = Factorial(i);
BM_END(0);
}
WriteData(); // 輸出每次階乘耗時
結果輸出範例 (圖5):每行一個模組的微秒數。
寫法 A - 外層包裹 (圖6):
BM_START(0);
for (int i=0; i<10000; i++) Factorial(20);
BM_END(0);
寫法 B - 內層累加 (圖7):
for (int i=0; i<10000; i++) {
BM_START(0);
Factorial(20);
BM_END(0); // += 累加
}
兩者結果相同 (圖8),寫法 B 更靈活可插入任意程式碼區塊。
CBenchmark 類別,支援 RAII 風格 (CAutoTimer 建構/解構自動計時)