使用 ffx profiler 剖析 CPU 使用率

ffx profiler 是一種工具,可讓您找出程式碼中的熱點並以視覺化方式呈現。CPU 分析器會定期對執行中的執行緒取樣,並記錄回溯追蹤記錄,可透過 pprof 工具查看。

使用 ffx profiler 的時機

CPU 剖析器最適合用於找出一段時間內 CPU 時間的耗用情形。透過頻繁擷取堆疊樣本,分析器會建構執行作業的統計圖片,協助您找出效能瓶頸 (「熱點」),不必修改或檢測程式碼。

  • 如要瞭解系統或特定元件中,哪些函式消耗最多 CPU 時間,請使用 ffx profiler
  • 如要瞭解事件的循序流程、特定作業之間的延遲時間,或不同程序 (例如 IPC) 之間的互動隨時間變化,請使用 ffx trace。如要有效追蹤,開發人員必須在原始碼中加入追蹤事件
  • 如要檢查確切的執行狀態、逐步執行程式碼,或分析特定時間點的記憶體,以瞭解正確性問題,請使用 zxdb (偵錯工具)

事前準備和設定

如要取得最準確的設定檔,同時將觀察員的負擔降到最低,請務必使用發布版本,並啟用核心輔助執行緒取樣器

--release建構作業的重要性

請務必針對 --release 建構作業進行剖析。偵錯版本缺少內嵌和最佳化傳遞。以 Rust 和 C++ 等語言為例,除非套用最佳化,否則標準程式庫中的「零成本抽象化」並非零成本。剖析偵錯版本時,產生的設定檔會以內部標準程式庫呼叫 (例如迭代器和 Option 處理) 為主,而非實際的應用程式邏輯。

雖然發布版本可能會因為內嵌而稍微難以追蹤堆疊,但可準確呈現實際效能。

啟用核心輔助取樣

核心輔助取樣可大幅減少擷取堆疊樣本的負擔。在 fx set 指令中新增下列引數:

fx set <PRODUCT>.<BOARD> \
    --release \
    --args='experimental_thread_sampler_enabled=true'

常見用途和範例

全系統剖析

如要剖析裝置上執行的所有項目,包括根工作和所有後代,請使用 --system-wide 標記:

ffx profiler attach --system-wide --duration 10

這項程序會執行 10 秒,並產生 profile.pb 檔案。

執行及分析測試

您可以指示剖析器啟動測試元件,並剖析其執行作業,直到完成為止。請注意,目標套件必須位於建構圖中 (如果是新的或選用測試,您可能需要使用 fx withfx add-test 明確新增套件,然後重新建構)。使用 --test 旗標:

ffx profiler launch \
    --url "fuchsia-pkg://fuchsia.com/gtest_target#meta/gtest_target.cm" \
    --test

如要剖析該套件中的特定測試案例,請使用 --test-filters

ffx profiler launch \
    --url "fuchsia-pkg://fuchsia.com/gtest_target#meta/gtest_target.cm" \
    --test \
    --test-filters "GtestTest.MakeWorkTest"

背景剖析 (與主機中斷連線)

有時您需要剖析事件,但與主機的連線可能會中斷,例如在「暫停/繼續」週期內。為此,請在背景執行剖析器工作階段。

  1. 在背景中啟動設定檔:

    ffx profiler attach --system-wide --background

    CLI 會輸出確認訊息,例如:

    Background session started. task_id: 1
    

    裝置現在會在背景持續錄製設定檔樣本。

  2. 中斷主機連線、觸發暫停,或執行要測量的動作。等待裝置喚醒並重新連線至主機。

  3. 停止工作階段並下載設定檔。這項指令會找出正在執行的背景工作階段、停止工作階段,並將資料下載至主機:

    ffx profiler stop
    Wrote profile to profile.pb
    

附加至現有程序

您可以附加至特定元件或程序。

依元件網址或別名:

首先,找出目標元件的路徑名稱。您可以使用 ffx component list 列出目前在系統上執行的所有元件:

ffx component list
.
bootstrap
bootstrap/archivist
bootstrap/archivist/archivist-pipelines
...
core/your_component

