在 Windows 上如何比較不同版本程式的執行速度 - 從電源模式等環境的對齊到可到的極限

· · Windows, Benchmark, Performance, Profiling, Power Management

想在 Windows 上比較程式版本 A 與 B。 這時最不該做的事,就是在同一台機器上各跑 1 次,然後說「看起來 B 快 8%」。

這 8% 可能真的是程式差異。 但實際上,更可能是 電源模式、power plan、熱、背景更新、搜尋索引、防毒掃描、親和性、執行順序、快取狀態 其中之一——這是 Windows benchmark 的日常,相當泥濘的世界。

本文整理在 Windows 上比較不同版本程式執行速度時,如何 儘量貼近「程式差異」 的做法。 以 Windows 11 為主,但 powercfgstart 這類指令大部分在 Windows 10 也通用。

先下結論

先把結論列出來,提高重現性的要訣有 6 項:

  1. 先決定「要比較什麼」
    想看程式本身差異,還是真實使用者體感,該對齊的環境不同。

  2. 把 power mode 與 power plan 當成兩件事記錄
    在 Windows 上馬虎處理這裡,比較很容易變成在比 OS 的省電策略。

  3. 冷啟動第 1 次與熱機後的穩態要分開
    第 1 次就特別快、後半特別慢,都不罕見。

  4. A→B→A→B 這樣交替跑
    先把 A 全跑完再跑 B,會把熱與背景活動的偏差全背下。

  5. 平均之外還要看中位數與分佈
    一個離群值就能毀掉世界觀,平均比想像中還脆。

  6. 差距小的時候,就用 ETW / WPR 挖到理由
    靠體感辯論,大多是霧中互毆。

先決定你要比較什麼

「速度比較」其實分成兩種。

1. 想看程式差異的比較

因為演算法、資料結構、編譯器優化、runtime 更新等因素,想知道 實作本身是否變快

這種情況要把環境雜訊削到最低: 專屬 benchmark session、固定 power mode、停通知、壓制搜尋索引與雲端同步,必要時做 clean boot。

2. 想看真實使用者體感的比較

想知道發布後,使用者在日常 Windows 上感受到的速度。

這種情況 不能把現實的雜訊全部消掉。 要在包含 OneDrive、Defender、通知、一般電源設定等的「像日常的環境」做比較,才會貼近現實結果。

把這兩種混用,結論就會擰著走: 「實驗室裡快 12%、現實中誤差」「現實中快、但 CPU 時間沒變」——都很常見。

Windows 上讓結果晃動的主要因素

先粗略列出會讓結果亂跳的因素:

晃動因素 典型例子
硬體 CPU / GPU、記憶體、SSD、散熱 薄筆電、有沒有散熱底座
韌體 BIOS / UEFI、OEM 控制 省電策略、風扇控制
OS Windows build、驅動、更新狀態 同台 PC 更新後行為就變了
電源 AC / DC、power mode、power plan 改電池供電就像另一個世界
室溫、風扇、先前負載 第 1 次 turbo、後半失速
背景 Update、Defender、同步、通知 執行中被掃描或同步打到
排程 優先權、親和性、NUMA 機器不同,CPU 配置就不同
資料/快取 OS 快取、應用快取 第一次慢、之後才快
建置條件 Debug / Release、PGO、有無 log 本來就在比不同東西

簡單說,「同一台 Windows 機器」若沒把條件對齊,就是不同實驗

power mode 與 power plan 要分開看

這一段非常關鍵。

Windows 有設定程式的 Power mode,與傳統的 Power plan(從 powercfg 可以看到的電源方案)。 外觀相似讓人容易混為一談,但草率處理比較就會亂掉。

在 Windows 的設定程式,從 Settings > System > Power & battery 可以選 Power mode。 Microsoft 文件中提到:Plugged in / On Battery 可以分別切換 Best power efficiencyBalancedBest performance。另外,Power mode 一變,背後的電源設定與 PPM(Processor Power Management)行為也會跟著變。也就是光這裡不同,核心停駐(core parking)與效能 scaling 策略就可能不同。

另一方面,Power plan 則是 BalancedHigh performance 等傳統電源方案。 可以用 powercfg /listpowercfg /getactivescheme 確認。

