编辑
2026-04-19
记录知识
0

目录

什么是metrics
为什么要metrics
使用metrics
perfetto ui
python
traceprocessorshell
自建metrics
输出结构化
准备sql
运行
维护
总结
参考

性能的重要点是保证核心程序的关键指标不会因为版本改动而出现回归,perfetto作为当前性能分析的终极神器,自然具备metrics监控的功能,本文介绍perfetto的metrics

什么是metrics

从 trace 数据中计算出来的性能指标摘要就是metrics

如果我们只是通过perfetto分析问题,那么metrics貌似没有它的作用

但是如果我们要做性能监控,快速评估程序的健康状态,那这是metrics的作用

为什么要metrics

原始 trace 包含大量原始事件(如每条 sched_switch、每个函数调用),数据量很大。

Metrics 是对这些原始数据做聚合统计,输出关键指标,这样就能够做到 持续监控、回归测试

使用metrics

使用metrics有三种场景,分别为

  • perfetto ui
  • python
  • trace_processor_shell

perfetto ui

我们直接点击metrics即可

image.png

点击run,即可看到指标信息

image.png

可惜的是,perfetto 默认没办法让我们预加载自己编写的metrics,根据官网的建议,我们可以自行搭建或者使用其他方式。

因为每家公司的关键metrics是核心机密

bash
pip install perfetto

python

默认安装perfetto即可加载metric

python
result = tp.metric(['android_cpu']) print(result)

代码为了节省篇幅,做了TOP10统计,如下

# 按 CPU 时间排序,显示 top 10 top_processes = [] for proc in process_info: proc_name = proc.get("name", "unknown") threads = proc.get("threads", []) # 计算进程总 CPU 时间 total_runtime_ns = 0 for thread in threads: thread_metrics = thread.get("metrics", {}) total_runtime_ns += thread_metrics.get("runtime_ns", 0) # 计算平均频率 freq_sum = 0 freq_count = 0 for thread in threads: thread_metrics = thread.get("metrics", {}) avg_freq = thread_metrics.get("avg_freq_khz", 0) if avg_freq > 0: freq_sum += avg_freq freq_count += 1 avg_freq = freq_sum / freq_count if freq_count > 0 else 0 top_processes.append({ "name": proc_name, "runtime_ms": total_runtime_ns / 1e6, "avg_freq_mhz": avg_freq / 1000 })

此时运行后输出如下

进程名 CPU时间(ms) 平均频率(MHz) ------------------------------------------------------------ com.google.android.GoogleCamera 13131.25 2061 /vendor/bin/hw/android.hardware.camera.provider@2.4-service 4421.94 2022 system_server 4199.63 1969 /system/bin/surfaceflinger 3441.93 1730 /system/bin/traced_probes 3036.97 1583 com.android.systemui 2621.47 2010 com.google.android.apps.nexuslauncher 1081.21 2105 com.breel.wallpapers 1062.34 1667 com.google.android.gms.persistent 1022.56 2103 system 978.19 1984 com.google.android.apps.messaging 942.45 2061 com.google.android.googlequicksearchbox:search 913.31 1989 kswapd0 888.81 2046 com.android.vending 843.65 2074 com.google.android.apps.photos 633.85 1894

trace_processor_shell

如果不是为了常态化监控,自行调试metrics最方便的办法是trace_processor_shell,我们可以直接使用--run-metrics运行metrics,下面开始演示

perfetto默认预置的metrics:

  • android_cpu:CPU 使用时间和周期统计
  • android_mem:内存使用统计
  • android_startup:应用启动时间分析
  • android_batt:电池使用情况
  • android_jank:卡顿检测

我们拿android_cpu来实验

# ./trace_processor_shell --run-metrics android_cpu ~/example.pftrace

输出很长,但是能看到每个进程的metrics, 我们需要排序,这里省略了,trace_processor_shell 默认没帮我做统计

