← 返回课程

性能优化

Camera全栈开发(Qcom Camx) 第 25 / 30 节

第 23 章:性能优化 ⭐


本章导读

性能优化是测量 → 分解 → 定位 → 验证的科学流程。

23.1 性能问题排查的标准流程

在提交 Camera 性能问题给高通分析之前,先完成以下排查步骤:

Step 1: 先确认是不是系统层面的问题

让性能团队做 breakdown:
  - CPU 频率是否跑在预期值?
  - CPU 调度策略是否正确?(大核/小核分配)
  - Power hint / perflock 是否生效?
  - 如果是系统负载导致的掉帧 → 先通性能团队调参

Step 2: 关掉日志再试

# 日志输出会影响系统负载,关掉所有日志后再测试
adb shell stop logd
adb shell stop logcat

# 在 camxoverridesettings.txt 中关闭所有日志
logVerboseMask=0x00000
logInfoMask=0x00000
traceGroupsEnable=0x00000
logEntryExitMask=0x00000
systemLogEnable=FALSE

# kernel 日志也关掉
adb shell "echo 0x0 > /sys/module/cam_debug_util/parameters/debug_mdl"

Step 3: 确认 Sensor 输出正常(SOF)

在 systrace 中检查 SOF(Start of Frame)IRQ:
  正常 30fps → SOF 间隔 33.3ms
  正常 60fps → SOF 间隔 16.6ms
  如果 SOF 间隔不稳定 → sensor 或 3A 问题

Step 4: 确认使用 perf build

测试性能必须使用 perf build(非 debug build)
debug build 有额外的日志和检查操作,影响性能数据

23.2 启动时间优化

启动时间分解

从 App 调用 openCamera() 到第一帧预览显示:

T0: App 调用 openCamera()
T1: HAL open() 返回                  ChiContext 初始化、EEPROM 读取 (~100ms)
T2: configure_streams()               Pipeline 创建、Buffer 分配 (~80ms)
T3: 第一帧完成 (CSLMessageHandler)    Sensor 曝光 + ISP 处理 (~50ms)

测量方法

adb logcat -v threadtime -d | grep -E "onOpened|onConfigured|CSLMessageHandler"

优化点

① 尽早 open camera
   App 端尽早调用 openCamera(),不等 UI 完全就绪

② 减少 open 中的延迟
   open camera 只做 HAL open + 注册回调,不需要延迟
   不要在这里做耗时的 I2C 通信

③ 延迟创建非实时 Session
   Offline Session / OIS 初始化可以延迟创建
   高通有 patch 支持 defer non-real time session

④ 优化 Sensor I2C setting array
   减少不必要的寄存器设置(缩短 configure_streams 时间)
   提高 I2C 总线速度(1MHz 代替 400KHz)

⑤ App 侧优化
   不等 SurfaceView 就绪再创建 Session
   先 createSession,第一帧 buffer ready 时间晚于 SurfaceView 就绪

案例:启动慢 500ms

从 logcat 抓到的各阶段耗时:
  10:00:00.000 - openCamera()
  10:00:00.250 - onOpened()           ← 250ms
  10:00:00.380 - onConfigured()       ← 130ms
  10:00:00.480 - CSLMessageHandler    ← 100ms

logcat:
  [CamX] [Sensor] EEPROM read completed: 45ms
  [CamX] [CHI]   ChiContext::Create() completed: 250ms

分析:
  T0-T1 = 250ms → HAL open 太慢,EEPROM 占用 45ms
  T1-T2 = 130ms → configure_streams 偏慢
  T2-T3 = 100ms → 第一帧延迟正常

解决的优先级:
  ① 减少 EEPROM 读取时间(I2C 速度不够)
  ② 优化 I2C setting array(移除不必要的配置)
  ③ 延迟非实时 Session 的创建(Offline/OIS)

23.3 预览帧率优化

帧率公式

帧间隔 = max(曝光时间, ISP 处理时间)
帧率   = 1000ms / 帧间隔