麻煩的是,Windows 同時存在 Power mode 的 overlayPower plan。 所以 benchmark 結果至少要記錄:

  • AC 或電池
  • Power mode 是什麼
  • Active power plan 是什麼

沒寫這 3 項的 benchmark 結果,日後回看會很痛苦。

先要固定的電源條件

  1. 筆電務必接 AC 比較
    電池運作常被加上意料外的限制。

  2. 固定 Power mode
    benchmark 用途可以先試 Best performance

  3. 記錄 Active power plan
    powercfg 把當時的值留下。

powercfg /list
powercfg /getactivescheme
  1. 必要時切成 High performance
# Balanced
powercfg /setactive 381b4222-f694-41f0-9685-ff5bb260df2e

# High performance
powercfg /setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c

「High performance 找不到」並不罕見

這裡也是地雷。 Microsoft 文件說明:在支援 Modern Standby 的裝置上,只允許使用 Balanced 或 Balanced 衍生的方案。 所以看到「High performance 沒有了,壞掉了嗎?」,更可能是 這台機器的設計本來就這樣

Microsoft 也指出:若 Power mode 無法變更,可能是用了 custom power plan,建議先切回 Balanced。Power mode UI 動不了時,這是首先該懷疑的方向。

抑制背景雜訊

Windows 是勤勞的 OS,你靜靜想 benchmark 時,它還在背後忙很多事。

先重開機,靜置一下

變更設定後先重開機,登入後不要馬上跑,等幾分鐘。 剛啟動時更新、索引、同步、Defender、各種常駐程式都還在躁動。

認真比較時用 clean boot

Microsoft 有說明怎麼做 clean boot,讓啟動項最精簡: 用 msconfig 停用非 Microsoft 的服務,再用 Task Manager 停用 Startup apps。

這招 降噪 很有效。 但它遠離日常環境,適合用在「專門比較程式本身差異的 lab 比較」。

讓通知閉嘴

Windows 的通知看似不起眼,其實很會打擾人。 不只視覺干擾,還會改變執行時機、焦點、背景應用活動。

手動開 Do not disturb,或至少在 benchmark 期間把通知關掉。

抑制搜尋索引與雲端同步

若 benchmark 會大量讀檔、寫檔、反覆重建原始樹,搜尋索引與雲端同步會低調地插你一刀。

  • 把 benchmark 用的資料夾排除在搜尋索引外
  • 停掉 OneDrive / Dropbox / Google Drive 的同步
  • 關掉瀏覽器、Teams、Discord、Slack

不起眼,但需要時效果很實在。

不對齊熱,等於在比熱

CPU 或 GPU 冷的時候和熱的時候是兩種生物。 薄筆電、薄型 mini PC、小型桌機更明顯。

要守的規則

  • 儘量對齊室溫
  • 筆電的擺放方式要固定
  • AC 變壓器、Dock、外接螢幕組合要固定
  • benchmark 前不要做重工作
  • 第一次執行與穩態要分開量

執行順序要交替

不要 A 跑 10 次、B 跑 10 次。 熱、快取、背景活動的偏差都會押到某一邊。

建議順序:

  • A B A B A B ...
  • A B B A A B B A ...
  • 事先生成隨機順序,按順序跑

量什麼,「快」就變成不同意思

把「快」壓到一個數字,多半會出事。 Windows 常用的有 3 個指標。

1. Wall-clock time(實際時間)

使用者在等的時間。 最貼近端對端體感,所以先看這個。

Windows 上 QueryPerformanceCounter(QPC)可以拿到高解析度時間。 managed code 則用 Stopwatch 系。 用 DateTime.Now 看毫秒,有點太無防備。

2. CPU time(user + kernel)

GetProcessTimes 可以拿到行程實際用到的 CPU 時間。

用來 看計算效率 相當好。 例如 wall-clock 變快但 CPU time 沒變,可能是快取、I/O、等待、排程在起作用。

3. Cycle count(CPU cycle 數)

QueryProcessCycleTime 能拿到整個行程的 CPU cycle 數。

同樣是量計算量,但和 wall-clock 是另一個面向。 想看「等待沒變,但計算部分變輕了嗎」時很有用。

priority、affinity、NUMA 放最後

這些有效。 但一開始就動,常會製造另一種現象。

先用預設狀態量

預設狀態就有差,那個差本身就有價值。 一上來就 /high/affinity,等於帶入 「真實 Windows 不會出現的條件」

