Perfetto 是谷歌開發(fā)的用于性能檢測和跟蹤分析的生產(chǎn)級(jí)開源堆棧。它提供用于記錄系統(tǒng)級(jí)和應(yīng)用程序級(jí)跟蹤的服務(wù)和庫,包括本機(jī) + Java堆分析,使用SQL分析跟蹤數(shù)據(jù)的C++庫以及基于Web的可視化UI,能夠清晰地展示GB級(jí)別體量的跟蹤數(shù)據(jù)。Perfetto 適用于Linux內(nèi)核和Android的整個(gè)系統(tǒng)范圍內(nèi)的性能數(shù)據(jù)收集、可視化及數(shù)據(jù)分析。

開啟設(shè)備追蹤
Android 11 (R)及以上默認(rèn)開啟Perfetto,Android 9 (P)和10 (Q) 需要手動(dòng)開啟,其他設(shè)備暫不支持:
# Needed only on Android 9 (P) and 10 (Q) on non-Pixel phones.
adb shell setprop persist.traced.enable 1
啟動(dòng)抓取方式
通過腳本工具tools/record_android_trace,使用命令行工具啟動(dòng)設(shè)備抓取
adb shell perfetto [ --time TIMESPEC ] [ --buffer SIZE ] [ --size SIZE ]
[ ATRACE_CAT | FTRACE_GROUP/FTRACE_NAME]...
通過抓取頁面Perfetto UI
Perfetto UI抓取簡介
Recording settings
三種錄制設(shè)置,適用不同的使用場景
Stop when full
- in-memory buffer size
設(shè)置存儲(chǔ)trace的最大buffer大小,存儲(chǔ)在內(nèi)存中,不會(huì)影響到IO。 -
Max duration
設(shè)置此次 trace 抓取的最大時(shí)長
該模式下Perfetto的停止受buffer大小和trace時(shí)長的控制,滿足兩個(gè)任意條件之一,即可停止trace。
優(yōu)點(diǎn):trace不會(huì)因?yàn)閛verwrite而導(dǎo)致丟失。
缺點(diǎn):如果trace太多,會(huì)導(dǎo)致提前結(jié)束,無法錄制到出現(xiàn)問題時(shí)候的trace。
Ring buffer
該模式只會(huì)收到Max duration的影響,時(shí)間到了就停止抓取trace,但是trace會(huì)有被overwrite的風(fēng)險(xiǎn)。

Long trace
用于長時(shí)間地抓取trace,但是由于需要定時(shí)將buffer中的trace寫到文件里面去,會(huì)有IO的影響。
Flush on disk every
間隔多長時(shí)間將buffer中的trace寫入到文件,這個(gè)數(shù)值不能太大也不能太小,太大容易丟trace,太小容易出現(xiàn)IO問題。trace的停止主要受控于Max duration,或者手動(dòng)停止。

CPU
CPU相關(guān)的常見功能統(tǒng)計(jì)

- Coarse CPU usage counter
粗粒度的CPU相關(guān)使用統(tǒng)計(jì) -
Scheduling details
詳細(xì)查看CPU運(yùn)行的每個(gè)task
-
CPU frequency and idle states
查看每顆CPU的運(yùn)行頻率和是否空閑
- Syscalls
記錄每一個(gè)系統(tǒng)調(diào)用,對性能影響較大,需要userdebug版本。
GPU
記錄GPU的主頻和內(nèi)存使用

-
GPU frequency
記錄GPU的頻率
-
GPU memory
GPU內(nèi)存使用量及各個(gè)進(jìn)程的占用,僅支持Android 12+
Power

Memory

Android apps & svcs

- Atrace userspace annotations
開啟這個(gè)選項(xiàng)之后,選擇合適的atrace tag就可以開啟對應(yīng)的trace了,這個(gè)tag就對應(yīng)了System Tracing的界面的catergray。 -
Event log (logcat)
可以實(shí)時(shí)記錄log,然后將log和trace信息一一對應(yīng)。 選擇合適的log類型,就可以記錄相應(yīng)的log。
Chrome
如果需要分析webview相關(guān)的性能問題,可以開啟該選項(xiàng)的相關(guān)功能

