
干嵌入式这几年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 GPUMali-G610 MP4四核MaliRK3588的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的MPPMedia Process Platform框架管理。VPU没有像CPU那样的标准sysfs“使用率”节点但可以看/proc/rk_vcodec里面会打印编解码器的工作状态。再配合v4l2-ctl --list-devices查看video设备节点就能判断编解码硬件是否注册成功。1.5 RGA2D图形加速器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内存控制器由DMCDynamic Memory Controller管理在Linux里注册成devfreq设备通常叫dmc。DDR的“状态”不仅是剩余内存大小更重要的是实时带宽和频率。有时候NPU算力上不去问题就出在DDR带宽被其他单元抢光了。这个知识点很多人忽略后面我会单独讲。2. 最基础的反而是CPU和DDR频率、状态和调优2.1 怎么确认CPU当前跑在什么状态拿到板子的第一件事先看CPU到底认出来几个核、跑在什么频率。终端下依次执行cat /proc/cpuinfo | grep -E processor|model name|CPU partCPU 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频率看devfreqcat /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到userspaceecho 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 21 | grep -i rga如果看到大量以0x...开头的ioctl调用并且其中包含RGA_BLIT_SYNC之类的命令字说明RGA在工作。这种排查方式比看sysfs准得多因为RGA驱动的内核接口经常变节点路径不稳定。基本上只要/dev/rga存在、驱动日志无报错、程序调用时有ioctlRGA就没问题。3.4 用一条ffmpeg命令同时压测CPU、GPU、VPU、DDR这几个单元经常协同工作我习惯用一条ffmpeg命令直观观察它们的状态变化。比如把一段4K视频转成H.265并缩放到1080Pffmpeg -i input.mp4 -c:v libx265 -vf scale1920: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和Core10x1表示只开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对象时开启verbosefrom rknn.api import RKNN rknn RKNN(verboseTrue) rknn.load_rknn(pathmodel.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(frknpu_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 ar /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 adbadb 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-infoGPU频率、utilization/sys/class/devfreq/*gpu*/cur_freq、/sys/kernel/debug/mali0/gpu_utilizationNPU三核负载、频率、core_mask/sys/kernel/debug/rknpu/load、freq、core_maskVPU编解码状态、设备节点/proc/rk_vcodec、v4l2-ctl --list-devicesRGA设备节点、驱动状态/dev/rga、dmesg | grep rgaDDR内存余量、频率、带宽/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的状态叠在一起看才能定位真正的问题。希望这篇能让你少走点弯路。