Windows上でプログラムの実行速度を正しく比較する
まず結論
再現性のあるベンチマークを取るための6つのポイント:
- 「何を比較したいか」を先に決める: コード差を見たいのか、実ユーザー体験を見たいのか
- power mode と power plan を別物として記録する
- 冷えた1回目と温まった後の定常状態を分ける
- A→B→A→B のように交互に回す
- 平均だけでなく中央値とばらつきを見る
- 差が小さいなら ETW/WPR で原因まで掘る
比較の種類を最初に決める
コード差を見たい比較
アルゴリズム変更やコンパイラ最適化など、実装そのものの差を知りたい場合。環境ノイズを可能な限り削る(clean boot、power mode 固定、通知停止など)。
実ユーザー体験を見たい比較
配布後にユーザーが実際に体感する速さを知りたい場合。ノイズを消してはいけない。OneDrive 同期、Defender、通知などを含めた日常環境で比較する。
この2つを混ぜると結論がねじれる(「ラボでは12%速いのに現実では誤差」など)。
結果がぶれる主な要因
| 層 | ぶれ要因 | 典型例 |
|---|---|---|
| ハードウェア | CPU/GPU、メモリ、SSD、冷却 | ノート PC の薄さ、冷却台の有無 |
| ファームウェア | BIOS/UEFI、OEM 制御 | 省電力ポリシー、ファン制御 |
| OS | Windows build、ドライバ、更新状態 | 更新後に挙動が変わる |
| 電源 | AC/DC、power mode、power plan | バッテリー駆動だと別世界 |
| 熱 | 室温、ファン、直前の負荷 | 1回目だけターボ、後半で失速 |
| バックグラウンド | Update、Defender、同期、通知 | 実行中にスキャンや同期が走る |
| データ/キャッシュ | OS キャッシュ、アプリキャッシュ | 初回だけ遅い、2回目以降だけ速い |
power mode と power plan を固定する
この2つは別物
- Power mode: 設定アプリの「システム > 電源とバッテリー」から選ぶ(Best power efficiency / Balanced / Best performance)
- Power plan: 従来の電源プラン(Balanced / High performance など)。
powercfgで確認
固定手順
- ノート PC は必ず AC 接続で比較する
- Power mode を固定する(ベンチ用途なら Best performance)
- Active power plan を記録する:
powercfg /list
powercfg /getactivescheme
- 必要なら High performance に切り替え:
REM High performance
powercfg /setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
注意点
- Modern Standby 対応デバイスでは High performance が表示されないことがある(機種の設計上の制限)
- Power mode が変更できない場合は、custom power plan が選択されている可能性あり。まず Balanced を選んでみる
バックグラウンドノイズを潰す
- 再起動して数分待つ: 起動直後は更新、インデックス、同期、Defender が暴れている
- 本格的な比較なら clean boot:
msconfigで Microsoft 以外のサービスを停止。コード差を見るラボ比較向け - 通知を切る: Do not disturb を有効にする
- 検索インデックスと同期を抑える: ベンチ用ディレクトリを検索対象から外す。OneDrive/Dropbox を止める。ブラウザや Teams を閉じる
熱を揃える
CPU/GPU は冷えている時と温まった後で別物。特にノート PC は顕著。
- 室温を揃える
- ノート PC の置き方を固定
- AC アダプタ、ドック、外部ディスプレイ構成を固定
- ベンチ前に重い作業をしない
- 初回実行と定常状態を分けて測る
実行順序は交互にする
A を10回やってから B を10回 → NG(熱とキャッシュの偏りが載る)
おすすめ:
A B A B A B ...A B B A A B B A ...- ランダム順序を事前生成して回す
何を測るか
| 指標 | 取得方法 | 用途 |
|---|---|---|
| Wall-clock time(実時間) | QueryPerformanceCounter / Stopwatch |
ユーザー体感に一番近い |
| CPU time(ユーザー+カーネル) | GetProcessTimes |
計算効率を見る |
| Cycle count | QueryProcessCycleTime |
待ち時間以外の計算負荷を見る |
指標の組み合わせで読む
- wall-clock だけ速い → I/O、待ち時間、キャッシュの改善かも
- CPU time も cycle も下がっている → 実装そのものが軽くなった
- 1回目だけ遅い/速い → cold/warm の差(起動、初期化、JIT)
- 回を重ねるほど遅くなる → 熱、スロットリング、メモリ圧迫
priority、affinity は最後の手段
デフォルト状態で差が出るなら、その差自体に価値がある。最初から /high や /affinity を入れると実際の Windows では起きない条件を持ち込むことになる。
start "" /high /wait myapp.exe --bench case1.json
start "" /affinity F /high /wait myapp.exe --bench case1.json
/realtime は使わない。 ノイズ除去ではなく別の事故を作る。
実践的な測定手順
- 比較対象を固定(commit hash、build number、Debug/Release、ログ有無)
- マシン条件を固定(Windows build、BIOS version、AC 接続、室温)
- 電源条件を固定(Power mode、Active power plan を記録)
- 再起動し、数分待つ
- 必要なら clean boot
- warm-up を入れる
- A/B を交互に回す(十分な回数を確保)
- 中央値・最小・最大・p95 を残す
- raw data を保存する
- 差が小さければ ETW/WPR を取る
記録すべき項目
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
ETW/WPR で「なぜ速いか」まで掘る
差が小さい、または理由が読めないときは ETW(Event Tracing for Windows)へ。
wpr -start CPU -filemode
REM ここでベンチを実行
wpr -stop trace.etl
これで「B は lock 待ちが減って ready time が下がっている」「A は file open が増えて cold start が遅い」といった理由付きで議論できるようになる。
まとめ
Windows でバージョン比較をするときに本当に効くのは地味だが再現性に効く作法:
- AC / Power mode / power plan を固定して記録
- cold と warm を分ける
- A / B を交互に回す
- 中央値と分布を見る
- 必要なら clean boot
- 差が小さければ ETW/WPR で理由まで掘る
一番大事なのは、何を固定し、何を固定しなかったかを結果と一緒に書くこと。 条件の書かれていないベンチ結果は再現性の面で頼りない。
参考資料
- 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
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
プログラミング言語の速度比較を正しく行う方法
C#・C++・Java・Goの実行速度を公平に比較するための測定設計、warm-upや環境固定の具体策、p95やGC pauseを含む統計の見方、実運用に近いベンチ項目の選び方までを実践目線で整理する解説記事です。
Windowsはなぜ今の形になったのか:開発者から見た歴代Windowsの進化
Windows 95からWindows 11までの変化を、見た目の年表ではなく、互換性、安定性、権限管理、ドライバ、Win32、.NET、セキュリティなどWindowsアプリ開発者の視点で整理します。
Windowsアプリ開発者のためのCPU設定入門:優先度・アフィニティ・Pコア/Eコア
Windowsアプリ開発者向けに、CPU優先度、アフィニティ、Pコア/Eコア、省電力設定、EcoQoS/Efficiency Modeの関係と、性能・応答性・発熱を測る考え方を整理します。
開発者の異常な愛情、または私は如何にして心配するのをやめてWindowsを愛するようになったか
Windowsは面倒くさい。けれど、その面倒くささは、現実の業務を背負ってきたOSだからこその面倒くささでもある。
PowerShell実用コマンド集 ── 日常作業でよく使う小さな機能を増やす
PowerShellで日常作業に使う実用コマンドとして、Measure-Object、Group-Object、Select-String、Compare-Object、Tee-Object、Start-Transcriptなどの使いどころを整理します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。