systrace 工具分析应用流畅性

1概述

以 密卷点评中的标记功能为例,

systrace 工具分析应用流畅性_第1张图片

优化前后的帧率对比

systrace 工具分析应用流畅性_第2张图片

可以看到大约 15 帧的提升。

2 分析方法

2.1 打印帧率

评估一个应用的流畅度,除了主观感受外,定量的帧率测量是很有必要的。从4.4 之后都支持通过设置属性来打开帧率输出。

具体操作:

 setprop debug.sf.fps 1

 stop;start(5.0 以后不需要,但是需要退到主界面滑动,直到下述 log 输出帧率)

 logcat –s SurfaceFlinger 观察帧率

从手写标记这个应用中可以看到,原始的帧率在 20 帧左右


2.2 瓶颈分析

分析瓶颈,我们可以利用谷歌提供的 DDMS 工具进行。首先我们使用 systrace 获取几项图形系统相关的数据。

具体操作:

 执行 adb root,确保 adb 具有 root 权限

systrace 工具分析应用流畅性_第3张图片
systrace 工具分析应用流畅性_第4张图片

点 击OK之 后 , 开 始 进 行 手 写 操 作 , 采 集 时 间 到 了 之 后 , 会 在

生成 html 文件。

 使用 chrome 浏览器打开该文件

systrace 工具分析应用流畅性_第5张图片

 查看被测进程


systrace 工具分析应用流畅性_第6张图片

 测量 draw 时间


systrace 工具分析应用流畅性_第7张图片

可以看到一帧的绘制时间在 45ms 左右,排除 input 派发等其他操作,折算一下,帧率大约就是1000ms/45ms≈20fps,超出了 60fps 下所要求的一帧 16ms。可以认为,draw 是瓶颈所在。

2.3 分析热点函数

热点函数我们同样使用 DDMS 自带的 Method Profiling 工具

具体操作:


systrace 工具分析应用流畅性_第8张图片
systrace 工具分析应用流畅性_第9张图片

 开始滑动,采集数据

systrace 工具分析应用流畅性_第10张图片

停止采集。

 这里建议在点击 start 之前就开始滑动,因为系统默认只能采集 8MB 的数据,超过 8M 是不会继续采集的。

systrace 工具分析应用流畅性_第11张图片

 展开之后,不需要使用列表中的统计功能,已经能够看到几个耗时的区块

systrace 工具分析应用流畅性_第12张图片

 点击几个色块,可以看到,热点函数集中在

 其中以下的红框调用是需要分析的

systrace 工具分析应用流畅性_第13张图片

做减法评估大头

om.eebbk.themeplayer.ScrollViewLinearLayout.drawCacheBackground(Canvas)----去掉,提升 5帧

com.eebbk.themeplayer.ScrollViewLinearLayout.drawDrawingStroke(Canvas)--------去掉,提升 10帧

 之后会出现一个问题,去掉上述函数调用之后,仍然没有办法达到 60 帧的满帧。因此将注意力集中到

 至此,工具已经没有办法提供更多的有用信息。

2.4 分析绘制代码

 打开 draw 相关 log 开关

--- a/core/java/android/view/ViewRootImpl.java

+++ b/core/java/android/view/ViewRootImpl.java

@@ -110,7 +110,7 @@ public final class ViewRootImpl implements ViewParent,

private static final boolean DBG = false;

private static final boolean LOCAL_LOGV = false;

/** @noinspection PointlessBooleanExpression*/

- private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;

+ private static final boolean DEBUG_DRAW = true || LOCAL_LOGV;

 查看 log,可以发现

Invalidate child: Rect(118, 170 - 1536, 1952)

脏区非常大,也就是每次需要重绘的区域非常大。

对比满帧的草稿纸应用,Invalidate child: Rect(532, 1004 - 547, 1023)这个脏区就很小。

 继续在 invalidate 的路径上(函数 invalidateInternal)添加 log

--- a/core/java/android/view/View.java

+++ b/core/java/android/view/View.java

@@ -11803,6 +11803,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,

if (p != null && ai != null && l < r && t < b) {

final Rect damage = ai.mTmpInvalRect;

damage.set(l, t, r, b);

+ //debug();

+ Log.e("cw","View:" + this + " dirty {" + l + ", " + t + ", " + r + ", " + b + "}", new

Throwable());

p.invalidateChild(this, damage);

}

对 比 密 卷 和 草 稿 纸 两 个 应 用 , 可 以 发 现 草 稿 纸 调 用 了

com.eebbk.draftpaper.slate.Slate.invalidate(Rect),是带矩形参数的,因此脏区可以控制的很小。

而密卷调用的是com.eebbk.themeplayer.ScrollViewLinearLayout.drawStroke(Bitmap, Bitmap, int,

int)中的 postInvalidate,不带参数会导致整个 ScrollViewLinearLayout 重绘。

3 应对方法

根据上述分析,瓶颈在于 draw 的脏区过大,导致重绘耗时。因此至少可以有两处优化:

可以参照草稿纸应用,减小脏区

将 com.eebbk.themeplayer.ScrollViewLinearLayout.drawCacheBackground(Canvas)做适当优化,避免每

次 draw 都重新绘制这个静止的背景。

你可能感兴趣的:(systrace 工具分析应用流畅性)