返回所有文章

合併前,先用 CI 比較遊戲效能

一次重構可能通過所有功能測試,卻增加了每個影格的處理量。無論程式碼出自開發者、Claude Code 還是 Codex,都可能發生這種情況:驗證行為是否正確的測試,並不測量程式碼在目標硬體上的執行成本。

效能檢查需要可重複的工作負載,以及實際測量過的基準。Framedash 的 perf-diff 比較兩個建置的遙測資料;run-profile-test 則先啟動測試指令,再執行比較。遊戲由自己的 PC 或 CI 執行器運行。在用結果阻止合併之前,先確認比較測量的是什麼,以及同一個建置在未修改時會有多大波動。

先重複測量未修改的基準建置

選擇一個每次都能依相同步驟執行的情境,例如沿固定路線穿過關卡。先測量基準建置,不改程式碼再執行一次,最後測量候選建置。保持以下條件一致,並隨結果一起記錄:

  • 硬體、作業系統、顯示卡驅動程式與電源設定
  • 引擎與 SDK 版本、建置組態與圖形 API
  • 解析度、畫質、VSync 與影格率上限
  • 測試情境、攝影機路線、暖機過程、測量時間與遙測設定

重複執行能看出單次基準測量無法呈現的波動。如果未修改的建置之間也會超過預定門檻,先檢查執行環境或測試流程,再啟用 CI 失敗判定。直接沿用範例中的百分比,並不等於估算了自己遊戲的測量雜訊。

也要避免混合不同條件下的資料。perf-diff 依 build_id 彙總查詢期間內的資料,預設為過去 30 天。重複使用同一個 ID 的執行會併入同一組;ci.scenario 只是中繼資料,這個指令不會據此自動篩選情境。需要分開比較某次執行或某種組態時,為測量分配不同的建置 ID,並用 ci.commit 保留原始碼提交。基準與候選都必須在所選期間內有仍保留的資料。

了解 P50 檢查如何判定

perf-diff 會列出已蒐集指標的 P50 與 P95。P50 是中位數,效能退化檢查依 P50 的變化率判定。 P95 用來觀察樣本值的高位區段,不決定結束代碼。

安裝並設定好 CLI 後,可以用以下範例檢查影格時間:

framedash perf-diff \
  --baseline "$BASELINE_BUILD_ID" --candidate "$CANDIDATE_BUILD_ID" \
  --api-key-file ci-read.key --metric frame_time \
  --threshold 5 --fail-on-regression

兩個 ID 必須與 SDK 實際傳送的值一致,FRAMEDASH_PROJECT_ID 則設為受測專案的 ID。私有檔案 ci-read.key 存放具有 analytics:read 權限的金鑰。這裡的 5% 是容許幅度的範例,並非建議門檻。

假設基準值大於零,影格時間 P50 從 10 ms 升至 10.5 ms,增幅恰好是 5%,這項檢查會通過;升至 10.6 ms,增幅為 6%,則會失敗。這些數字只用來說明判定方式。即使增幅在容許範圍內,報告的 isRegression 也可能為 true,因為 CLI 會另外套用 --threshold。如果只有 P95 變差,檢查仍可能通過,因此在意間歇性卡頓時,也需要查看尾端表現。

使用這些選項時,要區分以下情況:

  • 未加上 --fail-on-regression 時,指令只列出結果,不會因效能退化而失敗。加上後,增幅嚴格大於門檻才回傳結束代碼 1。預設門檻是 0%。
  • --metric 選擇用於通過或失敗判定的指標,報告中仍可能包含其他指標。省略時會檢查所有可比較的指標,並略過沒有資料的指標。因此,影格時間檢查通過,不代表 GPU 時間也接受了檢查。
  • 如果所選範圍內沒有任何可比較的指標,檢查會回傳結束代碼 1。這表示證據不足,而不是測到了效能下降。驗證錯誤、無效 ID 等也會讓指令失敗;修改程式碼前,先閱讀診斷訊息。

其他支援的指標有 memory、gpu_time、io.read_bytes、io.read_time_ms、io.read_ops、load_time_ms 與 mem.vram。每項都需要實際蒐集到對應資料;I/O 與地圖載入測量還需要 SDK 端的設定。檢查會將這些指標的上升都視為退化。對於 I/O 與載入時間,如果有效基準為 0、候選值為正,則無論百分比門檻是多少都會失敗,因為相對於零的百分比變化沒有定義。

--map 與 --platform 可以限定資料範圍,但不能證明兩台機器或兩個情境的測量條件可比。--metric load_time_ms 不能與 --map 一起使用,因為地圖載入事件沒有供該篩選器使用的 map_id。

從 CI 執行測試情境

重複執行的報告能用於判斷後,再把遊戲啟動與效能比較放進同一個 CI 工作。以下是 Bash 範例。./ci/profile-game.sh 代表自行提供的指令碼,並非 Framedash 隨附的檔案。它應啟動目標建置、執行情境、完成遙測傳送,再以測試結果對應的狀態碼結束。

