RGA(六)——调试方法论:日志与 debugfs 节点

0 阅读12分钟

一、HAL 层日志开关

HAL 层日志就是 librga.so 内部的打印。默认关闭,需要手动打开。

1.1 Linux 平台

FAQ 第 3.1.1 节原文:

Linux 平台支持通过设置环境变量的方式(librga 1.9.0 版本以上),开启/关闭 HAL 层日志打印:

  • 开启日志打印:export ROCKCHIP_RGA_LOG=1
  • 设置日志等级:日志等级分为全打印(0)、DEFAULT(1)、DEBUG(3)、INFO(4)、WRANING(5)、ERROR(6)
  • export ROCKCHIP_RGA_LOG_LEVEL=6

1.2 Android 平台

FAQ 第 3.1.1 节原文:

  • 开启日志打印:setprop vendor.rga.log 1,然后 logcat -s librga
  • 设置日志等级:setprop vendor.rga.log_level 6

1.3 使用建议

日常跑 demo 时关掉,避免 debug 日志淹没性能数据:

unset ROCKCHIP_RGA_LOG
unset ROCKCHIP_RGA_LOG_LEVEL
./3-best 2>&1 | tee log.txt

排查问题时打开,看 librga 传给驱动的参数:

export ROCKCHIP_RGA_LOG=1
export ROCKCHIP_RGA_LOG_LEVEL=6
./demo 2>&1 | tee debug.log

二、HAL 层日志怎么读

FAQ 第 3.1.2 节给出了一段完整的 librga 运行日志,逐行解读如下。

2.1 传入 librga 的参数

D librga : <<<<-------- print rgaLog -------->>
D librga : src->hnd = 0x0 , dst->hnd = 0x0 , src1->hnd = 0x0
D librga : src: Fd = 00 , phyAddr = 0x0 , virAddr = 0xb400007431ed6040
D librga : dst: Fd = 00 , phyAddr = 0x0 , virAddr = 0xb400007431b4f040

逐字段含义:

字段含义
src->hnd / dst->hnd / src1->hnd三个通道传入的内存句柄值
src: Fd = 00src 通道传入的 DMA_FD
src: phyAddr = 0x0src 通道传入的物理地址
src: virAddr = 0xb400007431ed6040src 通道传入的虚拟地址

注意:Fd = 00 是 librga 打印格式的写法,不是真的 fd = 0。FAQ 里示例日志也这样打印。

2.2 HAL 最终选择的内存类型

D librga : src: Fd = -01 , buf = 0xb400007431ed6040, mmuFlag = 1, mmuType = 0
D librga : dst: Fd = -01 , buf = 0xb400007431b4f040, mmuFlag = 1, mmuType = 0
字段含义
Fd = -01最终没有选择 DMA_FD(因为传入了虚拟地址)
buf最终传给驱动的地址
mmuFlag = 1使能 MMU
mmuType = 0MMU 类型

这一行告诉你:HAL 层最终把哪个地址传给了驱动。

2.3 模式信息

E librga : blend = 0 , perpixelAlpha = 1
D librga : scaleMode = 0 , stretch = 0;
E librga : rgaVersion = 3.200000 , ditherEn = 0
D librga : srcMmuFlag = 1 , dstMmuFlag = 1 , rotateMode = 0
字段含义
blend = 0混合模式(0 表示不混合)
perpixelAlpha = 1图像格式本身有 Alpha 值
scaleMode = 0缩放模式(RGA1 特有)
rgaVersion = 3.200000硬件版本号
ditherEn = 016 阶灰度图(Y4)dither 使能
srcMmuFlag / dstMmuFlagMMU 使能标志
rotateMode = 0旋转模式

2.4 配置入驱动的参数(重点)

E librga : <<<<-------- rgaReg -------->>
E librga : render_mode=0 rotate_mode=0
E librga : src:[0,b400007431ed6040,b400007431fb7040],x-y[0,0],w-h[1280,720],vw-vh[1280,720],f=0
E librga : dst:[0,b400007431b4f040,b400007431c30040],x-y[0,0],w-h[1280,720],vw-vh[1280,720],f=0
E librga : pat:[0,0,0],x-y[0,0],w-h[0,0],vw-vh[0,0],f=0
E librga : ROP:[0,0,0],LUT[0]
E librga : color:[0,0,0,0,0]
E librga : MMU:[1,0,80000521]
E librga : mode[0,0,0,0]

src 和 dst 行的字段含义(FAQ 里的解读):

