androidAndroid开发性能测试

Android性能分析工具 — CPU Profile

2019-06-28  本文已影响0人  Geekholt

目录

前言

我们都知道,应用启动慢、界面切换慢、动画不流畅卡顿等类似问题基本都是UI刷新不及时的表现,UI刷新不及时就是因为UI线程被其他逻辑方法长时间占用导致。当我们着手解决这些性能问题时,面对的第一个问题就是需要找到合适的工具来检测这些问题,通过各项性能指标来进行针对性的优化,这里我们主要讲解Android Studio自带的性能分析工具CPU Profile

本文基于Android Studio 3.2.1版本

CPU Profile简介

CPU Profile是 Android 平台配备一个很好的性能分析的工具。它可以通过图形化的方式让我们了解我们要跟踪的程序的性能,并且能具体到 method,它可以加载 trace 文件,用图形的形式展示代码的执行时间次数调用栈,便于我们分析,帮助我们最大限度减少应用的 CPU 使用率

trace 文件是 log 信息文件的一种,可以通过Debug类生成

生成Trace文件

1.通过代码生成

public void fun() {
      //开始trace,保存文件到 /sdcard/funTrace.trace
    Debug.startMethodTracing("funTrace");
    //想要监测的代码
    ....
    //结束trace
    Debug.stopMethodTracing();
}

第一步:通过Debug.startMethodTracing("funTrace");开始产生trace数据,通过 Debug.stopMethodTracing();结束监测,生成trace文件(如果系统达到最大缓存大小时,还没有调用stopMethodTracing(),系统会停止跟踪并发送一个通知)

第二步:通过adb命令 adb pull /sdcard/funTrace.trace /Users/geekholt/Downloadstrace文件导出到电脑

第三步:将trace文件直接拖到Android Studio中进行分析

通过代码生成trace文件更容易控制开始点和结束点,且可以导出trace文件。但是这种方式运行时开销严重,程序方法执行整体都会变慢,可能会带偏优化方向

traceview is deprecated.png

traceview官方文档

  1. 使用CPU Profile

第一步:点击Android studio工具栏中的Profile,运行项目

profile.png

第二步:选择CPU Profile,点击Record开始记录,相当于执行代码Debug.startMethodTracing();,再点一次停止记录,相当于执行代码 Debug.stopMethodTracing();,这样就生成了trace文件

第三步:生成trace文件后,Android Studio会自动加载trace文件,并展示图形化界面

Trace文件分析

默认视图分析

当您打开 CPU Profiler 时,它将立即开始显示应用的 CPU 使用率和线程 Activity。 您应该会看到类似图 1 的一些内容:

图 1. CPU Profiler.png

如图 1 所示,CPU Profiler 的默认视图包括以下内容:

  1. Event 时间线: 显示应用中在其生命周期不同状态间转换的 Activity,并表明用户与设备的交互,包括屏幕旋转 Event

  2. CPU 时间线: 显示应用的实时 CPU 使用率(以占总可用 CPU 时间的百分比表示)以及应用使用的总线程数。 此时间线还显示其他进程的 CPU 使用率(如系统进程或其他应用),以便您可以将其与您的应用使用率进行对比。 通过沿时间线的水平轴移动鼠标,您还可以检查历史 CPU 使用率数据

  3. 线程 Activity 时间线

    列出属于应用进程的每个线程并使用下面列出的颜色沿时间线标示它们的 Activity。 在您记录一个函数跟踪后,您可以从此时间线中选择一个线程以在跟踪窗格中检查其数据

    • 绿色: 表示线程处于活动状态或准备使用 CPU。 即,它正在“运行中”或处于“可运行”状态

    • 黄色: 表示线程处于活动状态,但它正在等待一个 I/O 操作(如磁盘或网络 I/O),然后才能完成它的工作

    • 灰色: 表示线程正在休眠且没有消耗任何 CPU 时间。 当线程需要访问尚不可用的资源时偶尔会发生这种情况。 线程进入自主休眠或内核将此线程置于休眠状态,直到所需的资源可用

trace文件视图分析

图 2. 记录函数跟踪后的 CPU Profiler
  1. 选择时间范围: 用于确定您要在跟踪窗格中检查所记录时间范围的哪一部分。 当您首次记录函数跟踪时,CPU Profiler 将在 CPU 时间线中自动选择您的记录的完整长度。 如果您想仅检查所记录时间范围一小部分的函数跟踪数据,您可以点击并拖动突出显示的区域边缘以修改其长度
  2. 时间戳: 用于表示所记录函数跟踪的开始和结束时间(相对于分析器从设备开始收集 CPU 使用率信息的时间)。 在选择时间范围时,您可以点击时间戳以自动选择完整记录,如果您有多个要进行切换的记录,则此做法尤其有用
  3. 跟踪窗格: 用于显示您所选的时间范围和线程的函数跟踪数据。 仅在您至少记录一个函数跟踪后此窗格才会显示。 在此窗格中,您可以选择想如何查看每个堆叠追踪(使用跟踪标签),以及如何测量执行时间(使用时间引用下拉菜单)
  4. 选择后,可通过 Top Down 树、Bottom Up 树、调用图表火焰图的形式显示您的函数跟踪。 您可以在下文中了解每个跟踪窗格标签的更多信息
  5. 从下拉菜单中选择以下选项之一,以确定如何测量每个函数调用的时间信息:
    • Wall clock time:壁钟时间信息表示实际经过的时间
    • Thread time:线程时间信息表示实际经过的时间减去线程没有消耗 CPU 资源的任意时间部分。 对于任何给定函数,其线程时间始终少于或等于其壁钟时间。 使用线程时间可以让您更好地了解线程的实际 CPU 使用率中有多少是给定函数消耗的

