RK3588 Linux CPU/GPU/NPU 性能调优指南
硬件平台: C-3588LQ V1.0 核心板 + SHIMETAPI-M5-R2A V1.0 底板
软件环境: Linux 6.1, Debian 12 / Ubuntu 22.04
文档版本: v1.0
更新日期: 2026-08-19
1 概述
1.1 文档目的
这篇指南讲解 RK3588 平台在 Linux 6.1 内核下如何调 CPU、GPU、NPU 三个部件的性能,内容包括调频策略配置(调频由 governor 决定,它是内核里的一套策略模块,负责根据负载决定频率升还是降,后面会反复用到)、任务调度优化、功耗管理、性能监控和基准测试。调优的本质是在性能、功耗和散热之间找平衡,读完你就能按自己的场景做出取舍。
1.2 RK3588 处理器架构
先认识芯片内部的结构。RK3588 是大小核(big.LITTLE)架构:4 个 Cortex-A76 大核干重活,4 个 Cortex-A55 小核处理轻负载;GPU 是 Mali-G610 MP4,NPU 有 3 个核心、算力 6 TOPS:
┌─────────────────────────────────────────────────────────────┐
│ RK3588 SoC │
│ │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ Cortex-A76 Cluster │ │ Cortex-A55 Cluster │ │
│ │ (Big Core) │ │ (Little Core) │ │
│ │ │ │ │ │
│ │ CPU0: 2.4 GHz │ │ CPU4: 1.8 GHz │ │
│ │ CPU1: 2.4 GHz │ │ CPU5: 1.8 GHz │ │
│ │ CPU2: 2.4 GHz │ │ CPU6: 1.8 GHz │ │
│ │ CPU3: 2.4 GHz │ │ CPU7: 1.8 GHz │ │
│ └─────────────────────────┘ └─────────────────────────┘ │
│ │
│ ┌─────────────────────┐ ┌───────────────────────────────┐│
│ │ Mali-G610 MP4 GPU │ │ NPU (6 TOPS, 3 cores) ││
│ │ up to 1.0 GHz │ │ fdab0000.npu ││
│ └─────────────────────┘ └───────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘1.3 调优目标分类
动手前先明确你要什么,不同目标对应不同的策略组合:
| 调优目标 | 典型场景 | 优先策略 |
|---|---|---|
| 最大性能 | AI推理、视频编码、3D渲染 | performance governor, 最高频率 |
| 均衡模式 | 桌面交互、多媒体播放 | schedutil governor, 动态调频 |
| 最低功耗 | 待机、传感器采集 | powersave governor, 最低频率 |
| 实时响应 | 工业控制、音频处理 | RT调度, CPU绑定, 中断亲和性 |
2 硬件准备
2.1 硬件平台信息
| 组件 | 规格 | 说明 |
|---|---|---|
| 核心板 | C-3588LQ V1.0 | 8nm工艺, 集成RK3588 |
| 底板 | SHIMETAPI-M5-R2A V1.0 | 扩展接口底板 |
| CPU | 4×A76 + 4×A55 | big.LITTLE架构 |
| GPU | Mali-G610 MP4 | 支持OpenCL 3.0 |
| NPU | 6 TOPS, 3核心 | 支持INT8/INT16/FP16 |
| 散热 | 需主动散热 | 大负载必须加风扇 |
2.2 散热方案建议
性能调优的前提是散热跟得上。RK3588 满载功耗可达 15-20W,必须配散热片和风扇,否则芯片过热降频,调优成果会被温度吃掉。按负载选方案:
散热方案参考:
├── 轻负载 (< 8W): 被动散热片 (铝制, >= 40mm×40mm×10mm)
├── 中负载 (8-12W): 散热片 + 低速风扇
└── 重负载 (> 12W): 散热片 + 高速风扇 + 导热硅脂2.3 电源要求
供电同样不能凑合,功率不足会带来系统不稳定和意外降频:
推荐供电:
- 5V/4A (20W) DC电源适配器 (至少)
- 使用底板DC接口供电, 避免USB供电功率不足
- 供电不足会导致系统不稳定和意外降频3 软件准备
3.1 系统环境
先确认系统版本符合预期:
# 确认内核版本
uname -r
# 预期输出: 6.1.x-rockchip
# 确认系统信息
cat /etc/os-release
# Ubuntu 22.04.x LTS / Debian 12.x
# 确认CPU信息
lscpu | head -203.2 必要软件包安装
把后面要用到的性能工具、NPU 工具(Rockchip 提供)和编译工具一次装齐:
# 更新系统
sudo apt update && sudo apt upgrade -y
# 安装性能工具
sudo apt install -y \
linux-tools-common \
linux-tools-$(uname -r) \
sysstat \
htop \
iotop \
cpufrequtils \
libhwloc-dev \
python3-pip \
glmark2 \
glmark2-wayland
# 安装NPU工具 (Rockchip提供)
sudo apt install -y \
rktool \
rknn-toolkit2 \
rknpu2
# 安装编译工具
sudo apt install -y \
build-essential \
cmake \
pkg-config \
libdrm-dev3.3 验证硬件节点
后面的调优基本都靠读写 sysfs 节点完成(sysfs 是内核暴露出来的虚拟文件系统,/sys 下的那些文件),先确认这些节点都存在:
# 检查CPU频率节点
ls /sys/devices/system/cpu/cpu0/cpufreq/
# 应存在: scaling_governor, scaling_max_freq, scaling_cur_freq 等
# 检查GPU频率节点
ls /sys/class/devfreq/fb000000.gpu/
# 应存在: governor, cur_freq, max_freq, min_freq
# 检查NPU设备
ls /sys/class/devfreq/fdab0000.npu/
# 应存在: governor, cur_freq, max_freq
# 检查thermal区域
ls /sys/class/thermal/thermal_zone*/
# RK3588通常有多个thermal zone (CPU, GPU, NPU等)4 操作步骤
4.1 CPU 调频策略配置
4.1.1 查看当前CPU状态
CPU 频率由内核的 cpufreq 子系统管理,governor 决定频率怎么随负载变化。动手前先看清本机现状,逐条执行并对照注释里的结果:
# ⚠ 勘误:本机 cpu0-3 是 A55 小核、cpu4-7 是 A76 大核(与部分资料相反)!
# 且默认 governor 是 ondemand(不是 schedutil)
# 查看当前调频策略( ondemand)
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# 查看当前频率
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
# 查看可用频率范围
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies
# A55(cpu0-3): 408000 ... 1800000(8 档,最高 1.8GHz)
cat /sys/devices/system/cpu/cpu4/cpufreq/scaling_available_frequencies
# A76(cpu4-7): 408000 ... 2016000 2208000 2256000(11 档,最高 2.256GHz)
# 查看可用调频策略( 7 种)
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors
# interactive conservative ondemand userspace powersave performance schedutil
# 本机 cpufreq policy 结构(3 个集群: policy0/4/6)
ls /sys/devices/system/cpu/cpufreq/
# policy0 policy4 policy6
# policy0=cpu0-3(A55) policy4=cpu4-5(A76) policy6=cpu6-7(A76)特别注意开头那条勘误:本机 cpu0-3 是 A55 小核、cpu4-7 是 A76 大核,与部分资料的写法相反,后面绑定核心时别弄反。下面是同一忙循环基准(cpu4)下三种 governor 的对比,powersave 会把频率锁在 408MHz,慢了 5.7 倍:
| governor | 循环耗时(3 次平均) | 说明 |
|---|---|---|
| performance | 491.0 ms | 锁 2.256GHz |
| ondemand | 497.6 ms | 动态,很快升满 |
| powersave | 2790.3 ms | 锁 408MHz,慢 5.7 倍 |
4.1.2 设置CPU调频策略
切换 governor 就是往对应的 sysfs 节点写一个词。方法一用循环写节点(临时生效,重启后恢复默认),方法二用 cpufreq-set 工具,效果一样:
# 方法一: 临时设置 (重启失效)
# 全部核心设置为performance
for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
echo performance | sudo tee $cpu
done
# 全部核心设置为schedutil (推荐)
for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
echo schedutil | sudo tee $cpu
done
# 方法二: 使用cpufreq-set工具
sudo cpufreq-set -g performance
# 或指定核心
sudo cpufreq-set -c 0-3 -g performance # A76集群
sudo cpufreq-set -c 4-7 -g powersave # A55集群4.1.3 schedutil 参数调优
schedutil 是由内核调度器直接驱动的 governor,比 ondemand 响应更快,它的 rate_limit_us 参数控制两次调频之间的最小间隔。本机默认 governor 是 ondemand,policy0 下没有 schedutil/ 子目录,想调参数得先把 governor 切过去:
# 注意:本机默认 governor 是 ondemand,policy0 下没有 schedutil/ 子目录!
# 想调 schedutil 参数先切 governor:
echo schedutil | sudo tee /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
cat /sys/devices/system/cpu/cpufreq/policy0/schedutil/rate_limit_us
echo 500 | sudo tee /sys/devices/system/cpu/cpufreq/policy0/schedutil/rate_limit_us
# ondemand 的等效参数(默认 governor 下直接可用):
cat /sys/devices/system/cpu/cpufreq/policy0/ondemand/sampling_rate4.2 GPU 频率调节
4.2.1 查看GPU状态
GPU 的调频接口走 devfreq 框架(可以理解成设备版的 cpufreq,GPU、NPU 这类非 CPU 设备都用它管理频率),操作方式同样是读写 sysfs 节点:
# GPU设备路径
GPU_PATH="/sys/class/devfreq/fb000000.gpu" # 本机 GPU 节点(fde40000 不存在)
# 查看GPU当前频率
cat ${GPU_PATH}/cur_freq
# 单位: Hz
# 查看GPU可用频率
cat ${GPU_PATH}/available_frequencies
# 查看GPU调频策略
cat ${GPU_PATH}/governor
# 查看GPU负载
cat ${GPU_PATH}/trans_stat下面是本机 fb000000.gpu 节点的实际值,后面几行是 governor 切换的验证过程,写入 performance 后频率立即锁到 1GHz:
cur_freq = 300000000 ← 空闲 300MHz
governor = simple_ondemand
available_frequencies = 1000000000 900000000 ... 300000000(8 档,最高 1GHz)
# governor 切换
echo performance | sudo tee ${GPU_PATH}/governor
cat ${GPU_PATH}/cur_freq # → 1000000000(立即锁 1GHz)
echo simple_ondemand | sudo tee ${GPU_PATH}/governor # 恢复4.2.2 GPU性能模式设置
需要压榨 GPU 时锁定最高频率,跑完测试记得切回动态调频并恢复默认频率范围,不然白费电:
# 设置GPU为性能模式 (锁定最高频率)
echo performance | sudo tee ${GPU_PATH}/governor
# 手动锁定GPU频率到最高
GPU_PATH="/sys/class/devfreq/fb000000.gpu"
MAX_FREQ=$(cat ${GPU_PATH}/available_frequencies | awk '{print $NF}')
echo ${MAX_FREQ} | sudo tee ${GPU_PATH}/min_freq
echo ${MAX_FREQ} | sudo tee ${GPU_PATH}/max_freq
# 设置GPU为动态调频模式
echo simple_ondemand | sudo tee ${GPU_PATH}/governor
# 恢复GPU默认频率范围
echo 200000000 | sudo tee ${GPU_PATH}/min_freq
echo 1000000000 | sudo tee ${GPU_PATH}/max_freq4.2.3 GPU频率与功耗对照
频率越高功耗越高,按场景选够用的档位即可:
| GPU频率 | 典型功耗 | 适用场景 |
|---|---|---|
| 200 MHz | ~0.5W | 2D显示、静态UI |
| 400 MHz | ~1.2W | 视频播放、轻度3D |
| 600 MHz | ~2.0W | 中度3D、游戏 |
| 800 MHz | ~3.0W | 重度3D、GPU计算 |
| 1000 MHz | ~4.5W | 满性能3D、OpenCL |
4.3 NPU 配置
4.3.1 查看NPU状态
NPU 也通过 devfreq 管理,设备节点是 fdab0000.npu:
# NPU设备路径( fdab0000.npu,不是 fdab0000.npu——那是 RK356x 的地址)
NPU_PATH="/sys/class/devfreq/fdab0000.npu"
# 查看NPU当前频率
cat ${NPU_PATH}/cur_freq
# 查看NPU可用频率
cat ${NPU_PATH}/available_frequencies
# 查看NPU调频策略
cat ${NPU_PATH}/governor4.3.2 NPU性能模式
设置方法和 GPU 一样,一点差别是本机 NPU 的动态调频 governor 叫 rknpu_ondemand,不是 simple_ondemand:
# NPU设置为性能模式
echo performance | sudo tee ${NPU_PATH}/governor
# 手动锁定NPU最高频率
MAX_FREQ=$(cat ${NPU_PATH}/available_frequencies | awk '{print $NF}')
echo ${MAX_FREQ} | sudo tee ${NPU_PATH}/min_freq
echo ${MAX_FREQ} | sudo tee ${NPU_PATH}/max_freq
# NPU设置为动态调频(本机 governor 名是 rknpu_ondemand,不是 simple_ondemand)
echo rknpu_ondemand | sudo tee ${NPU_PATH}/governor
# 本机 NPU devfreq:
# cur_freq = 1000000000 (1GHz)
# available_frequencies = 300M ~ 1000M 共 8 档
# governor = rknpu_ondemand4.3.3 NPU核心选择
RK3588 的 NPU 有 3 个核心,跑 RKNN 模型推理时可以通过 API 指定用哪几个,让不同模型互不抢核:
# RK3588 NPU有3个核心, 通过rknpu2库可以指定使用的核心
# 在RKNN模型推理时通过API选择:
# - RKNN_NPU_CORE_AUTO: 自动分配
# - RKNN_NPU_CORE_0: 仅核心0
# - RKNN_NPU_CORE_1: 仅核心1
# - RKNN_NPU_CORE_2: 仅核心2
# - RKNN_NPU_CORE_0_1: 使用核心0和1
# - RKNN_NPU_CORE_0_1_2: 使用全部3个核心
# 查看NPU设备信息
cat /sys/kernel/debug/rknpu/version 2>/dev/null || echo "需root权限"
dmesg | grep -i npu | head -104.4 CPU 亲和性与任务调度
4.4.1 CPU亲和性设置
CPU 亲和性(affinity)就是把某个进程固定在指定核心上运行,避免它在大核小核之间来回漂移。taskset 是最常用的绑核工具,后台杂活绑给小核,性能敏感任务绑给大核:
# 查看进程CPU亲和性
taskset -p <PID>
# ⚠ 本机: cpu0-3 是 A55 小核、cpu4-7 是 A76 大核
# 绑定到A55小核(后台任务)
taskset -c 0-3 ./background_task
# 绑定到A76大核(性能敏感任务)
taskset -c 4-7 ./my_application
# 同一忙循环(2 亿次加法):
# taskset -c 0 → 552.6 ms (A55)
# taskset -c 4 → 497.6 ms (A76)
# 简单整数循环收益有限(~11%,受限于循环本身);
# 真实计算密集任务(如 NPU 推理前处理)用 A76 收益更明显
# 使用numactl (如可用)
numactl --cpunodebind=0 --membind=0 ./my_application
# 查看CPU拓扑
lscpu -e
# 或
cat /sys/devices/system/cpu/cpu*/topology/physical_package_id
cat /sys/devices/system/cpu/cpu*/topology/core_type代码注释里有数据:同一个忙循环绑 A76 只比 A55 快约 11%,这类简单整数循环本身是瓶颈;换成真实计算密集任务(比如 NPU 推理前处理),大核的收益会明显得多。
4.4.2 big.LITTLE 调度策略
不手动绑核时,内核的 EAS(Energy Aware Scheduling,节能感知调度)会自动把任务往省电的核心上安排。相关状态可以这样查看:
# 查看EAS (Energy Aware Scheduling) 状态
cat /proc/sys/kernel/sched_energy_aware
# 1 = 启用, 0 = 禁用
# 查看CPU容量值 (A76 > A55)
cat /sys/devices/system/cpu/cpu0/cpu_capacity
# A76: 1024 (最大)
cat /sys/devices/system/cpu/cpu4/cpu_capacity
# A55: 600-700 左右
# 查看调度器域
ls /proc/sys/kernel/sched_domain/cpu0/4.4.3 实时调度配置
对延迟敏感的任务(音频处理、工业控制)可以用实时调度策略,设置工具是 chrt。SCHED_FIFO 按优先级抢占普通进程,SCHED_DEADLINE 更进一步,按「每个周期保证多少运行时间」的契约调度:
# 设置进程为SCHED_FIFO实时调度 (需要root)
sudo chrt -f 50 ./my_realtime_app
# 设置进程为SCHED_DEADLINE (最高优先级实时)
sudo chrt -d --sched-runtime 5000000 \
--sched-deadline 10000000 \
--sched-period 10000000 \
0 ./my_critical_app
# 设置进程优先级
sudo chrt -f -p 99 <PID>
# 查看当前实时进程
chrt -p
ps -eo pid,cls,rtprio,ni,comm | grep -E "FF|RR|DL"
# 降低非关键进程优先级
sudo renice +10 -p <PID>4.5 散热与温控配置
4.5.1 查看温度信息
所有调优动作都要在温度可控的前提下进行,先学会看温度。下面这个循环把每个 thermal zone(温度监测区)的类型和温度打印一遍:
# 查看所有thermal zone温度
for tz in /sys/class/thermal/thermal_zone*/; do
zone=$(cat ${tz}/type)
temp=$(cat ${tz}/temp)
echo "${zone}: $((temp/1000))°C"
done
# 常见thermal zone
# cpu-thermal: CPU温度
# gpu-thermal: GPU温度
# npu-thermal: NPU温度
# soc-thermal: SoC整体温度
# 本机 7 个 zone(空负载时):
# soc-thermal: 39.769°C bigcore0-thermal: 39.769°C
# bigcore1-thermal: 39.769°C littlecore-thermal: 39.769°C
# center-thermal: 39.769°C gpu-thermal: 38.846°C npu-thermal: 38.846°C4.5.2 温控策略配置
内核温控靠 trip point(温度触发点)工作:到 passive 点开始降频,到 active 点开风扇,到 critical 点直接关机保护硬件。触发温度可以改,单位是毫摄氏度:
# 查看温控触发点
cat /sys/class/thermal/thermal_zone0/trip_point_0_temp
cat /sys/class/thermal/thermal_zone0/trip_point_0_type
# type: passive (降频) / active (开风扇) / critical (关机)
# 修改被动降频触发温度 (单位: 毫摄氏度)
# 例如: 设置CPU在85°C开始降频
echo 85000 | sudo tee /sys/class/thermal/thermal_zone0/trip_point_0_temp
# 查看当前冷却设备状态
cat /sys/class/thermal/cooling_device*/type
cat /sys/class/thermal/cooling_device*/cur_state
# 查看是否支持风扇控制
ls /sys/class/thermal/cooling_device*/fan_speed4.5.3 温控优化建议
下面是一套常用的阈值配置,附一个大负载时的温度监控命令:
推荐温控阈值:
├── 降频触发 (passive): 85°C
├── 风扇全速 (active): 90°C
└── 关机保护 (critical): 105°C
大负载运行时监控脚本:
watch -n 2 "cat /sys/class/thermal/thermal_zone*/temp | \
awk '{printf \"%.1f°C \", \$1/1000}'"4.6 DVFS (动态电压频率调节) 配置
4.6.1 DVFS参数查看
DVFS 指动态电压频率调节:负载低时降频降压省电,负载高时升频保性能。前面改的 governor 其实就是 DVFS 的策略部分,这里集中查看各设备的频率表:
# 查看CPU DVFS表
cat /sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies
cat /sys/devices/system/cpu/cpufreq/policy0/scaling_available_governors
# 查看当前电压 (如支持)
cat /sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq
# 查看freq_table
cat /sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies
# GPU DVFS
cat /sys/class/devfreq/fb000000.gpu/available_frequencies
cat /sys/class/devfreq/fb000000.gpu/available_transitions4.6.2 DVFS锁定频率
跑基准测试前通常要把频率锁死,免得测试过程中自动升降频污染数据。做法是把最低频率和最高频率写成同一个值:
# 锁定CPU到最高频率
echo 1800000 | sudo tee /sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq # A55 上限 1.8G
echo 408000 | sudo tee /sys/devices/system/cpu/cpufreq/policy0/scaling_min_freq
# 锁定CPU到特定频率 (例如1.6GHz)
echo 1608000 | sudo tee /sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq
echo 1608000 | sudo tee /sys/devices/system/cpu/cpufreq/policy0/scaling_min_freq
# 恢复默认频率范围
echo 408000 | sudo tee /sys/devices/system/cpu/cpufreq/policy0/scaling_min_freq
echo 1800000 | sudo tee /sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq # A55 上限 1.8G4.7 一键性能配置脚本
不想每次手敲命令的话,把前面 CPU、GPU、NPU 的设置动作合成一个脚本,一键进入性能模式:
#!/bin/bash
# rk3588_performance_setup.sh
# RK3588 一键性能模式配置脚本
set -e
echo "=== RK3588 性能模式配置 ==="
# 检查root权限
if [ "$EUID" -ne 0 ]; then
echo "请使用sudo运行此脚本"
exit 1
fi
# 1. CPU设置为performance模式
echo "[1/5] 配置CPU调频策略..."
for gov in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
echo performance > $gov
done
echo " CPU调频策略: performance"
# 2. CPU锁定最高频率
echo "[2/5] 锁定CPU最高频率..."
for policy in /sys/devices/system/cpu/cpufreq/policy*/; do
MAX_FREQ=$(cat ${policy}/scaling_max_freq)
echo ${MAX_FREQ} > ${policy}/scaling_min_freq
done
echo " CPU频率已锁定"
# 3. GPU设置为性能模式
echo "[3/5] 配置GPU性能模式..."
GPU_PATH="/sys/class/devfreq/fb000000.gpu"
if [ -d "$GPU_PATH" ]; then
echo performance > ${GPU_PATH}/governor
MAX_FREQ=$(cat ${GPU_PATH}/available_frequencies | awk '{print $NF}')
echo ${MAX_FREQ} > ${GPU_PATH}/min_freq
echo " GPU已设置为性能模式 (${MAX_FREQ}Hz)"
fi
# 4. NPU设置为性能模式
echo "[4/5] 配置NPU性能模式..."
NPU_PATH="/sys/class/devfreq/fdab0000.npu"
if [ -d "$NPU_PATH" ]; then
echo performance > ${NPU_PATH}/governor
MAX_FREQ=$(cat ${NPU_PATH}/available_frequencies | awk '{print $NF}')
echo ${MAX_FREQ} > ${NPU_PATH}/min_freq
echo " NPU已设置为性能模式"
fi
# 5. 禁用powersave
echo "[5/5] 优化系统参数..."
echo 1 > /proc/sys/kernel/sched_child_runs_first
echo performance > /sys/devices/system/cpu/cpufreq/policy*/scaling_governor 2>/dev/null
echo ""
echo "=== 配置完成 ==="
echo "当前状态:"
echo " CPU0: $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq)Hz"
echo " CPU4: $(cat /sys/devices/system/cpu/cpu4/cpufreq/scaling_cur_freq)Hz"
echo " GPU: $(cat ${GPU_PATH}/cur_freq 2>/dev/null || echo N/A)Hz"
echo " NPU: $(cat ${NPU_PATH}/cur_freq 2>/dev/null || echo N/A)Hz"5 代码详解
5.1 CPU性能监控工具
5.1.1 perf 性能分析
perf 是 Linux 自带的性能剖析工具,能借助 CPU 硬件计数器统计指令数、缓存命中等指标,也能对全系统采样找出热点函数:
# 安装perf
sudo apt install linux-tools-$(uname -r)
# 查看CPU性能计数器事件
sudo perf list | head -30
# 记录CPU性能数据 (10秒)
sudo perf record -a -g -o perf.data -- sleep 10
# 分析性能数据
sudo perf report -i perf.data
# 统计CPU缓存命中率
sudo perf stat -e cache-references,cache-misses,instructions,cycles \
-a -- sleep 5
# 监控特定进程
sudo perf top -p <PID>5.1.2 使用mpstat监控多核
mpstat 属于 sysstat 套件,适合分别查看每个核心各自的使用率,确认负载有没有落在预期的核心上:
# 安装sysstat
sudo apt install sysstat
# 每2秒采样一次CPU使用率, 共10次
mpstat -P ALL 2 10
# 输出示例:
# CPU %usr %nice %sys %iowait %irq %soft %steal %idle
# all 25.34 0.00 5.12 0.23 0.01 0.45 0.00 69.85
# 0 30.12 0.00 6.23 0.11 0.00 0.52 0.00 63.02 (A76)
# 4 15.67 0.00 3.45 0.34 0.01 0.38 0.00 80.15 (A55)
# 查看每个核心的频率
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq | \
awk '{printf "CPU%d: %d MHz\n", NR-1, $1/1000}'5.1.3 使用top/htop监控
日常快速查看用 top 或 htop 就够了:
# htop安装和使用
sudo apt install htop
htop
# 在htop中:
# F5: 树状视图
# F6: 按CPU排序
# F9: 发送信号
# t: 显示/隐藏线程
# 按CPU核心分组显示
top -1 -d 2
# 按数字键1: 显示每个CPU核心
# 按P: 按CPU排序
# 按M: 按内存排序5.2 CPU亲和性编程示例
5.2.1 C语言示例
命令行绑核适合临时任务,程序内部绑核要用 pthread 的 affinity 接口。这个示例在所有核心上各起一个线程跑同样的计算,同时读出每个核心的实时频率,可以直接当基准测试用:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>
#include <pthread.h>
#include <time.h>
/* 获取CPU核心数 */
int get_cpu_count(void)
{
return sysconf(_SC_NPROCESSORS_ONLN);
}
/* 获取CPU频率 (KHz) */
unsigned long get_cpu_freq(int cpu)
{
char path[256];
FILE *fp;
unsigned long freq = 0;
snprintf(path, sizeof(path),
"/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", cpu);
fp = fopen(path, "r");
if (fp) {
fscanf(fp, "%lu", &freq);
fclose(fp);
}
return freq;
}
/* 将线程绑定到指定CPU核心 */
int pin_thread_to_cpu(pthread_t thread, int cpu_id)
{
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(cpu_id, &cpuset);
return pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
}
/* 工作线程函数 */
void *worker_thread(void *arg)
{
int cpu_id = *(int *)arg;
struct timespec start, end;
double elapsed;
volatile long long sum = 0;
/* 绑定到指定CPU */
pin_thread_to_cpu(pthread_self(), cpu_id);
printf("Thread running on CPU%d (freq: %lu KHz)\n",
cpu_id, get_cpu_freq(cpu_id));
/* 计算密集型任务 */
clock_gettime(CLOCK_MONOTONIC, &start);
for (long long i = 0; i < 1000000000LL; i++) {
sum += i * i;
}
clock_gettime(CLOCK_MONOTONIC, &end);
elapsed = (end.tv_sec - start.tv_sec) +
(end.tv_nsec - start.tv_nsec) / 1e9;
printf("CPU%d: %.3f seconds, sum=%lld\n", cpu_id, elapsed, sum);
return NULL;
}
int main(int argc, char *argv[])
{
int cpu_count = get_cpu_count();
pthread_t *threads;
int *cpu_ids;
printf("System has %d CPU cores\n", cpu_count);
printf("Running benchmark on each core...\n\n");
threads = malloc(cpu_count * sizeof(pthread_t));
cpu_ids = malloc(cpu_count * sizeof(int));
for (int i = 0; i < cpu_count; i++) {
cpu_ids[i] = i;
pthread_create(&threads[i], NULL, worker_thread, &cpu_ids[i]);
}
for (int i = 0; i < cpu_count; i++) {
pthread_join(threads[i], NULL);
}
free(threads);
free(cpu_ids);
return 0;
}编译运行:
gcc -o cpu_bench cpu_bench.c -lpthread -O2
./cpu_bench5.2.2 Python示例
这个脚本把前面用过的那些 sysfs 节点读取逻辑封装成一个循环监控器,每 2 秒打印一次 CPU、GPU、NPU 的频率、governor 和各处温度:
#!/usr/bin/env python3
"""
RK3588 CPU/GPU/NPU 性能监控工具
"""
import os
import time
import subprocess
import json
from pathlib import Path
from typing import Dict, List, Optional
class RK3588PerformanceMonitor:
"""RK3588性能监控器"""
CPU_BASE = Path("/sys/devices/system/cpu")
GPU_BASE = Path("/sys/class/devfreq/fb000000.gpu")
NPU_BASE = Path("/sys/class/devfreq/fdab0000.npu")
THERMAL_BASE = Path("/sys/class/thermal")
def __init__(self):
self.cpu_count = os.cpu_count()
self._detect_clusters()
def _detect_clusters(self):
"""检测CPU集群配置"""
self.clusters = {}
for cpu in range(self.cpu_count):
policy_path = self.CPU_BASE / f"cpu{cpu}" / "cpufreq" / "policy"
if policy_path.exists():
policy_dir = list(policy_path.parent.iterdir())[0] \
if policy_path.is_dir() else policy_path
# 简化: A76=0-3, A55=4-7
if cpu < 4:
self.clusters[cpu] = "A76"
else:
self.clusters[cpu] = "A55"
def get_cpu_info(self) -> List[Dict]:
"""获取所有CPU核心信息"""
info = []
for cpu in range(self.cpu_count):
base = self.CPU_BASE / f"cpu{cpu}" / "cpufreq"
info.append({
"cpu": cpu,
"cluster": self.clusters.get(cpu, "unknown"),
"cur_freq": self._read_file(base / "scaling_cur_freq"),
"max_freq": self._read_file(base / "scaling_max_freq"),
"min_freq": self._read_file(base / "scaling_min_freq"),
"governor": self._read_file(base / "scaling_governor"),
})
return info
def get_gpu_info(self) -> Dict:
"""获取GPU信息"""
return {
"cur_freq": self._read_file(self.GPU_BASE / "cur_freq"),
"max_freq": self._read_file(self.GPU_BASE / "max_freq"),
"governor": self._read_file(self.GPU_BASE / "governor"),
}
def get_npu_info(self) -> Dict:
"""获取NPU信息"""
if not self.NPU_BASE.exists():
return {"error": "NPU device not found"}
return {
"cur_freq": self._read_file(self.NPU_BASE / "cur_freq"),
"max_freq": self._read_file(self.NPU_BASE / "max_freq"),
"governor": self._read_file(self.NPU_BASE / "governor"),
}
def get_temperatures(self) -> Dict[str, float]:
"""获取所有温度"""
temps = {}
for tz_dir in self.THERMAL_BASE.glob("thermal_zone*"):
zone_type = self._read_file(tz_dir / "type")
zone_temp = self._read_file(tz_dir / "temp")
if zone_type and zone_temp:
try:
temps[zone_type] = int(zone_temp) / 1000.0
except (ValueError, TypeError):
pass
return temps
def print_status(self):
"""打印完整性能状态"""
print("=" * 65)
print("RK3588 Performance Status")
print("=" * 65)
# CPU
print("\n[Cores]")
for info in self.get_cpu_info():
freq_mhz = int(info["cur_freq"]) // 1000 if info["cur_freq"] else 0
print(f" CPU{info['cpu']} ({info['cluster']}): "
f"{freq_mhz} MHz | gov={info['governor']}")
# GPU
gpu = self.get_gpu_info()
gpu_mhz = int(gpu["cur_freq"]) // 1000000 if gpu.get("cur_freq") else 0
print(f"\n[GPU] {gpu_mhz} MHz | gov={gpu.get('governor', 'N/A')}")
# NPU
npu = self.get_npu_info()
if "error" not in npu:
npu_mhz = int(npu["cur_freq"]) // 1000000 if npu.get("cur_freq") else 0
print(f"[NPU] {npu_mhz} MHz | gov={npu.get('governor', 'N/A')}")
# 温度
temps = self.get_temperatures()
if temps:
print("\n[Temperatures]")
for zone, temp in temps.items():
print(f" {zone}: {temp:.1f} C")
print("=" * 65)
@staticmethod
def _read_file(path: Path) -> Optional[str]:
try:
return path.read_text().strip()
except (FileNotFoundError, PermissionError):
return None
def main():
monitor = RK3588PerformanceMonitor()
try:
while True:
monitor.print_status()
time.sleep(2)
except KeyboardInterrupt:
print("\nMonitoring stopped.")
if __name__ == "__main__":
main()运行:
chmod +x rk3588_monitor.py
sudo python3 rk3588_monitor.py5.3 GPU基准测试
glmark2 是常用的 OpenGL 基准测试,会跑一组场景并给出总分,适合对比 GPU 调优前后的差异:
# 使用glmark2测试GPU
# DRM模式 (适用于无桌面环境)
glmark2-drm
# Wayland模式
glmark2-wayland
# 2D测试
glmark2-drm --run-vertex-transform
# 查看GPU详细信息
cat /sys/class/devfreq/fb000000.gpu/trans_stat
# GPU负载监控
watch -n 1 "cat /sys/class/devfreq/fb000000.gpu/cur_freq; \
cat /sys/class/devfreq/fb000000.gpu/trans_stat | head -5"5.4 NPU推理基准测试
这份 C 代码用 rknpu2 的 API 分别测试 NPU 单核、双核、三核等配置下的推理速度,跑完就知道你的模型适合哪种核心组合:
/*
* NPU多核推理示例 (使用rknpu2 API)
* 文件: npu_benchmark.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <rknn_api.h>
#include <rknn_matmul_api.h>
/* 选择NPU核心进行推理 */
static rknn_context create_rknn_context(const char *model_path,
int core_mask)
{
rknn_context ctx;
int ret;
ret = rknn_init(&ctx, (void *)model_path, 0, 0, NULL);
if (ret < 0) {
fprintf(stderr, "rknn_init failed: %d\n", ret);
return -1;
}
/* 设置NPU核心掩码 */
ret = rknn_set_core_mask(ctx, core_mask);
if (ret < 0) {
fprintf(stderr, "rknn_set_core_mask failed: %d\n", ret);
rknn_destroy(ctx);
return -1;
}
return ctx;
}
/* 测试不同核心配置的推理性能 */
void benchmark_core_configs(const char *model_path)
{
struct {
int core_mask;
const char *desc;
} configs[] = {
{ RKNN_NPU_CORE_AUTO, "Auto" },
{ RKNN_NPU_CORE_0, "Core 0" },
{ RKNN_NPU_CORE_1, "Core 1" },
{ RKNN_NPU_CORE_2, "Core 2" },
{ RKNN_NPU_CORE_0_1, "Core 0+1" },
{ RKNN_NPU_CORE_0_1_2, "All 3" },
};
int num_configs = sizeof(configs) / sizeof(configs[0]);
printf("NPU Benchmark: %s\n", model_path);
printf("%-12s | %10s | %8s\n", "Config", "Time(ms)", "FPS");
printf("%-12s-+-%10s-+-%8s\n", "------------", "----------", "--------");
for (int i = 0; i < num_configs; i++) {
rknn_context ctx = create_rknn_context(model_path,
configs[i].core_mask);
if (ctx < 0) continue;
/* 获取输入输出信息 */
rknn_input_output_num io_num;
rknn_query(ctx, RKNN_QUERY_IN_OUT_NUM, &io_num,
sizeof(io_num));
/* 分配输入缓冲区 */
rknn_input inputs[io_num.n_input];
memset(inputs, 0, sizeof(inputs));
for (int j = 0; j < io_num.n_input; j++) {
inputs[j].index = j;
inputs[j].type = RKNN_TENSOR_UINT8;
inputs[j].fmt = RKNN_TENSOR_NHWC;
inputs[j].size = 224 * 224 * 3;
inputs[j].buf = calloc(1, inputs[j].size);
}
/* 预热 */
for (int w = 0; w < 5; w++) {
rknn_inputs_set(ctx, io_num.n_input, inputs);
rknn_output outputs[io_num.n_output];
memset(outputs, 0, sizeof(outputs));
for (int j = 0; j < io_num.n_output; j++) {
outputs[j].want_float = 1;
}
rknn_run(ctx, NULL);
rknn_outputs_get(ctx, io_num.n_output, outputs, NULL);
rknn_outputs_release(ctx, io_num.n_output, outputs);
}
/* 正式测试 */
struct timespec start, end;
int iterations = 50;
clock_gettime(CLOCK_MONOTONIC, &start);
for (int t = 0; t < iterations; t++) {
rknn_inputs_set(ctx, io_num.n_input, inputs);
rknn_output outputs[io_num.n_output];
memset(outputs, 0, sizeof(outputs));
for (int j = 0; j < io_num.n_output; j++) {
outputs[j].want_float = 1;
}
rknn_run(ctx, NULL);
rknn_outputs_get(ctx, io_num.n_output, outputs, NULL);
rknn_outputs_release(ctx, io_num.n_output, outputs);
}
clock_gettime(CLOCK_MONOTONIC, &end);
double elapsed = (end.tv_sec - start.tv_sec) +
(end.tv_nsec - start.tv_nsec) / 1e9;
double avg_ms = (elapsed / iterations) * 1000.0;
double fps = iterations / elapsed;
printf("%-12s | %10.2f | %8.1f\n",
configs[i].desc, avg_ms, fps);
/* 清理 */
for (int j = 0; j < io_num.n_input; j++) {
free(inputs[j].buf);
}
rknn_destroy(ctx);
}
}
int main(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "Usage: %s <model.rknn>\n", argv[0]);
return 1;
}
benchmark_core_configs(argv[1]);
return 0;
}编译:
gcc -o npu_benchmark npu_benchmark.c \
-lrknpu2 -I/usr/include/rknpu2 -O2
./npu_benchmark model.rknn6 常见问题
6.1 CPU频率无法提升
频率上不去通常逃不出三类原因:过热降频、权限不够、调度策略保守。先对照下表定位,再按后面的命令逐项检查:
| 问题 | 原因 | 解决方案 |
|---|---|---|
| CPU锁定在低频 | thermal throttling | 检查温度: cat /sys/class/thermal/thermal_zone*/temp |
| 无法切换governor | 权限不足 | 使用 sudo 执行 |
| 频率跳变不稳定 | schedutil参数过保守 | 调小 rate_limit_us |
| 某些核心不上频 | EAS调度策略 | 设置 performance governor |
# 诊断CPU频率问题
echo "=== CPU温度 ==="
cat /sys/class/thermal/thermal_zone0/temp
echo "=== 当前governor ==="
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
echo "=== 频率范围 ==="
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq
echo "=== 当前频率 ==="
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
# 如果thermal导致降频, 可以临时提高阈值
echo 95000 | sudo tee /sys/class/thermal/thermal_zone0/trip_point_0_temp6.2 GPU性能不足
GPU 的问题多半出在 governor 设置和频率波动上:
| 问题 | 原因 | 解决方案 |
|---|---|---|
| GPU频率上不去 | governor设置 | 切换到 performance |
| 3D渲染卡顿 | 频率波动大 | 锁定最高频率 |
| OpenCL慢 | 未使用GPU | 确认程序使用GPU而非CPU |
# GPU性能排查
echo "=== GPU信息 ==="
cat /sys/class/devfreq/fb000000.gpu/cur_freq
cat /sys/class/devfreq/fb000000.gpu/governor
# 设置GPU性能模式
echo performance | sudo tee /sys/class/devfreq/fb000000.gpu/governor
# 检查GPU是否在使用
cat /sys/kernel/debug/dri/0/state | grep -A5 "fb000000.gpu"6.3 NPU无法达到6 TOPS
推理速度上不来时,按下面的表逐项排查,多数情况是核心没用满或模型没量化:
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 推理速度慢 | 未使用全部NPU核心 | 设置 RKNN_NPU_CORE_0_1_2 |
| NPU频率低 | governor未设为performance | 切换governor |
| 模型未优化 | INT8量化 | 使用RKNN工具进行量化 |
| 内存带宽瓶颈 | DDR频率低 | 检查DDR频率配置 |
# NPU状态检查
cat /sys/class/devfreq/fdab0000.npu/cur_freq
cat /sys/class/devfreq/fdab0000.npu/governor
# 设置NPU性能模式
echo performance | sudo tee /sys/class/devfreq/fdab0000.npu/governor
# 查看NPU驱动加载状态
dmesg | grep -i "rknpu"
lsmod | grep rknpu
# RKNN模型转换优化 (使用rknn-toolkit2)
python3 -c "
import rknn.api
rknn = rknn.api.RKNN()
rknn.config(mean_values=[[128,128,128]],
std_values=[[128,128,128]],
target_platform='rk3588')
rknn.load_rknn('model.rknn')
print('RKNN model loaded successfully')
"6.4 实时任务延迟高
实时性问题的排查思路:先确认内核有没有实时支持(PREEMPT_RT 实时补丁,标准内核没有,需要单独编译),再检查中断和调度干扰,最后用 cyclictest(实时延迟测试工具)量化延迟:
# 诊断实时性能
# 1. 检查内核是否支持PREEMPT_RT
zcat /proc/config.gz | grep CONFIG_PREEMPT
# CONFIG_PREEMPT=y (标准内核)
# CONFIG_PREEMPT_RT=y (RT内核, 需要单独编译)
# 2. 检查中断亲和性
cat /proc/interrupts | head -20
# 3. 设置CPU隔离 (排除后台任务)
# 在内核启动参数中添加:
# isolcpus=4-7 (隔离A55核心给实时任务)
# 或
# isolcpus=2-3 (隔离部分A76核心)
# 4. 禁用CPU频率变化 (实时任务要求)
echo performance | sudo tee /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# 5. 测量任务切换延迟
sudo cyclictest -t8 -p99 -i1000 -l10000 -m
# -t8: 8个线程
# -p99: 最高优先级
# -i1000: 1ms间隔
# -l10000: 运行10000次
# -m: 锁定内存
# 6. 查看中断分布
watch -n 1 "cat /proc/interrupts | grep -E 'GIC|ethernet|usb'"6.5 功耗与散热问题
温度异常或功耗偏高时,按下面的命令检查供电、风扇和温度趋势:
# 监控功耗 (如硬件支持)
cat /sys/class/power_supply/*/power_now 2>/dev/null
# 检查散热风扇状态
cat /sys/class/thermal/cooling_device*/type
cat /sys/class/thermal/cooling_device*/cur_state
# 设置风扇策略
# active cooling: 温度达到阈值时开启风扇
cat /sys/class/thermal/thermal_zone*/trip_point_1_type
# active
# 监控温度变化趋势
for i in $(seq 1 60); do
temp=$(cat /sys/class/thermal/thermal_zone0/temp)
echo "$(date '+%H:%M:%S') CPU: $((temp/1000))°C"
sleep 1
done6.6 big.LITTLE调度异常
任务总是跑错核心时,先查 EAS 开关是否打开,再看任务实际分布在哪些核心上,必要时手动迁移:
# 查看EAS调度状态
cat /proc/sys/kernel/sched_energy_aware
# 确保为1
# 查看任务分布
ps -eo pid,psr,comm --sort=-pcpu | head -20
# psr: 运行在哪个CPU
# 手动迁移高负载任务到大核
taskset -c 0-3 ./heavy_computation
# 查看调度器统计
cat /proc/schedstat
cat /proc/sched_debug | head -50
# 查看CPU负载均衡
cat /proc/schedstat | awk '{print $2}' | sort -rn7 相关文档
| 文档名称 | 说明 | 路径 |
|---|---|---|
| RK3588 Linux开发指南 | Rockchip官方Linux开发文档 | S-01 |
| C-3588LQ核心板规格书 | 核心板硬件规格 | S-02 |
| SHIMETAPI-M5-R2A底板原理图 | 底板电路设计 | S-03 |
| RK3588 TRM | 技术参考手册 | Rockchip官网 |
| Linux Kernel Documentation - CPUFreq | CPU调频文档 | 内核源码Documentation/ |
| Mali-G610 GPU用户手册 | GPU开发指南 | Arm Developer |
