Systrace
Systrace是一个平台提供的工具,可以在很短的时间内记录设备活动。该工具生成一个报告,该报告结合了Android内核中的数据,例如CPU调度程序,磁盘活动和应用程序线程。报告可以确定如何最好地改善应用或游戏的性能。
报告提供了Android设备在给定时间段内的系统进程的总体情况。该报告还检查捕获的跟踪信息,以突出显示它所观察到的问题,例如UI jank或高功耗。
通过sdk自带的脚本工具获取想要的报告,报告只能用Chrome浏览器
分析查看
获取Systrace报告文件
使用sdk的工具生成报告文件
工具:/sdk/platform-tools/systrace
可以通过设定脚本参数得到自己想要的报告内容
通过命令查看连接设备所支持的类型列表
python systrace.py --list-categories
可以看到可以分析的模块十分全面从硬件到软件、从底层到上层app、从view到渲染引擎基本全覆盖,配合上Profiler、MAT、hprof-conv、Hierarchy view、OverDraw
工具可谓是一剑在手天下我有
获取报告的命令参数
./systrace.py -h
Commands | options | 描述 |
---|---|---|
-h | --help | 显示帮助信息 |
-l | --list-categories | 列出所连接设备可用的跟踪类别 |
-o | file | 将HTML跟踪报告写入指定的文件。如果未指定此选项,systrace请将报告保存到与其相同的目录中并为其命名。 systrace.pytrace.html |
-t N | --time=N | 跟踪设备活动N秒。如果未指定此选项,则systrace提示您通过从命令行按Enter键来结束跟踪。 |
-b N | --buf-size=N | 使用N千字节的跟踪缓冲区大小。此选项允许您限制跟踪期间收集的数据的总大小。 |
-k functions | --ktrace=functions | 跟踪以逗号分隔的列表中指定的特定内核函数的活动。 |
-a app-name | --app=app-name | 启用应用程序的跟踪,指定为以逗号分隔的进程名称列表 。应用程序必须包含来自Trace 类的跟踪检测调用 。每当您分析应用程序库时,都应指定此选项,例如 RecyclerView ,包括跟踪检测调用,这些调用在启用应用程序级跟踪时提供有用信息。有关更多信息,请转到有关如何检测应用程序代码的部分。 |
--from | -file=file-path | 从文件创建交互式HTML报告,例如包含原始跟踪数据的TXT文件,而不是运行实时跟踪。 |
-e device-serial | --serial=device-serial | 在特定连接设备上进行跟踪 |
categories | 包括您指定的系统进程的跟踪信息,例如gfx用于呈现图形的系统进程。您可以systrace使用该-l命令运行以查看所连接设备可用的服务列表。 | |
--walt | WALT trace options | 测量手机和计算机上物理传感器和输出的延迟 |
获取报告
无时间限制,需要enter键开始
./systrace.py -o trace.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res
加时间参数
./systrace.py -o trace.html -t 12 sched freq idle am wm gfx view binder_driver hal dalvik camera input res
完成后使用chrome打开得到的文件即可
Android9以上版本也可以通过开发者模式
获取
次方式不推荐使用
通过消息或通过ADB共享跟踪时,报告本身驻留在.ctrace文件中。使用此文件,可以生成跟踪的HTML报告。为此,请在终端窗口中运行以下命令:
cd / path-to-traces-on-my-dev-machine && \
systrace --from-file trace-file-name .ctrace
但是需要systrace命令行程序
报告分析
Systrace生成包含一系列部分的输出HTML文件。该报告列出了每个进程的线程。如果给定线程呈现UI帧,则报告还指示沿时间线的呈现帧。当在报告中从左向右移动时,时间会向前传递。
报告从上到下包含以下部分
- UI交互活动
第一部分包含表示应用或游戏中特定用户交互的条形图,例如点击设备屏幕。这些相互作用充当有用的时间标记
- CPU活动
显示了表示每个CPU中的线程活动的条形图。条形图显示所有应用程序(包括您的应用程序或游戏)的CPU活动。
折叠的CPU活动部分的示例
CPU活动部分是可扩展的,允许您查看每个CPU的时钟频率
- 系统事件
直方图显示特定的系统级事件,例如纹理计数和特定对象的总大小。
值得仔细检查的直方图是标记为SurfaceView的直方图。计数表示已传递到显示管道并等待在设备屏幕上显示的组合帧缓冲区的数量。由于大多数设备都是双缓冲或三缓冲,因此该计数几乎总是0,1或2。
描述Surface Flinger过程的其他直方图,包括VSync事件和UI线程交换工作,如下图
- 显示框架
这一部分,通常是报告中最多的部分,描绘了一条彩色线条,后面是成堆的条形图。这些形状表示已创建的特定线程的状态和帧堆栈。
UI线程或应用程序或游戏通常运行的主线程始终显示为第一个线程。
每堆条形图上方的多色线表示特定线程随时间变化的状态集。该行的每个部分可以包含以下颜色之一:
绿色:Running
线程正在完成与进程相关的工作或正在响应中断。
蓝色:Runnable
线程可以运行但当前没有安排。
白色:Sleeping
线程没有工作要做,可能是因为线程在互斥锁上被阻塞。
橙色:Uninterruptable sleep(不间断的睡眠)
线程在I / O上被阻塞或等待磁盘操作完成。
紫色:Interruptable sleep(可以中断睡眠)
线程在另一个内核操作(通常是内存管理)上被阻塞。
- 报告分析操作快捷键
key | 描述 |
---|---|
W | 放大时间轴 |
A | 在跟踪时间线上左移 |
S | 缩小时间轴 |
D | 在跟踪时间轴上向右平移 |
E | 将跟踪时间轴置于当前鼠标位置的中心 |
M | 选中当前帧 |
1 | 将当前活动的选择模型更改为“选择”模式。对应于鼠标选择器工具栏中显示的第一个按钮 |
2 | 将当前活动的选择模型更改为“平移”模式。对应于鼠标选择器工具栏中显示的第二个按钮 |
3 | 将当前活动的选择模型更改为“缩放”模式。对应于鼠标选择器工具栏中显示的第3个按钮 |
4 | 将当前活动的选择模型更改为“计时”模式。对应于鼠标选择器工具栏中显示的第4个按钮 |
G | 在当前所选任务的开头显示网格 |
Shift + G | 在当前所选任务的末尾显示网格 |
左键 | 在当前选定的时间轴上选择上一个事件 |
右键 | 选择当前所选时间轴上的下一个事件 |
自定义systrace数据获取
以上数据默认仅在系统级别向显示有关进程的信息,因此有时很难知道应用程序或游戏的哪些方法在给定时间相对于系统事件执行。
Android平台提供了一个trace API,可以使用它来标记特定的代码段。如果捕获应用程序“debug”
版本的新系统跟踪并包含该-a选项,如下面的代码段所示,这些自定义事件将显示在Systrace报告中:
python systrace.py -a com.zerone.qrcode -b 16384 -o my_systrace_report.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res
java 层code
堆栈的每个级别代表为应用或游戏定义beginSection()
的自定义跟踪事件的调用或开始
Trace.beginSection(String sectionName)
和Trace.endSection()
需要成对出现- 为保证每个
Trace.beginSection(String sectionName)
都会有对应的Trace.endSection()
,建议使用try {……} finally {……}
- 如果在
Trace.endSection()
之前有多个Trace.beginSection(String sectionName)
,Trace.endSection()
会匹配离它最近的一个未匹配过的Trace.beginSection(String sectionName)
Trace.beginSection(String sectionName)
和Trace.endSection()
需要在同一线程中
public class MyAdapter extends RecyclerView.Adapter {
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Trace.beginSection("MyAdapter.onCreateViewHolder");
MyViewHolder myViewHolder;
try {
myViewHolder = MyViewHolder.newInstance(parent);
} finally {
//在try和catch语句中,总是在a中调用“endSection()”
//“终于”阻止。这样,即使在a时也调用该方法
//发生异常。
Trace.endSection();
}
return myViewHolder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Trace.beginSection("MyAdapter.onBindViewHolder");
try {
try {
Trace.beginSection("MyAdapter.queryDatabase");
RowItem rowItem = queryDatabase(position);
dataset.add(rowItem);
} finally {
Trace.endSection();
}
holder.bind(dataset.get(position));
} finally {
Trace.endSection();
}
}
}
Native层code
Android 6.0(API级别23)及更高版本支持native trace API
,trace.h
将跟踪事件写入系统缓冲区,然后使用Systrace
进行分析。此API的常见用例包括观察特定代码块执行的时间以及将代码块与不良系统行为相关联的时间。
要定义应用或游戏中本机代码中发生的自定义事件,请完成以下步骤:
1、定义用于捕获游戏中自定义事件的ATrace函数的函数指针,如以下代码段所示:
#include
#include
void *(*ATrace_beginSection) (const char* sectionName);
void *(*ATrace_endSection) (void);
typedef void *(*fp_ATrace_beginSection) (const char* sectionName);
typedef void *(*fp_ATrace_endSection) (void);
2、在运行时加载ATrace符号,如以下代码段所示。通常,在对象构造函数中执行此过程。
//检索libandroid的句柄。
void *lib = dlopen("libandroid.so", RTLD_NOW || RTLD_LOCAL);
//访问本机跟踪功能。
if (lib != NULL) {
//使用dlsym()防止运行Android 5.1的设备崩溃
//(API级别22)或更低。
ATrace_beginSection = reinterpret_cast(
dlsym(lib, "ATrace_beginSection"));
ATrace_endSEction = reinterpret_cast(
dlsym(lib, "ATrace_endSection"));
}
出于安全原因,请dlopen()仅在您的应用或游戏的调试版本中包含调用 。
3、打电话ATrace_beginSection()和 ATrace_endSection()在开始和结束时,分别自定义事件:
#include
char *customEventName = new char[32];
sprintf(customEventName, “用户点击%s按钮” , buttonName);
ATrace_beginSection(customEventName);
//您的应用或游戏对按下按钮的响应。
ATrace_endSection();