位置含义
[0, b400007431ed6040, b400007431fb7040]三个 plane 地址(Y / UV / V)
x-y[0,0]偏移量(x_offset, y_offset)
w-h[1280,720]实宽实高(active width/height)
vw-vh[1280,720]虚宽虚高(virtual width/height = stride)
f=0格式

这三行就是判断"虚宽实宽有没有配错"的关键。 如果 x + w > vw,就会看到 err ws[...] 报错。

2.5 其他参数

E librga : pat:[0,0,0],x-y[0,0],w-h[0,0],vw-vh[0,0],f=0     ← pat/src1 通道,未使用
E librga : ROP:[0,0,0],LUT[0]                                ← ROP 模式、LUT 表
E librga : color:[0,0,0,0,0]                                 ← colorkey、填充色
E librga : MMU:[1,0,80000521]                                ← MMU 配置
E librga : mode[0,0,0,0]                                     ← palette、csc、colorkey

这些通常不用关心,除非你调 ROP / colorkey / MMU。


三、驱动调试节点

FAQ 第 3.2 节。驱动调试节点比 HAL 层日志更底层,能看到驱动真正下发给硬件的东西。

3.1 节点路径

不同驱动的调试节点不同:

驱动名称调试节点路径
RGA Device Driverrga_debug
RGA2 Device Driver(无版本号)rga2_debug
RGA2 Device Driver(v2.1.0)rkrga
RGA multicore Device Driverrkrga

RK3588 用的是 multicore 驱动,所以节点是 /sys/kernel/debug/rkrga/。

FAQ 原文:

不同的 SDK kernel 的配置不同,通常 RGA 的调试节点存在在以下两个目录其中一个或者均存在:

  • 使用默认使能 CONFIG_ROCKCHIP_RGA_DEBUG_FS 编译选项的 kernel:/sys/kernel/debug
  • 使能 ROCKCHIP_RGA_PROC_FS 编译选项的 kernel:/proc

3.2 六个子命令

FAQ 第 3.2.3.2.1 节给出六个命令,切换方式相同,每次 echo 切换状态:

命令作用
echo reg > debug打印每次 RGA 工作的寄存器配置值
echo msg > debug打印上层调用驱动传递的参数
echo time > debug打印每一次调用 RGA 工作的耗时
echo int > debugRGA 进入中断后打印中断寄存器和状态寄存器当前值
echo check > debug开启内部测试 case,每次工作时检查参数、内存与对齐。若内存存在越界,将会导致内核 crash。可以通过 crash 前的打印确认是 src 还是 dst 的问题
echo stop > debug开启后 RGA 不工作直接返回,用于特殊情况的调试
echo slt > debug让驱动执行内部 SLT case 测试硬件是否正常。若输出 rga slt success!! 表示功能正常

注意:这些日志的打印级别是 KERNEL_DEBUG,必须 dmesg 才能看到。

3.3 一次完整的驱动日志抓取

cd /sys/kernel/debug/rkrga/

# 查看当前开关状态
cat debug

# 打开 msg 和 time
echo msg  > debug
echo time > debug

# 确认已打开
cat debug

# 清空内核日志缓冲
dmesg -c

# …… 运行你的程序 ……
./demo

# 取出这一轮日志
dmesg -c

# 关闭
echo msg  > debug
echo time > debug

3.4 time 模式日志(FAQ 第 3.2.3.2.2 节)

librga 1.3.0 以下版本:

rga3_reg: set cmd use time = 196            // 开始处理请求到配置寄存器的耗时
rga_job: hw use time = 554                  // 硬件启动到硬件中断返回耗时
rga_job: (pid:3197) job done use time = 751  // 开始处理请求到请求完成的耗时
rga_job: (pid:3197) job clean use time = 933 // 开始处理请求到请求资源处理完毕的耗时

librga 1.3.0 及以上版本:

rga_mm: request[3300], get buffer_handle info cost 188 us    // 获取 buffer_handle 信息
rga3_reg: request[3300], generate register cost time 2 us    // 生成寄存器配置
rga3_reg: request[3300], set register cost time 301 us       // 配置寄存器
rga_job: request[3300], hardware[RGA3_core0] cost time 539 us // ★ 硬件核心完成任务
rga_mm: request[3300], put buffer_handle info cost 153 us    // 释放 buffer_handle
rga_job: request[3300], job done total cost time 1023 us     // ★ 从提交到完成返回用户态
rga_job: request[3300], job cleanup total cost time 1030 us  // 从提交到资源释放完毕