30fps → 帧间隔 33ms
60fps → 帧间隔 16ms

测量实际帧率

# 方法 1: CamX FPS 日志
echo "enableFPSLog=1" >> camxoverridesettings.txt
# logcat: [FPS] Current FPS: 29.8

# 方法 2: CSLMessageHandler 时间戳
adb logcat | grep "CSLMessageHandler"
# 相邻 frameMessage.timestamp 的差 = 帧间隔

# 方法 3: SOF trace(高通推荐,最精确)
adb root
adb shell "echo 1 > /d/tracing/events/camera/enable"
adb shell "echo 1 > /sys/kernel/debug/tracing/options/record-tgid"
# 然后抓 systrace,在 trace 中搜 SOF

Node 处理耗时定位

echo "dumpNodeProcessingInfo=1" >> camxoverridesettings.txt
echo "traceGroupsEnable=0x10080" >> camxoverridesettings.txt
echo "traceOutputEnable=0x10080" >> camxoverridesettings.txt
adb reboot

# logcat 输出:
# [NodeProcessing] IFE: 2.1ms BPS: 3.5ms IPE: 2.8ms

使用 systrace 查看 Node 处理时间:

在 systrace 中搜索 "Node::%s ProcessRequest":
  CAMX_TRACE_SYNC_BEGIN(CamxLogGroupCore, "Node::%s ProcessRequest")
  → Node 开始处理
  CAMX_TRACE_SYNC_END(CamxLogGroupCore)
  → Node 处理结束

HW Node 的 ProcessRequest trace 包括了提交到硬件和等待 CSL Fence 的时间
SW Node 的 ProcessRequest trace 就是 CPU 处理时间

用 "HAL3:RequestTrace" 追踪帧生命周期

在 systrace 中搜索 "HAL3:RequestTrace":

  static int process_capture_request → camxhal3.cpp
  CAMX_TRACE_ASYNC_BEGIN("HAL3:RequestTrace")
  → Request 进入 CamX 管线

  Session::AdvanceMinExpectedResult → camxsession.cpp
  CAMX_TRACE_ASYNC_END("HAL3:RequestTrace")
  → Request 处理完成,结果返回

这个 trace span 完整覆盖了从 request 进入 CamX 到 result 返回的时间。
可以精确测量每帧的延迟。

systrace 中的线程状态解读

在 systrace 中看线程状态条的颜色:

  灰色(Sleeping)   → 线程在休眠,没有工作可做
  蓝色(Runnable)   → 线程可以被调度,但还没被选中
  绿色(Running)    → 线程正在 CPU 上运行
  红色(Interruptible)→ 线程在内核中等待锁(可能 I/O 负载过高)

Camera 性能优化时重点关注:
  - Node 处理线程是不是长时间在红色状态(I/O 瓶颈)
  - CPU 核心是不是合理分配(大核跑高负载 Node)

常见帧率瓶颈及优化

① Node 处理时间过长
   开启 dumpNodeProcessingInfo 定位最慢的 Node
   如果自定义 Node 太慢 → 评估是否必要、能否先降分辨率再处理

② AWB/Stats 处理慢
   检查 subsample 是否启用:
     adb shell "echo logVerboseMask=0x04000200 >> /vendor/etc/camera/camxoverridesettings.txt"
     adb shell "echo logInfoMask=0x04000200 >> /vendor/etc/camera/camxoverridesettings.txt"
     adb reboot

   在 logcat 中搜索 total_Cnt:
     cnt = 768  → subsample 已启用
     cnt = 3072 → subsample 未启用(需要优化)

③ AF 处理慢
   减少 AF ROI 区域
   将 singleWindowProcessingLevel: DYNAMIC → LOW

④ CPU 频率不够
   检查 perflock 是否生效(KBA-190618011520)
   使用 MPCTLV3_SCHED_UPMIGRATE/DOWNMIGRATE 绑定大核
   必要时可解除 core7 隔离

