首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C/C++ Windows 高精度計時:QueryPerformanceCounter 完整指南

     編輯:關於C語言

前言

標準 clock() 精度僅 ~10-15 ms,無法滿足效能分析、遊戲迴圈、即時系統等場景需求。Windows 提供 高效能計數器(High-Resolution Performance Counter),透過 QueryPerformanceFrequency 與 QueryPerformanceCounter 可達到**奈秒級**精度。本文詳細說明原理、資料結構、完整範例與常見坑點。

核心 API 與資料結構

1. LARGE_INTEGER 聯合體

64 位元整數封裝,相容不支援 64 位元整數的舊編譯器:

typedef union _LARGE_INTEGER {
    struct { DWORD LowPart; LONG HighPart; };
    struct { DWORD LowPart; LONG HighPart; } u;
    LONGLONG QuadPart;  // 現代編譯器直接使用此欄位
} LARGE_INTEGER, *PLARGE_INTEGER;

建議: 直接使用 QuadPart 存取完整 64 位元值。

2. QueryPerformanceFrequency

BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
  • 取得計數器頻率(每秒計數次數),系統啟動後固定不變。
  • 典型值:2.5~3.5 GHz CPU 對應 ~2.5~3.5 億次/秒。
  • 失敗回傳 0(極少見,僅極舊硬體不支援)。

3. QueryPerformanceCounter

BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
  • 取得當前計數器值(開機以來的總計數)。
  • 極低延遲,適合高頻呼叫。

完整可執行範例

#include 
#include 

int main(int argc, char **argv) {
    LARGE_INTEGER freq;
    LARGE_INTEGER start_t, stop_t;
    double exe_time_ms;

    // 1. 取得頻率
    QueryPerformanceFrequency(&freq);
    printf("CPU 頻率: %lld Hz\n", freq.QuadPart);

    // 2. 開始計時
    QueryPerformanceCounter(&start_t);

    // 模擬工作負載
    Sleep(1000);  // 睡眠 1 秒

    // 3. 結束計時
    QueryPerformanceCounter(&stop_t);

    // 4. 計算經過時間(毫秒)
    exe_time_ms = 1e3 * (stop_t.QuadPart - start_t.QuadPart) / (double)freq.QuadPart;
    printf("實際執行時間: %.3f ms\n", exe_time_ms);

    getchar();
    return 0;
}

精度驗證與輸出範例

CPU 頻率: 3331234 Hz
實際執行時間: 1000.123 ms

誤差通常在微秒級,遠優於 clock() 的毫秒級量化誤差。

常見坑點與最佳實踐

問題說明解決方案
頻率為 0極舊硬體或虛擬機不支援啟動時檢查,失敗回退 timeGetTime 或 GetTickCount64
多核心 TSC 不同步早期多核 CPU 各核心 TSC 可能不同步現代 Windows (Vista+) 已在 HAL 層同步,可放心使用
長時間運行溢位64 位元計數器極難溢位(~584 年 @ 3GHz)忽略不計
編譯器優化干擾編譯器可能重排指令影響計時準確性關鍵區塊用 volatile 或編譯器屏障
跨執行緒/處理器遷移執行緒遷移可能導致計數器跳躍Windows 已處理,若極度敏感可用 SetThreadAffinityMask 綁核

封裝為可重用計時器類(C++11)


class PerfTimer {
    LARGE_INTEGER freq_, start_;
public:
    PerfTimer() { QueryPerformanceFrequency(&freq_); }
    void start() { QueryPerformanceCounter(&start_); }
    double elapsed_ms() const {
        LARGE_INTEGER now;
        QueryPerformanceCounter(&now);
        return 1e3 * (now.QuadPart - start_.QuadPart) / (double)freq_.QuadPart;
    }
    double elapsed_us() const { return elapsed_ms() * 1e3; }
    double elapsed_ns() const { return elapsed_ms() * 1e6; }
};

// 使用範例
PerfTimer timer;
timer.start();
// ... 待測程式碼 ...
printf("耗時: %.3f ms\n", timer.elapsed_ms());

跨平台考量

  • Linux/macOS: 使用 clock_gettime(CLOCK_MONOTONIC, ...)(奈秒精度)。
  • C++20: std::chrono::high_resolution_clock 統一抽象,Windows 內部即呼叫 QPC。

總結

QueryPerformanceCounter 是 Windows 平台高精度計時的黃金標準。掌握 LARGE_INTEGER.QuadPart 使用、頻率快取、雙精度浮點運算避免整數截斷,即可輕鬆實現微秒甚至奈秒級計時。配合 RAII 封裝,即為專案提供專業級效能分析基礎設施。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved