如何测试嵌入式处理器的CPU使用率 - yanhc

时间:2024-03-09 16:07:37

如何测试嵌入式处理器的CPU使用率

某个网站的方法

需要使用逻辑分析仪

https://www.embedded.com/how-to-calculate-cpu-utilization/

CPU Utilization使用率定义:

 

 由1,需要计算空闲任务执行时间。空闲任务一般如下:

 1 Listing 1: Simple example of a background loop
 2 
 3 int main( void )
 4 {
 5    SetupInterrupts();
 6    InitializeModules();
 7    EnableInterrupts();
 8 
 9    while(1)      /* endless loop – spin in the background */
10    {
11       CheckCRC();
12       MonitorStack();
13do other non-time critical logic here.
14    }
15 }

不改变代码的方式来计算空闲任务执行时间有3种。

第1种

使用逻辑分析仪LSA(Logic State Analyzer)检测地址线,若访问了while(1)里代码所在的地址(具体地址可以通过map文件获得),则认为在执行空闲任务(如何获得数据呢,访问一次地址记录一次时刻?文中180us是空闲任务执行时间?那剩余的时间被谁在执行呢?)。获取的数据需要做野值剔除,因为空闲任务会被中断打断,会被高优先级任务打断,若打断了则空闲任务时间会被延长。

第2种

用公式3,看不懂。

第3种

一种自动化的方式,需要高精度时钟,比如空闲任务需要180us,则需要20分之一精度的时钟,180/20=9us。

 

CPU使用率最好在50%以内。

 

一种针对Arduino的方法,AVR

https://spin.atomicobject.com/2012/05/02/measuring-cpu-utilization/

https://github.com/chrishonson/Arduino_CPU_Usage

基本原理就是需要一个高精度时钟,来计数。

Measuring CPU Utilization

Understanding processor load in an embedded system is important, yet often overlooked. It’s a step toward analyzing your processor’s ability to meet system deadlines. I have provided a sample arduino sketch to show how you can add real-time CPU utilization measurements to your embedded project.

CPU utilization is simply the ratio of time a processor spends doing real work over a given period of time. The time of measurement can be arbitrary. Ideally, it’s better to align your measurement time with the shortest deadline time in your project; it depends on the goals of the CPU utilization measurement. If you have to service a communication bus 10ms after receiving an input, and it takes 9ms to perform the necessary processing, then you may want to measure utilization over 10ms so that you can capture this 90% worst case, critical path. For the purpose of simplicity and illustration I will measure over 1s.

The first thing we are going to need is a reliable timing source. I recommend setting up a timer interrupt. I could explain how to, but luckily someone else already has here. In my example I chose to use timer 2 since timer 1 is used by the servo library and I might actually use that in the future.

The next step in setting up your project is defining what 0% utilization is. The most basic way of doing this is by incrementing a counter in your idle task (in this case loop()) and seeing how many idle counts occur during a measurement period. If no work is being done (besides the timer interrupt) then this represents the maximum number of idle counts and 0% utilization. One might argue that the act of calculating idle counts is work and that 0% utilization is not achievable with the instrumentation code in place. That’s true, but I think such concerns are negligible when the CPU utilization measurement period is sufficiently large.

Anyway, it’s important to note, here, that once you determine the maximum idle counts, no code can be added to the idle task. This would change the maximum idle counts. In general, I think the idle task should do essentially nothing. Where then can you get useful work done?

My example provides a very simple, round robin, periodic task scheduler. Here you can perform calculations as fast or as slow as required. It’s also noteworthy that I used the ISR only to notify tasks that they are ready to run. It’s good practice to keep ISR’s as fast as possible and to keep application code out in order to prevent problems with shared data.

To test my example I simply add a delay(50) to my 100ms task. This will run 10 times in one second. 10*50ms=500ms I should calculate 50% utilization and if I run the example I see that it does.

Feel free to use my template as you wish. I recommend moving any activity out of loop() and putting it into one of the task functions.
View Code

 

一个介绍任务和中断贡献资源保护的课件,

链接:https://pan.baidu.com/s/1UHnLI6SsJQnns7ys8kQd8g
提取码:zf5c

FreeRTOS的方法

FreeRTOSConfig.h使能configGENERATE_RUN_TIME_STATS

1 #define configGENERATE_RUN_TIME_STATS            1
2 #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ConfigureTimeForRunTimeStats()
3 #define portGET_RUN_TIME_COUNTER_VALUE() FreeRTOSRunTimeTicks

timer.c中配置定时器

 1 #include "timer.h"
 2 
 3 void TIM2_Init(u16 auto_data,u16 fractional)
 4 {
 5     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
 6     NVIC_InitTypeDef NVIC_InitStructure;
 7     
 8     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);      //ʹ��TIM2ʱ��
 9     
10   TIM_TimeBaseInitStructure.TIM_Period = auto_data;          //�Զ���װ��ֵ
11     TIM_TimeBaseInitStructure.TIM_Prescaler=fractional;      //��ʱ����Ƶ
12     TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //���ϼ���ģʽ
13     TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
14     
15     TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//��ʼ��TIM2
16     
17     TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //�����ʱ��2�����ж�
18     TIM_Cmd(TIM2,ENABLE);                    //ʹ�ܶ�ʱ��2
19     
20     NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn; //��ʱ��2�ж�
21     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //��ռ���ȼ�1
22     NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03;  //�����ȼ�3
23     NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
24     NVIC_Init(&NVIC_InitStructure);
25 }
26 
27 volatile unsigned long long FreeRTOSRunTimeTicks;
28 
29 void ConfigureTimeForRunTimeStats()
30 {
31     FreeRTOSRunTimeTicks = 0;
32     TIM2_Init(50-1, 90-1);
33 }
34 
35 
36 //��ʱ��3�жϷ�����
37 void TIM2_IRQHandler(void)
38 {
39     if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET) //����ж�
40     {
41         ++FreeRTOSRunTimeTicks;
42     }
43     TIM_ClearITPendingBit(TIM2,TIM_IT_Update);  //����жϱ�־λ
44 }

main.c,在某个任务中获取信息并通过串口打印

 1 char RunTimeInfo[400];
 2 
 3 void ToggleLed4(void * pvParameters)
 4 {
 5   while(1)
 6   {
 7     /* toggle LED4 each 250ms */
 8     GPIOE->ODR ^= GPIO_Pin_3;
 9     vTaskDelay(1000);
10 
11     memset(RunTimeInfo, 0, 400);
12     vTaskGetRunTimeStats((signed char *)RunTimeInfo);
13     printf("%s\r\n", RunTimeInfo);
14   }
15 }

串口打印结果:只能打印一次,后面就进Hard Fault了。。。原因未知。。。

LED4        0        0%
IDLE        24834        9%
slipif_loop        3        <1%
slipif_loop        0        0%
E_link        4        <1%
Eth_if        4        <1%
TCP/IP        811        <1%
ospf_task        3293        1%
udpsocktx_threa        14        <1%
Main        244709        89%
snmp_netconn        1        <1%