Stack Samples

- Callstack sampling
定期記錄進(jìn)程的當(dāng)前函數(shù)調(diào)用堆棧
Advanced settings
目前只有一個(gè)開啟ftrace功能,用于分析內(nèi)核性能問題,可以選擇相應(yīng)的tag進(jìn)行記錄

Recording command
配置匯總和執(zhí)行,完成上述參數(shù)配置后,可以在改選項(xiàng)中獲得所有的配置參數(shù),拷貝命令,直接adb開啟錄制追蹤。

adb shell perfetto \
-c - --txt \
-o /data/misc/perfetto-traces/trace \
<<EOF
buffers: {
size_kb: 63488
fill_policy: DISCARD
}
buffers: {
size_kb: 2048
fill_policy: DISCARD
}
data_sources: {
config {
name: "android.packages_list"
target_buffer: 1
}
}
data_sources: {
config {
name: "android.log"
android_log_config {
log_ids: LID_KERNEL
log_ids: LID_DEFAULT
log_ids: LID_RADIO
log_ids: LID_SECURITY
log_ids: LID_STATS
log_ids: LID_SYSTEM
}
}
}
data_sources: {
config {
name: "linux.perf"
perf_event_config {
timebase {
frequency: 100
timestamp_clock: PERF_CLOCK_BOOTTIME
}
callstack_sampling {
}
}
}
}
data_sources: {
config {
name: "org.chromium.trace_event"
chrome_config {
trace_config: "{\"record_mode\":\"record-until-full\",\"included_categories\":[\"accessibility\",\"audio\",\"aogh\",\"android_webview.timeline\",\"android_webview\",\"disabled-by-default-audio-worklet\",\"disabled-by-default-animation-worklet\",\"disabled-by-default-blink.debug\",\"log\",\"toplevel\",\"toplevel.flow\",\"scheduler\",\"sequence_manager\",\"disabled-by-default-toplevel.flow\",\"disabled-by-default-ipc.flow\",\"mojom\",\"v8\",\"blink\",\"cc\",\"gpu\",\"viz\",\"ui\",\"views\",\"benchmark\",\"evdev\",\"input\",\"loading\",\"net\",\"netlog\",\"navigation\",\"browser\"],\"excluded_categories\":[\"*\"],\"memory_dump_config\":{}}"
privacy_filtering_enabled: true
client_priority: USER_INITIATED
}
}
}
data_sources: {
config {
name: "track_event"
chrome_config {
trace_config: "{\"record_mode\":\"record-until-full\",\"included_categories\":[\"accessibility\",\"audio\",\"aogh\",\"android_webview.timeline\",\"android_webview\",\"disabled-by-default-audio-worklet\",\"disabled-by-default-animation-worklet\",\"disabled-by-default-blink.debug\",\"log\",\"toplevel\",\"toplevel.flow\",\"scheduler\",\"sequence_manager\",\"disabled-by-default-toplevel.flow\",\"disabled-by-default-ipc.flow\",\"mojom\",\"v8\",\"blink\",\"cc\",\"gpu\",\"viz\",\"ui\",\"views\",\"benchmark\",\"evdev\",\"input\",\"loading\",\"net\",\"netlog\",\"navigation\",\"browser\"],\"excluded_categories\":[\"*\"],\"memory_dump_config\":{}}"
privacy_filtering_enabled: true
client_priority: USER_INITIATED
}
track_event_config {
disabled_categories: "*"
enabled_categories: "accessibility"
enabled_categories: "audio"
enabled_categories: "aogh"
enabled_categories: "android_webview.timeline"
enabled_categories: "android_webview"
enabled_categories: "disabled-by-default-audio-worklet"
enabled_categories: "disabled-by-default-animation-worklet"
enabled_categories: "disabled-by-default-blink.debug"
enabled_categories: "log"
enabled_categories: "toplevel"
enabled_categories: "toplevel.flow"
enabled_categories: "scheduler"
enabled_categories: "sequence_manager"
enabled_categories: "disabled-by-default-toplevel.flow"
enabled_categories: "disabled-by-default-ipc.flow"
enabled_categories: "mojom"
enabled_categories: "v8"
enabled_categories: "blink"
enabled_categories: "cc"
enabled_categories: "gpu"
enabled_categories: "viz"
enabled_categories: "ui"
enabled_categories: "views"
enabled_categories: "benchmark"
enabled_categories: "evdev"
enabled_categories: "input"
enabled_categories: "loading"
enabled_categories: "net"
enabled_categories: "netlog"
enabled_categories: "navigation"
enabled_categories: "browser"
enabled_categories: "__metadata"
timestamp_unit_multiplier: 1000
filter_debug_annotations: true
enable_thread_time_sampling: true
filter_dynamic_event_names: true
}
}
}
data_sources: {
config {
name: "org.chromium.trace_metadata"
chrome_config {
trace_config: "{\"record_mode\":\"record-until-full\",\"included_categories\":[\"accessibility\",\"audio\",\"aogh\",\"android_webview.timeline\",\"android_webview\",\"disabled-by-default-audio-worklet\",\"disabled-by-default-animation-worklet\",\"disabled-by-default-blink.debug\",\"log\",\"toplevel\",\"toplevel.flow\",\"scheduler\",\"sequence_manager\",\"disabled-by-default-toplevel.flow\",\"disabled-by-default-ipc.flow\",\"mojom\",\"v8\",\"blink\",\"cc\",\"gpu\",\"viz\",\"ui\",\"views\",\"benchmark\",\"evdev\",\"input\",\"loading\",\"net\",\"netlog\",\"navigation\",\"browser\"],\"excluded_categories\":[\"*\"],\"memory_dump_config\":{}}"
privacy_filtering_enabled: true
client_priority: USER_INITIATED
}
}
}
data_sources: {
config {
name: "android.heapprofd"
target_buffer: 0
heapprofd_config {
sampling_interval_bytes: 4096
continuous_dump_config {
dump_phase_ms: 30000
dump_interval_ms: 10000
}
shmem_size_bytes: 8388608
block_client: true
}
}
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "clk/*"
ftrace_events: "ext4/*"
ftrace_events: "f2fs/*"
ftrace_events: "fastrpc/*"
ftrace_events: "i2c/*"
ftrace_events: "irq/*"
ftrace_events: "kmem/*"
ftrace_events: "memory_bus/*"
ftrace_events: "mmc/*"
ftrace_events: "oom/*"
ftrace_events: "power/*"
ftrace_events: "regulator/*"
ftrace_events: "sched/*"
ftrace_events: "sync/*"
ftrace_events: "task/*"
ftrace_events: "ftrace/print"
atrace_categories: "am"
atrace_categories: "adb"
atrace_categories: "aidl"
atrace_categories: "dalvik"
atrace_categories: "audio"
atrace_categories: "binder_lock"
atrace_categories: "binder_driver"
atrace_categories: "bionic"
atrace_categories: "camera"
atrace_categories: "database"
atrace_categories: "gfx"
atrace_categories: "hal"
atrace_categories: "input"
atrace_categories: "network"
atrace_categories: "nnapi"
atrace_categories: "pm"
atrace_categories: "power"
atrace_categories: "rs"
atrace_categories: "res"
atrace_categories: "rro"
atrace_categories: "sm"
atrace_categories: "ss"
atrace_categories: "vibrator"
atrace_categories: "video"
atrace_categories: "view"
atrace_categories: "webview"
atrace_apps: "*"
buffer_size_kb: 512
drain_period_ms: 100
}
}
}
duration_ms: 40000
EOF
trace 文件獲取
使用 adb pull /data/misc/perfetto-traces/trace ~/trace.perfetto-trace 提取跟蹤日志文件并在 Perfetto UI 中打開它。
trace文件過大加載問題
當(dāng)trace文件大于1G時(shí),Open trace file會(huì)出現(xiàn)oops 內(nèi)存溢出無法訪問。

