Traceview是你通过在代码中使用Debug类记录跟踪信息的执行日志的图像显示。Traceview可以帮助你调试应用和分析应用性能。
Traceview布局
当你有一个跟踪日志文件时(通过在应用中添加跟踪代码或DDMS生成),你可以在Traceview中加载日志文件,这样会在两个面板显示日志数据:
- 时间轴面板——描述每个线程和方法什么时候开始和结束
- 分析面板——提供在一个方法中发生的事件概要
下面部分提供关于traceview输出面板的额外信息。
时间轴面板
下图显示了时间轴面板的图像。每个线程的执行显示在它们自己的行中,右边是时间增长。每个方法使用另一种颜色(颜色以循环的方式复用,从包含最长时间的方法开始)。第一行底部的细线显示了选中方法的所用调用范围(进入和退出)。
分析面板
下图显示了分析面板,一个所有方法消耗时间的概要。这个表格显示了包含时间和不包含时间(以及占总时间的百分比)。不包含时间是方法内所消耗的时间。包含时间是方法内消耗的时间加上调用其他函数消耗的时间。我们称调用方法称为“parents”,被调用方法称为“children”。当一个方法被选择(通过点击它),它会展开来显示parents和children。parents用紫色背景,children用黄色背景。表格的最后一列显示了这个方法的调用次数加上递归调用的数目。在视图中,我们看到 LoadListener.nativeFinished() 调用了14次。查看时间轴面板,每个调用花费不同长的时间。
创建跟踪文件
要使用Traceview,你需要生成包含你想分析的跟踪信息的日志文件。
这里有两种方式生成跟踪日志:
- 在你的代码里包含Debug类,调用它的方法,诸如 startMethodTracing() 和 stopMethodTracing() ,来开始和结束记录跟踪信息到磁盘。这个方式非常精确,因为你可以在代码中明确指定从哪里开始和从哪里结束记录跟踪数据。
- 使用DDMS的方法分析特性来生成跟踪日志。这个方式不精确,因为你不修改代码而通过DDMS来指定什么时候开始和是什么时候结束记录。尽管你较少控制明确的记录开始和结束位置,这个方法也是很有用的,如果你不能够访问应用代码,或者你不需要精确的记录时间。
在你开始生成跟踪日志前,明确以下约束:
- 如果你使用Debug类,你的应用必须有写入外部存储的权限(READ_EXTERNAL_STORAGE)。
- 如果你使用DDMS:
- Android2.1及以前的设备必须有一个SD卡,你的应用必须有权限写入SD卡。
- Android2.2及之后的设备不需要有一个SD卡。跟踪日志文件直接流入到你的开发机上。
要创建跟踪文件,包含Debug类,调用某个 startMethodTracing() 方法。在这个调用中,你指定系统生成的跟踪文件的基名。要停止跟踪,调用 stopMethodTracing() 。这些方法开始和结束方法跟踪横跨整个虚拟机。例如,你可以在Activity的 onCreate() 方法中调用 startMethodTracing() ,在Activity的 onDestroy() 方法中调用 stopMethodTracing() 。
// start tracing to "/sdcard/calc.trace"
Debug.startMethodTracing("calc");
// ...
// stop tracing
Debug.stopMethodTracing();
当你的应用调用 startMethodTracing() 时,系统创建一个名为 <trace-base-name>.trace 的文件。这个文件包含二进制方法跟踪数据和一个线程和方法名称映射表。
系统然后缓冲生成的跟踪数据,直到你的应用调用 stopMethodTracing() 时,它将缓冲数据写入输出文件。如果系统在你调用 stopMethodTracing() 前达到了最大缓存大小,系统会停止跟踪并发送一个通知到控制台。
当启用分析时,代码运行得很慢。不要试图从分析结果中生成绝对计时(例如,“方法X运行耗时2.5秒”)。这个时间只在与其他分析输出关联中有用,你可以看到当发生改变,代码运行得比上一次分析运行快或者慢。
在Android4.4及之后,你可以使用采样分析来进行分析,从而有较少的性能影响。要启用采样分析,以一个指定的采样间隔调用 startMethodTracingSampling() 。系统会周期性地获取样本直到通过 stopMethodTracing() 停止跟踪。
复制跟踪文件到主机
在你的应用运行后,并且系统已经在设备或模拟器上创建了跟踪文件 <trace-base-name>.trace ,你必须复制这些文件到你的开发机上。你可以使用 adb pull 复制这些文件。这里有一个例子显示了如何复制一个例子文件calc.trace,从模拟器的默认位置到模拟主机的/tmp目录上:
adb pull /sdcard/calc.trace /tmp
在Traceview中查看跟踪文件
要运行Traceview并查看跟踪文件,输入 traceview <trace-base-name> 。例如,要对前面部分复制的例子文件运行Traceview,使用:
traceview /tmp/calc
记住:如果你试图查看一个启用ProGuard构建的应用的跟踪日志,一些方法和成员名可能被混淆。你可以使用Proguard的 mapping.txt 文件来指出原来未混淆的名称。
使用dmtracedump
dmtracedump 是一个工具给你一个可选的方式从跟踪日志文件生成图形调用栈示意图。这个工具使用了Graphviz Dot来创建图形输出,因此你需要在运行dmtracedump前安装Graphviz。
dmtracedump将调用栈数据生成一个树图,每个节点代表一个调用。它使用箭头显示调用流(从父节点指向子节点)。下面的图显示了一个dmtracedump的例子。
对于每个节点,dmtracedump显示了 <ref> callname (<inc-ms>, <exc-ms>, <numcalls>) :
- <ref>——调用引用序号,在跟踪日志中使用
- <inc-ms>——包含消耗时间(方法消耗的毫秒数,包含所有子方法)
- <exc-ms>——不包含消耗时间(方法消耗的毫秒数,不包含任何子方法)
- <numcalls>——调用的次数
dmtracedump的使用方法:
dmtracedump [-ho] [-s sortable] [-d trace-base-name] [-g outfile] <trace-base-name>
工具然后从<trace-base-name>.data 和& lt;trace-base-name>.key 中加载跟踪日志数据。下面的表格列出了dmtracedump的选项。
选项 | 描述 |
---|---|
-d <trace-base-name> | 与这个跟踪名称做差分 |
-g <outfile> | 生成输出到 |
-h | 打开HTML输出 |
-o | 转储跟踪文件替代分析 |
-s <sortable> | 基于URL的排序javascript文件位置 |
-t <persent> | 在图像中包含子节点的最小阈值(子节点的包含时间占父父节点包含时间的百分比)。如果没有使用这个选项,默认的阈值是20%。 |
Traceview已知问题
Traceview记录不能很好处理线程,有以下两个问题:
- 如果一个线程在分析中退出,这个线程名不会发出(在Android5.1及之后修复)。
- VM复用线程ID。如果一个线程停止,另一个启动,它们可能得到相同ID。
原文链接:
http://developer.android.com/tools/debugging/debugging-tracing.html
本博客会持续对Debug系列的以下文章进行翻译,后面追加链接的为已翻译的:
- Debugging——Android应用调试
- Debugging with Android Studio——在Android Studio中调试
- Debugging from Other IDEs——在其它IDE中调试
- Using DDMS——使用DDMS
- Reading and Writing Logs——读写日志
- Improving Your Code with lint——使用lint优化代码
- Optimizing Your UI——优化UI
- Profiling with Traceview and dmtracedump
- Improving Code Inspection with Annotations
- Analyzing Display and Performance
- Investigating Your RAM Usage
- Using the Dev Tools App