赞
踩
在Android开发中,开发者可通过"系统跟踪"观察Android设备的运行情况并生成跟踪报告,在此基础上进行分析优化。Android 平台提供了多种获取跟踪信息的工具:
其中,Android Studio CPU Profiler性能剖析器可实时检查应用的 CPU 使用率和线程活动,此外还可以查看方法跟踪记录、函数跟踪记录和系统跟踪记录中的详细信息。与CPU Profiler功能类似的TraceView、DDMS已弃用。
Systrace 是Android SDK Tools提供的旧版命令行工具,可记录短时间内的设备活动,并保存在压缩的文本文件中。该工具会生成一份html报告,其中汇总了 Android 内核中的数据,例如 CPU 调度程序、磁盘活动和应用线程。
Perfetto 是 Android 10 中引入的全新平台级跟踪工具,与Systrace类似,同样会生成汇总了Android 内核数据(例如CPU 调度程序、磁盘活动和应用线程)的跟踪文件。与 Systrace 不同的是,跟踪文件会以 Perfetto 格式保存,它提供数据源超集,可让您以 protobuf 编码的二进制流形式记录任意长度的跟踪记录。
"系统跟踪"应用是一款用于将设备活动保存到跟踪文件的 Android 工具。在搭载 Android 10(API 级别 29)或更高版本的设备上,跟踪文件会以 Perfetto 格式保存。在搭载较低版本 Android 系统的设备上,跟踪文件会以 Systrace 格式保存。
下面通过一个例子介绍如何用上面几种工具进行分析,例如在OpenCVActivity中点击"BC OPENCV BEFORE"按钮时,执行《Android OpenCV基础(三、图片处理)》中比较耗时的高斯滤波,代码如下:
public class OpenCVActivity extends Activity implements View.OnClickListener { private ImageView imageView1; private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.open_cv_activity_layout); imageView1 = findViewById(R.id.opencv_sample_image_view); button = findViewById(R.id.opencv_sample_button); button.setOnClickListener(this); } @Override public void onClick(View v) { if (v.getId() == R.id.opencv_sample_button) { Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.adventure_time); // 高斯滤波 Bitmap bitmap1 = OpenCVSample.blurBitmap(bitmap, 30); imageView1.setImageBitmap(bitmap1); Toast.makeText(this, "ok", Toast.LENGTH_SHORT).show(); button.setText("BC OpenCV After"); } } }
点击按钮后的执行效果如下图所示,后面几个小节介绍如何通过性能分析工具分析点击按钮后的方法执行情况。
Android Studio性能剖析器是Android Studio提供的一个可视化分析工具,可实时显示应用的 CPU、内存、网络和电池资源使用情况。Android Studio 3.0 及更高版本中的 Android Profiler 取代了 Android Monitor 工具。如下图所示,性能剖析器展示了四类信息:CPU、MEMORY、NETEORK、ENERGY,点击后可分别进入CPU性能分析,内存性能分析、网络性能分析、电池性能分析:
其中在点击CPU时间轴后,进入的CPU Profiler常用来分析方法执行耗时情况。
CPU 性能分析器可以在APP运行时,实时检查应用的 CPU 使用率和线程活动,也可以检查记录的方法轨迹、函数轨迹和系统轨迹的详情。
CPU Profiler使用方式为:
在例子1.2中,我们点击页面中的"BC OPENCV BEFORE"按钮,在执行结束后停止记录,方法采样记录如下所示:
在Android studio Profiler中,按"w"键可放大查看(按"s"可缩小、"a"左移、"d"右移、"0"复位),放大后如下图所示:
可以看到,点击方法"performClick()"内先执行了"blurBitmap()"方法,然后执行了"imageView1.setImageBitmap()"方法,后面在主线程中继续执行了"doTraversal()"来更新view,方法执行顺序符合预期,同时可以看到"blurBitmap()"执行耗时较长,是需要进行优化的。接着,点击"blurBitmap"可以看到该方法的耗时总结,如下图所示:
另外,CPU Profiler可以查看线程的运行情况,在这个例子中onClick()方法总耗时1350ms,其中Running状态占744ms(对应blurBitmap耗时),Idle状态占602ms(对应sleep耗时)。
下面介绍,如何查看CPU Profiler收集到的方法跟踪结果。结合例子2.1.2中收集到的方法跟踪结果可见,对系统 API 的调用显示为橙色,对应用自有方法的调用显示为绿色,对第三方 API(包括 Java 语言 API)的调用显示为蓝色。此外,CPU 性能分析器中的轨迹视图提供了多种方法查看所记录的轨迹的信息(例如Top Down、Flame Chart、Bottom Up、Event视图),开发者可自行切换视图查看,这里不再详细介绍。
通常情况下,方法跟踪信息可以帮助您找出应用中用时最多的方法,帮助您定位并针对性分析优化。但是,方法跟踪不适合用于识别卡顿,因为它们会因开销过大而导致出现假正例卡顿,且无法查看线程何时运行以及何时处于阻塞状态。
2.1.1小节在步骤4中提到,Android Studio CPU Profiler提供了四种可选的记录配置,如下图所示,开发者可根据需要选择合适的配置。
下面结合1.2中的例子,介绍四种配置的记录结果。
在CPU Profiler中选择"Sample JAVA Methods"后并点击"Record"按钮,CPU Profiler开始记录方法执行顺序,然后我们点击"1.2例子中APP上的blur按钮"完成需要分析的操作,接着点击CPU Profiler中的"Stop"按钮停止采集,最终得到如下记录结果:
局部放大后如下图所示,可以看到部分耗时很短的方法未被采样,这是因为这种记录方式是间隔采样,再次采样时一些耗时很短的方法已经执行结束所以就没被记录下来。
同样地,在CPU Profiler中选择"Trace JAVA Methods",最终得到如下记录结果:
局部放大后,如下图所示,可以看到部分耗时很短的方法也被跟踪;
同样地,在CPU Profiler中选择"Sample C/C++ Functions",最终得到如下记录结果,可以看到成功采集到了例子中"com_bc_sample_OpenCVSample_blurBitmap"的native方法调用:
同样地,在CPU Profiler中选择"Trace System Calls",最终得到如下记录结果,可以看到SurfaceFlinger、VSYNC、RenderThread、app进程(com.bc.sample)的系统调用等信息:
(1)Sample JAVA Methods不能采集耗时很短的方法,而Trace JAVA Methods可以采集耗时很短的方法;
(2)Sample JAVA Methods和Trace JAVA Method会带来性能损耗,在DEMO中,Sample JAVA Methods和Trace JAVA Method记录到的方法执行耗时差别不大,但在大型APP中,Sample JAVA Methods收集到的方法执行耗时偏长,Trace JAVA Methods收集到的方法执行耗时比实际执行耗时更长,而且执行Trace JAVA Methods时APP卡顿比较明显;
(3)Sample C/C++ Functions只能采集native层方法;
(4)Trace System Calls可以采集SurfaceFlinger、VSYNC、RenderThread、app进程的系统调用等信息。
CPU 性能分析器可以把跟踪记录保存为.trace 文件。此外,开发者也可以自己保存trace文件,用CPU 性能分析器打开trace文件来查看函数调用。除了CPU 性能分析器外,以下几种方法也可以生成trace文件。
Android系统还提供了Debug类来跟踪方法执行顺序,并输出一个trace文件,开发者可使用Android Studio Profiler来查看trace文件。通过这种方式,开发者可以更精确地控制设备何时开始和停止记录跟踪信息。
在执行Debug API开始跟踪后,方法执行速度会比实际执行速度慢很多,且默认情况下Debug的缓存空间限制是8MB(支持开发者配置更大的参数),因此DebugAPI专为时间间隔较短或难以手动启动/停止记录的场景而设计。
Debug类通过startMethodTracing()和stopMethodTracing()结合使用,方法如下:
public void onClick(View v) {
if (v.getId() == R.id.opencv_sample_button) {
// 开始方法跟踪,默认参数为空,也可以传入指定路径
// 默认输出路径是'/sdcard/Android/data/[application_pacake_name]/files/dmtrace.trace'
Debug.startMethodTracing();
Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.adventure_time);
Bitmap bitmap1 = OpenCVSample.blurBitmap(bitmap, 30);
imageView1.setImageBitmap(bitmap1);
Thread.sleep(500);
button.setText("BC OpenCV After");
// 结束方法跟踪
Debug.stopMethodTracing();
}
}
对于APP冷启动场景,还可以使用 adb am 命令记录方法跟踪,如下所示:
# 1.打开com.bc.example.MainActivity 并开始方法跟踪
# --sampling 100表示方法采样间隔
adb shell am start -n com.bc.example/com.bc.example.MainActivity --start-profiler /data/local/tmp/bc—sample.trace --sampling 100
# 2.Activity启动后,输入以下命令停止跟踪
adb shell am profile stop <process>
# 3.把手机上的trace文件pull出来
adb pull /data/local/tmp/bc—sample.trace ./
simpleperf也提供了冷启动方法跟踪的方法如下所示,暂不详细介绍。
# Start simpleperf recording, then start the Activity to profile.
$ ./app_profiler.py -p simpleperf.example.cpp -a .MainActivity
# We can also start the Activity on the device manually.
# 1. Make sure the application isn't running or one of the recent apps.
# 2. Start simpleperf recording.
$ ./app_profiler.py -p simpleperf.example.cpp
# 3. Start the app manually on the device.
Systrace是一个Python脚本,是Android SDK tools提供的旧版本分析工具(在Android platform tools 33.0.1版本中已经移除systrace,建议用Studio 性能分析器、gpuinspector.dev 或 Perfetto 取代)。它记录了一段时间内的设备活动(包括CPU调度、磁盘操作、应用线程等信息),并产生一个HTML格式的Systrace报告,可以帮助开发者分析系统瓶颈,改进性能。
systrace.py实际上是多种其他工具的封装容器:它是 atrace 的主机端封装容器。atrace 是用于控制用户空间跟踪和设置 ftrace 的设备端可执行文件,也是 Linux 内核中的主要跟踪机制。systrace 在主机端通过adb使用 atrace 来启用跟踪,然后读取 ftrace 缓冲区并生成易于查看的HTML。
Systrace 工具位于/Users/bc/Library/Android/sdk/platform-tools/systrace/systrace.py,使用方法如下:
# 使用方式为:python systrace.py [options] [categories] # 其中,[options] 表示参数,可选的参数有: # -a 进程名 # -b 跟踪缓冲区大小,单位KB # -o 输出文件名字 # -t 跟踪设备活动 N,可不指定,用Enter键结束跟踪 # [categories]表示需要trace的类别,可选的跟踪信息有: # sched - CPU Scheduling;CPU 调度信息,例如线程调度、锁信息等; # load - CPU Load # view - View System;view绘制系统的相关信息,比如onMeasure,onLayout等,常用来分析卡顿 # app - Application;应用的跟踪信息,如果设备不支持则不能收集APP的trace # gfx - Graphics;Graphic相关信息,包括SerfaceFlinger、VSYNC、Texture等,常用来分析卡顿 # input - Input # webview - WebView # wm - Window Manager # am - Activity Manager # sm - Sync Manager # audio - Audio # video - Video # camera - Camera # hal - Hardware Modules # app - Application # res - Resource Loading # dalvik - Dalvik VM # rs - RenderScript # bionic - Bionic C Library # power - Power Management # freq - CPU Frequency # idle - CPU Idle # 例如以下命令会生成名为my_systrace_report.html的跟踪文件 python /Users/bc/Library/Android/sdk/platform-tools/systrace/systrace.py -a com.bc.sample -b 16384 -o my_systrace_report.html app load view
如下所示,在命令行运行Systrace后,可以按Enter键结束跟踪,结束后会将系统跟踪输出到html文件中。
➜ ~ python /Users/bc/Library/Android/sdk/platform-tools/systrace/systrace.py -a
com.bc.example -b 16384 -o my_systrace_report.html app load view
These categories are unavailable: load
Starting tracing (stop with enter)
Tracing completed. Collecting output...
Outputting Systrace results...
Tracing complete, writing results
Wrote trace HTML file: file:///Users/bc/my_systrace_report.html
打开结果html,可通过键盘WSAD放大缩小,左右移动来检查html,如下图所示:
从上图可以看到,UI线程中只显示了系统方法调用情况,没有app中的方法调用,这是因为systrace默认只跟踪系统级别进程的信息,如果想跟踪自己APP相对系统事件的代码执行状态,需要在代码中增加自己的trace,即自定义事件(详见第5章节)。
在3.2.3中生成html后,可通过键盘WSAD放大缩小,左右移动来检查html。点击UI thread、Render Thread等,可以看到线程的当前状态,如下所示:
线程运行状态与颜色对应如下:
如下图所示,APP进程中’F’表示一帧,红色的’F’表示可能发生卡顿。因为在设备的渲染流程上,普遍采用了Double Buffer或Triple Buffer,所以App进程中的红色Frame并不一定代表有卡顿发生,需要结合SurfaceFlinger进程、BufferQueue的大小等一起分析,才能判断是否真正发生了卡顿。因篇幅较大,暂不深入介绍。
Perfetto 是 Android 10 中引入的全新平台级跟踪工具,可用来从设备上收集多种性能跟踪数据(内核信息、用户空间信息、服务&内存使用信息)。Perfetto底层实现上:
ftrace
收集内核信息atrace
收集服务和应用中的用户空间信息heapprofd
收集服务和应用的本地内存使用情况信息Perfetto在Android 11上默认开启,如果要在Android 9 和Android 10上使用,请先输入如下命令,确保trace服务开启:
# Needed only on Android 9 (P) and 10 (Q) on non-Pixel phones.
adb shell setprop persist.traced.enable 1
下面继续介绍,官方提供了两种方式:命令行方式和UI方式来使用Perfetto。
通过命令行方式,也有两种方法:
/system/bin/perfetto
命令;Perfetto官方建议使用record_android_trace脚本,这个脚本和直接运行’adb shell perfetto’命令功能一样,但是省去了设置输出文件路径等参数,并且在抓取结束后会自动用Chrome浏览器打开结果。
# 1.下载record_android_trace脚本
curl -O https://raw.githubusercontent.com/google/perfetto/master/tools/record_android_trace
# 2.设置脚本执行权限
chmod u+x record_android_trace
# 3.运行record_android_trace脚本
# See ./record_android_trace --help for more
./record_android_trace -o trace_file.perfetto-trace -t 10s -b 32mb \ sched freq idle am wm gfx view binder_driver hal dalvik camera input res memory app
运行record_android_trace脚本后,perfecto会开始记录手机的运行信息,运行结束后,可以看到脚本会自动把结果保存到本地文件"trace_file.perfetto-trace"中,并自动用浏览器打开。结果如下图所示,与Systrace类似,可以看到设备的运行情况、APP进程的运行情况、APP内线程的状态等(如果想跟踪自己APP的方法执行顺序,详见第5章自定义事件):
# Perfetto命令使用方式如下: ➜ ~ adb shell perfetto [ --time TIMESPEC ] [ --buffer SIZE ] [ --size SIZE ] [ ATRACE_CAT | FTRACE_GROUP/FTRACE_NAME | FTRACE_GROUP/* ] # Perfetto的更多参数可以参考:https://developer.android.com/studio/command-line/perfetto?hl=zh-cn # perfetto可选参数 ➜ ~ adb shell perfetto --help perfetto_cmd.cc:205 --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 --dropbox TAG : Upload trace into DropBox using tag TAG --no-guardrails : Ignore guardrails triggered when using --dropbox (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. --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) ATRACE_CAT : Record ATRACE_CAT (e.g. wm) FTRACE_GROUP/FTRACE_NAME : Record ftrace event (e.g. sched/sched_switch) FTRACE_GROUP/* : Record all events in group (e.g. sched/*) 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://docs.perfetto.dev/#/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).
例如在命令行输入如下信息:
# 1.命令行输入如下信息:
# 其中:dalvik app sched idle frep load view 表示perfetto使用atrace抓取的信息类型
# --time 5s表示:抓取时长5s
# --out 表示:perfetto运行的结果输出到该文件
> adb shell perfetto -o /data/misc/perfetto-traces/trace_file.perfetto-trace -t 20s \
sched freq idle am wm gfx view binder_driver hal dalvik camera input res memory app
# 开始运行后,可以看到命令行提示如下信息:
[032.653] perfetto_cmd.cc:792 Connected to the Perfetto traced service, TTL: 5s
[037.695] perfetto_cmd.cc:916 Wrote 4370324 bytes into /data/misc/perfetto-traces/trace
# 2.运行结束后,可以输入如下命令,把perfecto结果从手机上拉到电脑上
> adb pull /data/misc/perfetto-traces/bc_perfetto_trace ./bc_perfetto_trace
在把perfetto的trace结果保存到本地后,用chrome浏览器打开"https://ui.perfetto.dev "可视化界面操作,然后打开trace文件如下图所示:
Chrome浏览器打开"https://ui.perfetto.dev/#!/record "可视化界面操作,如右下所示可以看到底层也是通过"adb shell perfetto"实现抓取。
在 Android 4.3(API 级别 18)及更高版本中,您可以在代码中使用 Trace
类来定义随后会出现在 Perfetto 和 Systrace 报告中的自定义事件。在自定义事件的起点和终点分别调用Trace.beginSection()
和Trace.endSection()
,如以下代码段所示:
// 自定义事件的起点
Trace.beginSection("BC blurBitmap");
// ...省略部分代码,起点和终点间的代码会作为一个"BC blurBitmap"事件被统计
// 自定义事件的终点
Trace.endSection();
// 注意必须在同一个线程上调用这两个方法,不能在一个线程上调用 beginSection(),而在另一个线程上结束它
对于native代码,Android 6.0(API 级别 23)及更高版本提供了native跟踪 API trace.h
头文件,在自定义事件的起点和终点分别调用ATrace_beginSection()
和ATrace_endSection()
,如下所示:
#include <android/trace.h>
char *customEventName = new char[32];
sprintf(customEventName, "User tapped %s button", buttonName);
// 自定义事件起点
ATrace_beginSection(customEventName);
// 省略native代码...
// 自定义事件终点
ATrace_endSection();
在1.2中的例子,自定义java事件(“BC blurBitmap”)如下所示:
public class OpenCVActivity2 extends Activity implements View.OnClickListener { private Bitmap blurBitmap(Bitmap bitmap) { // 自定义事件"BC blurBitmap"的起点 Trace.beginSection("BC blurBitmap"); Bitmap result = OpenCVSample.blurBitmap(bitmap, 30); // 自定义事件"BC blurBitmap"的终点 Trace.endSection(); return result; } @Override public void onClick(View v) { if (v.getId() == R.id.opencv_sample_button) { Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.adventure_time); Bitmap bitmap1 = blurBitmap(bitmap); imageView1.setImageBitmap(bitmap1); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }
在自定义事件后,在使用Systrace和Perfetto时就可以看到app内的自定义事件执行情况。
运行Systrace时,注意需要加上"-a com.bc.example"才会生效:
➜ ~ python /Users/bc/Library/Android/sdk/platform-tools/systrace/systrace.py -a
com.bc.example -b 16384 -o my_systrace_report.html app load view
运行结果如下,可以看到方法跟踪的结果显示了自定义事件"BC blurBitmap"的运行情况:
(1)首先,本地新建一个文件’bc_example.cfg’用来存放Perfetto配置,如下所示:
buffers: { size_kb: 522240 fill_policy: DISCARD } data_sources: { config { name: "linux.ftrace" ftrace_config { ftrace_events: "sched/sched_switch" atrace_categories: "dalvik" atrace_categories: "view" atrace_apps: "com.bc.example" } } } duration_ms: 10000
(2)然后,运行4.1.1小节的record_android_trace脚本,并使用’-c’指定配置文件:
./record_android_trace -c bc_example.cfg -o trace_file.perfetto-trace
运行后的结果如下图所示,同样可以看到自定义事件"BC blurBitmap"的运行情况:
(1)部分手机Systrace抓到的trace看不到APP内的方法跟踪,这是因为部分手机不支持抓取app类型的trace信息,可以换个手机试下。另外,可以通过如下命令查看机器支持Systrace的类型:
python systrace.py -l
(2)实际开发中,每个方法中都手动加入Trace自定义事件比较麻烦,可以尝试开发一个gradle脚本来完成Trace插桩。
(3)使用Systrace抓APP的方法执行顺序,要求App必须是debuggable的,如果要在release包中开启自定义事件,需要用到反射打开Trace功能:
Class<?> trace = Class.forName("android.os.Trace");
Method setAppTracingAllowed = trace.getDeclaredMethod("setAppTracingAllowed", boolean.class);
setAppTracingAllowed.invoke(null, true);
"系统跟踪"应用是Android手机上的一个功能,其原理类似于 Systrace 或 Perfetto 命令行。通过"系统跟踪"应用,开发者可以直接从测试设备本身录制跟踪记录,而无需插入设备并通过命令行操作。
如下图所示,"系统跟踪"应用位于开发者选项 - 调试 - System Tracing下,或者也可以在打开"开发者选项"后通过如下命令行启动"系统跟踪"应用,但是国内很多设备都没有该功能应用,暂不详细介绍。
adb shell am start com.android.traceur/com.android.traceur.MainActivity
在Android 10(API 级别 29)或更高版本的设备上,"系统跟踪"应用的跟踪文件会使用 ‘.perfetto-trace’ 文件扩展名保存到/data/local/traces/目录下,并可在 Perfetto 界面中打开。在较旧 Android 版本的设备上,跟踪文件会使用 ‘.ctrace’ 文件扩展名(表示 Systrace 格式)保存。之后就可以把perfetto或trace文件分别用对应工具打开进行分析优化。
欢迎关注我,一起解锁更多技能:BC的掘金主页~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。