JasonWang's Blog

Android常用的性能分析工具

字数统计: 2.9k阅读时长: 13 min
2023/10/20

在Android系统开发过程中,经常碰到CPU占用率高、内存泄露、内存占用高等性能相关的问题,这时通常需要抓取系统的trace日志,用以查看进程的CPU占用,内存分配等情况。怎么抓取系统trace, 这时一般需要用到系统性能相关的分析工具。这篇文章就以Android S为例,说明Android开发中常用的一些性能优化工具的使用方法,主要包括如下几个工具:

  • atrace
  • systrace
  • dumpsys
  • simpleperf
  • perfetto
  • Android Profiler

atrace

atraceAndroid系统的自带的一个抓取systrace的工具,不仅可用于抓取系统服务的状态,如inputSurfaceFlingerWindow Manager等,也可以用于抓取内核的trace日志,如CPU调度、irq中断、内存等信息, 具体支持那些类型的trace日志,可以通过adb shell atrace --list_categories查看。

atrace实现感兴趣的同学,可以查看frameworks/native/cmds/atrace的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

usage: atrace [options] [categories...]
options include:
-a appname enable app-level tracing for a comma separated list of cmdlines; * is a wildcard matching any process
-b N use a trace buffer size of N KB
-c trace into a circular buffer
-f filename use the categories written in a file as space-separated
values in a line
-k fname,... trace the listed kernel functions
-n ignore signals
-s N sleep for N seconds before tracing [default 0]
-t N trace for N seconds [default 5]
-z compress the trace dump
--async_start start circular trace and return immediately
--async_dump dump the current contents of circular trace buffer
--async_stop stop tracing and dump the current contents of circular
trace buffer
--stream stream trace to stdout as it enters the trace buffer
Note: this can take significant CPU time, and is best
used for measuring things that are not affected by
CPU performance, like pagecache usage.
--list_categories
list the available tracing categories
-o filename write the trace to the specified file instead
of stdout.

比如,如果我们想查看SurfaceFlinger(对应的类型未gfx),可以再设备上执行如下命令抓取(默认只抓取5s的记录):

1
2
3
4
5

adb shell

atrace gfx irq sched > /data/gfx.trace

把抓取到的gfx.trace文件拉到本地,然后使用perfetto工具打开即可查看。

systrace

atrace类似,systrace也是一个用于抓取系统trace日志的工具(适用于Android4.3以后的所有版本),不过systrace通过一个python脚本将抓取到的日志转换成html的可视化格式,这样就可以通过在chrome浏览器中输入chrome://tracing/,然后将对应的html加载即可浏览。

systrace.py工具可以通过google的网站下载或者再SDK中下载;如果是SDK,可以在platform-tools/systrace中找到对应的脚本

通过python2.7 systrace.py -h查看具体的命令说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

Usage: systrace.py [options] [category1 [category2 ...]]

Example: systrace.py -b 32768 -t 15 gfx input view sched freq

Options:
-h, --help show this help message and exit
-o FILE write HTML to FILE
-t N, --time=N trace for N seconds
-b N, --buf-size=N use a trace buffer size of N KB
-k KFUNCS, --ktrace=KFUNCS
specify a comma-separated list of kernel functions to
trace
-l, --list-categories
list the available categories and exit
-a APP_NAME, --app=APP_NAME
enable application-level tracing for comma-separated
list of app cmdlines
--link-assets link to original CSS or JS resources instead of
embedding them
--from-file=FROM_FILE
read the trace from a file (compressed) rather than
running a live trace
--asset-dir=ASSET_DIR
-e DEVICE_SERIAL, --serial=DEVICE_SERIAL
adb device serial number


比如可以通过如下命令抓取图形、输入以及调度相关的systrace日志:

1
2
3
4

python2.7 systrace.py systrace.py -b 32768 -t 15 gfx input view sched freq


默认会抓取15s的日志,然后自动保存到一个trace.html的HTLM文件中;这个问题我们可以通过在Chrome浏览器中输入chrome://tracing/查看,也可以使用perfetto进行日志的浏览分析。

更多的使用规则可以参考systrace usage

dumpsys

dumpsysAndroid自带的一个工具,除了用于dump系统中注册的服务状态外,还可以用于各个进出的CPU占用、内存分配等情况,在分析一些系统的问题可能会有帮助:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