怎么用这组数据(FAQ 建议):

现象判断
hardware cost 大真的在跑,看是否符合理论值(第五篇公式)
get/put buffer_handle 大(几百 us)你踩了 buffer pool 的坑,或用了虚拟地址/cacheable buffer
job done total ≫ hardware cost大量时间花在调度与映射上,检查 buffer 是否复用、是否有多核争抢

四、四个状态查询节点

FAQ 第 3.2.3.3 ~ 3.2.3.7 节。

4.1 版本信息 driver_version

cat /sys/kernel/debug/rkrga/driver_version
# → RGA multicore Device Driver: v1.2.23

4.2 负载查询 load

cat /sys/kernel/debug/rkrga/load

FAQ 给出的示例输出:

num of scheduler = 3              // 当前搭载硬件核心数
================= load =================
scheduler[0]: rga3_core0
         load = 0%                // 对应核心负载占比
-----------------------------------
scheduler[1]: rga3_core1
         load = 0%
-----------------------------------
scheduler[2]: rga2
         load = 0%
-----------------------------------

用途:看三颗核的实时负载。如果某颗核长期 100%,说明负载不均衡,可能需要 imconfig 指定核心。

4.3 内存管理器 mm_session

cat /sys/kernel/debug/rkrga/mm_session

FAQ 给出的示例输出:

rga_mm dump:
buffer count = 3                                  // 内存管理器内保存的 buffer 数量
===============================================================
handle = 34 refcount = 1 mm_flag = 0x2 tgid = 3210   // 句柄/引用计数/内存标识/进程号
virtual address:
         va = 0xb400007286e1c000, pages = 0x...ae081f65, size = 3686400
         iova = 0xffc70000, offset = 0x0, sgt = 0x...cc976f9e, size = 3686400, map_core = 0x1
---------------------------------------------------------------
handle = 35 refcount = 1 mm_flag = 0x2 tgid = 3210
virtual address:
         va = 0xb400007286a95000, pages = 0x...2f083efc, size = 3686400
         iova = 0xff8e0000, offset = 0x0, sgt = 0x...62bb1297, size = 3686400, map_core = 0x1
---------------------------------------------------------------
handle = 36 refcount = 1 mm_flag = 0x2 tgid = 3210
virtual address:
         va = 0xb40000728670e000, pages = 0x...785fef63, size = 3686400
         iova = 0xff550000, offset = 0x0, sgt = 0x...cdd7688d, size = 3686400, map_core = 0x1

用途:

  • buffer 是否被正确释放:buffer count 是否持续增长
  • 映射到了哪个核心:map_core
  • 句柄、引用计数、进程号:排查"这个 buffer 被谁占着"

4.4 任务请求 request_manager

cat /sys/kernel/debug/rkrga/request_manager

FAQ 给出的示例输出:

rga internal request dump:
request count = 1                                 // 任务管理器内任务请求数量
===============================================================
------------------ request: 200073 ------------------
         set cmd num: 1, finish job: 0, failed job: 0, flags = 0x0, ref = 2
         cmd dump:
                 rotate_mode = 0
                 src: y = 25 uv = 0 v = e1000 aw = 1280 ah = 720 vw = 1280 vh = 720
                 src: xoff = 0, yoff = 0, format = 0x0, rd_mode = 1
                 dst: y=26 uv=0 v=e1000 aw=1280 ah=720 vw=1280 vh=720
                 mmu: mmu_flag=0 en=0
                 alpha: rop_mode = 0
                 yuv2rgb mode is 0
                 set core = 0, priority = 0, in_fence_fd = -1

用途:

  • 卡住时的排查利器:request count 持续增长或 finish job 停滞,说明有任务没完成
  • rd_mode 含义:1 = raster,2 = FBC,3 = tile 16×16

4.5 硬件信息 hardware

cat /sys/kernel/debug/rkrga/hardware

FAQ 给出的示例输出:

rga3_core0, core 1: version: 3.0.76831
input range: 68x2 ~ 8176x8176
output range: 68x2 ~ 8128x8128
scale limit: 1/8 ~ 8
byte_stride_align: 16
max_byte_stride: 32768
csc: RGB2YUV 0xf YUV2RGB 0xf
feature: 0x4
mmu: RK_IOMMU
rga3_core1, core 2: version: 3.0.76831
...(同上)
rga2, core 4: version: 3.2.63318
input range: 2x2 ~ 8192x8192
output range: 2x2 ~ 4096x4096
scale limit: 1/16 ~ 16
byte_stride_align: 4
max_byte_stride: 32768
csc: RGB2YUV 0x7 YUV2RGB 0x7
feature: 0x5f
mmu: RGA_MMU

