文章

Trace工具

Trace工具

可观测性技术

可观测性技术是一个系统性工程,它能够让你更深入的了解软件里发生的事情。可用于了解软件系统内部运行过程(特别是对于业务逻辑或者交互关系复杂的系统)、排查问题甚至通过寻找瓶颈点优化程序本身。对于复杂的系统来说,你通过阅读代码来了解整个运行过程其实是很困难的事情,更高效的方法就是借助此类工具,以最直观的的方式获取软件运行的状态。

下面将从 数据类型数据获取方法分析方法 这三个主题来帮助你了解可观测性技术。

数据类型

日志的形式可能是键值对(key=Value),JSON、CSV,关系型数据库或者其他任何格式。其次我们通过日志还原出系统当时运行的整个状态,目的是为了解决某个问题,观察某个模块的运行方式,甚至刻画系统使用者的行为模式。在可观测性技术上把日志类型分类为 Log 类型Metric 类型,以及 Trace 类型

![image.png600](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian202406120047183.png)

Log 类型

Log 是最朴素的数据记录方式,一般记录了什么模块在几点发生了什么事情,日志等级是警告还是错误。几乎所有的 Log 类型是通过 string 类型的方式存储,数据呈现形式是一条一条的文本数据。Log 是最基本的类型,因此通过转换,可以将 Log 类型转换成 Metric 或者 Trace 类型。

为了标识出不同的日志类型等级,一般使用 错误警告调试 等级别来划分日志等级。

Metric 类型

Metric 类型,它记录的是某个维度上数值的变化。知识点是「维度」与「数值」的变化。维度可能是 CPU 使用率CPU Cluster 运行频率,或者 上下文切换次数。数值变化既可以是采样时候的瞬时值(成为快照型)、与前一次采样时的差值(增或减)、或者某个时段区间的统计聚合值。

Metric 类型的另外一个好处是它的内容格式是比较固定的,因此可以通过预编码的方式进行数据存储,空间的利用率会更紧凑进而占用的磁盘空间就更少。最简单的应用就是数据格式的存储上,如果使用 Log 类型,一般采用的是 ASCII 编码,而 Metric 使用的是整数或者浮点等固定 byte 数的数据,当存储较大数值时显然 ASCII 编码需要的字节数会多于数字型数据,并且在进行数据处理的时候你可以直接使用 Metric 数据,而不需要把 Log 的 ASCII 转换成数字型后再做转换。

Trace 类型

Trace 类型标识了 事件发生的时间名称耗时。多个事件通过关系,标识出了是父与子还是兄弟。当分析多个线程间复杂的调用关系时 Trace 类型是最方便的数据分析方式。

Trace 类型特别适用于 Android 应用与系统级的分析场景,因为用它可以诊断:

  1. 函数调用链
  2. Binder 调用时的调用链
  3. 跨进程事件流跟踪

Trace 类型可以由你手动添加开始与结束点,在一个函数里可以添加多个这种区间。通过预编译技术或者编程语言的特性,在函数的开头与结尾里自动插桩 Trace 区间。理想情况下后者是最好的方案,因为我们能知道系统中运行的所有的函数是哪些、执行情况与调用关系是什么。可以拿这些信息统计出调用次数最多(最热点)的函数是什么,最耗时的函数又是什么。可想而知这种方法带来的性能损耗非常大,因为函数调用的频次跟量级是非常大的,越是复杂的系统量级就越大。

因此有一种迂回的方法,那就通过采样获取调用栈的方式近似拟合上面的效果。采样间隔越短,就越能拟合真实的调用关系与耗时,但间隔也不能太小因为取堆栈的操作本身的负载就会变高因为次数变多了。这种方法,业界管他叫 Profiler,你所见过的绝大部分编程语言的 Profiler 工具都是基于这个原理实现的。

数据获取方法

![image.png600](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian202406120106461.png)

数据采集方式

静态代码

静态代码的采集方式是最原始的方式,优点是实现简单,缺点是每次新增内容的时候需要重新编译、安装程序。当遇到问题之后你想看的信息恰好没有的话,就没有任何办法进一步定位问题,只能重新再来一遍整个过程。更进一步的做法是预先把所有可能需要的地方上加入数据获取点,通过动态判断开关的方式选择是否输出,这既可以控制影响性能又能够在需要日志的时候可以动态打开,只不过这种方法的成本非常高。

动态跟踪

动态跟踪技术其实一直都存在,只是它的学习成本比较高,被誉为调试跟踪领域里的屠龙刀。它需要你懂比较底层的技术,特别是编译、ELF 格式、内核、以及熟悉代码中的预设的探针、动态跟踪所对应的编程语言。对,你没看错,这种技术甚至还有自己的一套编程语言用于「动态」的实现开发者需求。这种方式兼具性能、灵活性,甚至线上版本里遇到异常后可以动态查看你想看的信息。

Android 应用开发、系统级开发中用的比较少,内核开发中偶尔会用一些。只有专业、专职的性能分析人员才可能会用上这类工具。它有两个关键点,探针与动态语言,程序运行过程中需要有对应的探针点将程序执行权限交接到动态跟踪框架,框架执行的逻辑是开发者使用动态语言来编写的逻辑。

所以,你的程序里首先是要有探针,好在 Linux 内核等框架埋好了对应的探针点,但是 Android 应用层是没有现成的。所以目前 Android 上能用动态框架,如 eBPF 基本都是内核开发者在使用。

触发条件

无条件抓取

无条件式抓取比较好理解,触发抓取之后不管发生任何事情,都会持续抓取数据。缺点是被观测对象产生的数据量非常大的时候可能会对系统造成比较大的影响,这种时候只能通过降低数据量的方式来缓解。需要做到既能满足需求,性能损失又不能太大。