usage: dumpsys
To dump all services.
or:
dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--thread] [--help | -l | --skip SERVICES | SERVICE [ARGS]]
--help: shows this help
-l: only list services, do not dump them
-t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds
-T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds
--pid: dump PID instead of usual dump
--thread: dump thread usage instead of usual dump
--proto: filter services that support dumping data in proto format. Dumps
will be in proto format.
--priority LEVEL: filter services based on specified priority
LEVEL must be one of CRITICAL | HIGH | NORMAL
--skip SERVICES: dumps all services but SERVICES (comma-separated list)
SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it

如果我们只需要dump部分服务,可以先dumpsys -l获取到当前的服务列表, 然后保存对应的服务的dump日志:

1
2
3
4
5
6
7

dumpsys SurfaceFlinger

dumpsys cpuinfo

dumpsys meminfo

simpleperf

simpleperf是Android原生自带的一个用于采集APP或者系统日志的分析工具,其实际上包含了一系列工具库,包括可以在Android Native的直接运行的工具simpleperf;可以在PC上执行的脚本集合,包括生成火焰图的inferno.py, 用于分析APP(包括Native进程)的app_profile.py,所有的这些包括源代码都可以在AOSP的源代码仓库路径system/extras/simpleperf中找到。

先来看下如何使用simpleperf在Android本地上抓取分析的日志(如果没有simpleperf,可以到simpleperf目录下载或者自行编译一个push到系统中);输入simpleperf -h查看使用说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

Usage: simpleperf [common options] subcommand [args_for_subcommand]
common options:
-h/--help Print this help information.
--log <severity> Set the minimum severity of logging. Possible severities
include verbose, debug, warning, info, error, fatal.
Default is info.
--log-to-android-buffer Write log to android log buffer instead of stderr.
--version Print version of simpleperf.
subcommands:
api-collect Collect recording data generated by app api
api-prepare Prepare recording via app api
debug-unwind Debug/test offline unwinding.
dump dump perf record file
help print help information for simpleperf
inject parse etm instruction tracing data
kmem collect kernel memory allocation information
list list available event types
merge merge multiple perf.data into one
monitor monitor events and print their textual representations to stdout
record record sampling info in perf.data
report report sampling information in perf.data
report-sample report raw sample information in perf.data
stat gather performance counter information
trace-sched Trace system-wide process runtime events.

这里比较关键的两个命令是simpleperf record/report, record命令用于抓取进程的perf数据,而report指令则用于展示抓取到的perf.data,比如我们用如下命令抓取某个进程的分析日志:

1
2
3
4
5
6
7
8

# perf.data会保存在该目录
cd /data

simpleperf record -p 1047 --duration 10

simpleperf report

除了在Android查看perf.data之外,也可以将perf.data的数据保存到PC上,用scripts下面的report_html.py脚本以网页的形式查看结果, 只需要执行./report_html.py -i perf.data,脚本就会自动解析日志并在浏览器中展示一个HTML形式的报告。

simpleperf里边还有一个很有趣的工具inferno.sh,可以一个指令快速生成火焰图:

1
2
3

./inferno.sh --pid 2481 --title system

执行后会自动生成一个对应进程调用链的火焰图,然后在浏览器中查看各个线程执行的调用堆栈。

flamegraph

另外我们还可以通过simpleperf来获取某个进程内核的CPU占用以及指令执行的统计信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# Stat using default events (cpu-cycles,instructions,...), and monitor process 7394 for 10 seconds.
$ simpleperf stat -p 7394 --duration 10
Performance counter statistics:

# count event_name # count / runtime
16,513,564 cpu-cycles # 1.612904 GHz
4,564,133 stalled-cycles-frontend # 341.490 M/sec
6,520,383 stalled-cycles-backend # 591.666 M/sec
4,900,403 instructions # 612.859 M/sec
47,821 branch-misses # 6.085 M/sec
25.274251(ms) task-clock # 0.002520 cpus used
4 context-switches # 158.264 /sec
466 page-faults # 18.438 K/sec

Total test time: 10.027923 seconds.

更多详情可以参考simpleperf usage或者AOSP中的代码目录system/extras/simpleperf

perfetto

perfetto是Google开源的用于系统性能分析、Trace日志抓取的工具,是一个综合了Trace日志抓取、分析以及UI展示的工具链。perfetto采集的数据主要来自ftrace(收集内核信息),atrace(收集服务与应用的Trace日志)以及heapprofd(用于收集APP的内存使用情况);Android 10以后的版本都默认集成了一个perfetto的可执行程序用于Trace的抓取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