然後使用產生的路徑名稱附加:

ffx profiler attach --moniker core/your_component

或者,您可以使用元件的套件網址附加:

ffx profiler attach --url 'fuchsia-pkg://fuchsia.com/your_component#meta/your_component.cm'

依據 KOID (PID/TID/工作 ID): 首先,請在裝置上使用 ps 指令,找出目標的程序 ID (PID):

ffx target ssh ps
TASK                       PSS PRIVATE  SHARED   STATE NAME
j: 1045                 620.7M  464.7M                 root
  p: 1122                17.7M   17.7M   4944K         bin/component_manager
...
    j: 1944             126.0K     24K
      p: 1993           126.0K     24K   5076K         kernel-args-forwarder.cm

然後附加至產生的 PID (在本例中,kernel-args- forwarder.cm 的 PID 為 1993):

ffx profiler attach --pids 1993 --duration 5

(指定 PID 會自動剖析該程序中的所有執行緒)。

指令列參數和最佳做法

下列選項適用於 ffx profiler attachffx profiler launchffx profiler stop

  • --output:輸出追蹤記錄檔案的名稱或路徑。預設為 profile.pb
  • --print-stats:將剖析工作階段的統計資料列印到 stdout。
  • --color-output:如果為 true,輸出內容會包含顏色代碼。如果偵測到終端機輸出內容,則預設為 true。

下列選項適用於 ffx profiler attachffx profiler launch

  • 取樣週期 (--sample-period-us):預設取樣週期為 10000 微秒 (10 毫秒)。降低這個值 (例如降至 1 毫秒) 可提供更高的解析度,但會增加剖析器本身的 CPU 負擔,可能改變您嘗試測量的系統行為 (即「觀察者效應」)。
  • 緩衝區大小 (--buffer-size-mb):如果您要長時間分析活動量高的系統,分析器完成擷取作業前,預設緩衝區大小可能會用盡。如果遇到缺少樣本或警告的情況,請增加記憶體配置。
  • 時間長度 (--duration):如果未指定 --duration,剖析器會以互動方式執行,並等待您按下 <ENTER> 停止擷取。
  • 背景 (--background):在背景執行分析器工作階段。

你也可以選擇其他解決方式。這些選項主要用於排解分析器問題,以及精細控管分析器執行作業。詳情請參閱 ffx 分析器參考資料

分析設定檔

分析器停止後,系統會在目前的目錄中產生 profile.pb 檔案。您可以使用 Perfetto UI 或 Google 的 pprof 工具分析這個檔案。

你可以將 profile.pb 直接上傳至 Perfetto UI,在瀏覽器中以視覺化方式呈現設定檔。這通常是探索設定檔最直覺且功能豐富的方式。

使用 pprof 的互動式網頁 UI

您也可以使用 pprof 的互動式網頁介面,其中包含圖形火焰圖。

pprof -http=localhost:8080 profile.pb

瀏覽器會開啟 http://localhost:8080。你可以從頂端選單選取下列檢視畫面:

  • Top:顯示耗用最多 CPU 時間的函式。
  • 火焰圖:以視覺化方式呈現呼叫堆疊階層。方塊的寬度代表函式或其子項的取樣總時間。

終端機頂層函式

如要直接在終端機中快速列印頂層函式,請執行下列操作:

pprof -top profile.pb

這項指令會產生文字輸出,顯示平坦和累計百分比:

Showing nodes accounting for 272, 100% of 272 total
      flat  flat%   sum%        cum   cum%
       243 89.34% 89.34%        243 89.34%   count(int)
        17  6.25% 95.59%        157 57.72%   main()
         4  1.47% 97.06%          4  1.47%   collatz(uint64_t*)
         3  1.10% 98.16%          3  1.10%   add(uint64_t*)
         3  1.10% 99.26%          3  1.10%   sub(uint64_t*)
         1  0.37% 99.63%          1  0.37%   rand()
  • 平坦:此函式在堆疊頂端主動執行的樣本數。
  • 累計:執行此函式執行任何後代函式的樣本數。