framedash run-profile-test \
  --command "./ci/profile-game.sh" \
  --build-id "$CANDIDATE_BUILD_ID" --commit "$GITHUB_SHA" \
  --scenario plaza-loop --api-key-file ci-read.key \
  --baseline "$BASELINE_BUILD_ID" --metric frame_time \
  --threshold 5 --fail-on-regression

GITHUB_SHA 是 GitHub Actions 提供的提交值;使用其他 CI 時,換成對應變數。基準必須事先完成測量。調整檢查規則期間,可以移除 --fail-on-regression,先觀察結果。

run-profile-test 會在有對應值時,將 FRAMEDASH_BUILD_ID、FRAMEDASH_GIT_BRANCH、FRAMEDASH_GIT_COMMIT 與 FRAMEDASH_TEST_SCENARIO 傳給子行程。在 Unity 與 Godot C# 中,先初始化 SDK,再於測試進入點讀取這些值:

Framedash.TelemetrySDK.Instance.BeginAutomatedSessionFromEnvironment();
// Run the scenario, then flush and wait using your SDK's CI procedure.
Framedash.TelemetrySDK.Instance.EndAutomatedSession();

這段程式碼只示範會話標記,不是完整的測試框架。UE5 在 UFramedashSubsystem 上提供對應方法。會話會設定頂層欄位 build_id,以及 ci.branch、ci.commit、ci.scenario 屬性。會話與執行器的設定見 CI 整合效能分析指南。結束會話不代表緩衝區中的事件已到達伺服器;請依所用 SDK 的步驟送出緩衝資料並等待傳送完成,在此之前不要關閉遊戲。

兩個行程使用不同的金鑰。CLI 用 ci-read.key 中的 analytics:read 金鑰讀取資料,遊戲則用 events:write 金鑰傳送資料。透過 --api-key-file 傳入讀取金鑰後,遊戲初始化程式仍可從 FRAMEDASH_API_KEY 讀取資料收集用金鑰。兩把金鑰都應保存在 CI 的機密管理功能或私有檔案中,不要寫入版本庫或日誌。

測量繪圖效能時,要啟用繪圖

UE5 的 -nullrhi 會停用正常繪圖。它適合部分無頭模式的邏輯測試,卻無法重現繪圖時的負載,也不能提供有意義的 GPU 效能比較。要測量繪圖效能,應在目標 GPU 上啟用繪圖,並保持兩次測試的設定一致。其他引擎的停用繪圖模式也應依同樣原則處理。

確認測量確實完成

run-profile-test 會等待候選建置的效能事件數高於執行前的值。這能避免重試時僅憑舊資料就結束等待,但不能證明本次執行的所有事件都已到達。遊戲行程失敗或逾時後,執行器也會直接失敗,不再進行效能退化判定。

現有 perf-diff 檢查沒有統計意義上的最低樣本數要求,也不會驗證前面列出的所有測量條件。應在測試流程中檢查樣本數、會話數、情境是否完成,以及 SDK 日誌。少量樣本也可能產生比較結果,但未必足以支持發布決策。

這些百分位數描述的是已接收的遙測樣本,不一定涵蓋每個繪製的影格。週期性心跳與事件發生時的快照可能漏掉短暫卡頓;改變事件頻率,也可能改變參與統計的樣本分布。對需要限定擷取區間、逐影格取樣的 Unity 專案,獨立的 Unity 效能執行比較試行功能可透過 run-diff 比較基準、未修改的重複執行與候選。它列出影格間隔分布並檢查擷取是否完整,不執行本文的 P50 效能退化判定,也不會為 perf-diff 增加 P95 失敗條件。

調查差異,再以相同條件驗證修正

可比較的結果超過門檻時,先在相同條件下重新執行。如果差異仍然存在,再縮小到受影響的工作負載,用引擎的效能分析工具擷取詳細資料。影格時間或記憶體增加只能指出症狀,不能直接指出造成問題的函式或配置操作。

如果情境傳送了帶有位置和已註冊地圖 ID 的事件,效能熱圖可以協助找出高負載區域。認定熱點來自候選建置之前,先核對建置及其他已啟用的篩選條件。建置比較本身不要求設定地圖。

代理也可以透過 Framedash 的唯讀 MCP 工具協助查看證據。get_heatmap 等彙總工具需要 analytics:read;透過 query 直接執行 SQL,還需要 data:admin。只有調查確實需要直接查詢時,才授予較大的權限。能讀取遙測,不代表代理的原因解釋或程式碼修改已獲得驗證:仍要用效能分析工具檢驗假設、審查修正,並以同一情境測量修正後的建置。

指令選項見 CLI 參考。Claude Code 外掛包含 MCP 設定與整合指南:

claude plugin marketplace add crane-valley/framedash-claude-plugin
claude plugin install framedash@framedash

從一個已了解重複執行波動範圍的情境開始。把基準、候選報告、測試設定與後續修正驗證結果一起保存在提取要求中,審查者才能據此判斷這次效能變化是否可以接受。

在自己的執行環境中比較基準與候選建置 提供 Unity、UE5 與 Godot (C#) SDK。
免費開始 UnityUE5Godot (C#)