Camera HAL性能优化中Perfetto分析 - 第1节
1.1 Perfetto 是什么
Perfetto 是 Google 在 Android 10 之后推出的新一代全平台性能追踪与剖析基础设施。它统一了内核级与用户级的 trace 数据采集,覆盖 CPU、GPU、内存、调度、I/O、显示管线、Camera HAL 等子系统,并提供基于 SQL 的深度分析能力。
与旧工具相比,Perfetto 的核心设计理念是:一次 trace,全栈可见。它不再局限于 Java 层或 Native 层的某一部分,而是将 Linux 内核的 ftrace、atrace、heapprofd、perf 等多种数据源整合到同一个时间轴中。
- 支持长达数十分钟的高精度 trace 录制(默认 30 秒,可配置)
- 数据源可插拔:ftrace、atrace、heapprofd、perf、power rails、frame timeline 等
- 基于 protobuf 的二进制 trace 格式,体积小、解析快
- 提供 Web UI(ui.perfetto.dev)和命令行工具(perfetto、traceconv)
- 支持 SQL 查询分析,可自定义指标和切片
1.2 Perfetto 与 Systrace 的关系
Systrace 是 Android 4.1 引入的旧版 trace 工具,基于 Python 脚本和 atrace 命令,主要面向应用层和 Framework 层。Perfetto 是其官方继任者,两者关系如下:
| 对比维度 | Systrace | Perfetto |
|---|---|---|
| 数据源 | atrace + 部分 ftrace | ftrace、atrace、heapprofd、perf、power rails、frame timeline 等 |
| trace 时长 | 通常 5~10 秒,过长易丢帧 | 支持 30 秒~数分钟,大 buffer 不丢数据 |
| 文件格式 | HTML(含可视化) | protobuf 二进制(.perfetto-trace) |
| 分析能力 | 仅可视化浏览 | 可视化 + SQL 查询 + 自定义指标 |
| Camera HAL 支持 | 仅 atrace marker,深度不足 | 支持 HAL 层自定义 trace、buffer 状态、帧边界 |
| 维护状态 | 已停止功能更新 | 活跃开发,Android 14+ 默认工具 |
systrace.py 命令,底层实际调用的也是 Perfetto 的 traced 服务。建议新项目直接使用 Perfetto 工作流。
1.3 Perfetto 在 Camera HAL 优化中的核心价值
Camera HAL 性能优化的难点在于:多线程、多流水线、硬件交互密集。一次拍照或预览涉及 ISP、DMA、GPU、HAL 线程、Framework 回调等多个环节,任何一个环节的延迟或阻塞都会导致卡顿、丢帧或 ANR。
Perfetto 为 Camera HAL 优化提供了以下不可替代的能力:
1.3.1 全链路时间轴对齐
Perfetto 将内核调度、中断、HAL 函数调用、Framework 回调、SurfaceFlinger 合成等事件统一到同一条时间轴上。优化者可以一眼看出:
- 某个帧的 HAL 处理耗时是否被内核调度延迟拉长
- ISP 中断响应是否及时
- buffer 在 HAL 和 Framework 之间传递的延迟分布
1.3.2 自定义 trace marker 注入
Camera HAL 开发者可以在关键路径上注入自定义 trace 事件,例如:
// 在 HAL 的 processCaptureRequest 中注入
ATRACE_BEGIN("HAL::processCaptureRequest");
// ... 实际处理逻辑 ...
ATRACE_END();
// 在 ISP 回调中标记帧边界
ATRACE_INT("HAL::frame_number", frameNumber);
这些标记会出现在 Perfetto 时间轴上,精确到微秒级,帮助定位具体哪个函数或哪个帧出现了异常。
1.3.3 内存与堆分析
通过 heapprofd 数据源,Perfetto 可以追踪 Camera HAL 进程的内存分配热点,识别:
- buffer 泄漏或未及时释放
- 大块内存分配导致的 GC 或抖动
- gralloc 分配与释放的时序
1.3.4 帧边界与 pipeline 分析
Perfetto 的 Frame Timeline 功能可以自动识别 Camera 帧的边界(从 HAL 接收到 SurfaceFlinger 合成),并以可视化的方式展示每一帧的耗时分布。这对于定位“哪一帧卡了”以及“卡在哪个阶段”至关重要。
processCaptureRequest 函数本身耗时正常(8ms),但每次调用前都有一个 15ms 的 doSchedYield 调度延迟。进一步分析 ftrace 调度数据,发现是 CPU 调频策略导致 HAL 线程被迁移到小核。优化方案:绑定 HAL 线程到大核 + 调整 cpufreq 策略,帧率恢复至 28fps。