更新紀錄(2 筆,最後更新 2026年09月04日)
本文的修改紀錄。已保存的更新前版本,可透過附有 DOI 的永久連結閱讀。
引用本文(DOI: 10.5281/zenodo.21616293)
本文保存於 Zenodo。以下同時提供一律指向最新版本的 DOI,以及固定於您正在閱讀版本的 DOI。
Go Komura(2026)。〈在 Windows 上正確比較程式各版本速度的方法〉。小村軟體有限公司。https://doi.org/10.5281/zenodo.21616293 https://comcomponent.com/zh-TW/blog/2026/03/16/002-windows-benchmark-comparing-program-versions/
- DOI(最新版本)
- 10.5281/zenodo.21616293
- DOI(此版本)
- 10.5281/zenodo.22297134
想在 Windows 上比較程式的 A 版與 B 版。 這時最不該做的,就是在同一台電腦上各跑 1 次,然後說「感覺 B 快 8%」。
那 8% 也許真的是程式碼的差異。 但在 Windows 的基準測試裡,更常見的情況是:真正的原因其實是 Power mode(電源模式)、Power plan(電源計劃)、溫度、背景更新、搜尋索引、病毒掃描、親和性、執行順序、快取狀態 其中之一。接下來要做的,是把條件一個一個排除掉的瑣碎工作。
flowchart TB
accTitle: 「感覺快 8%」的真面目
accDescr: 說明各跑一次得到的差異也許是程式碼差異,但常常其實是電源、溫度、背景活動或快取其中之一,因此需要把條件一個一個排除的圖。
one1["各跑 1 次來比較"] --> dif2["得到「感覺快 8%」"]
dif2 -->|"也許是"| code1["真的是程式碼差異"]
dif2 -->|"常見的真面目"| env1["電源、溫度、雜訊、快取"]
env1 --> crush1["把條件一個一個排除"]
圖 1: 只跑 1 次得到的差異未必是程式碼差異,要先排除條件才能下定論。
本文梳理在 Windows 上比較不同版本程式執行速度的做法,目標是 盡量貼近程式碼本身的差異。
主要以 Windows 11 為對象,但 powercfg、start 等指令大部分在 Windows 10 上同樣可用。
先掌握的術語
本文中有些術語會直接以英文出現。為了避免第一次看到就卡住,先在這裡整理起來。
| 術語 | 意義 |
|---|---|
| ETW | Event Tracing for Windows。Windows 內建的追蹤基礎架構,可以把 OS、驅動程式與應用程式送出的事件一起記錄下來 |
| WPR / WPA | Windows Performance Recorder 與 Windows Performance Analyzer。前者是記錄 ETW 追蹤的工具,後者是開啟追蹤並加以分析的工具,兩者都包含在 Windows ADK 中 |
| clean boot | 停用 Microsoft 以外的服務與啟動應用程式,以最精簡的設定啟動的步驟(全新啟動)。目的是減少常駐應用程式帶來的雜訊 |
| PGO | Profile-Guided Optimization。先執行一次收集分支與呼叫的統計,再把這些統計用在下一次建置的最佳化判斷上。它會改變建置條件,因此是檢查比較對象是否對齊時的項目之一 |
| p95 / p99 | 百分位數。把所有 run 由快到慢排列後,位於第 95% / 99% 位置的值。「每 20 次會有 1 次比這個更慢」就是 p95 |
| NUMA | Non-Uniform Memory Access。從 CPU 看過去,到記憶體的距離並不一致的架構。在哪個節點上執行,記憶體存取的速度就會不同 |
| core parking(核心停駐) | 負載較低時,讓用不到的邏輯處理器休息的電源管理機制 |
先講結論
要提高重現性,歸結起來就是下面 6 點。
-
先決定「要比較什麼」 想看的是程式碼差異,還是真實使用者的體感,該對齊的環境並不相同。
-
把 Power mode(電源模式)與 Power plan(電源計劃)當成兩件不同的事來記錄 在 Windows 上如果這裡處理得草率,比較很容易變成在比 OS 的省電策略。
-
把冷機的第 1 次與熱機後的穩態分開 只有第一次特別快、只有後半特別慢,都不算罕見。
-
以 A→B→A→B 的方式交替執行 先把 A 全部跑完再跑 B,溫度與背景狀態的偏差就會全部壓在其中一邊。
-
除了平均,也要看中位數與離散程度 只要有 1 個離群值,整體樣貌就會嚴重扭曲。平均比想像中更脆弱。
-
差異很小時,就用 ETW / WPR 追查到原因為止 只憑體感爭論,雙方的主張都沒有依據,只會平行線下去。
圖中實線表示始終成立的關係,虛線表示附帶條件的關係(成立條件寫在詳細頁面中各關係的說明中)。關係的完整清單(共 25 條,附依據與可信度)以及主要概念的定義,彙整在知識地圖詳細頁面(日文)。資料:JSON-LD / Turtle
先決定你要比較什麼
同樣說是「速度比較」,其實分成 2 種。
1. 想看程式碼差異的比較
想知道演算法變更、資料結構變更、編譯器最佳化、執行階段更新等等,是否讓 實作本身變快 的比較。
這種情況要盡量削掉環境雜訊。 基準測試專用的工作階段、固定 Power mode(電源模式)、停用通知、抑制搜尋索引與同步,必要時做到全新啟動(clean boot)。
2. 想看真實使用者體感的比較
想知道散發之後,使用者在平常的 Windows 上實際感受到的速度。
這種情況 不能把現實中存在的雜訊全部消掉。 在包含 OneDrive 同步、Defender、通知、一般電源設定的「像日常一樣的環境」下比較,結果才會貼近現實。
把這 2 種混在一起,結論就會扭曲。 「實驗室裡快 12%,在現實中卻只是誤差」「在現實中比較快,但 CPU 時間沒有變化」這類情況很常發生。
flowchart TB
accTitle: 不要把兩種比較混在一起
accDescr: 說明想看程式碼差異的比較要盡量削掉環境雜訊,想看真實使用者體感的比較則要在保留現實雜訊的日常環境下量測,兩者混在一起會讓結論扭曲的圖。
q5["要比較什麼"] -->|"程式碼差異"| lab1["削掉雜訊的實驗室環境"]
q5 -->|"真實使用者體感"| real1["保留雜訊的日常環境"]
q5 -.->|"混在一起"| twist2["結論會扭曲"]
圖 2: 目的不同,該對齊的環境剛好相反,所以要先決定這是哪一種比較。
Windows 上讓結果浮動的主因
先粗略把會讓結果亂跳的因素列成一張表。
| 層 | 浮動因素 | 典型例子 |
|---|---|---|
| 硬體 | CPU / GPU、記憶體、SSD、散熱 | 筆記型電腦的厚薄、有沒有散熱底座 |
| 韌體 | BIOS / UEFI、OEM 控制 | 省電原則、風扇控制 |
| OS | Windows build、驅動程式、更新狀態 | 同一台電腦更新後行為就變了 |
| 電源 | AC / DC、Power mode(電源模式)、Power plan(電源計劃) | 改用電池供電就是另一個世界 |
| 溫度 | 室溫、風扇、前一刻的負載 | 只有第 1 次進 turbo,後半就失速 |
| 背景 | Update、Defender、同步、通知 | 執行途中跑起掃描或同步 |
| 排程 | 優先權、親和性、NUMA | 電腦不同,CPU 的配置就不同 |
| 資料 / 快取 | OS 快取、應用程式快取 | 只有第一次慢,第 2 次以後才快 |
| 建置條件 | Debug / Release、PGO、有沒有日誌 | 根本就在比較不同的東西 |
簡單說,即使是「同一台 Windows 電腦」,只要條件沒有對齊,就是不同的實驗。
flowchart TB
accTitle: 條件沒對齊就是不同的實驗
accDescr: 說明就算在同一台 Windows 電腦上量測,從硬體、電源、溫度、背景到建置條件這些橫跨多層的條件若沒有對齊,實質上就是不同的實驗,把條件固定並記錄下來才算是比較的圖。
same1["在同一台 Windows 電腦上量測"] -.->|"條件沒有對齊"| oth1["實質上是不同的實驗"]
same1 -->|"固定並記錄多層的條件"| cmp1["這樣才算是比較"]
圖 3: 就算是同一台電腦,橫跨各層的條件沒有對齊,比較就不成立。
Power mode(電源模式)與 Power plan(電源計劃)要分開看
這一段相當重要。
Windows 上同時有設定應用程式裡的 Power mode(電源模式),以及傳統的 Power plan(電源計劃)(powercfg 看得到的電源計劃)。
兩者外觀相似,很容易被混為一談,但處理得草率,比較條件就會變得含糊,結果也失去重現性。
在 Windows 的設定應用程式中,可以從 Settings > System > Power & battery 選擇 Power mode。
Microsoft 的文件指出,可以針對 Plugged in / On Battery 分別切換 Best power efficiency、Balanced、Best performance。而且 Power mode 一旦改變,背後的電源相關設定與 PPM(Processor Power Management)的行為也會受到影響。也就是說,光是這裡不同,core parking 與效能調節的策略就可能改變。
另一方面,Power plan 是 Balanced、High performance 這類傳統的電源計劃。
可以用 powercfg /list 或 powercfg /getactivescheme 查看。
麻煩的地方在於,Windows 上同時存在 Power mode(電源模式)的 overlay 與 Power plan(電源計劃)。 把兩者的關係畫成圖,就是下面這樣。
flowchart TB
subgraph upper["上層:Power mode - overlay"]
direction LR
M1["Best power efficiency"]
M2["Balanced"]
M3["Best performance"]
end
subgraph lower["下層:Power plan - 電源計劃"]
direction LR
P1["Balanced"]
P2["High performance"]
P3["custom plan"]
end
UI["設定應用程式<br/>Power and battery 的 Power mode"] --> upper
CLI["用 powercfg /setactive 切換"] --> lower
upper --> PPM["實際生效的電源設定<br/>PPM 與圖形的子群組"]
lower --> PPM
AC["接 AC 還是用電池"] --> PPM
PPM --> RESULT["頻率上限 / core parking / 效能調節"]
圖 4: Power mode(overlay)與 Power plan 這兩層再加上 AC/DC,共同決定實際生效的電源設定。
只看上層或只看下層,都無法決定實際的行為。因此在基準測試結果中,至少要記錄下面這些。
- 接 AC 還是用電池
- Power mode 是哪一個
- Active power plan 是哪一個
沒有寫下這 3 項的基準測試結果,日後回頭看時無法還原當時的條件。
flowchart TB
accTitle: 至少要記錄的 3 個項目
accDescr: 說明接 AC 還是用電池、Power mode 是哪一個、Active power plan 是哪一個這 3 項若沒有和結果一起記錄下來,日後回頭看時就無法還原條件的圖。
r1["接 AC 還是用電池"] --> rec2["和結果一起記錄下來"]
r2["Power mode"] --> rec2
r3["Active power plan"] --> rec2
rec2 --> rst1["日後可以還原條件"]
圖 5: 電源相關的這 3 項,沒寫下來的話整份結果都會無法重現,是最低限度的紀錄。
首先要固定的電源條件
-
筆記型電腦一定要接 AC 再比較 使用電池時,很容易被加上非預期的限制。
-
固定 Power mode 如果是基準測試用途,可以先試
Best performance。 -
記錄 Active power plan 用
powercfg把當下的值留下來。
powercfg /list
powercfg /getactivescheme
powercfg /list 的輸出,在 Microsoft 的文件中是以下面的形式呈現。作用中的配置會在行尾加上 *。在日文環境下,標題與配置名稱會以日文顯示。
Existing Power Schemes (* Active)
-----------------------------------
Power Scheme GUID: {guidPlan1} (Balanced) *
Power Scheme GUID: {guidPlan2} (Power saver)
把這裡出現的 GUID 原封不動抄到結果檔案的 power_plan 欄位。重點是留下 GUID 而不是名稱。因為即使同樣叫「平衡」,也可能是複製或自訂出來的另一個配置。
- 必要時切換到 High performance
# Balanced
powercfg /setactive 381b4222-f694-41f0-9685-ff5bb260df2e
# High performance
powercfg /setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
Power mode 能不能用命令列切換
這裡是常見的卡關處。在 powercfg 公開的命令列選項清單中,沒有可以直接改選 Power mode(overlay)本身的選項。正規的做法是從設定應用程式的 Settings > System > Power & battery 切換。
另一方面,powercfg 支援對 overlay scheme 讀寫設定值。文件中有下列敘述。
- 把 overlay 的別名與子群組傳給
powercfg /q,可以讀取 overlay 這一側的設定 powercfg /setacvalueindex與/setdcvalueindex也可以用在 overlay scheme 上- 沒有指定 scheme 時,對象是 目前作用中的 overlay(沒有 overlay 時則是目前的電源計劃)
- 別名的清單可以用
powercfg /aliases查看
換句話說,命令列能做的是「讀取並調整目前生效的 overlay 內容」,而不是改變「要選哪一個 overlay」。就基準測試的重現步驟而言,在設定應用程式中用人手固定 Power mode,再把該值寫進結果才是可行的做法。操作手冊上要明確寫出「已將 Power mode 設定為 Best performance」,而且每次執行前都在畫面上確認。
flowchart TB
accTitle: powercfg 做得到與做不到的事
accDescr: 說明 powercfg 支援讀寫目前生效的 overlay 設定值,但沒有選項可以改變要選哪一個 overlay,因此 Power mode 只能在設定應用程式中用人手固定並記錄下來的圖。
pc1["powercfg"] -->|"做得到"| rw1["讀取並調整 overlay 的內容"]
pc1 -.->|"做不到"| sel1["改變要選哪一個 overlay"]
sel1 --> hand1["在設定應用程式中用人手固定並記錄"]
圖 6: overlay 的選擇無法用命令列改變,只能用人手固定並記錄下來。
「找不到 High performance」是很常見的事
這裡也是常見陷阱。 Microsoft 的文件指出,在支援 Modern Standby 的裝置上,只允許 Balanced 或從 Balanced 衍生出來的配置。 所以不是「找不到 High performance,是不是壞掉了?」,而是 這台機種的設計本來就是如此 的可能性很高。
另外,Microsoft 也說明:「如果 Power mode 無法變更,可能是選到了 custom power plan,先試著選 Balanced」。Power mode 的 UI 沒有反應時,先從這裡懷疑會比較快。
flowchart TB
accTitle: 找不到 High performance 時該怎麼看
accDescr: 說明在支援 Modern Standby 的裝置上只允許 Balanced 或其衍生配置,因此看不到 High performance 是設計使然,而 Power mode 的 UI 無法變更時要先懷疑選到了 custom plan 的圖。
nohp1["找不到 High performance"] --> ms1["支援 Modern Standby 就是設計如此"]
nomv1["Power mode 的 UI 沒有反應"] --> cst1["懷疑是 custom plan"]
cst1 --> bl1["先試著選 Balanced"]
圖 7: 配置沒出現、UI 沒反應不一定是故障,先看機種的設計與選到的配置。
排除背景雜訊
就算這邊想安靜地量測,Windows 仍然會在背後跑更新、建立索引與掃描。第一步是把這些活動的量降下來。
先重新開機,等它穩定下來
變更設定之後先重新開機,登入後不要馬上執行,等幾分鐘。 剛啟動時,更新、索引、同步、Defender 與各種常駐程式都還在活動。
flowchart TB
accTitle: 重新開機後等它穩定下來
accDescr: 說明變更設定後先重新開機,由於剛啟動時更新、索引、同步與 Defender 都還在動作,因此登入後不要馬上執行,等幾分鐘再開始量測的步驟的圖。
chg1["變更設定"] --> rb1["重新開機一次"]
rb1 --> wt1["登入後等幾分鐘"]
wt1 --> ms2["然後才開始量測"]
rb1 -.-> nzz1["剛啟動時常駐程式還在活動"]
圖 8: 要等重新開機後背景活動穩定下來,才開始量測。
需要嚴謹比較時就用全新啟動
Microsoft 說明了以全新啟動把啟動時的設定縮到最小的步驟:
用 msconfig 停用 Microsoft 以外的服務,再用工作管理員停用 Startup apps。
這個做法在 減少雜訊 上很有效。 但它離日常使用環境很遠,比較適合用在「為了看程式碼差異的實驗室比較」。
讓通知安靜下來
Windows 的通知橫幅看起來不起眼,其實相當礙事。 它不只是視覺上的干擾,還可能改變執行時機、焦點,以及背景應用程式的活動。
手動啟用 Do not disturb,或至少在基準測試期間把通知關掉。
抑制搜尋索引與同步
如果受測對象會讀取大量檔案、寫出大量產出物,或反覆重建原始碼樹,搜尋索引與雲端同步就會不動聲色地拖累結果。
- 把基準測試用的目錄排除在搜尋範圍之外
- 停掉 OneDrive / Dropbox / Google Drive 等的同步
- 關掉瀏覽器、Teams、Discord、Slack
這些做法都不起眼,但該有效的時候相當有效。
flowchart TB
accTitle: 會拖累大量存取檔案的基準測試的雜訊
accDescr: 說明在會大量讀寫檔案的基準測試中,搜尋索引、雲端同步與常駐應用程式都會拖累量測,因此要用排除設定或停用來減少雜訊的圖。
ix1["搜尋索引"] --> hit1["拖累大量存取檔案的基準測試"]
sy1["雲端同步"] --> hit1
ap2["常駐應用程式"] --> hit1
hit1 --> cutn1["用排除或停用來減少雜訊"]
圖 9: 讀寫檔案越多的基準測試,停用索引與同步的效果越明顯。
不對齊溫度的比較,多半是在比溫度
CPU 與 GPU 在冷的時候和熱起來之後,運作時脈並不相同。也就是說,即使是同一份程式碼,每次執行的條件都在變。 筆記型電腦、薄型迷你電腦、小型桌上型電腦尤其明顯。
flowchart TB
accTitle: 溫度改變條件的機制
accDescr: 說明 CPU 與 GPU 在冷的時候和熱起來之後運作時脈不同,因此同一份程式碼每次執行的條件都在變,不對齊溫度的比較多半是在比溫度的機制的圖。
cold1["在冷的狀態下執行"] --> hot1["熱起來後時脈改變"]
hot1 --> vary1["每次執行條件都在變"]
vary1 -.-> heatc1["不對齊的比較是在比溫度"]
圖 10: 時脈會隨溫度變動,不對齊溫度條件就會變成在比較散熱而不是程式碼。
要遵守的規則
- 盡量對齊室溫
- 固定筆記型電腦的擺放方式
- 固定 AC 變壓器、擴充座與外接顯示器的接法
- 基準測試之前不要做繁重的工作
- 把第一次執行與穩態分開量測
執行順序要交替
要避免先跑 A 十次再跑 B 十次。 因為溫度、快取與背景活動的偏差會壓在其中一邊。
建議採用下面其中一種。
A B A B A B ...A B B A A B B A ...- 事先產生隨機順序,再依該順序執行
flowchart TB
accTitle: 執行順序會改變偏差落在哪一邊
accDescr: 說明先把 A 全部跑完再跑 B 會讓溫度、快取與背景活動的偏差只壓在其中一邊,改成交替或隨機順序執行則能把偏差分散到兩邊的圖。
seq1["A 全部跑完 → 再跑 B 全部"] --> bias1["偏差只壓在其中一邊"]
alt1["A B A B 交替或隨機順序"] --> even1["偏差分散到兩邊"]
even1 --> fair1["可以把順序的影響從差異中排除"]
圖 11: 把順序集中起來就會連偏差一起比較,所以要交替或隨機執行。
量測的對象不同,「快」的意思也不同
把「快」壓進 1 個數字裡,多半會出事。 在 Windows 上該看的代表性指標有下面 3 個。
1. Wall-clock time(實際經過時間)
使用者實際在等的時間。 最貼近端對端的體感,所以第一個要看的就是這個值。
在 Windows 上,QueryPerformanceCounter (QPC) 可以用來取得高解析度的時間。
受管理的程式碼(managed code)則基本上使用 Stopwatch 這一系列。
用 DateTime.Now 去看毫秒,實在有點不保險。
2. CPU time(使用者時間 + 核心時間)
可以用 GetProcessTimes 取得,是處理程序實際使用 CPU 的時間。
這個指標很適合用來 看計算效率。 舉例來說,如果 wall-clock 變快了但 CPU time 沒有變化,那可能是快取、I/O、等待時間或排程在起作用。
3. Cycle count(CPU 週期數)
用 QueryProcessCycleTime 可以取得整個處理程序的 CPU 週期數。
這同樣是看 CPU work 的指標,但呈現的面向與 wall-clock 不同。 特別是想看「等待時間相同,但計算的部分是否變輕了」的時候很好用。
flowchart TB
accTitle: 3 個指標所看的面向差異
accDescr: 說明 wall-clock time 是使用者在等的時間、CPU time 是處理程序實際使用 CPU 的時間、cycle count 是 CPU 週期數,三者呈現不同的面向,組合起來才能讀出快的內涵的圖。
spd1["看清楚「快」的內涵"] --> w1["wall-clock:等待的時間"]
spd1 --> u1["CPU time:用掉的 CPU 時間"]
spd1 --> cy1["cycle:計算部分的份量"]
w1 -.-> mixr1["用組合來推測理由"]
圖 12: 不要壓進 1 個數字,用 3 個指標的組合來讀出「快」的意義。
priority、affinity、NUMA 是最後的手段
這一類設定有時候確實有效。 但正因為有效,一開始就動它,很容易製造出另一種現象。
先用一般狀態量測
如果在預設狀態下就出現差異,那個差異本身就有價值。
一開始就加上 /high 或 /affinity,等於帶入 「實際的 Windows 上不會發生的條件」。
flowchart TB
accTitle: priority 與 affinity 是最後的手段
accDescr: 說明先在預設狀態下量測,有差異的話那個差異本身就有價值,一開始就固定優先權或親和性等於帶入實際 Windows 上不會發生的條件,因此要用時得先確定目的並放到最後的圖。
def1["先用預設狀態量測"] --> val1["有差異的話那個差異就有價值"]
early1["一開始就用 /high 或 /affinity"] -.-> art1["帶入現實不會發生的條件"]
val1 -->|"有需要時再確定目的"| lastr1["當成最後的手段來固定"]
圖 13: 優先權與親和性,要在完成預設狀態的量測之後,帶著目的再使用。
要用就要把目的講清楚
- /high:不想受到其他處理程序的干擾
- /affinity:想固定 CPU 的配置再比較
- NUMA 控制:想在大型電腦上連記憶體區域性一起對齊
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 雖然可以用,但 最好不要用。
它往往不是在去除雜訊,而是往製造另一種事故的方向作用。
建議的量測步驟
根據前面的內容,整理出實務上好操作的步驟。
偏實驗室的比較步驟
- 固定比較對象
- commit hash / build number
- compiler / runtime version
- Debug / Release
- 日誌、assert、追蹤的有無
- 固定電腦條件
- Windows build
- BIOS / UEFI version
- driver version
- 接 AC
- 室溫、擺放方式
- 固定電源條件
- 決定 Power mode
- 記錄 Active power plan
- 重新開機
- 基準測試前等幾分鐘
- 必要時做全新啟動
- 加入 warm-up
- A / B 交替執行
- 確保執行次數
- 留下中位數、最小值、最大值與 p95
- 保存 raw data
- 差異很小時就取 ETW / WPR
要跑幾次
第 9 點「確保執行次數」的大致參考值也先定下來。以下不是統計上的嚴格解,而是實務上的折衷點。
| 想看的東西 | 每個版本的執行次數參考值 |
|---|---|
| 只看中位數,想確認較大的差異(1 成以上) | 10 次 |
| 想主張數 % 的差異,也想看離散程度 | 30 次 |
| 想讀到 p95 | 30 次以上。只跑 20 次的話,p95 會直接落在最上面的 1〜2 個值本身,會直接受到離群值的影響 |
所需時間可以用 單次執行時間 × 次數 × 版本數 + warm-up 來估算。單次 30 秒的處理,A / B 各跑 30 次,加上 warm-up 大約是 35 分鐘左右。如果這不切實際,比起減少次數,把量測對象切小(只把繁重的工序切出來)方向會比較對。
如果不知道該在哪裡收手,一邊增加次數一邊看中位數的變化,等到再增加也不動時就停下來,是比較好懂的做法。
flowchart TB
accTitle: 執行次數的收手時機
accDescr: 說明一邊增加次數一邊觀察中位數的變化,等到再增加中位數也不再變動時就停下來,這種決定執行次數的實務做法的圖。
add2["增加次數繼續跑"] --> mdz1["觀察中位數的變化"]
mdz1 -->|"還在動"| add2
mdz1 -->|"增加也不動了"| stop1["就在這裡停下來"]
圖 14: 就算無法事先把次數定死,也可以把中位數穩定下來的點當成收手時機。
先記錄下來、日後會派上用場的項目
基準測試的 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
基準測試有時候 事後能不能解釋 比 量測本身 更重要。
除了平均,也要看中位數與分佈
平均很方便,但在 Windows 的基準測試中很容易壞掉。 只要有 1 次 Defender 插進來、跳出通知,或別的處理程序去敲 SSD,平均就被帶走了。
flowchart TB
accTitle: 平均會被離群值帶走
accDescr: 說明只要有一次 Defender 掃描、通知或別的處理程序的 I/O 插進來,平均就會被帶走,因此要以中位數為軸,再搭配 p95、p99 與 min/max 用分佈來讀的圖。
once3["只有 1 次混進雜訊"] --> avg1["平均被帶走"]
med2["以中位數為軸"] --> dist1["也看 p95 / p99 與 min / max"]
dist1 --> robust1["變成對離群值有抵抗力的讀法"]
圖 15: 平均會被 1 次雜訊弄壞,所以要用中位數與分佈的組合來讀。
建議採用這個組合。
- 中位數:先看這個
- p95 / p99:看 tail 有沒有惡化
- min / max:看離群的程度
- 箱型圖或散佈圖:差異很小時派得上用場
出現差異時的讀法
解讀結果時,把指標組合起來看會比較清楚。
只有 wall-clock 變快
可能是 I/O、等待時間、快取或排程獲得改善。
CPU time 與 cycle 都下降
實作本身變輕的可能性很高。
只有第 1 次慢或快
這是 cold / warm 的差異。懷疑啟動、初始化、快取產生與 JIT。
跑越多次越慢
懷疑溫度、throttling、記憶體壓力與背景活動。
flowchart TB
accTitle: 從差異的樣態讀出原因
accDescr: 說明只有 wall-clock 變快就懷疑等待與 I/O,CPU time 與 cycle 也下降就是實作變輕,只有第一次不同就是 cold 與 warm 的差異,跑越多次越慢就懷疑溫度與背景活動的讀法的圖。
pt2["看差異出現的樣態"] -->|"只有實際時間"| c1a["等待與 I/O 相關"]
pt2 -->|"CPU 時間也減少"| c2a["實作變輕"]
pt2 -->|"只有第一次"| c3a["cold / warm"]
pt2 -->|"後半變慢"| c4a["溫度與背景活動"]
圖 16: 比起差異本身,差異出現的樣態更能指出原因的方向。
用 ETW / WPR 挖到「為什麼比較快」
差異很小,或看不出理由的時候,往 Windows 的 ETW(Event Tracing for Windows)系工具走是最正統的做法。
Microsoft 的 Windows Performance Recorder (WPR) 是以 ETW 為基礎的記錄工具,包含在 Windows ADK 中。
CPU、I/O、內容切換(context switch)、分頁錯誤等等可以一起取得。
最基本的用法像下面這樣。
wpr -start CPU -filemode
REM 在這裡執行基準測試
wpr -stop trace.etl
用 WPA 開啟之後,最先要看的圖表大致上是固定的。
| 想看的東西 | 要開啟的圖表 | 讀法 |
|---|---|---|
| 哪個函式在用 CPU | CPU Usage (Sampled) | 以 Weight 排序,比較 A 與 B 的堆疊。因為是取樣,DPC / ISR 這種很短的處理不容易被拍到 |
| 為什麼在等 | CPU Usage (Precise) | 查看 Ready 時間、等待時間與內容切換的原因。lock 等待與 I/O 等待的差異會出現在這裡 |
| 是不是驅動程式造成的卡住 | DPC/ISR | 查看各模組的時間。這裡的數值很大的話,差異根本不在應用程式這一側 |
| 磁碟是不是在起作用 | Disk Usage | 查看 I/O 的次數與大小,以及服務時間 |
比較時的基本做法是 在相同情境下各取一份 A 與 B 的追蹤,把同樣的圖表並排來看。只看一份是無法判斷「這樣算慢嗎」的。
走到這個階段,就不再只是 「B 快 3%」, 而能像 「B 的 lock 等待減少,ready time 下降了」 「A 的 file open 變多,cold start 比較慢」 這樣,帶著理由把事情說清楚。
flowchart TB
accTitle: 從只有數字的差異走到帶理由的差異
accDescr: 說明差異很小或看不出理由時,用 WPR 在相同情境下各取一份 A 與 B 的追蹤,再用 WPA 把同樣的圖表並排比較,就能從快幾 % 變成帶著理由說明的流程的圖。
small2["差異很小、看不出理由"] --> tr1["用 WPR 取得 A 與 B 的追蹤"]
tr1 --> cmp2["用 WPA 把同樣的圖表並排來看"]
cmp2 --> rsn1["能帶著理由把事情說清楚"]
cmp2 -.-> onen1["只看一份無法判斷是不是慢"]
圖 17: 挖到 ETW 這一層,「快幾 %」就會變成「為什麼快」。
一頁式檢查清單
最後整理成可以直接貼進操作手冊的形式。
固定
- 已固定比較對象(commit hash / build number / Debug 或 Release / PGO 等建置條件 / 有沒有日誌與 assert)
- 已把筆記型電腦接上 AC
- 已在設定應用程式中固定 Power mode
- 已用
powercfg /getactivescheme查看 Active power plan - 已停用通知,並停掉搜尋索引與雲端同步
- 必要時已改成全新啟動
- 已重新開機,並等幾分鐘後才開始
執行
- 已加入 warm-up
- 已把 cold(第一次)與 warm(穩態)分開量測
- 已用交替或隨機順序執行 A / B
- 已決定次數後執行(參考值見上面的表)
記錄
- 已留下每次執行 1 列的 raw data(
elapsed_ms/user_ms/kernel_ms/cycles) - 已留下接 AC 還是 DC、Power mode(電源模式)、Power plan(電源計劃)的 GUID、Windows build 與 driver version
- 已留下室溫與擺放狀態
- 也寫下了沒有固定的條件
解讀
- 已查看中位數,沒有只用平均判斷
- 已用 p95 / p99 查看 tail
- 已用 min / max 確認離群值
- 已用 wall-clock / CPU time / cycle 的組合推測理由
- 差異很小時已挖到 ETW / WPR
總結
在 Windows 上比較不同版本的程式時,真正管用的不是花俏的旁門左道。 重要的是下面這些 不起眼卻對重現性很有用的做法。
- 固定並記錄 AC / Power mode(電源模式) / Power plan(電源計劃)
- 把 cold 與 warm 分開
- A / B 交替執行
- 查看中位數與分佈
- 必要時做全新啟動
- 差異很小時就用 ETW / WPR 挖到理由
而最重要的是,把固定了什麼、沒有固定什麼和結果寫在一起。 基準測試既是速度的比較,同時也是實驗條件的紀錄。
沒有寫下條件的加速報告,別人無法確認能不能做出相同的結果。因為只留下數字,卻沒有留下重現的方法。 反過來說,只要條件寫得完整,就算差異很小,那份結果也確實有價值。
flowchart TB
accTitle: 條件的紀錄決定結果的價值
accDescr: 說明沒有寫下條件的加速報告只留下數字、沒有留下重現的方法,條件寫得完整就算差異很小也有價值,也就是基準測試同時是實驗條件的紀錄的圖。
norec1["沒有寫下條件的報告"] --> onlyn1["只留下數字"]
onlyn1 --> norep1["別人無法確認"]
rec3["寫下條件的報告"] --> rep1["留下重現的方法"]
rep1 --> worth1["就算差異很小也有價值"]
圖 18: 基準測試的價值不在數字,而在於固定了什麼、沒固定什麼的紀錄。
參考資料
- Microsoft Support: Change the power mode for your Windows PC
- Microsoft Learn: Power Policy Settings
- Microsoft Learn: Customize the Windows performance power slider
- Microsoft Learn: Powercfg command-line options
- Microsoft Support: How to perform a clean boot in Windows
- Microsoft Support: Notifications and Do Not Disturb in Windows
- Microsoft Support: Search indexing in Windows
- Microsoft Learn: Configure custom exclusions for Microsoft Defender Antivirus
- Microsoft Support: Device Security in the Windows Security App
- Microsoft Learn: QueryPerformanceCounter function
- Microsoft Learn: Acquiring high-resolution time stamps
- Microsoft Learn: GetProcessTimes function
- Microsoft Learn: QueryProcessCycleTime function
- Microsoft Learn: start command
- Microsoft Learn: SetPriorityClass function
- Microsoft Learn: SetProcessAffinityMask function
- Microsoft Learn: Processor Groups
- Microsoft Learn: Windows Performance Recorder
- Microsoft Learn: WPR Command-Line Options
- Microsoft Learn: CPU Analysis in Windows Performance Analyzer - 用哪個圖表看什麼。
- Microsoft Learn: Set the Default Power Plan -
powercfg -LIST的輸出範例。
相關文章
共用相同標籤的最新文章。能以相近的主題延伸理解。
公平比較 C#/C++/Java/Go 執行速度的方法
本文梳理公平比較 C#、C++、Java、Go 執行速度的方法,涵蓋測量設計、warm-up、環境固定、統計的看法,以及具體的 bench 項目。
為什麼「剩餘1秒」遲遲不結束?── 進度列與剩餘時間的運作原理
剩餘1秒持續很久、停在99%、一直顯示準備中,分別是怎麼回事?從進度的分母、速度預測、最後的處理步驟與畫面更新逐一說明,並提供同一工作不同進度顯示的互動示範。
Windows 共用資料夾為何時而能連線、時而失敗——釐清 Kerberos、NTLM 與認證資訊問題
從症狀與記錄釐清 Windows 共用資料夾連線不穩定的原因。說明 IP 與名稱差異、只有應用程式失敗、空白密碼、1219、重新啟動及 SMB 簽章的檢查步驟,以及各項結果能證明什麼。
同樣是 1GB,為什麼複製照片資料夾比複製一部影片還慢?
圖解 Windows 中容量相同、複製耗時卻不同的原因。整理檔案數量、SSD 與 NAS 的等待時間、打包成 ZIP 的效果、把建立·傳輸·解壓縮都算進去的比較步驟,以及 robocopy 的適用場合。
Windows 的「硬體加速 GPU 排程」是什麼?打開就會變快嗎?
以圖解方式向一般使用者說明 Windows 的硬體加速 GPU 排程(HAGS):它改變了什麼、開與關如何判斷、設定項目不出現的原因、與影格生成的關係,以及安全的比較步驟。
相關主題
與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。
Windows 技術主題
彙整 KomuraSoft LLC 關於 Windows 開發、故障調查與既有資產活用文章的主題中心。
與本主題相關的服務
本文連結到以下服務頁面,歡迎從最接近的入口查看。
技術諮詢 & 設計審查
從效能比較的設計、量測條件的對齊方式,到用 ETW / WPR 深入追查,都很適合以技術諮詢與設計審查的形式進行。
故障調查 & 根本原因分析
當版本之間出現快慢差異時,要釐清原因是出在電源條件、溫度、背景雜訊還是實作差異,這個流程很適合以缺陷調查與原因分析的方式推進。
常見問題
整理諮詢這個主題時常見的問題。
- 在 Windows 上,基準測試結果浮動的主要原因是什麼?
- 原因橫跨多個層次:Power mode(電源模式)、Power plan(電源計劃)、溫度、背景更新、搜尋索引、病毒掃描、優先權與親和性、執行順序、快取狀態等等。即使是同一台 Windows 電腦,只要這些條件沒有對齊,實質上就是不同的實驗。筆記型電腦特別明顯,接 AC 與使用電池的行為差很多,因此一定要在接 AC 的狀態下比較,並把條件記錄下來。
- Power mode(電源模式)與 Power plan(電源計劃)有什麼不同?
- Power mode 是在設定應用程式的 Power & battery 中選擇 Best power efficiency、Balanced、Best performance 的切換,會影響背後的電源相關設定與 PPM(Processor Power Management)的行為。Power plan 則是用 powercfg 可以查看的 Balanced、High performance 等傳統電源計劃。Windows 上兩者同時存在,因此基準測試結果至少要記錄接 AC 還是用電池、Power mode、Active power plan 這三項。
- 找不到 High performance 電源計劃,是故障嗎?
- 多半不是故障。Microsoft 的文件指出,在支援 Modern Standby 的裝置上,只允許 Balanced 或從 Balanced 衍生出來的配置。也就是說,因為機種的設計而看不到 High performance 是很常見的情況。另外,如果 Power mode 的 UI 無法變更,可能是選到了 custom power plan,先試著選 Balanced 會比較快找到答案。
- 比較 A 版與 B 版的速度時,應該用什麼順序執行?
- 應該避免先把 A 全部跑完再跑 B,因為溫度、快取與背景活動的偏差會只壓在其中一邊。改成 A B A B 交替執行,或依事先產生的隨機順序執行。此外,把冷機的第一次與熱機後的穩態分開量測,並且不只看平均,還要看中位數、p95、最小值與最大值,就能避免結果被離群值帶走。