Perfetto工具使用简介

简介

Perfetto工具是Android下一代全新的统一的trace收集和分析框架,可以抓取平台和app的trace信息,是用来取代systrace的,但systrace由于历史原因也还会一直存在,并且Perfetto抓取的trace文件也可以同样转换成systrace视图,如果习惯用systrace的,可以用Perfetto UI的"Open with legacy UI"转换成systrace视图来看,Perfetto的几个主要特点如下所示:

  • 可以在线抓取长时间的trace,可以长达一个小时,另外抓取的文件size也可以达到GB级别,这样就可以在后台开启,让它一直抓取trace了,特别适用于那种复现概率很低,又比较严重的性能问题。
  • 抓取到trace文件之后,它的格式是protobuf或者json,需要用到Perfetto的一个C++库,这个库可以基于protobuf或者json提供出来一个SQL语言操作的接口,这个C++库可以基于命令行,也可以集成到其他工具中,后面会有相关介绍。
  • Perfetto具有很好的可扩展性,它除了提供标准的tracepoints之外,例如CPU调度信息,内存信息等,还可以通过atrace HAL层扩展,在Android P当中,Google新增加了一个atrace HAL层,atrace进程可以调用这个HAL的接口来获取当前的扩展信息,相关代码可见Google 提交,这样如果需要扩展tracepoints的话,就可以按照graphic的示例添加即可。
  • 提供全新的Perfetto UI网站,可以在上面通过选取开关的方式,自动生成抓取trace的命令,同时可以打开trace文件,自动把protobuf或者json转变成UI,另外还集成了几种预定义的trace分析统计工具,详情可见它的 Metrics and auditors 选项。
    Perfetto本身是一个框架,关于它的架构和模块的详细介绍,有兴趣的可以参考它的doc网站,它的源码可以参考Android Source Tree的 /external/perfetto 目录,里面有很多的tools和脚本,可以拿来直接使用,本文只对这个工具做简单的使用介绍。

Trace收集流程

在讲具体的收集流程之前,可以先看一下它的整体框架图,它的进程结构,其中有几个重要的进程需要说明一下:


Perfetto整体框架图
  • traced:
    The unprivileged trace daemon that owns the log buffers and maintains a registry of Producers and Consumers connected.
  • traced_probes:
    The privileged daemon that has access to the Kernel tracefs (typically mounted under /sys/kernel/debug/tracing). It drives Ftrace and writes its protobuf-translated contents into traced.
  • perfetto:
    A command line utility client that drive the trace and save back the results (either to a file or to Android’s Dropbox)
    为了能更好的了解这几个进程的用途,这里就没有使用中文来翻译了,免得更加不好理解,perfetto是一个命令行工具,在shell环境下执行,同时在手机端也有两个进程:traced和traced_probes,这两个进程运行在手机端,如果只是使用这个工具的话,只要懂得perfetto命令行工具的用法就可以了,如果还想深入了解Perfetto的话,可以直接看它的源码,对于它的理解在它的doc网站上其实还有另一种视图:
Perfetto的另一种视图

暂时还没有去研究它的源码,所以还无法将上面的两种视图一一对应起来,这里列出另一种视图,只是想让大家增加对这个工具的更深一步了解,上面说了除了标准的tracepoints之外,Perfetto还可以提供很好的可扩展性,这里我们先看一下标准的tracepoints有哪些,如下图所示,相对于以前的systrace来说,我们发现Perfetto还是可以提供一些其他的功能的,例如它可以直接抓取event log了,还有Virtual memory events等等。


标准的tracepoints

在Pixel和Pixel2机型上面,traced和traced_probes这两个进程是默认开启的,但是在其他机型上面,可能需要执行如下命令才会开启这两个进程,开启这两个进程之后,才能正常抓取trace信息,开启的方式也很方便,只要设置一个属性就可了。

adb shell setprop persist.traced.enable 1

执行上面的命令后,如果看到如下类似的Log,那么就说明开启成功了,也可以直接ps看有没有这两个进程。

$ adb logcat -s perfetto
perfetto: service.cc:45 Started traced, listening on /dev/socket/traced_producer /dev/socket/traced_consumer
perfetto: probes.cc:25 Starting /system/bin/traced_probes service
perfetto: probes_producer.cc:32 Connected to the service

开启了守护进程之后,就可以执行perfetto命令行工具了,这个命令行的工具的使用方式,具体参数的含义就不一一介绍了,直接看comment就好。

1902:/ # perfetto
perfetto_cmd.cc:89
Usage: perfetto
  --background     -b     : Exits immediately and continues tracing in background
  --config         -c     : /path/to/trace/config/file or - for stdin
  --out            -o     : /path/to/out/trace/file
  --dropbox        -d TAG : Upload trace into DropBox using tag TAG (default: perfetto)
  --no-guardrails  -n     : Ignore guardrails triggered when using --dropbox (for testing).
  --help           -h

statsd-specific flags:
  --alert-id           : ID of the alert that triggered this trace.
  --config-id          : ID of the triggering config.
  --config-uid         : UID of app which registered the config.

其中 --out是用来指定trace输出文件,--config 是用来指定配置的,也就是像抓多长时间,间隔多久把内存数据写回文件,抓取哪些tracepoints等等,这个config文件内容,我们可以自己手动编写,也可以用Perfetto UI网站生成,另外在Perfetto里面默认集成了一个test配置,你可以使用如下命令抓取一个使用test config的trace文件。

$ adb shell perfetto --config :test --out /data/misc/perfetto-traces/trace //使用内置的test配置,然后输出到/data/misc/perfetto-traces/trace

抓取完后,把/data/misc/perfetto-traces/trace文件内容pull出来,然后使用Perfetto UI网站打开即可,如下所示:


UI模式

自定义Config

目前最方便的配置文件生成方式是使用ui.perfetto.devPerfetto UI来帮助生成,点开Perfetto UI的"Record new trace"之后,你会看到有很多的配置界面,如以下几个图所示:

RecordingMode配置界面

CPU配置页面

Android apps和Service配置页面

选择好你想要的tracepoints之后,点击Start recording,就会生成如下命令内容,将这个命令内容拷贝出来直接在终端就可以执行,完成之后就把/data/misc/perfetto-traces/trace 这个文件拷贝出来,用上面的ui.perfetto.dev分析就可以了。

adb shell perfetto \
  -c - --txt \
  -o /data/misc/perfetto-traces/trace \
<<EOF

buffers: {
    size_kb: 8960
    fill_policy: DISCARD
}
buffers: {
    size_kb: 1280
    fill_policy: DISCARD
}
data_sources: {
    config {
        name: "linux.process_stats"
        target_buffer: 1
        process_stats_config {
            scan_all_processes_on_start: true
        }
    }
}
data_sources: {
    config {
        name: "android.log"
        android_log_config {
        }
    }
}
data_sources: {
    config {
        name: "linux.ftrace"
        ftrace_config {
            ftrace_events: "sched/sched_switch"
            ftrace_events: "power/suspend_resume"
            ftrace_events: "sched/sched_wakeup"
            ftrace_events: "sched/sched_wakeup_new"
            ftrace_events: "sched/sched_process_exit"
            ftrace_events: "sched/sched_process_free"
            ftrace_events: "task/task_newtask"
            ftrace_events: "task/task_rename"
        }
    }
}
duration_ms: 10000

EOF

推荐阅读更多精彩内容