工程技術文章

雲端 Mac 用 xctrace 建立 iOS 能耗回歸門禁

雲端 Mac 用 xctrace 建立 iOS 能耗回歸門禁

一段看似普通的清單重新整理邏輯,可能讓 CPU 持續保持活躍,也可能因為過於密集的計時器、重複的網路請求或背景工作而增加喚醒次數。功能測試通常不會報錯,程式碼覆蓋率也看不出問題。若要在合併前發現這類變化,可以在 OVPS 雲端 Mac 上固定測試環境,使用 xctrace 錄製同一段使用者操作,再將結果與已確認的基線比較。

先定義門禁要測量什麼

能耗不是脫離情境後仍有意義的單一數值。首頁閒置、連續捲動、圖片解碼與背景同步的資源特徵完全不同,不能混用同一條基線。首先選擇一段持續 60 至 120 秒、可穩定重現的核心路徑,例如啟動應用程式、進入訊息清單、捲動三個畫面、開啟詳細資料後返回。

每個情境至少應記錄以下條件:

  • App 提交版本與建置設定;
  • 裝置型號、系統版本及電量範圍;
  • 螢幕亮度、網路類型與低耗電模式狀態;
  • 測試帳戶的資料規模;
  • 採樣時間、預熱次數與正式執行次數。

模擬器適合用來驗證自動化指令碼與操作是否穩定,但無法代表實機能耗。正式門禁應綁定固定實機;模擬器結果只能作為程序活動的輔助證據。

不要直接採用第一次執行的結果。首次啟動可能包含資料庫遷移、著色器準備或快取填充。先預熱一次,再正式錄製至少三次,並使用中位數抵消偶發系統工作造成的雜訊。

固定雲端 Mac 與測試裝置狀態

執行節點應固定 Xcode 主要版本,並明確選擇開發者目錄。不要依賴互動式 Shell 中碰巧生效的環境變數。

set -euo pipefail

export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
xcodebuild -version
xcrun xctrace version
xcrun xctrace list devices
xcrun xctrace list templates

最後兩條命令也用於相容性檢查。不同 Xcode 版本可用的範本與匯出結構可能改變,因此指令碼不應假設 Energy Log 永遠存在。找不到範本時,應立即結束並保留版本資訊,而不是退化成一次毫無意義的空白採樣。

實機在開始前應回到一致狀態:關閉不相關的應用程式、維持相近的電量區間、確認溫度已恢復、停用自動更新,並保持網路條件穩定。測試期間不要同時執行封存、相依套件下載或磁碟清理工作。共享節點上的額外負載會污染 CPU 與 I/O 讀數。

建立執行前檢查

將裝置 UDID、Bundle ID、情境名稱與提交編號寫入同一個執行目錄。目錄名稱應保持唯一,但不要把權杖或簽章資料寫入路徑與日誌。

RUN_ID="$(date -u +%Y%m%dT%H%M%SZ)-${GIT_COMMIT:-local}"
OUT_DIR="artifacts/energy/${RUN_ID}"
mkdir -p "$OUT_DIR"

xcrun simctl list devices > "$OUT_DIR/devices.txt"
xcrun xctrace list templates > "$OUT_DIR/templates.txt"
git rev-parse HEAD > "$OUT_DIR/commit.txt"

連接實機時,可以將第一條命令替換成團隊自己的裝置探測命令。重點不在命令形式,而是失敗時必須停止測量,避免把「裝置未連接」誤判為「能耗下降」。

錄製可重複的 xctrace 軌跡

先啟動待測程序並完成預熱,再依程序名稱附加。以下指令碼要求裝置、程序與範本都必須由 CI 參數明確提供:

DEVICE_UDID="${DEVICE_UDID:?missing DEVICE_UDID}"
PROCESS_NAME="${PROCESS_NAME:?missing PROCESS_NAME}"
TRACE="$OUT_DIR/energy.trace"