可以使用Trace Processor來加載trace文件
# Download prebuilts (Linux and Mac only)
curl -LO https://get.perfetto.dev/trace_processor
chmod +x ./trace_processor
# Start the interactive shell
./trace_processor trace.perfetto-trace
# Start a local trace processor instance to replace wasm module in the UI
./trace_processor trace.perfetto-trace --httpd
執(zhí)行./trace_processor trace.perfetto-trace --httpd后,Chrome瀏覽器打開 https://ui.perfetto.dev/#!/ ,會(huì)自動(dòng)檢測本地是否已經(jīng)有trace_processor生成的HTTP SERVER(9001端口),如下圖提示,請選擇“YES, use loaded trace”,將自動(dòng)解析 trace_processor已經(jīng)加載的pftrace文件。

分析方法簡介
slice 片段
對應(yīng)代碼中 Trace.beginSection/ATRACE_BEGIN 記錄的事件,選中后會(huì)顯示黑色邊框

counter
計(jì)數(shù)器,記錄離散的數(shù)值點(diǎn),對應(yīng)代碼中 Trace.beginCounter/ATRACE_INT 記錄的事件

CPU調(diào)度和頻率

線程狀態(tài)
點(diǎn)擊片段上方線程調(diào)度信息片段(Running),可以看到線程當(dāng)前運(yùn)行在哪個(gè)CPU上