⑤ Stats 各 Node 之间是否可以并行处理
   检查 pipeline 拓扑,无依赖关系的 Node 可以并行

⑥ 自定义 Feature(实时 HDR/实时 Bokeh/实时美颜)
   评估是否需要先降分辨率再处理
   考虑 perflock boost CPU 频率是否生效

暗光下帧率下降

60fps → 帧间隔 16ms → 曝光时间不能超过 16ms
30fps → 帧间隔 33ms → 曝光时间不能超过 33ms

暗光下 AE 把 exposureTime 拉到 66ms:
  [AEC] exposureTime=66000000
  → 帧率上限 = 1000/66 ≈ 15fps

取舍:
  要流畅(30fps) → 限制最大曝光 33ms(提 ISO,噪点多)
  要纯净          → 允许长曝光(帧率下降)

23.4 拍照延迟优化

测量方法

adb logcat -v threadtime | grep -E "ProcessCaptureRequest|ProcessCaptureResult"
# 同一条 requestId 的时间差 = 拍照延迟

# 也可以从 systrace 看 "HAL3:RequestTrace" 的 span 长度

案例:拍照延迟 600ms

logcat 时间线:
  10:00:00.000 ProcessCaptureRequest() frame=42
  10:00:00.100 AE converged
  10:00:00.150 AF locked
  10:00:00.200 CSLMessageHandler() requestID=42      ← ISP 处理完
  10:00:00.600 ProcessCaptureResult() requestId=42   ← JPEG 编码完

瓶颈: JPEG 编码 400ms
验证: adb shell dumpsys media.camera | grep -A 5 "Pipeline"
      如果只有 pipelineId=0 → Offline Pipeline 未启用

23.5 性能分析工具用法汇总

Systrace 完整采集步骤

# Step 1: 在 camxoverridesettings.txt 中配置
traceGroupsEnable=0x10080       # 启用 UMD trace events
traceErrorEnable=TRUE
traceOutputEnable=0x10080

# Step 2: 启用 KMD trace
adb shell "echo 1 > /d/tracing/events/camera/enable"
adb shell "echo 1 > /sys/kernel/debug/tracing/options/record-tgid"

# Step 3: 抓取 systrace
systrace.py gfx camera view input sched freq video idle -b 20480 -t 5 -o trace.html

不同场景的 traceGroupsEnable 值:

0x10080      → 基本 Camera trace
0x40100C0    → 含 AWB 详细 trace
0x80100C0    → 含 AF 详细 trace
0x12080      → 含 multi-camera SAT trace
0xFFFFFFFF   → 全部 trace(性能影响大,只在必要时用)

Simpleperf(CPU 热点分析)

adb shell "/system/bin/simpleperf record -p <camera_provider_pid> \
    --callgraph fp -o /data/misc/perf.data --duration 10"
adb shell "/system/bin/simpleperf report -i /data/misc/perf.data -g \
    --full-callgraph > /data/misc/report_callgraph.txt"
adb pull /data/misc/report_callgraph.txt

添加调试 trace

在怀疑有耗时的代码位置添加 systrace tag:

#define ATRACE_TAG ATRACE_TAG_ALWAYS
ATRACE_BEGIN("CustomTag");
// 需要观测耗时的代码
ATRACE_END();

23.6 本章总结

性能问题排查流程:
  perf build → 关日志 → 确认 SOF → 检查 Node → 加 trace

关键工具:
  traceGroupsEnable=0x10080   → systrace
  dumpNodeProcessingInfo=1     → Node 耗时
  enableFPSLog=1               → 实时帧率
  SOF trace                    → Sensor 帧间隔
  HAL3:RequestTrace            → 帧生命周期
  Simpleperf                   → CPU 热点

优化方向:
  启动: 尽早 open + 延迟非实时 Session + I2C 优化
  帧率: Node 并行 + AWB subsample + AF ROI + 绑定大核
  拍照: Offline Pipeline + 硬件 JPEG 编码