同一個提交在雲端 Mac 上連續建置時,第一輪耗時 11 分鐘,到了第四輪卻增加到 15 分鐘,此時不應急著斷定「機器效能不穩定」。快取命中、索引程序、測試並行度與熱壓力,都可能造成類似的曲線。正確做法是固定變因、連續取樣,再判斷耗時增加是否與功耗及熱壓力同步。
先定義可比較的建置樣本
診斷對象應該是能夠穩定重現的命令,而不是開發者臨時點選的 Scheme。固定程式碼提交、Xcode 路徑、SDK、目標、建置設定與 DerivedData 目錄,並記錄機器啟動後的閒置時間。若每輪都切換分支或更新相依套件,量測到的只會是工作負載變化。
在 VMOrbit 的獨享實體節點上,主機資源不會受到其他租戶虛擬機器排程的干擾,但節點內仍可能出現索引、相依套件解析、模擬器與殘留建置程序之間的資源競爭。開始前先儲存基本環境資訊:
mkdir -p "$HOME/build-thermal-check"
system_profiler SPHardwareDataType > "$HOME/build-thermal-check/hardware.txt"
xcodebuild -version > "$HOME/build-thermal-check/xcode.txt"
pmset -g > "$HOME/build-thermal-check/power.txt"
ps -axo pid,%cpu,%mem,etime,command > "$HOME/build-thermal-check/processes-before.txt"
分開量測冷建置與熱建置
冷建置用於觀察完整編譯負載,熱建置則用於觀察增量建置路徑,兩者不能混在同一組統計資料中。冷建置應使用全新且專用的 DerivedData,熱建置則重複使用前一輪的目錄;不要清除全域快取,以免影響節點上的其他工作。
| 樣本 | DerivedData | 主要用途 |
|---|---|---|
| 冷建置 | 每組重新建立 | 比較完整編譯的持續負載 |
| 熱建置 | 同組重複使用 | 檢查增量建置與快取效果 |
| 閒置對照 | 不執行建置 | 辨識背景程序與基準功耗 |
同步收集耗時與熱壓力
只看總耗時無法證明發生了熱節流。至少要連續執行三輪,並在建置期間同步收集 powermetrics 資料。這項工具通常需要管理員權限,授權範圍應限制在明確的命令與參數內。
RUN_ROOT="$HOME/build-thermal-check/run-01"
mkdir -p "$RUN_ROOT/DerivedData"
sudo powermetrics --samplers cpu_power -i 1000 -n 900 \
-o "$RUN_ROOT/powermetrics.txt" &
METRIC_PID=$!
/usr/bin/time -lp xcodebuild \
-workspace App.xcworkspace \
-scheme App \
-configuration Release \
-destination 'generic/platform=iOS' \
-derivedDataPath "$RUN_ROOT/DerivedData" \
build > "$RUN_ROOT/build.log" 2> "$RUN_ROOT/time.txt"
wait "$METRIC_PID"
pmset -g therm > "$RUN_ROOT/thermal.txt"
-n 900 表示最多收集 900 次;如果建置提早完成,背景取樣仍會繼續。專案指令碼可以在建置結束後向取樣程序傳送 TERM,但必須保留結束處理,避免 CI 中殘留取樣程序。若無法使用 powermetrics,至少應儲存 pmset -g therm、time -lp,以及依 CPU 使用率排序的程序快照。
熱節流必須同時獲得「耗時趨勢」與「系統訊號」的支持,不能只因一次 CPU 使用率偏高就直接定論。
依據曲線而非單一資料點下結論
將每一輪的實際耗時、最大常駐記憶體、熱壓力,以及同時段的高負載程序放入同一張記錄表。若第一輪較慢、後續明顯加快,通常是快取預熱所致;若某一輪突然變慢,且同時出現相依套件下載或索引程序,則更可能是資源競爭。
更值得注意的模式是:程式碼與快取狀態不變,連續幾輪的耗時卻逐步增加;CPU 長時間維持滿載;熱壓力訊號也隨之升高;停止負載並靜置後,下一輪又恢復正常。只有這些證據同時出現時,才應將熱節流列為主要原因。
排除三類常見假象
首先確認建置是否在未察覺的情況下執行了測試、封存或指令碼下載。其次比較日誌中的編譯檔案數量,確認每輪工作量一致。最後檢查是否有多個 xcodebuild、模擬器或套件管理程序同時執行。可以在異常輪次儲存以下資訊:
date -u
pgrep -alf 'xcodebuild|swift-frontend|clang|Simulator'
top -l 3 -o cpu -stats pid,command,cpu,mem,time
du -sh "$RUN_ROOT/DerivedData"
top 的即時排名只能顯示取樣當下哪些程序正在消耗資源,無法單獨證明根本原因。建置日誌中的工作數量與持續時間,才是連結系統狀態與專案負載的依據。
透過對照實驗找出觸發條件
確認趨勢後,每次只變更一個變因。先將 CI 並行作業數降為 1,其他條件維持不變;接著恢復並行設定,改採錯峰啟動;最後比較冷建置與熱建置。若降低並行度後,耗時曲線恢復穩定,問題更可能來自同一節點上的工作競爭或持續功耗過高,而不是編譯器本身效能退化。
不要直接以更激進的快取清理作為修復方式。清理會增加下一輪的工作量,並掩蓋原有趨勢。也不要把重新啟動當成唯一證據:重新啟動會同時終止背景程序、清除部分狀態並提供冷卻時間,因此無法判斷究竟是哪一項變化發揮作用。
調整建置排程,而非追逐瞬時頻率
穩定的方案通常是限制同一節點上的高負載工作數量,將封存、完整測試與靜態分析錯開執行,並為每條流水線分配獨立的 DerivedData。對於必須並行執行的工作,可以先量測並行度為 1、2、3 時的中位耗時,再選擇總吞吐量最高的設定,而不是單一工作峰值效能最高的設定。
將診斷結果固化為 CI 基線
基線應保存命令、提交、Xcode 版本、建置類型、連續執行次數與中位耗時。不要以最快的一輪作為基準,也不要因單次逾時就阻止合併。更穩妥的規則是以滾動方式比較最近若干次的中位數,只有在連續多次超過閾值後才產生診斷記錄。
最終產出至少應包括建置日誌、time 輸出、熱壓力記錄、程序快照與取樣參數。若問題需要升級處理,請附上節點區域、發生時間、重現步驟與最低限度的必要日誌,但不要提交密碼、私密金鑰或完整存取憑證。如此一來,下次發生類似波動時,團隊便能直接重新執行同一套樣本,而不必重新猜測。
常見問題
單次 Xcode 建置變慢就代表發生熱節流嗎?
不代表。應固定程式碼、Xcode 版本、快取狀態與並行度,至少連續執行三次,再同步比較 CPU 功耗、熱壓力和背景程序。
執行 powermetrics 是否需要管理者權限?
通常需要。建議只授權帶有限參數的採樣命令,並將輸出寫入受控目錄;無法授權時可用 pmset、time 與 top 輔助判斷。
將建置工作交給獨享雲端 Mac
選擇 VMOrbit M4 或 VMOrbit M4 Pro,並依團隊所在位置選擇節點。實際可用性與交付資訊以控制台即時回傳結果為準。