android_cpu { process_info { name: "/system/bin/init" process { name: "/system/bin/init" pid: 1 is_kernel_task: true } metrics { mcycles: 4 runtime_ns: 2856408 min_freq_khz: 1900800 max_freq_khz: 2457600 avg_freq_khz: 2164000 } threads { name: "init" metrics { mcycles: 4 runtime_ns: 2856408 min_freq_khz: 1900800 max_freq_khz: 2457600 avg_freq_khz: 2164000 } core { id: 1 metrics { mcycles: 1 runtime_ns: 570365 min_freq_khz: 1900800 max_freq_khz: 1900800 avg_freq_khz: 1902017 } }

自建metrics

在实际开发工程中,我们经常要维护一些核心指标,这些指标可以自行开发metrics来实现,现在以android的抖动分析metrics进行实战演示

输出结构化

首先我们选用protos将需要的数据格式化出来,生成名为frame_jitter_metric.proto的proto文件

syntax = "proto2"; package perfetto.protos; import "protos/perfetto/metrics/metrics.proto"; message FrameJitterMetric { optional int64 total_vsync_requests = 1; optional double avg_interval_ms = 2; optional double min_interval_ms = 3; optional double max_interval_ms = 4; optional double avg_jitter_ms = 5; optional double variance_ms = 6; optional int64 potential_dropped_frames = 7; optional int64 severe_hitches = 8; optional double pct_under_8ms = 9; optional double pct_8_to_16ms = 10; optional double pct_16_to_24ms = 11; optional double pct_over_24ms = 12; } extend TraceMetrics { optional FrameJitterMetric frame_jitter_metric = 500; }

可以看到这里格式化了一些抖动相关的数据

准备sql

既然我们知道需要格式化哪些数据,我们针对这些metrics编写SQL即可,如下

CREATE VIEW frame_intervals AS SELECT ts, (ts - LAG(ts) OVER (ORDER BY ts)) / 1e6 AS interval_ms FROM slice WHERE name = 'requestNextVsync'; CREATE VIEW frame_stats AS SELECT COUNT(*) AS total_vsync_requests, AVG(interval_ms) AS avg_interval_ms, MIN(interval_ms) AS min_interval_ms, MAX(interval_ms) AS max_interval_ms, AVG(ABS(interval_ms - 16.67)) AS avg_jitter_ms, -- Variance calculation AVG((interval_ms - 16.67) * (interval_ms - 16.67)) - AVG(ABS(interval_ms - 16.67)) * AVG(ABS(interval_ms - 16.67)) AS variance_calc, -- Dropped frames (interval > 20ms means we missed at least one frame) SUM(CASE WHEN interval_ms > 20 THEN 1 ELSE 0 END) AS potential_dropped_frames, -- Severe hitches (interval > 32ms = 2+ frames missed) SUM(CASE WHEN interval_ms > 32 THEN 1 ELSE 0 END) AS severe_hitches FROM frame_intervals WHERE interval_ms IS NOT NULL; CREATE VIEW frame_distribution AS SELECT 100.0 * SUM(CASE WHEN interval_ms < 8 THEN 1 ELSE 0 END) / COUNT(*) AS pct_under_8ms, 100.0 * SUM(CASE WHEN interval_ms >= 8 AND interval_ms < 16 THEN 1 ELSE 0 END) / COUNT(*) AS pct_8_to_16ms, 100.0 * SUM(CASE WHEN interval_ms >= 16 AND interval_ms < 24 THEN 1 ELSE 0 END) / COUNT(*) AS pct_16_to_24ms, 100.0 * SUM(CASE WHEN interval_ms >= 24 THEN 1 ELSE 0 END) / COUNT(*) AS pct_over_24ms FROM frame_intervals WHERE interval_ms IS NOT NULL; -- The view name must match the proto extend field name: {name}_output CREATE VIEW frame_jitter_metric_output AS SELECT FrameJitterMetric( 'total_vsync_requests', total_vsync_requests, 'avg_interval_ms', avg_interval_ms, 'min_interval_ms', min_interval_ms, 'max_interval_ms', max_interval_ms, 'avg_jitter_ms', avg_jitter_ms, 'variance_ms', IFNULL(variance_calc, 0.0), 'potential_dropped_frames', potential_dropped_frames, 'severe_hitches', severe_hitches, 'pct_under_8ms', pct_under_8ms, 'pct_8_to_16ms', pct_8_to_16ms, 'pct_16_to_24ms', pct_16_to_24ms, 'pct_over_24ms', pct_over_24ms ) FROM frame_stats, frame_distribution;

可以看到,proto文件和sql文件信息对应起来

运行

接下来我们只需要run-metrics即可监控核心指标了,如下

# ./trace_processor_shell --run-metrics /tmp/frame_jitter_metric.sql ~/example_android_trace_15s [054.860] processor_shell.cc:2151 Trace loaded: 57.20 MB in 1.02s (56.0 MB/s) [perfetto.protos.frame_jitter_metric] { total_vsync_requests: 6082 avg_interval_ms: 2.419482 min_interval_ms: 0.000677 max_interval_ms: 20.754741 avg_jitter_ms: 14.261968 variance_ms: 12.778111 potential_dropped_frames: 1 severe_hitches: 0 pct_under_8ms: 89.641565 pct_8_to_16ms: 9.289707 pct_16_to_24ms: 1.068727 pct_over_24ms: 0.000000 }

可以看到,正常加载了抖动分析的metrics

维护

完成metrics的自动化性能看板后,我们只需要推送到daliybuild上进行看护即可。非常方便

总结

本文介绍了perfetto的另一个核心功能,metrics。

如果没有metrics,perfetto就是一个利用trace进行分析的调试工具。

如果我们把SQL抽象成metrics的概念,编写核心的sql和格式化的proto文件,这样就能够输出我们想要的关键信息。

利用这些关键信息就可以实现通过核心指标看护系统的性能状态

参考