有条件抓取

有条件式抓取经常用在可以识别出的异常的场景里。比如当系统的某个观测值超过了预先设定的阈值时,此时触发抓取日志并且持续一段时间或者达到另外一种阈值之后结束抓取。这相比于前面一个方法稍微进步了一些,仅在出问题的时候对系统有影响,其他时候没有任何影响点。但它需要你能够识别出异常,并且这种异常是不需要异常发生之前的历史数据。当然你可以通过降低阈值来更容易达到触发点,这可能会提高触发数据抓取的概率,这时候会遇到前面介绍的无条件式抓取遇到的同样的问题,需要平衡性能损失。

落盘策略

持续落盘是存储整个数据抓取过程中的所有数据,代价是存储的压力。

如果能知道触发点,比如能够检测到异常点,这时候可以选择性的落盘。为了保证历史数据的有效性,因此把日志先暂存储到 RingBuffer 中,只有接受到落盘指令后再进行落盘存储。这种方式兼顾了性能与存储压力,但成本是运行时内存损耗与触发器的准确性。

分析方式

![image.png600](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian202406120113199.png)

谷歌提供的 Android 性能分析工具

初代系统性能分析工具 - Systrace

Systrace 是 Trace 类型的可视化分析工具,是第一代系统级性能分析工具。Trace 类型所支持的功能它都有支持。在 Perfetto 出现之前,基本上是唯一的性能分析工具,它将 Android 系统和 App 的运行信息以图形化的方式展示出来,与 Log 相比,Systrace 的图像化方式更为直观;与 TraceView 相比,抓取 Systrace 时候的性能开销基本可以忽略,最大程度地减少观察者效应带来的影响。

[[01-Systrace入门]]

新一代性能分析全栈工具 - Perfetto

官网上号称它是下一代面向可跨平台的 Trace/Metric 数据抓取与分析工具。应用也比较广泛,除了 Perfetto 网站,Windows Performance Tool 与 Android Studio,以及华为的 GraphicProfiler 也支持 Perfetto 数据的可视化与分析。 我们相信谷歌还会持续投入资源到 Perfetto 项目,可以说它应该就是下一代性能分析工具了,会完全取代 Systrace。

[[Perfetto入门]]

Android Studio Profiler 工具

Profiler 是一个集合体,集成了多种性能分析工具于一体,让开发者可以在 Android Studio 做开发应用,也不用再下载其它工具就能让能做性能调优工作。

目前 Android Studio Profiler 已经集成了 4 类性能分析工具: CPUMemoryNetworkBattery,其中 CPU 相关性能分析工具为 CPU Profiler,也是本章的主角,它把 CPU 相关的性能分析工具都集成在了一起,开发者可以根据自己需求来选择使用哪一个。可能很多人都知道,谷歌已经开发了一些独立的 CPU 性能分析工具,如 PerfettoSimpleperf、Java Method Trace 等,现在又出来一个 CPU Profiler,显然不可能去重复造轮子,CPU Profiler 目前做法就是:从这些已知的工具中获取数据,然后把数据解析成自己想要的样式,通过统一的界面展示出来。

  • [[Android Studio Profiler入门]]

性能优化工具对比

工具名称应用场景数据类型获取方法分析方式
SystraceAndroid 系统与应用性能分析Trace 类型无条件抓取 持续落盘可视化分析
PerfettoAndroid 系统与应用性能分析Metric 类型 Trace 类型无条件抓取 持续落盘可视化分析 数据库分析
AS ProfilerAndroid 系统与应用性能分析Trace 类型无条件抓取 持续落盘可视化分析
SimplePerfJava/C++ 函数执行耗时 分析 PMU 计数器Trace 类性无条件抓取 持续落盘可视化分析 文本分析
Snapdragon Profiler Tools & Resources主要是高通 GPU 性能分析器Trace 类型 Metric 类型无条件抓取 持续落盘可视化分析
Mali Graphics DebuggerARM GPU 分析器(MTK、麒麟芯片)Trace 类型 Metric 类型无条件抓取 持续落盘可视化分析
Android Log/dumpsys综合分析Log 类型有条件抓取 持续抓取但不落盘文本分析
AGI(Android GPU Inspector)Android GPU 分析器Trace 类型 Metric 类型无条件抓取 持续落盘可视化分析
eBPFLinux 内核行为动态跟踪Metric 类型动态跟踪 有条件抓取 持续抓取但不落盘文本分析
FTraceLinux 内核埋点Log 类型静态代码有条件抓取持续抓取但不落盘文本

做好性能优化,不仅需要趁手的工具,而且对工具的要求还很高,具体来说,必需满足要求:

  • 高性能,保证自身高性能,以防带偏优化方向
  • 多维度,能监控多维度信息,帮助全面发现问题
  • 易用性,方便的可视化界面,方便分析

目前业界主流的 APP 性能探测工具有 TraceView、CPU Profiler、Systrace、Perfetto。

![700](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian202406272354160.png)

Perfetto 提供了强大的 Trace 分析模块:Trace Processor,可以把多种类型的日志文件(Android systracePerfettolinux ftrace)通过解析、提取其中的数据,结构化为 SQLite 数据库,并且提供基于 SQL 查询的 Python API,可通过 python 实现自动化分析;同时有良好的可视化页面,可通过可视化页面查看火焰图和写 SQL 进行 Trace 分析。

从性能、监控维度的丰富程度和提供的配套的分析和可视化工具来选择,Perfetto 是最好的选择,但前期由于 Perfetto 是9.0以后默认内置服务但是默认不可用,Android 11服务才默认可用,对低版本系统支持不够,所以需要选择 Systrace+Perfetto 工具结合,可覆盖所有 Android 系统。

本文由作者按照 CC BY 4.0 进行授权