首先说下在RT-Thread中如何计算CPU使用率的,它先在关闭中断的情况下,在一个时间片内(比如100ms),对一个基准变量进行循环累加,得出最大的基准累加值。然后系统正常运行,在Idle任务中对另一个变量进行累加,时间片结束时,累加停止,与基准累加值计算,得出CPU使用率。
这种计算得出的cpu使用率,由于时间片较大,一般是用于调试或交互的信息输出。
在事件驱动机制中,由于除中断外所有待处理任务都会被放在vsfsm_evtq_head链表中,程序可以很清楚的知道下一刻是否有任务需要执行。这种情况下,只要提供一个us级的硬件定时器,并将其中断周期设置为我们所需要的时间片长度(如2ms),然后,当程序在空闲(vsfsm_evtq_head链表为空)和运行(vsfsm_evtq_head链表非空)两种状态间切换时,可以获得本次状态所维持的us时间,进行累加记录。当一个时间片结束时,就可以通过两种状态的总维持时间获得CPU的使用/空闲率了。当然这个比率是将中断剔除在外的,并不是十分的精确。
与RT-Thread中不一样,事件驱动中的cpu使用率并不仅仅是给大家看的,这个使用率可以用来动态调整cpu的工作频率。当使用率高时,我们可以提高cpu频率,当使用率低时,可以降低cpu频率。通过辅以一个较好的时间片长度和频率调整规则,便可以让cpu长时间工作在低频率状态下,并可以非常快的提升频率以响应重负载任务。
但是,如果系统一直处于可休眠状态,这个cpu频率动态调整的意义就不是很大,当系统不可休眠时,cpu降频将是一个非常好的节能方案。
参考代码:
- // vsfsm_get_event_pending should be called with interrupt disabled
- uint32_t vsfsm_get_event_pending(void)
- {
- #if VSFSM_CFG_AUTO_FREQ_EN
- static void vsfsm_auto_freq_record(uint32_t is_busy);
- vsfsm_auto_freq_record(vsfsm_evt_count);
- #endif // VSFSM_CFG_AUTO_FREQ_EN
- return vsfsm_evt_count;
- }
复制代码- #if VSFSM_CFG_AUTO_FREQ_EN
- static uint32_t intervalus = 10000, busyus = 0, freeus = 0;
- static void (*app_auto_freq_callback_int)(uint8_t rate);
- enum vsfsm_cpu_state_t
- {
- CPU_STATE_FREE = 0,
- CPU_STATE_BUSY = 1,
- } static vsfsm_cpu_state = CPU_STATE_BUSY;
- static void vsfsm_auto_freq_record(uint32_t is_busy)
- {
- if ((vsfsm_cpu_state == CPU_STATE_FREE) && (is_busy != 0))
- {
- //freeus += core_interfaces.core.get_increment_ustick();
- vsfsm_cpu_state = CPU_STATE_BUSY;
- }
- else if ((vsfsm_cpu_state != CPU_STATE_FREE) && (is_busy == 0))
- {
- //busyus += core_interfaces.core.get_increment_ustick();
- vsfsm_cpu_state = CPU_STATE_FREE;
- }
- }
- static void vsfsm_auto_freq_callback_int(uint32_t us)
- {
- uint8_t cpu_rate; // 0 -> 0%, 1 -> 0.5%, ..., 200 -> 100%
- if (vsfsm_cpu_state == CPU_STATE_FREE)
- {
- freeus += us;
- }
- else if (vsfsm_cpu_state != CPU_STATE_FREE)
- {
- busyus += us;
- }
- cpu_rate = (busyus * 200) / intervalus;
- freeus = 0;
- busyus = 0;
- // TODO: freq adjust
- // if (cpu_rate > )
- // if (cpu_rate < )
- if (app_auto_freq_callback_int)
- app_auto_freq_callback_int(cpu_rate);
- }
- vsf_err_t vsfsm_auto_freq_init(uint32_t interval,
- void (*callback_int)(uint8_t rate))
- {
- if (interval < 500)
- return VSFERR_INVALID_PARAMETER;
- else
- intervalus = interval;
- busyus = 0;
- freeus = 0;
- app_auto_freq_callback_int = callback_int;
- vsfsm_cpu_state = CPU_STATE_BUSY;
- //return core_interfaces.core.ustick_init(interval,
- // vsfsm_auto_freq_callback_int);
- }
- #endif // VSFSM_CFG_AUTO_FREQ_EN
复制代码
工程:git.oschina.net/le062/LPCXpresso54102-leop