k210计算cpu使用率
前言
博客停更一年多,快两年,少见的更新一下,表示一下这个博客我还在用,hahahaha
运行环境
- MAIX-GO (K210双核400M单片机)
- rt-thread 4.0.3
- eclipse GNU
找轮子
本着不重复造轮子的准则,我先找找有没有可以重复使用的轮子,果不其然我在rt-thread的官方例程里找到了计算cpu使用率的例子。
好,本篇完!
正片
好了,不开玩笑,如果真是这样我还写什么记录。
要知道在这里我们的k210是一片双核400M的芯片,而例程提供的是单核的。
rt-thread提供的例子原理就是先关闭所有中断,然后记录100ms里,cpu对一变量的累加次数得total count,再以此为参考,在之后的每100ms进行累加得count。count值比total count值即为cpu使用率。
原理很简单,理解之后我们进行一些简单的改造,这里,我这里定义了一个结构体
typedef struct cpu_usage
{
rt_uint64_t total_count;
rt_uint64_t count;
rt_uint8_t cpu_usage_major;
rt_uint8_t cpu_usage_minor;
} cpu_usage;
static cpu_usage cpus[2] = {0};
很好理解,这个结构体记录了各个核心各自的数据,计算的钩子函数也顺理成章的写出来
static void cpu_usage_idle_hook()
{
rt_tick_t tick;
rt_uint8_t core = current_coreid();
if (cpus[core].total_count == 0)
{
/* get total count */
rt_enter_critical();
tick = rt_tick_get();
while (rt_tick_get() - tick < CPU_USAGE_CALC_TICK)
{
cpus[core].total_count++;
}
rt_exit_critical();
}
cpus[core].count = 0;
/* get CPU usage */
tick = rt_tick_get();
while (rt_tick_get() - tick < CPU_USAGE_CALC_TICK)
{
cpus[core].count++;
}
/* calculate major and minor */
if (cpus[core].count < cpus[core].total_count)
{
cpus[core].count = cpus[core].total_count - cpus[core].count;
cpus[core].cpu_usage_major = (cpus[core].count * 100) / cpus[core].total_count;
cpus[core].cpu_usage_minor = ((cpus[core].count * 100) % cpus[core].total_count) * 100 / cpus[core].total_count;
}
else
{
cpus[core].total_count = cpus[core].count;
/* no CPU usage */
cpus[core].cpu_usage_major = 0;
cpus[core].cpu_usage_minor = 0;
}
}
我们再写一个查看cpu使用率的函数
static void get_cpu_usage(void)
{
rt_kprintf("cpu usage total\n");
rt_kprintf("--- ------ ---------\n");
for (int core = 0; core < 2; core++)
{
rt_kprintf(" %d %02d.%02d%% %8d\n", core, cpus[core].cpu_usage_major, cpus[core].cpu_usage_minor,
cpus[core].total_count);
}
}
MSH_CMD_EXPORT(get_cpu_usage, get cpu usage);
ok,编写完成,编译,下载!
核心2获取失败
事情并没有那么一番风顺,下载到板子上后具体的效果
msh >get_cpu_usage
cpu usage total
--- ------ ---------
0 04.56% 1115625
1 00.00% 0
???可以看到核心2的total是0,这意味着钩子函数在核心2上一次都没有运行过。
简单判断一下,应该是钩子函数没有挂上核心2或者rt-thread对核心2根本不支持钩子函数。有了思路就很容易定位到应该是idle线程的处理方式上有一些特别之处,打开源码
static void rt_thread_idle_entry(void *parameter)
{
#ifdef RT_USING_SMP
if (rt_hw_cpu_id() != 0)
{
while (1)
{
rt_hw_secondary_cpu_idle_exec();
}
}
#endif
while (1)
{
#ifdef RT_USING_IDLE_HOOK
rt_size_t i;
for (i = 0; i < RT_IDLE_HOOK_LIST_SIZE; i++)
{
if (idle_hook_list[i] != RT_NULL)
{
idle_hook_list[i]();
}
}
#endif
rt_thread_idle_excute();
#ifdef RT_USING_PM
rt_system_power_manager();
#endif
}
}
可以看到,对于不是核心1,idle线程都会进入到函数rt_hw_secondary_cpu_idle_exec()中,打开这个函数发现他是一个内联汇编函数,运行指令wfi。
void rt_hw_secondary_cpu_idle_exec(void)
{
asm volatile ("wfi");
}
wfi指令就是wait for interrupt,意思就是等待中断到来,他会停止当前cpu的指令流,直到发生中断,这个指令的目的就是为了降低功耗。wfi有点类似于NOP,不同的是,nop还是在运行指令,而wfi是停止运行了。
找到问题,那我们简单修改一下空闲线程的处理方式就好了。让他非核心1的时候也运行钩子函数。
if (rt_hw_cpu_id() != 0)
{
while (1)
{
#ifdef RT_USING_IDLE_HOOK
rt_size_t i;
for (i = 0; i < RT_IDLE_HOOK_LIST_SIZE; i++)
{
if (idle_hook_list[i] != RT_NULL)
{
idle_hook_list[i]();
}
}
#endif
rt_hw_secondary_cpu_idle_exec();
}
}
再运行一次
msh >get_cpu_usage
cpu usage total
--- ------ ---------
0 04.73% 1115760
1 01.76% 1115681
msh >
Great! 这次两块核心的cpu使用率都显示出来了,到这对于k210的cpu使用率的计算就到这里,准备再出一期计算各个线程的cpu使用率的记录,应该最近就出,不过也有可能是有生之年系列,hahahahaha
对于代码我已经上传到我的仓库,同时我对k210的几乎所有魔改都会上传到这个仓库,有兴趣的可以自己去看看。
觉得有意思就点个star吧,秋梨膏