一、前言
开发板:香橙派 5Plus。
librknnrt.so 版本:2.3.0。
rknn driver:0.9.8。
本次的页面设计基于之前写的手写FrameBuffer驱动:
Linux手写FrameBuffer任意引脚驱动spi屏幕_rk3588 framebuffer-CSDN博客https://blog.csdn.net/plmm__/article/details/145193029?spm=1001.2014.3001.5501之前只写好了应用层的框架,具体的页面内容只有时间。本次基于之前的驱动接口和应用框架,使用sysfs接口查询常用的硬件信息,解析字符串后显示到oled。
二、硬件信息查询
由于本人的需求是快速查看CPU和NPU的占用率,便于实时调整软件资源,所以显示的信息共四条:CPU占用率、GPU占用率、NPU占用率、芯片温度。
1、CPU占用率
CPU占用率使用 mpstat 软件查看,C程序内的函数为:
/**
* @Description: 获取 CPU 占用率
* @return {*}
*/
int get_cpu_usage(char *cpu_usage, size_t size) {
// 使用mpstat命令获取CPU占用率,popen 打开的文件会将命令的输出保留在一个缓冲区中
// mpstat 1 1 表示每秒采样一次,共采样一次
// /all/:匹配包含 all 的行,$NF 表示最后一列(即 %idle,CPU 空闲率),head -n 1 限制只输出第一行
FILE *fp = popen("mpstat 1 1 | awk '/all/ {print 100 - $NF}' | head -n 1", "r");
if (fp == NULL) {
perror("Failed to run mpstat command");
return -1;
}
// 读取命令输出
char temp[size];
if (fgets(temp, size, fp) == NULL) {
perror("Failed to read CPU usage");
pclose(fp);
return -1;
}
pclose(fp);
// 添加前缀
snprintf(cpu_usage, size, "CPU: %.2f%%", atof(temp));
// 查找字符串中的换行符并将其替换为终止符 \0,确保字符串没有多余的换行符
cpu_usage[strcspn(cpu_usage, "\n")] = '\0';
return 0;
}
mpstat 1 1是查看CPU使用相对简单的指令,便于快速截取需要的信息,两个1分别代表间隔1秒和查询1次,它的输出为:
输出没有占用率的总和,用100减去最后的空闲即可,其余细节代码中都有详细说明。
2、GPU占用率
sysfs接口以开发板实际为准,我这里为:
/sys/class/devfreq/fb000000.gpu/load
C函数:
/**
* @Description: 获取 GPU 占用率
* @return {*}
*/
int get_gpu_usage(char *gpu_usage, size_t size) {
FILE *file = fopen("/sys/class/devfreq/fb000000.gpu/load", "r");
if (file == NULL) {
perror("Failed to open GPU load file");
return -1;
}
char line[size];
if (fgets(line, size, file) == NULL) {
perror("Failed to read GPU load");
fclose(file);
return -1;
}
fclose(file);
// 提取@前的数字
char *at_pos = strchr(line, '@');
if (at_pos == NULL) {
fprintf(stderr, "Invalid GPU load format\n");
return -1;
}
*at_pos = '\0'; // 截断字符串,保留@前的部分
// 添加前缀
snprintf(gpu_usage, size, "GPU: %d%%", atoi(line));
return 0;
}
3、NPU占用率
瑞芯微的接口应该都是一样的:
/sys/kernel/debug/rknpu/load
C函数:
/**
* @Description: 获取 NPU 占用率
* @return {*}
*/
int get_npu_usage(char *npu_usage, size_t size) {
FILE *file = fopen("/sys/kernel/debug/rknpu/load", "r");
if (file == NULL) {
perror("Failed to open NPU load file");
return -1;
}
// 读取文件内容
char line[size];
if (fgets(line, size, file) == NULL) {
perror("Failed to read NPU load file");
fclose(file);
return -1;
}
fclose(file);
// 添加前缀
snprintf(npu_usage, size, "NPU: ");
// 使用 strchr 查找 % 并提取数字
char *ptr = line;
int core_count = 0;
while ((ptr = strchr(ptr, '%')) != NULL) {
char *num_start = ptr - 1;
// 回溯直到找到数字的起始位置
while (num_start >= line && isdigit(*(num_start - 1))) {
num_start--;
}
// 提取数字,atoi 会从给定的字符串起始位置开始解析,直到遇到第一个非数字字符为止(%前的所有数字)
if (isdigit(*num_start)) {
int value = atoi(num_start);
if (value >= 0 && value <= 100) {
// 将数字追加到结果字符串中
char buffer[4]; // 最多三位数字
snprintf(buffer, sizeof(buffer), "%d%%", value);
strcat(npu_usage, buffer);
if (core_count >= 0 && core_count < 2) {
strcat(npu_usage, " "); // 添加空格分隔
}
core_count++;
} else {
// 如果数字不在 0-100 范围内,跳过
fprintf(stderr, "Invalid NPU load value: %d (must be 0-100)\n", value);
}
} else {
// 如果 num_start 指向的位置不是数字字符,跳过
fprintf(stderr, "Invalid NPU load format: expected a number before %%\n");
}
ptr++; // 继续查找下一个 %
}
return 0;
}
由于官方给的输出结果较长,于是我选择先找百分号,再找它前面的数字,实现起来相对简单,就是代码长了点。
4、芯片温度
温度使用 sensors 软件获取,香橙派手册使用的就是这个。这里我使用 awk 来解析输出,代码中也给出了解释:
/**
* @Description: 获取芯片温度
* @return {*}
*/
int get_temperature(char *temperature, size_t size) {
// 使用sensors命令获取温度
FILE *fp = popen("sensors | awk '/temp1/ {print $2}' | head -n 1", "r");
if (fp == NULL) {
perror("Failed to run sensors command");
return -1;
}
// 读取命令输出
char line[size];
if (fgets(line, size, fp) == NULL) {
perror("Failed to read chip temperature");
pclose(fp);
return -1;
}
pclose(fp);
// 添加前缀
snprintf(temperature, size, "Temper: %s", line);
// 去掉换行符
temperature[strcspn(temperature, "\n")] = '\0';
return 0;
}
三、总结
源码我会推送至 Github 仓库和 Gitee 仓库,由于懒得设计UI,都是直接显示字符串,这里放一张 YOLO 推理时的截图(C艹多线程,140+帧):
1125962926/spi-oled-driver: Framebuffer drivers implemented by char-devices that can change pins at willhttps://github.com/1125962926/spi-oled-driverspi-oled-driver: 手写Linux FrameBuffer 0.96 寸 spi 屏幕驱动,支持从 app 传入任意引脚
https://gitee.com/lrf1125962926/spi-oled-driver