xcrun xctrace record \
  --template "Energy Log" \
  --device "$DEVICE_UDID" \
  --attach "$PROCESS_NAME" \
  --time-limit 90s \
  --output "$TRACE"

錄製開始後,再由 UI 自動化執行固定操作。操作指令碼應使用輔助使用識別碼,而不是螢幕座標;測試資料應預先載入,網路請求最好指向穩定的測試環境。若某次執行發生登入失敗、彈出視窗遮擋或未抵達目標頁面,應將該次結果標記為無效,不能納入中位數。

xctrace 成功返回只表示 trace 已產生,不代表情境已正確執行。每次錄製還應保存 UI 測試結果、開始與結束時間、應用程式日誌摘要,以及情境完成標記。缺少任何一項時,門禁應回報「測量無效」,而不是回報效能測試通過。

匯出指標並比較基線

先匯出 trace 的目錄結構,確認目前 Xcode 可以提供哪些表格,再針對該版本維護解析規則:

xcrun xctrace export \
  --input "$TRACE" \
  --toc \
  --output "$OUT_DIR/toc.xml"

不要使用一條脆弱的正規表示式直接解析二進位 trace。更穩妥的做法是依 Xcode 主要版本保存 XPath 或 XML 解析器,並同時封存原始 trace。門禁可以關注四類變化:持續的 CPU 活動、執行緒喚醒、計時器觸發密度與網路傳輸量。這些是協助定位問題的線索,不應粗略合併成單一「能耗分數」。

基線應來自相同裝置、相同情境與相同建置類型的多次正常執行。建議保存最近確認版本的中位數,同時保留每次執行的原始值。比較時應同時採用相對變化與絕對下限:極小的數值即使增加一倍,也未必具有工程意義。

分級處理異常

輕微偏移應先產生警告,不阻擋合併;連續多次超過臨界值,或 CPU 與喚醒情況同時惡化時才判定失敗。臨界值必須根據團隊的歷史樣本制定,不應直接套用通用百分比。

失敗報告至少應包含提交編號、裝置與系統版本、三次採樣值、中位數、基線、變化比例、trace 路徑及 UI 情境結果。如此一來,開發者可以直接開啟相關證據,而不是只看到一句「能耗過高」。

從異常軌跡回到程式碼

CPU 持續偏高時,應先檢查主執行緒輪詢、圖片處理、重複的版面配置計算,以及未結束的背景佇列。喚醒次數升高時,應重點檢查短週期計時器、頻繁的磁碟寫入、重複通知,以及未合併的網路重試。若網路活動異常,則應核對分頁請求、快取命中、遙測批次與重新連線策略。

常見的誤判因素也必須逐一排除:裝置剛充電造成溫度變化、首次執行時仍在建立快取、測試帳戶的資料量改變、系統彈出視窗中斷操作,以及雲端 Mac 同時執行其他繁重工作。修正後必須在相同條件下重新完整執行三次,不能用一次較好的結果覆蓋失敗紀錄。

最終,能耗門禁的價值不在於產生一個好看的分數,而在於把測試情境、裝置條件、原始軌跡與程式碼提交綁定起來。只有這些證據能夠重複採集,異常才會有明確歸屬,門禁也不會淪為經常被略過的雜訊來源。

常見問題

iOS 模擬器可以取代真機執行能耗門禁嗎?

不能完全取代。模擬器適合驗證腳本與場景穩定性,最終能耗基線仍應在固定型號及固定系統版本的真機上建立。

能耗超過基線一次就要阻止合併嗎?

不建議。至少連續採樣三次並比較中位數;輕微偏移先警告,持續超標且 trace 證據完整時才阻止合併。

OVPS CLOUD MAC

將下一次建置部署至獨享物理節點

從三種 Apple Silicon 配置與六個在售節點中選擇,實際可用狀態以控制台即時回傳為準。

選擇配置並下單