干嵌入式这几年,RK3588应该是我接触最多的国产旗舰SoC之一了。8核CPU、Mali-G610 GPU、6 TOPS算力的NPU,再加上VPU、RGA、DDR控制器,塞进一颗芯片里,跑Linux、跑Android、跑容器都没问题。可一旦你想知道这颗芯片到底跑得有多欢,问题就来了:这些单元的“状态查看与操作”路径分散在sysfs、debugfs、devfreq、procfs里,而且不同内核版本差异还不小。这篇就把我在RK3588上摸出来的CPU、GPU、NPU、VPU、RGA、DDR状态查看与操作方法整理一遍,适合刚拿到RK3588开发板、开始调系统的人参考。
1. 先搞懂RK3588的“家底”:六个硬件单元分别干什么
1.1 CPU:大小核异构,两个频率域
RK3588的CPU是4个Cortex-A76大核加4个Cortex-A55小核的big.LITTLE架构。大核通常对应cpu4到cpu7,小核对应cpu0到cpu3。注意,这个编号不是绝对的,不同内核设备树里可能反转,但主流Rockchip SDK默认是小核在前。
CPU在Linux里由cpufreq框架管理,分成两个policy节点:一个管A55簇,一个管A76簇。你可以在/sys/devices/system/cpu/cpufreq/下看到类似policy0和policy4的目录。搞清楚这个,是因为后面所有调频操作都得找对policy,不然你调了大核,小核没动,性能测试结果还是一塌糊涂。
1.2 GPU:Mali-G610 MP4,四核Mali
RK3588的GPU是Mali-G610 MP4,支持Vulkan、OpenGL ES、OpenCL。它在Linux里由Mali kbase驱动管理,会注册成一个devfreq设备。GPU不像CPU那样有“负载百分比”节点可以直接读,通常通过Mali驱动暴露的utilization节点或者GPU设备下的计数器来间接判断。
GPU频率和GPU绑定的内存带宽是影响显示流畅度的关键。跑GUI、跑OpenGL、跑部分推理库时,GPU频率上不去,帧率就会卡在瓶颈上。
1.3 NPU:三核异构AI加速器
NPU是RK3588最受关注的单元,标称6 TOPS算力,实际由3个NPU核心组成,支持INT4/INT8/INT16/FP16等混合精度。NPU运行时由RKNPU驱动接管,暴露在debugfs的rknpu目录下。
很多人问NPU怎么看状态,其实就是看这几个文件:load显示每个核心的负载,freq显示当前频率,core_mask可以配置参与计算的核数。这几个节点我后面会详细拆。
1.4 VPU:视频编解码单元
VPU负责硬件编解码,支持H.265/H.264/VP9/AV1等格式。注意,RK3588的编解码器是分开的:解码器叫VPU,编码器叫VEPU,但在系统层面统一由Rockchip的MPP(Media Process Platform)框架管理。
VPU没有像CPU那样的标准sysfs“使用率”节点,但可以看/proc/rk_vcodec,里面会打印编解码器的工作状态。再配合v4l2-ctl --list-devices查看video设备节点,就能判断编解码硬件是否注册成功。
1.5 RGA:2D图形加速器
RGA是Rockchip的2D图形加速单元,负责格式转换、缩放、旋转、混合等操作。在安卓里很多UI合成会用到它,在Linux里做图像处理也可以用librga。
RGA在用户态对应/dev/rga,驱动注册情况可以看dmesg | grep rga。它不像GPU那么复杂,但在做摄像头预览、图像拼接的时候,如果RGA没工作,CPU会被拷贝操作拖得很惨。
1.6 DDR:内存控制器和带宽通道
DDR在芯片内部的位置很特殊,CPU、GPU、NPU、VPU全部通过它交换数据。RK3588支持LPDDR4/LPDDR4X/LPDDR5,内存控制器由DMC(Dynamic Memory Controller)管理,在Linux里注册成devfreq设备,通常叫dmc。
DDR的“状态”不仅是剩余内存大小,更重要的是实时带宽和频率。有时候NPU算力上不去,问题就出在DDR带宽被其他单元抢光了。这个知识点很多人忽略,后面我会单独讲。
2. 最基础的反而是CPU和DDR:频率、状态和调优
2.1 怎么确认CPU当前跑在什么状态
拿到板子的第一件事,先看CPU到底认出来几个核、跑在什么频率。终端下依次执行:
cat /proc/cpuinfo | grep -E "processor|model name|CPU part"CPU part字段能看到核心架构,0x410fd0d0之类对应Arm内核。再看每个CPU当前频率:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq cat /sys/devices/system/cpu/cpu4/cpufreq/scaling_cur_freq这里读出的是kHz,比如1800000就是1.8GHz。如果读出来是0,很可能是cpufreq驱动没绑定好,或者节点路径不对。
还可以看每个核的在线状态:
cat /sys/devices/system/cpu/online如果输出0-7说明8个核全部在线。如果只有0-3,可以用以下命令强制唤醒大核:
echo 1 > /sys/devices/system/cpu/cpu4/online注意,在线状态受CPU热插拔策略影响,有些内核默认会把大核休眠。
2.2 CPU调频的实际操作
控制CPU频率,核心是操作scaling_governor和scaling_setspeed。先看当前策略:
cat /sys/devices/system/cpu/cpufreq/policy0/scaling_governor cat /sys/devices/system/cpu/cpufreq/policy4/scaling_governor一般默认是schedutil,这是内核根据负载自动调频。想固定最高频,把governor切到userspace,然后直接写频率:
echo userspace > /sys/devices/system/cpu/cpufreq/policy4/scaling_governor echo 2400000 > /sys/devices/system/cpu/cpufreq/policy4/scaling_setspeed但这里有个大坑:scaling_setspeed要求先设置scaling_governor为userspace,否则写不进去。更稳妥的做法是直接用cpufreq-set工具:
cpufreq-set -c 4 -g performance cpufreq-set -c 4 -f 2400000-c 4要注意,cpufreq-set的处理器编号对应的是policy,不是物理核。你写-c 4,实际操作的是包含cpu4到cpu7的policy。验证一下:
cat /sys/devices/system/cpu/cpufreq/policy4/scaling_cur_freq能稳定读到2400000,才算设置成功。如果读出来还是跳来跳去,说明系统里存在其他热管理机制,比如thermal框架的cooling device会把频率压下来。
2.3 DDR带宽怎么看、怎么压
DDR状态看两样东西:剩余内存和实时带宽。剩余内存很简单:
cat /proc/meminfo | grep -E "MemTotal|MemFree|MemAvailable"带宽才是难点。RK3588的DMC devfreq节点通常在/sys/class/devfreq/dmc/,里面没有直接的“带宽多少MB/s”字段,但可以看到当前频率:
cat /sys/class/devfreq/dmc/cur_freq cat /sys/class/devfreq/dmc/available_frequencies另外,Rockchip在DRM调试接口里暴露了DDR带宽统计:
cat /sys/kernel/debug/dri/0/summary输出里会有类似DDR Bandwidth: 1200 MB/s的信息。这个节点依赖debugfs挂载,如果没有,先执行:
mount -t debugfs none /sys/kernel/debug想看DDR实际能压多高,用mbw做内存带宽测试:
mbw -n 5 256256表示测试256MB内存,-n 5表示做5轮。结果里的AVG列就是内存复制带宽。在DDR4-2133的RK3588板子上,实测单通道跑出4000到5000 MB/s很正常。如果数值远低于预期,检查DDR频率是否被devfreq限频了。
2.4 CPU稳定性验证
改完频率后,最好跑一下压力测试:
stress-ng --cpu 8 --cpu-method matrixprod --timeout 60s跑的时候同时开另一个终端观察频率:
watch -n 1 "cat /sys/devices/system/cpu/cpufreq/policy*/scaling_cur_freq"如果发现某些核心掉频,基本就是温控阀值到了。RK3588的CPU大核长时间满载,温度很容易冲到85°C以上。
3. GPU、VPU、RGA:多媒体单元的查看和触发
3.1 Mali GPU:利用率和频率
GPU的状态没有统一的“使用率”文件,但Mali kbase驱动在debugfs里提供了一个gpu_utilization节点。先挂载debugfs,然后:
cat /sys/kernel/debug/mali0/gpu_utilization输出一般是三个数,分别代表顶点着色器、片元着色器和几何着色器的占用率,接近100说明GPU被吃满了。如果这个节点不存在,也可以读GPU的计数器接口,但那个比较麻烦。
GPU频率看devfreq:
cat /sys/class/devfreq/fdab0000.gpu/cur_freq cat /sys/class/devfreq/fdab0000.gpu/available_frequenciesfdab0000.gpu是设备树里GPU节点的基地址,不同SDK可能叫fdb00000.gpu,可以用通配符:
ls /sys/class/devfreq/ | grep gpu想锁住GPU最高频,同样切governor到userspace:
echo userspace > /sys/class/devfreq/fdab0000.gpu/governor echo 1000000000 > /sys/class/devfreq/fdab0000.gpu/userspace/set_freq注意,Mali的devfreq governor一般还有mali_simple,写频率前先看available_frequencies,别写一个不存在的值。
3.2 VPU编解码单元:找设备、看状态
VPU在Linux里以V4L2节点呈现。先列设备:
v4l2-ctl --list-devices通常会看到rkvdec和rkvenc对应的/dev/video0、/dev/video1等节点。如果列表里没有,说明驱动或者设备树有问题,先看:
dmesg | grep -E "rkvdec|rkvenc|vpu"驱动加载成功的情况下,/proc/rk_vcodec会存在:
cat /proc/rk_vcodec这个文件内容会列出编解码器的通道、码流状态、帧数等信息。不过不同SDK版本输出格式差异很大,别指望统一格式,看到里面有值就说明VPU在工作。
想看VPU频率,找devfreq节点:
ls /sys/class/devfreq/ | grep -E "vpu|vepu"在实际项目里,编解码往往和GPU、DDR同时跑,所以如果需要排查“视频卡顿是不是VPU瓶颈”,最有效的方法是同时抓/proc/rk_vcodec和/sys/class/devfreq/dmc/cur_freq,看看是不是DDR带宽被顶满了。
3.3 RGA:设备节点和驱动日志
RGA的状态查看相对简单。先确认设备节点:
ls -l /dev/rga如果存在,说明驱动注册成功。再看驱动日志:
dmesg | grep -i rga初始化成功会看到类似rga2: Module initialized的信息。
想判断RGA到底有没有被用户程序调用,在跑图像处理程序时用strace跟踪:
strace -p <pid> -e ioctl 2>&1 | grep -i rga如果看到大量以0x...开头的ioctl调用,并且其中包含RGA_BLIT_SYNC之类的命令字,说明RGA在工作。这种排查方式比看sysfs准得多,因为RGA驱动的内核接口经常变,节点路径不稳定。
基本上,只要/dev/rga存在、驱动日志无报错、程序调用时有ioctl,RGA就没问题。
3.4 用一条ffmpeg命令同时压测CPU、GPU、VPU、DDR
这几个单元经常协同工作,我习惯用一条ffmpeg命令直观观察它们的状态变化。比如把一段4K视频转成H.265并缩放到1080P:
ffmpeg -i input.mp4 -c:v libx265 -vf "scale=1920:1080" -c:a copy output.mp4转码过程中,CPU会跑x265编码,VPU如果是硬件转码则会降低CPU占用,GPU如果开启滤镜加速也会介入,DDR带宽会因为大块数据搬运而上升。此时同时开着四个watch窗口分别看CPU频率、GPU utilization、/proc/rk_vcodec和dmc/cur_freq,基本能摸清整个系统的瓶颈。
如果发现CPU占用极高而GPU utilization一直为0,说明你的ffmpeg没有启用硬件加速,滤镜和编码都在用CPU。这在纯软件栈下很正常,不算故障。
4. NPU:三核AI加速器的状态查看和调度
4.1 挂载debugfs,找到rknpu目录
NPU相关状态几乎都挂在debugfs下,所以第一步是确保debugfs已挂载:
mount -t debugfs none /sys/kernel/debug然后看:
ls /sys/kernel/debug/rknpu/如果看到version、load、total_load、core_mask、freq之类的文件,说明RKNPU驱动已经正常加载。没有这个目录时,先查驱动:
dmesg | grep rknpu常见报错是固件没加载或者依赖模块没装全。RKNPU驱动需要rknpu.bin固件,通常在/vendor/etc/firmware/或/lib/firmware/下。缺失的话,NPU会直接初始化失败。
4.2 读NPU负载和频率
NPU负载的读取方式在RK3588上很直观:
cat /sys/kernel/debug/rknpu/load输出类似:
NPU load: Core0: 35%, Core1: 12%, Core2: 0%, total: 15%这是三个核心各自的占用率,以及总负载。total_load则是一段时间内的平均负载,更适合画曲线。
NPU频率:
cat /sys/kernel/debug/rknpu/freq有些驱动版本把频率放在devfreq里:
cat /sys/class/devfreq/fdab0000.npu/cur_freq如果你在跑YOLOv8推理,可以在运行前用watch每秒刷新一次NPU负载:
watch -n 1 "cat /sys/kernel/debug/rknpu/load"正常情况下,推理时某个核心会冲到70%以上,而推理间歇期则快速降到个位数。如果看到三个核心全部满载但帧率很低,大概率是DDR带宽不够,或者模型本身算子效率低。
4.3 修改NPU core_mask,控制参与计算的核数
RK3588的3个NPU核心可以独立开关。core_mask节点用bitmask控制,通常0x7表示三核全开,0x3表示只开Core0和Core1,0x1表示只开Core0。
修改方式:
echo 0x7 > /sys/kernel/debug/rknpu/core_mask注意,这个操作在部分内核版本中需要root权限,而且写入之前最好确认当前没有推理任务在跑。在跑任务时动态改core_mask,可能导致驱动内部上下文切换异常,甚至出现内存访问错误。
实际项目里,为什么要限制核数?两个场景:一是降低峰值功耗,NPU三核全开的时候整板功耗会显著升高;二是避免NPU抢占过多DDR带宽,影响实时视频流。我们做过实验,同一个YOLOv8模型,三核全开比单核跑得快2倍左右,但DDR带宽占用也几乎是单核的三倍。如果系统同时要做视频编码,限制成两个核反而更稳。
4.4 用rknn-toolkit2运行时监测NPU
除了sysfs,在用户态跑RKNN模型时,也可以直接看运行时日志。rknn-toolkit2的Python接口里,初始化RKNN对象时开启verbose:
from rknn.api import RKNN rknn = RKNN(verbose=True) rknn.load_rknn(path="model.rknn") rknn.init_runtime()运行推理时,终端会打印NPU算子耗时、内存分配情况。如果发现某个算子耗时异常高,多半是模型转换时没有使用NPU支持的原生算子,导致部分层回退到了CPU。
在板端,还可以用rknn_server的日志:
journalctl -u rknn_server -f能看到每次推理请求的到达时间、处理时间。配合/sys/kernel/debug/rknpu/load,基本能定位是模型问题还是系统调度问题。
4.5 用Prometheus和Grafana盯NPU负载
如果要在设备上长期监控NPU资源,手动cat肯定不现实。我的做法是写一个node_exporter文本文件采集器,定时读取/sys/kernel/debug/rknpu/load,输出成Prometheus格式。
采集脚本核心逻辑如下:
import time import os def read_npu_load(): with open('/sys/kernel/debug/rknpu/load', 'r') as f: line = f.read().strip() # 解析 Core0: 35%, Core1: 12%, Core2: 0% cores = {} for part in line.split(','): if 'Core' in part: name, val = part.split(':') cores[name.strip()] = float(val.strip().replace('%', '')) return cores outfile = '/var/lib/node_exporter/textfile_collector/npu_load.prom' while True: cores = read_npu_load() with open(outfile, 'w') as f: for name, val in cores.items(): f.write(f'rknpu_load{{core="{name}"}} {val}\n') time.sleep(5)Prometheus每15秒抓一次,Grafana里画三根线,NPU温度、频率、负载一目了然。这个方法不依赖任何官方监控插件,只要文本采集器目录配置正确即可。
唯一要注意的是,debugfs节点在高版本内核里可能限制非root用户读取。用udev规则或systemd服务以root权限运行采集器,再让node_exporter读取生成的文件,能避开权限问题。
5. 常见问题与避坑清单
5.1 Permission denied:先挂debugfs,再查用户组
看NPU节点报权限拒绝,90%是因为debugfs没挂载,或者当前用户不在root组。先执行:
sudo mount -t debugfs none /sys/kernel/debug sudo chmod -R a+r /sys/kernel/debug/rknpu注意,chmod只在当前启动周期内有效,重启后需要重新设置。更稳定的做法是在/etc/fstab里加一行:
none /sys/kernel/debug debugfs defaults 0 0这样开机自动挂载。
5.2 频率锁不住,总是自动跳回
如果你设置了userspace固定频率,但几秒后又变了,先看是不是thermal冷却设备在干预。RK3588的CPU、GPU、NPU都注册了thermalcooling device,温度超过阈值后,内核会强制降频。
查看当前温度:
cat /sys/class/thermal/thermal_zone*/temp温度单位是毫摄氏度,85000代表85°C。如果你的板子散热不好,固定2.4GHz跑不了几分钟就会回落到1.8GHz。想验证是不是温控造成的,可以临时把温控阈值调高:
echo 95000 > /sys/class/thermal/thermal_zone0/trip_point_0_temp但我不建议长期这么做,芯片长期高温工作会加速老化。最靠谱的方案是加强散热,而不是屏蔽温控。
5.3 不同内核版本,节点路径不一样
RK3588的SDK迭代很快,同一个rknpu目录在老内核里可能在/sys/kernel/debug/rknpu/load,新内核则变成/sys/kernel/debug/rknpu/power。遇到节点缺失,先用find扫一遍:
find /sys -name "*rknpu*" 2>/dev/null find /sys -name "*gpu*" 2>/dev/null find /sys -name "*dmc*" 2>/dev/null用通配符思路找,比死记路径高效得多。我在RK3588上遇到过dmc节点从/sys/class/devfreq/dmc改成/sys/class/devfreq/opp_ddr的情况,都是靠find定位的。
5.4 ADB连板子和AB分区的影响
如果你是Android系统或者某些Linux发行版,要用adb连RK3588,先确认板子开了USB adb:
adb devices如果设备列表为空,检查adb服务:
adb kill-server adb start-server再插拔一次USB线。Linux板端一般需要开启adbd服务,Android则已经在init里默认启动。
另外,RK3588不少固件用AB分区方案,/dev/block/by-name下会有boot_a、boot_b之类的分区。查看AB状态:
cat /proc/cmdline | grep -o "slot_suffix=[^ ]*"如果输出slot_suffix=_a,说明当前启动槽位是A。这不会直接影响状态查看,但升级内核后发现/sys节点没变化时,先确认你是不是还在老槽位运行。
5.5 常用状态查看指令速查表
| 硬件单元 | 查看内容 | 常用命令/路径 |
|---|---|---|
| CPU | 在线核、频率、governor | /proc/cpuinfo、/sys/devices/system/cpu/cpu*/cpufreq/、cpufreq-info |
| GPU | 频率、utilization | /sys/class/devfreq/*gpu*/cur_freq、/sys/kernel/debug/mali0/gpu_utilization |
| NPU | 三核负载、频率、core_mask | /sys/kernel/debug/rknpu/load、freq、core_mask |
| VPU | 编解码状态、设备节点 | /proc/rk_vcodec、v4l2-ctl --list-devices |
| RGA | 设备节点、驱动状态 | /dev/rga、dmesg | grep rga |
| DDR | 内存余量、频率、带宽 | /proc/meminfo、/sys/class/devfreq/dmc/cur_freq、/sys/kernel/debug/dri/0/summary |
这张表基本覆盖了日常开发和调试需要的信息。再多说一句:网上很多帖子直接给路径让你cat,但不同板子的设备树基地址不一样,路径里的fdab0000.gpu可能变成fdb00000.gpu。拿到板子先跑一遍ls /sys/class/devfreq/,看到实际名字再操作,这比复制命令更容易避免踩坑。
做RK3588平台调试这大半年,我最深的体会是:查看状态只是第一步,能看懂状态背后的因果关系才关键。频率上不去不一定是芯片不行,先查温度;NPU负载低不一定是模型快,先查DDR带宽;GPU utilization为0不一定没在干活,先确认Mali驱动有没有开调试节点。这些硬件单元不是孤立存在的,它们共享电源、共享DDR、共享总线的热约束,只有把CPU、GPU、NPU、VPU、RGA、DDR的状态叠在一起看,才能定位真正的问题。希望这篇能让你少走点弯路。