用途:确认当前搭载的核心数、每颗核的能力。


五、dump 运行数据

FAQ 第 3.2.3.8 节。

5.1 设置 dump 路径

echo /data/rga_image > /sys/kernel/debug/rkrga/dump_path
dmesg -c
# → rga_debugger: dump path change to: /data/rga_image

5.2 设置 dump 帧数

echo 1 > /sys/kernel/debug/rkrga/dump_image
dmesg -c
# → rga_debugger: dump image 1

5.3 运行 RGA,看 dump 结果

# …… 运行 RGA ……
./demo

dmesg -c
# → rga_debugger: dump image to:
#   /data/rga_image/1_core1_src_plane0_virt_addr_w1280_h720_RGBA8888.bin
#   /data/rga_debugger: dump image to:
#   /data/rga_image/1_core1_dst_plane0_virt_addr_w1280_h720_RGBA8888.bin

ls /data/rga_image/
# 1_core1_dst_plane0_virt_addr_w1280_h720_RGBA8888.bin
# 1_core1_src_plane0_virt_addr_w1280_h720_RGBA8888.bin

"没有该节点说明当前 kernel 不支持内核写入写出数据。"

5.4 用途:定位"图像是花的"(FAQ Q2.20)

官方原文:

通常 RGA 的异常不会出现图像花掉的现象,一般遇到这种问题需要先定位问题是否是 RGA 出现的问题,在一些系统流程中需要先确认输入 RGA 的源数据是否已经是异常的,可以通过在调用 RGA 前将内存里的数据调用 fwrite() 写文件出来,查看源数据是否正常。

用 dump_path + dump_image 就能 dump 出 RGA 真正读到的 src 和写出的 dst,对比就知道是输入问题还是 RGA 问题。


六、实战:用 debugfs 排查Color Fill 失败

可以用 debugfs 定位问题:

6.1 打开驱动日志

cd /sys/kernel/debug/rkrga/
echo msg  > debug
echo time > debug
dmesg -c

6.2 运行程序

./demo

6.3 看驱动日志

dmesg -c

如果看到:

rga_policy: start policy on core = 4
rga_policy: RGA2 only support under 4G memory!
rga_policy: optional_cores = 0
rga_policy: invalid function policy
rga_policy: assign core: -1
rga_job: job assign failed

就确认了:Color Fill 落到 RGA2 上,但 buffer 落在 4G 以上,RGA2 访问不了。

这正是 FAQ Q4.6 给的日志。

6.4 对照 cat hardware

cat hardware | grep -A 2 "rga2"
# rga2, core 4:
# ...
# mmu: RGA_MMU          ← 32bit IOMMU,只支持 4G 内

看到 RGA_MMU,就知道 RGA2 只支持 4G 内。 对照 rga3_core0/1 的 RK_IOMMU(40bit),就明白为什么 Color Fill 必须用 dma32。


七、本篇小结

第一,HAL 层日志用环境变量开关:

  • export ROCKCHIP_RGA_LOG=1
  • export ROCKCHIP_RGA_LOG_LEVEL=6

第二,HAL 层日志看 src / dst 的 x-y、w-h、vw-vh:这是判断"虚宽实宽有没有配错"的关键。

第三,驱动调试节点在 /sys/kernel/debug/rkrga/,六个子命令:

  • msg:看上层传的参数
  • time:看硬件耗时
  • reg:看寄存器配置
  • check:检查参数/内存/对齐(越界会 crash)
  • stop:让 RGA 不工作
  • slt:硬件自检

第四,四个状态查询节点:

  • driver_version:驱动版本
  • load:三颗核的负载
  • mm_session:内存管理器状态
  • request_manager:任务请求状态
  • hardware:硬件拓扑

第五,dump_path + dump_image 能把 RGA 真正读到的 src 和写出的 dst dump 到文件,用于定位"图像是花的"。

第六,time 模式日志分四段:

  • get/put buffer_handle:映射耗时
  • generate/set register:寄存器配置耗时
  • hardware[RGAx_corex]:硬件真正执行耗时
  • job done total:从提交到返回用户态的全程耗时

对比 job done total 和 hardware cost,就知道时间花在哪。

第七,日志打印级别是 KERNEL_DEBUG,必须 dmesg 才能看到,cat /var/log/syslog 看不到。