點(diǎn)擊箭頭 ,可以在CPU調(diào)度中看到該運(yùn)行片段以及調(diào)度時(shí)延信息。

被P: /system/bin/traced_probes [1488]T: traced_probes [1488]線程喚醒,從就緒到運(yùn)行延遲了 774us 792ns,再次點(diǎn)擊箭頭,可以回到原片段,這個(gè)跳轉(zhuǎn)比較靈活方便。
鎖競爭(lock contention)
在lock contention 片段上,可以點(diǎn)擊上邊的monitor contention來查看當(dāng)前對象鎖競爭發(fā)生的調(diào)用棧,如下詳情中顯示當(dāng)前對象鎖被Owner (Binder:1754_16)持有,其持鎖當(dāng)前運(yùn)行在serviceDoneExecuting (AMS.java 16426行),且當(dāng)前等待該對象鎖的線程已經(jīng)有5個(gè)了;當(dāng)前線程執(zhí)行被阻塞在getUidState方法中(AMS.java 6614行)。

SQL查詢
Perfetto支持通過sql語句查詢數(shù)據(jù),提供常見的格式和關(guān)鍵字段信息:
slice表,橫向track上的一條條小片段
ts:片段起始時(shí)間戳(單位ns)
dur:片段持續(xù)時(shí)長(ns)
track_id屬于哪個(gè)track(水平timeline)
name: 片段標(biāo)注的名稱,對應(yīng)Trace中打印的方法名、標(biāo)記等信息
thread_track表,utid標(biāo)識(shí)線程tid,并不是真實(shí)的線程tid
thread表,表示各線程信息,其中utid和thread_track表的utid關(guān)聯(lián)
process表,upid和thread表的upid關(guān)聯(lián),表示線程所屬的父進(jìn)程
sched_slice,線程調(diào)度片段
thread_state,各track上邊的線程調(diào)度片段,標(biāo)識(shí)線程運(yùn)行狀態(tài)
Slices
橫向軸上的一小段時(shí)間片段,具有指定的名稱

> SELECT ts, dur, name FROM slice
ts dur name
-------------------- -------------------- ---------------------------
261187017446933 358594 eglSwapBuffersWithDamageKHR
261187017518340 357 onMessageReceived
261187020825163 9948 queueBuffer
261187021345235 642 bufferLoad
261187121345235 153 query
...
Counters
根據(jù)時(shí)間記錄的離散數(shù)值點(diǎn)

···
SELECT ts, value FROM counter
ts value
261187012149954 1454.000000
261187012399172 4232.000000
261187012447402 14304.000000
261187012535839 15490.000000
261187012590890 17490.000000
261187012590890 16590.000000
...
···
Scheduler slices
CPU運(yùn)行的詳細(xì)task

> SELECT ts, dur, cpu, utid FROM sched
ts dur cpu utid
-------------------- -------------------- -------------------- --------------------
261187012170489 267188 0 390
261187012170995 247153 1 767
261187012418183 12812 2 2790
261187012421099 220000 6 683
261187012430995 72396 7 2791
...





