1.前言

在这段时间的分析trace学习中,刚开始总是不会有条理的分析,想到一处是一处,这导致分析的有可能不全面,也会影响自己的学习情况,于是写下这篇笔记。

帮助我在分析时能更加全面。

2.准备工作

这里我们就以常用的冷启动作为一个例子吧。由于只是概述流程,所以并不涉及具体分析。

我习惯先圈出总的区域,以便快速定位

接着,圈出三方应用UI线程的cpu状态:

从这里可以很清楚的看出cpu状态的差异,当你看完这篇文章之后,相信你在这一阶段,就有了大概的判断。

3.Running状态分析

3.1 软件版本

有可能是软件版本不同导致执行流程或者代码复杂度不同导致。

3.2 编译方式

有可能是编译方式不同导致时长不一致,这部分可以查看下面的blog进行学习

安卓Art编译方式 | Arden の 勇者聚集地 (ardenlee.love)

3.3 以解释方式运行

首先我们要有一个大致理解,一般有三种程序运行方式:

  1. 解释执行

    源代码或字节码在运行时逐条被解释器解释执行,不进行预先的编译。可以理解为,安装快,启动运行慢。

    当在trace中发现了大量 Compiling 字眼时有可能是处于解释方式运行。

  2. 编译执行

    程序在运行之前将源代码或字节码一次性编译成本地机器码,然后直接执行编译后的机器码。比如我们很常见的 dex2oat 。

  3. 及时编译

    介于解释执行和编译执行之间的一种方式,不属于传统的编译执行,但也不同于解释执行。它是一种动态编译技术,可以在一定程度上提高程序的执行效率,比如常见的 jit。

3.4 跑小核

小核可能性能达不到我们的需要,这时可以与对比机比较,看是否调度出现问题。

3.5 跑大核,频点低

是否是限频?如果不是限频,为什么频点没拉起来?

如果是限频,是否是温控限频,省电精灵限频。

可以查看对比机log大致判断对比机温控策略是否比测试机激进。

3.6 温升导致拔核

确定是否环境引起

是否是一些发热严重的器件导致的,比如是不是 cpu负载太高,对比机是否由于负载较低所以温度较低无拔核状态。

4.Runnable状态分析

同一时刻 CPU 只能跑一个线程,当一个任务准备好只差 cpu资源时的状态,所有的 running 执行前一定有一个 runnable 状态。

4.1 优先级设置问题

某一个线程设置过高,或过低,会导致自己抢占别的线程CPU资源或者,别的线程抢占该线程的CPU资源。

4.2 绑核问题

现在的机器,一般会将重要线程,比如surfacefliger,前台UI线程绑大核,主要还是和对比机来看绑核策略是否一致。

4.3 锁

系统线程锁或者应用自身锁

5.Sleeping状态分析

他们都是处于睡眠状态,拿不到 CPU的时间片,只有满足某些条件时才会拿到时间片,即变为 Runnable,随后是 Running。

Sleeping状态一般是由程序主动等待某个事件发生造成的,比如锁等待。

5.1 Binder耗时长

如果发现binder时间长,我们需要查看对端binder,是否是跑小核?是否是优先级问题,等等。

5.2 锁竞争

这类情况在整机负载高情况下容易出现。

5.3 等待

有可能会出现主线程等在渲染线程导致sleeping,渲染线程处理太慢导致sleeping耗时长。

6.不可中断睡眠状态分析

6.1 non-io

6.1.1 低内存等待

低内存的时候要回收其他程序或者缓存上的内存,有可能导致内存命中率问题,或缺页等。

6.1.2 Binder等待

6.1.3 内核锁

6.2 io

6.2.1程序大量读写

6.2.2 多线程都需要io操作

6.2.3 swap

开启 Swap 机制的内核下,数据从 Swap 中读取

开启swap机制之后,当系统内存不足时,部分不常用的数据会被移动到Swap分区,同时释放物理内存,当需要从Swap中读取数据的时候,触发页面置换,之后进行相应的操作。

这个功能不怎么开启

内存置换和swap是有区别的。