macOS-Trace:自主應用程式效能最佳化
macOS-Trace 是一個專為原生 macOS 應用程式(SwiftUI、AppKit、Metal、CoreAudio、WebKit 及原生二進位檔)設計的閉環式效能最佳化引擎。
其目標是消除手動操作 Instruments GUI 的需求。AI 智慧體可以自主診斷、找出瓶頸、實作程式碼修改、透過差異化基準測試進行重新測試,並持續迭代,直到效能目標能透過經驗數據得到驗證。
+-------------------------------------------------------------------------+
| 自主最佳化循環 |
| |
| 1. 目標對齊 ──> 2. 診斷追蹤 ──> 3. 精準程式碼修復 |
| ^ │ |
| │ ▼ |
| └────── 若目標未達成則迭代 <── 4. 重新測試驗證 |
+-------------------------------------------------------------------------+
階段 1:使用者目標對齊(飛行前問卷)
在修改程式碼或收集追蹤資料之前,智慧體必須與使用者就最佳化目標和成功標準達成一致。
模態工具 vs 對話互動
- 如果你的智慧體平台提供互動式問卷/模態工具(例如
ask_question、輸入對話框或可選選項列表),請呼叫它以乾淨的方式向使用者呈現這些選項。 - 如果沒有可用的模態工具,請直接在對話中向使用者提問,提供結構化的選項和具體的建議值。
需要詢問使用者的問題
- 主要最佳化目標:
- 選項 A:降低 CPU 使用率、功耗和熱節流。
- 選項 B:降低記憶體佔用、瞬態分配峰值或消除洩漏。
- 選項 C:消除 UI 畫面卡頓和掉幀(Hitches)。
- 選項 D:加速應用程式冷啟動時間。
- 具體效能目標(提供建議的預設值):
- CPU / 能源目標:
- 閒置基線目標:< 20 M/s 指令,CPU 影響 < 0.5。
- 活躍工作負載目標:< 100 M/s 指令(或指定:減少 30% - 50%)。
- 記憶體目標:
- 最大常駐記憶體:上限 < 150 MB(工具/音訊)或 < 300 MB(媒體/豐富 UI)。
- 分配事件率:穩定執行期間 < 500 事件/秒。
- 記憶體洩漏:恰好 0 個持續性洩漏。
- UI 流暢度目標:
- 卡頓比率:< 5.0 毫秒/秒(可接受),< 1.0 毫秒/秒(流暢/無掉幀)。
- 啟動時間目標:
- 到第一幀的時間:< 400 毫秒(優秀),< 800 毫秒(可接受)。
- CPU / 能源目標:
- 基準測試使用者場景:
- 詢問使用者要對哪個特定畫面、使用者互動或工作負載進行基準測試。
一旦目標確認,進入階段 2。
範圍與先決條件
- 目標平台:僅限 macOS 原生桌面應用程式(SwiftUI, AppKit, Metal, CoreAudio / AVAudioEngine, WebKit 宿主視圖, 原生 CLI 可執行檔)。不支援 iOS 模擬器、遠端行動裝置或僅限外部瀏覽器的網頁應用程式。
- Xcode 工具:需要 macOS 12+ 以及完整的 Xcode 或 Xcode 命令列工具(
xcode-select -p,xcrun xctrace version)。 - Python:Python 3.8+(macOS 預安裝;零外部 pip 依賴)。
- 程序權限:除錯版本或帶有
get-task-allow授權的二進位檔,才能在 Hardened Runtime 下使用--attach <PID>。
智慧體規則
在自動化分析期間,遵循這些不可協商的規則:
- 首先建立基線:永遠不要只記錄活躍工作負載。在記錄活躍狀態之前,一定要先捕捉一個閒置基線(應用程式在前景開啟,工作負載暫停)。計算:
差異 = 活躍 - 基線。 - 在錄製前驗證目標狀態:使用
pgrep -x <ProcessName>檢查程序是否存在,並在錄製視窗期間確認目標功能正在活躍執行。 - 保持視窗在前景:macOS 會對被遮擋或最小化的視窗(
NSWindowOcclusionState)限制渲染和顯示連結。被遮擋的視窗會產生虛假的低 GPU 和 CPU 讀數。 - 使用相同的測試參數:在相同的樣本持續時間(預設:
60s)、相同的顯示比例、相同的視窗大小和相同的測試輸入資料下比較各次執行。永遠不要比較除錯版本與發行版本。 - 無第三方 Python 依賴:所有捆綁的腳本(
scripts/compare_elements.py,scripts/parse_power.py,scripts/top_categories.py)僅使用 Python 3 標準函式庫。不要安裝 pip 套件。 - 將輸出儲存到
/tmp/macos-traces/:將所有.trace套件和.xml匯出檔案儲存在/tmp/macos-traces/中,並使用時間戳記和場景標記的檔案名稱。 - 保護對話上下文預算:追蹤檔案和原始匯出的 XML 文件可能達到數十或數百 MB。永遠不要將原始的
.trace輸出、完整的呼叫樹或未解析的 Allocations XML 傾印到智慧體對話上下文中。始終使用捆綁的 Python 腳本在讀取之前進行串流、過濾、排序和總結資料。 - 專注於主要瓶頸:不要將微最佳化分散到數十個無關緊要的工具函數中。先進行分析以確認主要的貢獻者(例如冗餘的表面實例、高頻計時器重新評估、無緩衝 I/O),並將最佳化工作專門集中在該根本原因上。
- 永遠不要悄悄更改 UI、視覺效果或核心行為:如果效能瓶頸涉及視覺保真度(例如模糊/玻璃材質、幀動畫、陰影、佈局轉換)或基本軟體行為:
- 不要單方面移除或降級視覺功能。
- 正式請求使用者許可(使用互動式提示或明確的聊天訊息)。
- 清楚說明權衡取捨:描述視覺變化前後的差異,解釋為什麼該功能會消耗資源,並呈現具體的預期效能提升(例如,「停用動態背景模糊會將活躍 GPU 影響從 1.5 降低到 0.2,並節省約 50 M/s 的 CPU 指令」)。
- 清理錄製遺留物:每次
xctrace錄製都會在每個使用者的系統暫存資料夾($TMPDIR)中寫入數 GB 的瞬態核心追蹤(instruments*.ktrace)和一個 Instruments CLI 快取(C/com.apple.dt.InstrumentsCLI)。scripts/run_trace.sh會在退出時自動刪除它們(無論成功或失敗)。當直接執行xctrace時,在結束前自行清理它們:永遠不要在留下數百 GB 的暫態錄製資料的情況下結束一個工作階段。find "${TMPDIR:-/tmp}" -maxdepth 1 -type f -name 'instruments*.ktrace' -delete 2>/dev/null || true
4 階段最佳化協定
階段 2:診斷分析與歸因
在編寫程式碼之前,測量當前狀態並隔離根本原因:
# 1. 飛行前檢查:應用程式必須正在執行且視窗可見
APP_NAME="YourApp"
pgrep -x "$APP_NAME" || { echo "[錯誤] $APP_NAME 未在執行。請先啟動它。"; exit 1; }
# SKILL_DIR = 此技能的安裝目錄(若安裝在其他位置請調整)
SKILL_DIR="$HOME/.claude/skills/macos-trace"
# 2. 錄製 60 秒閒置基線(工作負載暫停,視窗可見)
# run_trace.sh 會自行將程序名稱解析為 PID
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "01-baseline"
# 3. 在應用程式中觸發工作負載,錄製活躍狀態
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "02-pre-opt"
# 4. 計算最佳化前差異
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/macos-traces/01-baseline-power.xml:"閒置基線" \
/tmp/macos-traces/02-pre-opt-power.xml:"最佳化前-活躍"
使用專門的範本歸因瓶頸:
- 執行
--template time以隔離熱點呼叫樹函數。 - 執行
--template alloc搭配scripts/top_categories.py以識別抖動的分配。 - 在滾動期間執行
--template hitches以隔離渲染與提交延遲。
階段 3:精準程式碼修改
根據發現套用最小、精確的修復:
- 即時音訊執行緒在分配堆積記憶體?改用預先分配的無鎖環形緩衝區。
- WebKit IPC 飽和?節流狀態更新並切換到 CSS transform 動畫。
- Metal 片段著色器在 Retina 上過度繪製?加入動態解析度縮放或暫停離屏渲染循環。
- 高解析度影像解碼峰值?採用
CGImageSourceCreateThumbnailAtIndex降取樣。
重新建構應用程式。
階段 4:重新測試、定量審查與決策閘門
在相同條件下重新執行分析,並評估差異:
# 1. 錄製最佳化後活躍工作負載
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "03-post-opt"
# 2. 比較最佳化前 vs 最佳化後與基線的差異
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/macos-traces/01-baseline-power.xml:"閒置基線" \
/tmp/macos-traces/02-pre-opt-power.xml:"最佳化前-活躍" \
/tmp/macos-traces/03-post-opt-power.xml:"最佳化後-活躍"
範例決策輸出:
場景 時間 CPU 平均 CPU 最大 顯示 GPU 平均 總指令數 指令 M/s
=============================================================================================
閒置基線 60 0.15 0.80 0.05 0.00 1.02G 17.0
最佳化前-活躍 60 2.40 4.80 1.10 1.50 16.20G 270.0
最佳化後-活躍 60 0.65 1.20 0.25 0.10 4.80G 80.0
---------------------------------------------------------------------------------------------
與基線 [閒置基線] 的差異:
最佳化前-活躍 +253.0 M/s 指令, CPU 平均差異 +2.25
最佳化後-活躍 +63.0 M/s 指令, CPU 平均差異 +0.50
決策閘門:
- 如果目標達成(例如,指令率從 270 M/s 降至 80 M/s,滿足 < 100 M/s 的目標):向使用者呈現前後對比的經驗報告並結束。
- 如果目標未達成:隔離剩餘的瓶頸並開始下一個迭代循環。
報告後清理:在使用者接受最終最佳化報告後,刪除 /tmp/macos-traces/ 下累積的 .trace 套件(每個可能達數十 GB),除非使用者明確要求保留。報告中顯示的最終比較表和 .xml 匯出檔案已足夠作為證據。
直接 CLI 參考
# 附加到執行中的程序
xcrun xctrace record \
--template 'Power Profiler' \
--time-limit 60s \
--output /tmp/macos-traces/power.trace \
--attach $PID
# 匯出電源影響表(指令、CPU、GPU、顯示)
xcrun xctrace export \
--input /tmp/macos-traces/power.trace \
--xpath "/trace-toc/run[@number='1']/data/table[@schema='ProcessSubsystemPowerImpact']" \
> /tmp/macos-traces/power.xml
# 匯出配置摘要表
xcrun xctrace export \
--input /tmp/macos-traces/alloc.trace \
--xpath "/trace-toc/run[@number='1']/data/table[@schema='all-allocations-summary']" \
> /tmp/macos-traces/alloc.xml
範本參考
scripts/run_trace.sh 和無頭 xctrace 支援的 Instruments 範本:
計算與能源
| 範本 | 短名稱 | 目標指標與匯出模式 | 使用案例 |
|---|---|---|---|
Power Profiler | power | 指令/秒(M/s)、CPU/GPU/Display 能源影響(ProcessSubsystemPowerImpact)。 | 客觀的 A/B 基準測試和能源效率測試。 |
Time Profiler | time | 按執行緒的 CPU 樣本權重、呼叫樹熱點、主執行緒阻塞方法。 | 高 CPU 使用率、失控執行緒和熱點函數路徑。 |
CPU Counters | counters | IPC(每週期指令數)、L1/L2 快取未命中、分支預測錯誤。 | 低階計算和 DSP 演算法效能瓶頸。 |
UI 響應性與流暢度
| 範本 | 短名稱 | 目標指標與匯出模式 | 使用案例 |
|---|---|---|---|
Animation Hitches | hitches | 卡頓持續時間(毫秒)、卡頓比率(毫秒/秒)、掉幀、應用程式 vs 渲染階段延遲。 | 滾動卡頓、動畫掉幀和 CoreAnimation 提交延遲。 |
SwiftUI | swiftui | View body 評估次數、State 失效計數、視圖更新頻率。 | 不必要的視圖重新評估和狀態失效級聯。 |
Metal System Trace | metal | GPU 編碼器時間、頂點/片段著色器持續時間、幀邊界延遲。 | 著色器執行瓶頸、粒子特效開銷和渲染管線停頓。 |
記憶體與配置
| 範本 | 短名稱 | 目標指標與匯出模式 | 使用案例 |
|---|---|---|---|
Allocations | alloc | 堆積配置、瞬態 vs 持續性記憶體、類別事件率(all-allocations-summary)。 | 高頻臨時配置、記憶體峰值和緩衝區抖動。 |
Leaks | leaks | 超出父生命週期的保留記憶體洩漏、參考循環。 | 遺棄的記憶體、閉包捕獲洩漏和未釋放的委派循環。 |
啟動與並發
| 範本 | 短名稱 | 目標指標與匯出模式 | 使用案例 |
|---|---|---|---|
App Launch | launch | 到第一幀的時間、dyld 載入時間、靜態初始化和執行循環設定。 | 冷啟動最佳化(--launch -- <binary_path>)。 |
Swift Concurrency | concurrency | Swift Tasks(已建立/執行中/已暫停)、Actor 可重入性、協作式池使用情況。 | async/await 資源飢餓、Actor 競爭和長時間暫停的任務。 |
System Trace | sys | 執行緒狀態轉換(執行中... |
(原文截斷)