使用 Call Chart 标签检查跟踪

Call Chart 标签提供函数跟踪的图形表示形式,其中,水平轴表示函数调用(或调用方)的时间段和时间,并沿垂直轴显示其被调用者。 对系统 API 的函数调用显示为橙色,对应用自有函数的调用显示为绿色,对第三方 API(包括 Java 语言 API)的函数调用显示为蓝色。 下面的图 3 展示了一个调用图表示例,并描绘了给定函数的 self time、children time 以及总时间的概念

图 3. 一个调用图表示例,描绘了函数 D 的 self、children 及总时间

提示: 若要跳转到某个函数的源代码,请右键点击该函数并选择 Jump to Source

使用 Flame Chart 标签检查跟踪

Flame Chart 标签提供一个倒置的调用图表,其汇总相同的调用堆栈。 即,收集共享相同调用方顺序的完全相同的函数,并在火焰图中用一个较长的横条表示它们(而不是将它们显示为多个较短的横条,如调用图表中所示)。 这样更方便您查看哪些函数消耗最多时间。 不过,这也意味着水平轴不再代表时间线,相反,它表示每个函数相对的执行时间

为帮助说明此概念,请考虑以下图 4 中的调用图表。 请注意,函数 D 多次调用 B(B1、B2 和 B3),其中一些对 B 的调用也调用了 C(C1 和 C3)

图 4. 包含多个共享通用调用方顺序的函数调用的调用图表

由于 B1、B2 和 B3 共享相同的调用方顺序 (A → D → B),因此,可将它们汇总在一起,如下所示。 同样,将 C1 和 C3 汇总在一起,因为它们也共享相同的调用方顺序 (A → D → B → C)—请注意,未包含 C2,因为它具有不同的调用方顺序 (A → D → C)

图 5. 汇总共享相同调用堆栈的相同函数

汇总的函数调用用于创建火焰图,如图 6 所示。请注意,对于火焰图中任何给定的函数调用,消耗最多 CPU 时间的被调用方首先显示

使用 Top Down 和 Bottom Up 检查跟踪

Top Down 标签显示一个函数调用列表,在该列表中展开函数节点会显示函数的被调用方。 图 7 显示图 3 中调用图表的“Top Down”图表。图表中的每个箭头都从调用方指向被调用方

如图 7 所示,在“Top Down”标签中展开函数 A 的节点可显示它的被调用方,即函数 B 和 D。 然后,展开函数 D 的节点可显示它的被调用方,即函数 B 和 C 等等。 与 Flame chart 标签相似,“Top Down”树汇总共享相同调用堆栈的相同函数的跟踪信息。 也就是说,Flame chart 标签可提供Top down 标签的图形化表示形式

Top Down 标签提供以下信息以帮助说明在每个函数调用上所花费的 CPU 时间(时间也可以用线程总时间占所选时间范围的持续时间的百分比表示):

图 7. “Top Down”树和“Bottom Up”树

Bottom Up 标签显示一个函数调用列表,在该列表中展开函数节点将显示函数的调用方。 通过使用图 7 中展示的跟踪示例,图 7 为函数 C 的Bottom Up”树。 在“Bottom Up”树中打开函数 C 的节点可显示它独有的调用方,即函数 B 和 D。 请注意,尽管 B 调用 C 两次,但在“Bottom Up”树中展开函数 C 的节点时,B 仅显示一次。 然后,展开 B 的节点显示其调用方,即函数 A 和 D

Bottom Up 标签用于按照消耗最多(最少)CPU 时间排序函数。 您可以检查每个节点以确定在调用函数上哪些调用方花了最多 CPU 时间。 与“Top Down”树相比,“Bottom Up”树中的每个函数的时间信息引用每个树顶部的函数(顶部模式)。 CPU 时间也可表示为在该记录期间占线程总时间的百分比。 下表有助于阐述如何解释顶部节点的时间信息及其调用方函数(子节点)

Self Children 合计
“Bottom Up”树顶部的函数(顶部模式) 表示函数在执行自己的代码(而非其被调用方的代码)上所花的时间。 与“Top Down”树相比,此时间信息表示在记录的持续时间内对此函数所有调用的总和。 表示函数执行它的被调用方(而非它自己的代码)上所花的总时间。 与“Top Down”树相比,此时间信息表示在记录的持续期间内所有对此函数被调用方的调用总和。 self time 和 children time 的总和。
调用方函数(子节点) 表示在由调用方调用时被调用方的总 self time。 以图 7 中的“Bottom Up”树为例,被 B 调用时,函数 B 的 self time 将等于函数 C 每个执行的 self time 的总和。 表示在由调用方调用时被调用方的总 children time。 以图 7 中的“Bottom Up”树为例,被 B 调用时,函数 B 的 children time 将等于函数 C 每个执行的 children time 的总和。 self time 和 children time 的总和。
上一篇下一篇

猜你喜欢

热点阅读