Android Studio 如何分析 CPU 活动
前面的小节我们学习了应用开发,构建,发布,接下来几个小结我们学习如何剖析应用性能。本小节我们将学习如何分析 CPU 活动。
1. 什么是 CPU Profiler
1.1 CPU Profiler 概览
优化应用的 CPU 使用率能带来诸多好处,如提供更快、更顺畅的用户体验,以及延长设备电池续航时间。我们可以使用 CPU Profiler 在与应用交互时实时检查应用的 CPU 使用率和线程活动,也可以检查记录的方法跟踪数据、函数跟踪数据和系统跟踪数据的详细信息。
CPU Profiler 记录和显示的特定信息类型由我们选择的记录配置确定:
系统跟踪数据
捕获精细的详细信息,以便我们检查应用与系统资源的交互情况。
方法和函数跟踪数据
对于应用进程中的每个线程,我们可以了解一段时间内执行了哪些方法 (Java) 或函数 (C/C++),以及每个方法或函数在其执行期间消耗的 CPU 资源。我们还可以使用方法和函数跟踪数据来识别调用方和被调用方。调用方是指调用其他方法或函数的方法或函数,而被调用方是指被其他方法或函数调用的方法或函数。我们可以使用此信息来确定哪些方法或函数负责调用常常会消耗大量资源的特定任务,并优化应用的代码以避免不必要的工作。
1.2 打开 CPU Profiler
要打开 CPU Profiler,请按以下步骤操作:
依次选择 View > Tool Windows > Profiler 或点击工具栏中的 Profile 图标 。如果 Select Deployment Target 对话框显示提示,请选择要将我们的应用部署到哪个设备上以进行性能剖析。
点击 CPU 时间轴上的任意位置以打开 CPU Profiler。当打开 CPU Profiler 时,它会立即开始显示应用的 CPU 使用率和线程活动。系统会显示类似于下图的界面。
-
事件时间轴:显示应用中的 Activity 在其生命周期内不断转换而经历各种不同状态的过程,并指示用户与设备的交互,包括屏幕旋转事件;
-
CPU 时间轴:显示应用的实时 CPU 使用率(以占总可用 CPU 时间的百分比表示)以及应用当前使用的线程总数。 此时间轴还会显示其他进程(如系统进程或其他应用)的 CPU 使用率,以便我们可以将其与我们应用的 CPU 使用率进行对比。我们可以通过沿时间轴的横轴方向移动鼠标来检查历史 CPU 使用率数据;
-
线程活动时间轴:列出属于应用进程的每个线程,并使用下面列出的颜色在时间轴上指示它们的活动。记录跟踪数据后,我们可以从此时间轴上选择一个线程,以在跟踪数据窗格中检查其数据。
-
绿色:表示线程处于活动状态或准备使用 CPU。也就是说,线程处于正在运行或可运行状态。
-
黄色:表示线程处于活动状态,但它正在等待一项 I/O 操作(如磁盘或网络 I/O),然后才能完成它的工作。
-
灰色:表示线程处于休眠状态并且没有占用任何 CPU 时间。 当线程需要访问尚不可用的资源时,就会出现这种情况。在这种情况下,要么线程主动进入休眠状态,要么内核将线程置于休眠状态,直到所需的资源可用。
-
2. 记录 CPU 活动
2.1 记录跟踪数据
要开始记录跟踪 CPU 活动数据,请从 CPU Profiler 顶部的下拉菜单中选择记录配置,然后点击 Record,如下图,CPU Profiler 显示了正在进行的记录的状态、持续时间和类型。
与我们的应用交互,然后在完成时点击 Stop。分析器将自动选择记录的时间范围,并在跟踪数据窗格中显示其跟踪信息,如下图所示。如果要检查其他线程的跟踪数据,请从线程活动时间轴上选择相应线程。
-
选定范围:确定要在跟踪数据窗格中检查所记录时间的哪一部分。当我们首次记录跟踪数据时,CPU Profiler 会自动在 CPU 时间轴上选择记录的完整长度。要仅检查已记录的时间范围中的一部分的跟踪数据,请拖动突出显示区域的边缘;
-
时间戳:指示所记录跟踪数据的开始和结束时间(相对于分析器开始收集 CPU 使用率信息的时间)。要选择完整的记录,请点击时间戳;
-
跟踪数据窗格:显示我们选择的时间范围和线程的跟踪数据。此窗格要在我们至少记录一条跟踪数据后才会显示。 在此窗格中,我们可以选择如何查看每个堆栈轨迹(使用跟踪数据标签页),以及如何测量执行时间(使用时间参考下拉菜单);
-
跟踪数据窗格标签页:选择如何显示跟踪数据详细信息;
-
时间参考菜单:选择以下选项之一,以确定如何测量每次调用的时间信息:
- Wall clock time:该时间信息表示实际经过的时间。
- Thread time:该时间信息表示实际经过的时间减去线程没有占用 CPU 资源的那部分时间。对于任何给定的调用,其线程时间始终小于或等于其挂钟时间。使用线程时间可以让我们更好地了解线程的实际 CPU 使用率中有多少是给定方法或函数占用的。
2.2 选择记录配置
在开始记录跟踪信息之前,请为要捕获的分析信息选择适当的记录配置:
-
对 Java 方法采样:在应用的 Java 代码执行期间,频繁捕获应用的调用堆栈。分析器会比较捕获的数据集,以推导与应用的 Java 代码执行有关的时间和资源使用信息;
-
跟踪 Java 方法:在运行时检测应用,以在每个方法调用开始和结束时记录一个时间戳。系统会收集并比较这些时间戳,以生成方法跟踪数据,包括时间信息和 CPU 使用率;
-
对 C/C++ 函数采样:捕获应用的原生线程的采样跟踪数据。要使用此配置,我们必须将应用部署到搭载 Android 8.0(API 级别 26)或更高版本的设备上;
-
跟踪系统调用:捕获非常翔实的细节,以便我们检查应用与系统资源的交互情况。我们可以检查线程状态的确切时间和持续时间、直观地查看所有内核的 CPU 瓶颈在何处,并添加要分析的自定义跟踪事件。 当我们排查性能问题时,此类信息至关重要。要使用此配置,我们必须将应用部署到搭载 Android 7.0(API 级别 24)或更高版本的设备上。
2.3 Debug API 记录 CPU 活动
除了手动点击 Record 和 Stop 来记录跟踪数据外,我们还可以在代码中使用 Debug API 让应用能够在 CPU Profiler 中开始和停止记录 CPU 活动。
当我们的应用调用 startMethodTracing(String tracePath) 时,CPU Profiler 将开始记录;当我们的应用调用 stopMethodTracing() 时,CPU Profiler 将停止记录。在记录使用此 API 触发的 CPU 活动时,CPU Profiler 会将 Debug API 显示为作用中的 CPU 记录配置。
Tips:要使用 Debug API 控制 CPU 活动的记录,请将检测的应用部署到搭载 Android 8.0(API 级别 26)或更高版本的设备上。
2.4 记录应用启动的 CPU 活动
要在应用启动过程中自动开始记录 CPU 活动,请执行以下操作:
- 依次选择 Run > Edit Configurations;
2. 在 Profiling 标签中,勾选 Start recording a method trace on startup 旁边的复选框;
-
从菜单中选择 CPU 记录配置;
-
点击 Apply;
-
依次选择 Run > Profile,将我们的应用部署到搭载 Android 8.0(API 级别 26)或更高版本的设备上。
3. 导入导出 CPU 活动
3.1 导出跟踪数据
使用 CPU Profiler 记录 CPU 活动后,我们可以将相应数据导出为 .trace 文件,以便与他人共享或日后进行检查。
要从 CPU 时间轴导出跟踪文件,请执行以下操作:
-
在 CPU 时间轴上,右键点击要导出的记录的方法跟踪数据或系统跟踪数据;
-
从菜单中选择 Export trace;
-
浏览到要保存文件的目标位置,指定文件名,然后点击 OK。
要从 Sessions 窗格导出跟踪文件,请执行以下操作:
-
在 Sessions 窗格中,右键点击要导出的记录的跟踪数据;
-
点击会话条目右侧的 Export method trace 或 Export system trace 按钮;
-
浏览到要保存文件的目标位置,指定文件名,然后点击 OK。
3.2 导入跟踪数据
我们可以导入使用 Debug API 或 CPU Profiler 创建的 .trace 文件。
要导入跟踪文件,请在分析器的 Sessions 窗格中点击 Start new profiler session 图标 ,然后选择 Load from file。
我们可以检查导入到 CPU Profiler 中的跟踪数据,就像检查直接在 CPU Profiler 中捕获的跟踪数据一样,但有下面几点不同:
-
CPU 活动未显示在 CPU 时间轴上。
-
线程活动时间轴仅指明了可在哪里获取各线程的跟踪数据,而未指明实际线程状态(如运行中、等待中或休眠中)。
4. 检查 CPU 活动
CPU Profiler 中的跟踪数据窗格提供多个标签页,供我们选择如何查看所记录的跟踪数据中的信息。
要查看方法跟踪数据和函数跟踪数据,我们可以从 Call Chart、Flame Chart、Top Down 和 Bottom Up 标签页中进行选择。要查看系统跟踪数据,我们可以从 Trace Events、Flame Chart、Top Down 和 Bottom Up 标签页中进行选择。
4.1 Call Chart 标签页
Call Chart 标签页会以图形来呈现方法跟踪数据或函数跟踪数据,其中调用的时间段和时间在横轴上表示,而其被调用方则在纵轴上显示。对系统 API 的调用显示为橙色,对应用自有方法的调用显示为绿色,对第三方 API(包括 Java 语言 API)的调用显示为蓝色。
上图显示了一个调用图表示例,说明了给定方法或函数的 Self 时间、Children 时间和 Total 时间的概念。
4.2 Flame Chart 标签页
Flame Chart 标签页提供一个倒置的调用图表,用来汇总完全相同的调用堆栈。也就是说,将具有相同调用方顺序的完全相同的方法或函数收集起来,并在火焰图中将它们表示为一个较长的横条(而不是将它们显示为多个较短的横条,如调用图表中所示)。这样更方便我们查看哪些方法或函数消耗的时间最多。不过,这也意味着,横轴不代表时间轴,而是表示执行每个方法或函数所需的相对时间。
为帮助说明此概念,不妨考虑下图中的调用图表。请注意,方法 D 多次调用 B(B1、B2 和 B3),其中一些对 B 的调用也调用了 C(C1 和 C3)。
由于 B1、B2 和 B3 具有相同的调用方顺序 (A → D → B),因此系统将它们汇总在一起,如下图所示。同样,也将 C1 和 C3 汇总在一起,因为它们也具有相同的调用方顺序 (A → D → B → C)。请注意,C2 不包括在内,因为它具有不同的调用方顺序 (A → D → C)。
汇总的调用用于创建火焰图,如下图所示。 请注意,对于火焰图中的任何给定调用,占用最多 CPU 时间的被调用方最先显示。
4.3 Top Down 和 Bottom Up 标签页
Top Down 标签显示一个调用列表,在该列表中展开方法或函数节点会显示它的被调用方。
如下图所示,在 Top Down 标签页中展开方法 A 的节点会显示它的被调用方,即方法 B 和 D。在此之后,展开方法 D 的节点会显示它的被调用方,即方法 B 和 C,依此类推。与 Flame chart 标签页类似, Top Down 树也汇总了具有相同调用堆栈的完全相同的方法的跟踪信息。也就是说,Flame chart 标签页提供了 Top down 标签页的图形表示方式。
Top Down 标签提供以下信息来帮助说明在每个调用上所花的 CPU 时间(时间也可表示为在选定范围内占线程总时间的百分比):
-
Self:方法或函数调用在执行自己的代码(而非被调用方的代码)上所花的时间;
-
Children:方法或函数调用在执行它的被调用方(而非自己的代码)上所花的时间;
-
Total:方法的 Self 时间和 Children 时间的总和。这表示应用在执行调用时所用的总时间。
Bottom Up 标签页显示一个调用列表,在该列表中展开函数或方法的节点会显示它的调用方。如下图,提供了方法 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 时间也可表示为在该记录期间占线程总时间的百分比。
4.4 Trace Events 标签页
检查系统跟踪数据时,我们可以使用 Trace Events 标签查看每个线程上发生的事件的详细信息。
要查看某个线程的详细信息,请在 Threads 窗格中选择该线程。这样将在 Kernel 窗格中突出显示该线程在每个 CPU 内核上的活动,并在 Trace Events 标签页中显示该线程的事件。在 Trace Events 标签页中将鼠标指针悬停在某个事件上可查看该事件的名称以及在每种状态下所用的时间。
例如,下图中,在 Threads 窗格中选择了 RenderThread,在 Kernel 窗格中突出显示了该线程在 CPU 0 和 CPU 1 上的活动,并在 Trace Events 标签页中显示了在特定事件上所花的时间。
5. 小结
本节课程我们主要学习了如何记录和分析 CPU 活动。本节课程的重点如下:
- 掌握如何记录跟踪 CPU 数据;
- 掌握如何检查分析 CPU 数据。
- 还没有人评论,欢迎说说您的想法!