
最近在给一块RK3588平台做YOLOv8部署推理速度总是上不去一开始怀疑模型转换出了问题后来才发现更基础的问题我压根没有确认NPU到底有没有接管计算。当时想查看NPU占用率手边居然没有任何现成的工具只能去翻内核文档。这件事让我意识到很多RK3588开发者的注意力都放在“怎么把代码跑起来”上却普遍缺少一套“怎么确认跑对了”的手段。这篇内容就把RK3588平台上的六个关键硬件模块——CPU、GPU、NPU、VPU、RGA、DDR——的状态查看与操作方式一次讲透。包括频率读取、负载统计、调频调核、问题定位等实操内容适合嵌入式Linux开发者、边缘AI部署工程师、以及正在基于瑞芯微平台做系统移植的朋友参考。我会尽量按实际调试场景来写你拿到板子之后照着敲命令就能用。1. 先搞清楚RK3588这六个模块到底在忙什么1.1 一颗SoC里为什么塞了这么多加速引擎RK3588是瑞芯微的旗舰SoC8nm制程CPU部分是4颗Cortex-A76大核加4颗Cortex-A55小核GPU是Mali-G610 MP4支持OpenGL ES 3.2和Vulkan 1.1NPU是三核架构INT8算力6 TOPSVPU负责8K级别视频编解码RGA做2D图形加速DDR控制器支持LPDDR4/4x/5最高频率可以到4266MT/s以上。这颗芯片的思路很清楚把重复性高的计算任务从CPU上拆出来各自丢给专用硬件单元去跑。视频编解码丢给VPU图像缩放旋转丢给RGA神经网络推理丢给NPU3D渲染和显示合成丢给GPUCPU只承担调度和通用逻辑。这个设计本身没问题但调试的复杂度上来了——因为每个模块都有自己的频率域、电源域和状态寄存器你在系统层面看到的只是“整机负载”判断不出具体瓶颈在哪。1.2 状态查看的本质是什么所谓“状态查看”本质是两件事频率和负载。频率决定模块当前的工作速度负载决定它到底被使唤了多少。两者结合才能判断一个硬件模块是不是真正在干活。以NPU为例如果模型推理很慢你去看NPU频率是300MHz而负载是0%那基本可以断定推理没有跑到NPU上还是CPU在硬算。反之如果频率顶到1GHz且负载接近100%那瓶颈就在NPU本身需要从模型算子角度优化。这就是状态数据的基本价值——有了数据对话才有依据。另外要提醒一点RK3588的驱动在很多固件版本上会输出不同路径的调试节点前面说过老内核和定制内核可能路径不同所以后文列的命令如果遇到No such file or directory优先去巡检对应模块的debugfs目录而不是直接怀疑命令写错。2. CPU状态查看频率、负载与大小核调度2.1 上手就能用的三组基础命令RK3588的CPU在Linux下被抽象为8个逻辑核心cpu0到cpu3对应4颗A55小核cpu4到cpu7对应4颗A76大核。按我习惯刚拿到板子第一件事就是查这八个核的实时频率一条命令全打出来for i in 0 1 2 3 4 5 6 7; do echo cpu$i: $(cat /sys/devices/system/cpu/cpu$i/cpufreq/cpuinfo_cur_freq) kHz donecpuinfo_cur_freq是当前实际频率单位kHz。这个值会随负载自动变化如果你看到小核在1.8GHz、大核在2.0GHz左右浮动都是正常的。想确认每个核心被系统识别成哪种型号直接查CPU信息cat /proc/cpuinfo | grep -E processor|model name|CPU partCPU part一列可以看到0x804A76和0x805A55这样的数字或者直接看Processor项后面会标注ARMv8-A architecture variant。搭配top -H或者mpstat -P ALL能同时看到每个核的占用率。如果没有mpstat先装sysstatsudo apt install sysstat跑一遍mpstat -P ALL 1它会每秒刷新一次把单核使用率清楚列出来。对于判断大小核调度是否合理这个结果非常直观。2.2 手动调频与核心启停的实操细节如果发现系统默认的调频策略不合适可以手动干预。RK3588的CPU调频通过cpufreq框架管理操作方式很标准。先看当前策略cat /sys/devices/system/cpu/cpu4/cpufreq/scaling_governor默认通常是ondemand或者schedutil。需要手动锁定频率时先切到userspace再写入目标频率echo userspace /sys/devices/system/cpu/cpu4/cpufreq/scaling_governor echo 1800000 /sys/devices/system/cpu/cpu4/cpufreq/scaling_setspeed注意写入频率时必须用scaling_setspeed不是直接写cpufreq目录下的cpuinfo_*文件那些是只读的。想要让所有大核统一锁频写个循环for i in 4 5 6 7; do echo userspace /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor echo 1800000 /sys/devices/system/cpu/cpu$i/cpufreq/scaling_setspeed done核心启停操作则通过online节点控制。例如把cpu6暂时关掉echo 0 /sys/devices/system/cpu/cpu6/online关核时千万注意别把当前SSH所在的CPU关掉建议先确认当前进程运行在哪个核上。用taskset -c 4-7绑定可以避免进程被调度到小核对AI推理类任务很关键。注意userspace模式设置锁频后如果系统没有cooling device干预CPU温度会快速上升。实测RK3588大核锁频到1.8GHz跑满两分钟温度能上到75度左右建议配合散热风扇并在测试后及时恢复schedutil。2.3 实测心得大核小核分工是有讲究的调RK3588跑YOLOv8的时候我起初把所有线程都丢给大核CPU占用率看着不高但推理延迟反而上去了。后来排查发现UI线程、日志线程和模型预处理线程都在抢大核时间片喂给NPU的数据经常断流。我的做法是把推理调度线程绑到cpu4到cpu7绑定视频采集和图像预处理到cpu0到cpu3让大核专注做数据供给小核负责网络服务和日志。实测帧率从27fps提升到35fps左右这中间的差距全是调度策略带来的。3. GPU状态查看Mali-G610的利用率与频率观测3.1 devfreq节点读GPU频率RK3588的GPU在设备树里的节点名通常包含fdab0000.gpu对应/sys/class/devfreq/fdab0000.gpu。查看当前频率cat /sys/class/devfreq/fdab0000.gpu/cur_freq查看支持的频率列表cat /sys/class/devfreq/fdab0000.gpu/available_frequenciesGPU频率是动态调度的空闲时可能掉到很低比如297MHz满载时会冲到1GHz上下。不过频率高不代表利用率高只能说明有计算需求在拉频率真正的占用数据要从Mali内核驱动里拿。3.2 通过debugfs读GPU实时占用Mali GPU驱动在挂载debugfs之后会暴露实时统计节点。先确保debugfs已经挂载mount -t debugfs debugfs /sys/kernel/debug然后读取GPU占用数据cat /sys/kernel/debug/mali/device/utilisation输出通常是三个数字我习惯把它们理解为GPU在内核采样周期内的忙碌、阻塞和空闲占比。数字含义在不同内核版本上有微调但只要看到第一个数字明显高企就说明GPU正在高负荷渲染。如果想直观跑一个GPU压力测试glmark2-es2是便捷选择sudo apt install glmark2-es2 glmark2-es2跑分过程中切到另一个终端同时观察utilisation节点你会发现第一个数字直线上升频率也顶到最高档。这套组合拳在验证GPU驱动是否正常工作时很有用。注意debugfs节点不是每个固件都有。有些第三方固件关闭了Mali debugfs相关配置读不到utilisation时可以退而求其次观察cur_freq的变化曲线或者编译内核时打开Mali的CONFIG_MALI_DEBUG选项。3.3 GPU调用排查的一个高频假象经常有人跑来问GUI界面明明很卡但GPU频率和利用率都不高是不是GPU坏了我遇到过两次最后定位都是CPU侧的渲染线程有问题。因为Mali-G610的渲染需要CPU不断提交绘制命令如果CPU被其他任务占满GPU就是等米下锅的状态利用率和频率自然起不来。排查时不要只盯GPU的状态同时开mpstat -P ALL 1看CPU如果显示多个核被某个渲染进程打满先解决CPU瓶颈再看GPU数据。这一点在外接HDMI显示输出的应用场景里很容易踩中。4. NPU状态查看算力有没有吃上一眼看穿4.1 从rknpu驱动节点读NPU负载NPU是RK3588上最强悍也最容易用错的部分。它由三个独立的NPU核心组成在/sys/kernel/debug/rknpu/目录下能看到驱动暴露的调试信息。最常见的查询命令cat /sys/kernel/debug/rknpu/load输出类似load: core0: 80%, core1: 65%, core2: 0%三个数字分别代表三个NPU核心的负载。跑单模型推理时通常会看到一个核占满、另外两个空闲这是正常现象因为RKNN运行时默认把单模型绑定到单个核上。如果你激活了多模型并发那么也能看到多个核同时被拉高。还有部分固件保留了/proc/rknpu用cat /proc/rknpu能看到驱动版本和负载摘要。这两个路径在不同内核上的差异比较大我习惯先ls看一下再决定用哪个。4.2 通过devfreq看NPU频率和电源域NPU同样被devfreq管理设备节点一般叫fdab0000.npucat /sys/class/devfreq/fdab0000.npu/cur_freq cat /sys/class/devfreq/fdab0000.npu/available_frequenciesRK3588的NPU频率通常从300MHz到1GHz左右动态变化。这里有一个判断技巧当模型推理正在进行时cur_freq应该自动跳到较高档位。如果推理时NPU频率纹丝不动且load节点全为0那基本可以断定推理逻辑并没有调用到NPU。判断NPU驱动是否正常加载用lsmod | grep rknpu dmesg | grep -i rknpu正常会看到rknpu模块已经在列表里dmesg中有初始化信息。如果驱动没加载后续所有NPU操作都不可能生效。4.3 用rknn-toolkit-lite在板子上直接监控除了内核节点在板子上跑Python时还能用rknn-toolkit-lite的runtime接口获取NPU状态。在Rockchip官方Python环境里安装rknn-toolkit-lite之后可以这样查询from rknnlite.api import RKNNLite rknn RKNNLite() rknn.load_rknn(/path/to/model.rknn) rknn.init_runtime() # 跑一次推理 output rknn.inference(inputs[input_data]) # 查看NPU状态部分版本支持 print(rknn.get_sdk_version())注意rknn-toolkit-lite主要是推理接口不同版本对NPU状态查询的支持程度不同。最稳妥的判断方法还是回到第4.1节的内核节点。4.4 一个真实的排查案例YOLOv8推理慢朋友遇到过一个问题RK3588上部署YOLOv8NCNN和OpenCV都能正常跑但帧率只有个位数他觉得是NPU没启用。我登录板子后发现NPU负载节点确实全为0频率也停在最低档。进一步查进程发现他跑的是OpenCV的DNN后端也就是CPU推理。转换流程压根没用RKNN工具生成.rknn模型自然不可能调用NPU。后来用rknn-toolkit2把YOLOv8导出成RKNN格式再用rknn-toolkit-lite加载运行NPU负载直接拉满帧率翻了接近10倍。这个案例说明一个核心逻辑NPU不会自动接管模型推理必须显式将模型转换成RKNN格式并用对应runtime调用。状态查看工具在这里的核心价值就是让你第一时间看出“算力到底有没有被真正用上”。5. VPU、RGA、DDR状态查看与操作细节5.1 VPU视频编解码单元的工作确认RK3588的VPU由编码单元和译码单元组成支持H.265/H.264/VP9/AV1等格式的8K编解码。在Linux系统里VPU本身没有像GPU那样丰富的用户态工具你通常看不到一个进程叫“vpu”真正干活的是vpu_service内核服务用户态程序通过libmpp或rockchip-mpp来调用它。确认VPU服务已经启动ps -A | grep -i vpu输出里应该能看到类似vpu_service的进程。接着用ffmpeg配合rkmpp硬件解码来验证解码链路是否通ffmpeg -c:v h264_rkmpp -i input.mp4 -f null -跑的时候开另一个终端观察CPU占用率。如果CPU占用率很低、解码流畅说明VPU确实在干活。如果CPU被打满且解码卡顿很可能没有正确调用h264_rkmpp或者rkmpp插件缺失。如果要查看更细粒度的编解码会话信息部分内核在/sys/kernel/debug/vpu_service/下有clients信息能看到当前接入VPU的进程句柄。这个目录在定制内核上经常没有不用强求。注意硬解8K视频时数据搬运压力对内存带宽影响很大。如果解码画面正常但整机响应变慢优先怀疑DDR带宽而不是VPU本身。5.2 RGA2D加速引擎的占用与调试RGA全称Raster Graphic Acceleration负责图像缩放、旋转、格式转换等2D操作。RK3588集成了RGA2和RGA3两个引擎常见设备节点是/dev/rga和/dev/rga3。系统里通常有rga_service进程ps -A | grep -i rga检查RGA驱动是否正常注册了设备节点ls -l /dev/rga*验证RGA基本功能最好的方式是跑librga自带的测试demo。在RK3588板子上通过Rockchip提供的librga源码编译出im2d_api示例执行缩放、旋转、格式转换等测试用例观察是否返回成功。这个测试能同时验证RGA硬件通路和驱动状态。实际项目中RGA调用很频繁比如摄像头采集YUV数据后缩放到模型输入尺寸很多教程教你用CPU去做但RGA一条硬件指令就能完成效率差出几个数量级。想确认自己的图像库是否在用RGA可以看用户态进程的/proc/PID/syscall或者在执行图像处理时观察CPU占用率有没有明显下降。5.3 DDR频率与带宽观测DDR内存控制器在RK3588 Linux下对应devfreq的dmc节点cat /sys/class/devfreq/dmc/cur_freq cat /sys/class/devfreq/dmc/available_frequenciescur_freq会随负载小幅波动。DDR频率提升对带宽敏感型场景——比如8K视频解码、NPU大尺寸输入——有直接帮助。想看DDR是否成为瓶颈可以用stress-ng压内存sudo apt install stress-ng stress-ng --mem 2G --vm-bytes 1G --timeout 60 压测过程中观察cur_freq是否顶到最高档以及整体系统响应状况。如果频率已经顶格但程序性能依旧不佳问题就在实际带宽利用率的优化上比如内存对齐、DMA分散/聚集配置而不是频率本身。5.4 一张表总结所有状态查看路径模块频率/状态节点负载/占用节点建议工具CPU/sys/devices/system/cpu/cpuN/cpufreq/cpuinfo_cur_freqtop / mpstat -P ALLstress-ng、tasksetGPU/sys/class/devfreq/fdab0000.gpu/cur_freq/sys/kernel/debug/mali/device/utilisationglmark2-es2NPU/sys/class/devfreq/fdab0000.npu/cur_freq/sys/kernel/debug/rknpu/load 或 /proc/rknpurknn-toolkit-liteVPU无典型通用频率节点vpu_service进程、ffmpeg硬解效率ffmpeg (rkmpp)、mppRGA设备节点 /dev/rga*rga_service进程、测试demolibrga im2d_apiDDR/sys/class/devfreq/dmc/cur_freq无直接负载节点以压力和频率判断stress-ng这张表是我自己板子上验证过的常用路径实际固件有出入时按模块名在/sys/kernel/debug和/sys/class/devfreq下ls去寻找对应节点思路是一样的。6. 把这套状态监控沉淀成可持续运维手段6.1 写一个简单的状态收集脚本每次登录板子一条一条敲命令不现实我习惯把状态查看逻辑固化成脚本。下面这个脚本会在终端里循环打印六个模块的温度、频率和核心负载跑起来之后直接挂后台或者配合watch -n 1 ./rk3588_status.sh每隔一秒刷新#!/bin/bash while true; do clear echo RK3588 Status Monitor echo --- CPU freq --- for i in 0 1 2 3 4 5 6 7; do if [ -f /sys/devices/system/cpu/cpu$i/cpufreq/cpuinfo_cur_freq ]; then echo cpu$i: $(cat /sys/devices/system/cpu/cpu$i/cpufreq/cpuinfo_cur_freq) kHz fi done echo --- GPU --- echo gpu freq: $(cat /sys/class/devfreq/fdab0000.gpu/cur_freq) Hz if [ -f /sys/kernel/debug/mali/device/utilisation ]; then echo gpu usage: $(cat /sys/kernel/debug/mali/device/utilisation) fi echo --- NPU --- echo npu freq: $(cat /sys/class/devfreq/fdab0000.npu/cur_freq) Hz if [ -f /sys/kernel/debug/rknpu/load ]; then echo npu load:; cat /sys/kernel/debug/rknpu/load fi echo --- DDR --- echo ddr freq: $(cat /sys/class/devfreq/dmc/cur_freq) Hz echo --- Temperature --- for zone in /sys/class/thermal/thermal_zone*; do echo $zone: $(cat $zone/temp) 摄氏度 done sleep 1 done将这个脚本保存为/usr/local/bin/rk3588_status.sh并加上可执行权限后续每次调试都直接运行。它虽然简陋但在定位“模块有没有被真正使用”这类问题上非常高效。提示如果批量查询时提示Permission denied先确认用户是否在sudo组或者对相关sysfs节点是否有写权限。部分固件对debugfs路径做了权限收紧。6.2 进阶思路将状态数据接入监控面板如果你想做长时间压力测试或者跑多板卡集群监控可以引入Prometheus生态。思路很简单写一个脚本周期性读取Proc和sysfs节点转换成exporter格式输出给Prometheus抓取Grafana出图。这样NPU负载、GPU利用率、DDR频率都能按时间轴画出曲线对找出偶发性能问题很有帮助。具体做法可以基于node_exporter的textfile collector实现不需要自己写exporter——只要把脚本输出写到指定目录的.prom文件node_exporter会自动收集。步骤大致是mkdir -p /var/lib/node_exporter/textfile然后把前面的状态脚本改造成直接把指标写入这个目录下的rk3588.prom。采集粒度建议10秒一次太频繁会占系统资源。接入之后你就能在Grafana里同时看到CPU、NPU、GPU、DDR的频率曲线和负载曲线排查瓶颈会直观得多。6.3 我踩过几次坑之后总结的注意事项RK3588状态查看这件事看似简单实际操作中还是有一些坑值得注意。第一不要随意把scaling_governor切成userspace之后忘了恢复。我有一次为了压测CPU频率把八个核全部切到userspace并锁到最高频跑完测试忘记恢复板子放在机柜里持续高热运行第二天系统直接重启了。养成习惯测试结束立刻恢复正常调度。第二调试NPU卡顿问题时不要只盯着NPU自身频率。很多时候NPU负载只有50%看起来“还有余力”但推理速度就是上不去。真正的瓶颈往往出在数据输入链路上图片解码用CPU做、缩放用CPU做、颜色转换用CPU做这些环节把大核占满了NPU干等数据。正确做法是让RGA处理缩放和格式转换让VPU参与视频解码CPU只做最上层调度——这也是RK3588异构架构的核心价值所在。第三不同固件之间的sysfs和debugfs路径差异真的很大。RK3588官方固件、第三方桌面固件、自己编译的Buildroot固件同一模块的节点路径命名可能完全不同。遇到No such file or directory时先ls /sys/class/devfreq/看看有哪些设备名再ls /sys/kernel/debug/找对应模块目录按图索骥远比背路径可靠。第四注意温度对频率的影响。RK3588各模块频率都是温控驱动的芯片温度一旦逼近阈值无论你设置多少频率都会被被强制拉低。如果发现频率“锁不住”先去查温度节点别在调频策略上浪费时间。板子散热条件好的话频率表现完全两个样。我个人在实际调试中的体会是状态查看工具不只是用来定位问题的更应该把它当成日常开发流程的一部分。每次拿到一块新的RK3588板子第一件事就是把六个模块的频率和版本信息打印一遍存成基线。后续移植系统、换固件、调驱动哪怕出的是完全不相干的bug有基线数据在手排查效率都会高很多。这套方法不限于RK3588整个RK系列的调试逻辑都是相通的。