news 2026/9/27 1:37:12

RK3588嵌入式SoC六大硬件单元状态监控与频率调优实操

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RK3588嵌入式SoC六大硬件单元状态监控与频率调优实操

干嵌入式这几年,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 256

256表示测试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_frequencies

fdab0000.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的状态叠在一起看,才能定位真正的问题。希望这篇能让你少走点弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/27 1:37:10

C++航班查询课设实战:结构体+链表基数排序+二分查找

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 1:37:07

Android 15在米尔RK3576开发板上的实测:系统升级与部署全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 1:36:47

VC++聊天室课程设计:Socket编程与MFC线程避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 1:36:46

图盲去模糊实战:从图构建、核估计到图神经网络训练与避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 1:36:25

13.56MHz NFC天线设计:从等效电路到PCB布局的调试实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 1:36:21

光流法+机器学习:雷达临近预报从60分钟到120分钟

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华