Windows 標準計時器(GetTickCount、timeGetTime)精度僅 1~15 ms。對於效能分析、遊戲迴路、即時系統,需CPU 週期級(納秒級)計時器。本文提供基於 RDTSC 指令的 KTimer 類別,支援 CPU 頻率校準、開銷扣除、週期轉納秒/毫秒。
RDTSC(Read Time-Stamp Counter):讀取 CPU 內部 64 位元週期計數器,指令級精度。Start()/Stop() 開銷(m_overhead),後續測量自動扣除。Sleep(1000) 校準 CPU 頻率(MHz),假設睡眠誤差可忽略。#pragma once
#ifndef STRICT
#define STRICT
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
// 內嵌 RDTSC:_emit 0x0F 0x31
inline unsigned __int64 GetCycleCount() {
_asm _emit 0x0F
_asm _emit 0x31
}
class KTimer {
unsigned __int64 m_startCycle;
unsigned __int64 m_overhead; // 開銷週期數
public:
KTimer() : m_overhead(0) {
Start();
m_overhead = Stop(); // 校準開銷
}
void Start() {
m_startCycle = GetCycleCount();
}
// 返回扣除開銷後的經過週期
unsigned __int64 Stop() {
return GetCycleCount() - m_startCycle - m_overhead;
}
// 週期 → 納秒
static unsigned __int64 CyclesToNanos(unsigned __int64 cycles, unsigned int cpuMHz) {
return cycles * 1000 / cpuMHz;
}
// 週期 → 毫秒
static unsigned __int64 CyclesToMillis(unsigned __int64 cycles, unsigned int cpuMHz) {
return cycles / cpuMHz / 1000;
}
// 校準 CPU 頻率(MHz)
unsigned int CPUSpeedMHz() {
Start();
Sleep(1000);
unsigned __int64 cputime = Stop();
return static_cast<unsigned int>(cputime / 1000000);
}
};
int main() {
KTimer kt;
unsigned int cpuMHz = kt.CPUSpeedMHz(); // 校準頻率
kt.Start();
Sleep(1234); // 模擬待測程式碼
unsigned __int64 cycles = kt.Stop();
std::printf("CPU Speed: %.2f GHz\n", cpuMHz / 1000.0);
std::printf("Elapsed: %llu cycles (%llu ns, %llu ms)\n",
cycles,
KTimer::CyclesToNanos(cycles, cpuMHz),
KTimer::CyclesToMillis(cycles, cpuMHz));
return 0;
}
| 議題 | 說明 |
|---|---|
| 多核心/多處理器 | 舊 CPU TSC 不同步,跨核心遷移導致時間倒流。現代 CPU(Intel Nehalem+、AMD Bulldozer+)支援 Invariant TSC,可安全跨核心。建議 SetThreadAffinityMask 綁定單核心。 |
| 睡眠/休眠 | 系統睡眠期間 TSC 不計數,喚醒後數值不連續。長時間測量需配合 QueryPerformanceCounter 修正。 |
| 虛擬機 | Hypervisor 可能虛擬化 TSC,精度與頻率不可信。生產環境建議改用 QueryPerformanceCounter(QPC)。 |
| 編譯器內建 | MSVC/GCC/Clang 提供 __rdtsc() / __builtin_ia32_rdtsc(),優先使用內建函式替代內嵌組語。 |
| 序列化 | Out-of-order 執行可能導致 RDTSC 提前/延後。嚴格測量需加 CPUID 序列化(RDTSCP 指令隱含序列化)。 |
QueryPerformanceCounter / QueryPerformanceFrequency:OS 提供、跨平台(Windows)、自動處理 TSC 虛擬化/睡眠修正,精度通常 < 100 ns。std::chrono::high_resolution_clock(C++11):C++ 標準介面,Windows 實作基於 QPC。clock_gettime(CLOCK_MONOTONIC_RAW) 或 RDTSC(同樣需注意 TSC 同步)。KTimer 展示了「貼近硬體」的極致計時技術,適合微基準測試、效能計數器開發。
一般應用開發請優先使用std::chrono或 QPC,兼具可攜性與正確性。