真的要用,就要講清楚目的

  • /high:不想被其他行程干擾
  • /affinity:把 CPU 配置固定來比較
  • NUMA 控制:在大型機器上連記憶體 locality 一起對齊

Windows 的 start 可以指定 priority class 與 affinity mask 啟動。

start "" /high /wait myapp.exe --bench case1.json
start "" /affinity F /high /wait myapp.exe --bench case1.json

但 /realtime 就別用

/realtime 雖然能用,最好不要。 它常常不是在降噪,而是在製造另一種事故。

建議的量測流程

把上面這些整理成好操作的流程。

偏 lab 的比較流程

  1. 固定比較對象
    • commit hash / build number
    • compiler / runtime 版本
    • Debug / Release
    • log、assert、trace 有無
  2. 固定機器條件
    • Windows build
    • BIOS / UEFI 版本
    • 驅動版本
    • 接 AC
    • 室溫、擺放方式
  3. 固定電源條件
    • 決定 Power mode
    • 記錄 Active power plan
  4. 重新開機
  5. benchmark 前等幾分鐘
  6. 必要時做 clean boot
  7. 加上 warm-up
  8. A / B 交替跑
  9. 確保回合數
  10. 留下中位數、最小、最大、p95
  11. 保存 raw data
  12. 若差距很小,再取 ETW / WPR

留下來之後會救你一命的欄位

benchmark 的 CSV 或 JSON,至少留下面這些:

timestamp,version,scenario,elapsed_ms,user_ms,kernel_ms,cycles,power_mode,power_plan,ac_or_dc,room_temp_c,notes

可能的話再加:

cpu_package_temp_start_c,cpu_package_temp_end_c,affinity_mask,priority_class,windows_build,driver_version

benchmark 真正重要的,有時不是 本身,而是 後面能不能解釋

除了平均,也要看中位數與分佈

平均方便,但在 Windows benchmark 上很容易被摧毀。 Defender 偶爾插一下、通知彈一下、別的程式打一下 SSD,平均就被帶走。

建議:

  • 中位數:先看
  • p95 / p99:看 tail 有沒有惡化
  • min / max:看離群程度
  • 箱型圖或散佈圖:差距小時特別有用

出現差異時怎麼讀

把結果組合起來看比較清楚。

只有 wall-clock 變快

可能是 I/O、等待、快取、排程改善。

CPU time 與 cycle 都下降

很可能是實作本身變輕。

只有第 1 次慢 / 快

cold / warm 的差異。懷疑啟動、初始化、快取建立、JIT。

回合越多越慢

懷疑熱、throttling、記憶體壓力、背景活動。

用 ETW / WPR 挖「為何變快」

當差距小、或理由不清楚時,走 Windows 的 ETW(Event Tracing for Windows)路線是王道。

Microsoft 的 Windows Performance Recorder(WPR)是以 ETW 為基礎的錄製工具,包含在 Windows ADK 裡。 CPU、I/O、context switch、page fault 都能一起抓。

最小用法:

wpr -start CPU -filemode

REM 在這裡執行 benchmark

wpr -stop trace.etl

走到這一層,就不再是: 「B 快 3%」, 而能說出: 「B 的 lock 等待變少,ready time 下降」 「A 的 file open 變多,cold start 變慢」 這種帶理由的結論。

總結

在 Windows 上比較版本差異,真正有效的不是花俏的偏門招。 真正有用的,是下列 樸素但提升重現性 的做法:

  • 固定並記錄 AC / Power mode / Power plan
  • 分開 cold 與 warm
  • A / B 交替跑
  • 看中位數與分佈
  • 必要時做 clean boot
  • 差距小時用 ETW / WPR 挖原因

最重要的是:把「固定了什麼、沒固定什麼」和結果寫在一起。 benchmark 同時也是實驗條件的紀錄。

沒有條件的「速度報告」,像偶爾猜中的占卜,但重現性相當可疑。 反過來,只要條件寫得扎實,就算差距很小,結果也真的有價值。

參考資料

共用相同標籤的最新文章。能以相近的主題延伸理解。

與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。

本文連結到以下服務頁面,歡迎從最接近的入口查看。

作者檔案

本文作者的個人檔案頁面。

Go Komura

小村軟體有限公司 代表

以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。

回到部落格一覽