Usage: perfetto
--background -d : Exits immediately and continues tracing in
background
--config -c : /path/to/trace/config/file or - for stdin
--out -o : /path/to/out/trace/file or - for stdout
--upload : Upload field trace (Android only)
--dropbox TAG : DEPRECATED: Use --upload instead
TAG should always be set to 'perfetto'
--no-guardrails : Ignore guardrails triggered when using --upload
(for testing).
--txt : Parse config as pbtxt. Not for production use.
Not a stable API.
--reset-guardrails : Resets the state of the guardails and exits
(for testing).
--query : Queries the service state and prints it as
human-readable text.
--query-raw : Like --query, but prints raw proto-encoded bytes
of tracing_service_state.proto.
--save-for-bugreport : If a trace with bugreport_score > 0 is running, it
saves it into a file. Outputs the path when done.
--help -h


light configuration flags: (only when NOT using -c/--config)
--time -t : Trace duration N[s,m,h] (default: 10s)
--buffer -b : Ring buffer size N[mb,gb] (default: 32mb)
--size -s : Max file size N[mb,gb] (default: in-memory ring-buffer only)
--app -a : Android (atrace) app name
ATRACE_CAT : Record ATRACE_CAT (e.g. wm)
FTRACE_GROUP/FTRACE_NAME : Record ftrace event (e.g. sched/sched_switch)

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.
--subscription-id : ID of the subscription that triggered this trace.

Detach mode. DISCOURAGED, read https://perfetto.dev/docs/concepts/detached-mode :
--detach=key : Detach from the tracing session with the given key.
--attach=key [--stop] : Re-attach to the session (optionally stop tracing once reattached).
--is_detached=key : Check if the session can be re-attached (0:Yes, 2:No, 1:Error).

perfetto包含以下两种模式,可确定用于记录跟踪数据的数据源:

  • 轻量模式:只能选择一部分数据源,具体来说就是atraceftrace。但此模式可提供类似于systrace的接口。
  • 普通模式:从协议缓冲区获取其配置,并允许您更充分地利用perfetto功能,方法是使用atraceftrace之外的数据源。

使用轻量模式来抓取Trace日志,这个跟systrace的用法类似,只需要制定APP的名字即可:

1
2
3

perfetto --app <app_name> --time 15s -o /data/ss.trace

如果使用普通模式,首先需要参考标准的TraceConfig写一个配置文件;生成配置文件后,可以选择以PBTX(ProtoBuf TeXtual representation)的传递(生产环境不推荐)或者通过protoc工具转换成Binary形式的protobuf文件传给给perfetto:

1
2
3
4

#把本地的sys_stats.cfg推到/data/misc/perfetto-configs
perfetto -c /data/misc/perfetto-configs/sys_stats.cfg --txt -o /data/sys-stats.trace

在AOSP源码目录external/perfetto/test/configs下面提供了很多perfetto的配置文件可以参考。除了使用Android系统自带的perfetto工具抓取Trace之外,还可以用网页版的perfetto工具抓取: 点击Record new trace,会弹出一个页面,可以选择抓取CPUGPUMemory以及APP与服务的Trace日志:

perfetto-ui usage

Android Profiler

除了使用上述几个工具之外,Android Studio(AS)中也提供了一个可视化的图形界面工具Profiler来分析APP或者设备中进程的性能,包括CPU占用、内存分配以及网络使用等常见的性能指标。

打开AS后,点击界面的下方中的仪表指针的图标Profiler,然后点击弹出的界面左侧SESSIONS一栏中点击+按钮,选择需要分析跟踪的进程后,会弹出一个显示进程CPU、内存以及网络占用情况的界面:

android profiler ui

点击图中的CPU可以看到进程中各个线程的CPU占用情况,如果想要查看某个线程的调用堆栈,可以通过界面上的Record的功能来抓取Java或者C/C++代码Trace日志,抓取完成后会生产对应Trace的火焰图,可以用来进一步分析各个线程执行耗时; 类似的,MEMORY工具可以用来分析热点代码的内存分配情况,用来分析内存泄露、内存占用不合理的情况。

有关更多Profiler工具的使用说明,可以参考Android Profiler官网链接

参考资料

原文作者:Jason Wang

更新日期:2023-10-20, 11:57:31

版权声明:本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可

CATALOG
  1. 1. atrace
  2. 2. systrace
  3. 3. dumpsys
  4. 4. simpleperf
  5. 5. perfetto
  6. 6. Android Profiler
  7. 7. 参考资料