Skip to content

Commit ee72f27

Browse files
committed
add context switch test code
1 parent a1e8651 commit ee72f27

File tree

4 files changed

+203
-0
lines changed

4 files changed

+203
-0
lines changed

examples/utest/testcases/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ rsource "posix/Kconfig"
1717
rsource "mm/Kconfig"
1818
rsource "tmpfs/Kconfig"
1919
rsource "smp_call/Kconfig"
20+
rsource "pref/Kconfig"
2021
endif
2122

2223
endmenu
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
menu "System Performance Testcase"
2+
3+
config UTEST_SYS_PREF_TC
4+
bool "system performance test"
5+
default n
6+
7+
choice
8+
prompt "Select time reference for System Performance Testcase"
9+
default USING_TICK_AS_TIME_REF
10+
depends on UTEST_SYS_PREF_TC
11+
config USING_HWTIME_AS_TIME_REF
12+
bool "Use hardware timer as time reference"
13+
depends on RT_USING_HWTIMER
14+
15+
config USING_TICK_AS_TIME_REF
16+
bool "Use system tick as time reference"
17+
default y
18+
endchoice
19+
20+
config UTEST_SYS_CONTEXT_SWITCH
21+
bool "system context switch test"
22+
default n
23+
24+
endmenu
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Import('rtconfig')
2+
from building import *
3+
4+
cwd = GetCurrentDir()
5+
src = []
6+
CPPPATH = [cwd]
7+
8+
if GetDepend(['UTEST_SYS_CONTEXT_SWITCH']):
9+
src += ['context_switch.c']
10+
11+
group = DefineGroup('utestcases', src, depend = ['UTEST_SYS_PREF_TC'], CPPPATH = CPPPATH)
12+
13+
Return('group')
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
#include <rtthread.h>
2+
#include <rthw.h>
3+
#include <rtdevice.h>
4+
5+
// 定义信号量
6+
static rt_sem_t sem1, sem2;
7+
8+
// 定义线程控制块
9+
static rt_thread_t thread1, thread2;
10+
#define THREAD_STACK_SIZE 1024
11+
#define THREAD_PRIORITY 10
12+
#define THREAD_TIMESLICE 5
13+
14+
// 记录切换次数
15+
#define SWITCH_COUNT 1000
16+
17+
#ifdef RT_USING_HWTIMER
18+
#define HWTIMER_DEV_NAME "timer0" /* 定时器名称 */
19+
static rt_device_t hw_dev = RT_NULL;
20+
21+
// 获取当前时间(微秒)
22+
static rt_size_t get_timer_us(rt_hwtimerval_t *timeout_s)
23+
{
24+
if (hw_dev)
25+
return rt_device_read(hw_dev, 0, timeout_s, sizeof(rt_hwtimerval_t));
26+
return 0;
27+
}
28+
#endif
29+
30+
// 线程1入口函数
31+
static void thread1_entry(void *parameter)
32+
{
33+
while (1)
34+
{
35+
rt_sem_take(sem1, RT_WAITING_FOREVER); // 获取信号量1
36+
rt_sem_release(sem2); // 释放信号量2
37+
}
38+
}
39+
40+
// 线程2入口函数
41+
static void thread2_entry(void *parameter)
42+
{
43+
rt_uint32_t total_time = 0;
44+
rt_uint32_t sem_op_time = 0;
45+
rt_uint32_t i;
46+
#ifdef RT_USING_HWTIMER
47+
rt_hwtimerval_t start_time, end_time;
48+
rt_uint16_t ret;
49+
// 测量信号量操作时间(单次获取+释放)
50+
ret = get_timer_us(&start_time);
51+
for (i = 0; i < SWITCH_COUNT; i++)
52+
{
53+
rt_sem_take(sem2, RT_WAITING_FOREVER);
54+
rt_sem_release(sem2);
55+
}
56+
ret +=get_timer_us(&end_time);
57+
sem_op_time = (end_time.sec - start_time.sec) * 1000 + (end_time.usec - start_time.usec); // 转换为微秒
58+
59+
// 测量上下文切换总时间
60+
ret += get_timer_us(&start_time);
61+
for (i = 0; i < SWITCH_COUNT; i++)
62+
{
63+
rt_sem_take(sem2, RT_WAITING_FOREVER); // 获取信号量2
64+
rt_sem_release(sem1); // 释放信号量1
65+
}
66+
ret +=get_timer_us(&end_time);
67+
total_time = (end_time.sec - start_time.sec) * 1000 + (end_time.usec - start_time.usec); // 转换为微秒
68+
69+
if(hw_dev)
70+
rt_device_close(hw_dev);
71+
72+
#else
73+
rt_uint32_t start_time, end_time;
74+
start_time = rt_tick_get();
75+
for (i = 0; i < SWITCH_COUNT; i++)
76+
{
77+
rt_sem_take(sem2, RT_WAITING_FOREVER);
78+
rt_sem_release(sem2);
79+
}
80+
end_time = rt_tick_get();
81+
sem_op_time = (end_time - start_time) * (1000u / RT_TICK_PER_SECOND) * 1000u;
82+
start_time = rt_tick_get();
83+
for (i = 0; i < SWITCH_COUNT; i++)
84+
{
85+
rt_sem_take(sem2, RT_WAITING_FOREVER); // 获取信号量2
86+
rt_sem_release(sem1); // 释放信号量1
87+
}
88+
end_time = rt_tick_get();
89+
total_time = (end_time - start_time) * (1000u / RT_TICK_PER_SECOND) * 1000u;
90+
#endif
91+
92+
// 计算单次上下文切换时间
93+
rt_uint32_t single_switch_time = total_time / SWITCH_COUNT; // 单次切换总时间
94+
rt_uint32_t single_sem_op_time = sem_op_time / SWITCH_COUNT; // 单次信号量操作时间
95+
rt_uint32_t context_switch_time = single_switch_time - single_sem_op_time; // 上下文切换时间
96+
97+
// 打印结果
98+
rt_kprintf("Total time for %d switches: %d us\n", SWITCH_COUNT, total_time);
99+
rt_kprintf("Single switch time (including semaphore): %d us\n", single_switch_time);
100+
rt_kprintf("Semaphore operation time: %d us\n", single_sem_op_time);
101+
rt_kprintf("Pure context switch time: %d us\n", context_switch_time);
102+
}
103+
104+
// 初始化测试
105+
int context_switch_test(void)
106+
{
107+
int ret = RT_EOK;
108+
#ifdef RT_USING_HWTIMER
109+
rt_hwtimerval_t timeout_s; /* 定时器超时值 */
110+
111+
hw_dev = rt_device_find(HWTIMER_DEV_NAME);
112+
if (hw_dev == RT_NULL)
113+
{
114+
ret = RT_ERROR;
115+
rt_kprintf("hwtimer sample run failed! can't find %s device!\n", HWTIMER_DEV_NAME);
116+
return ret;
117+
}
118+
119+
/* 以读写方式打开设备 */
120+
ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
121+
if (ret != RT_EOK)
122+
{
123+
rt_kprintf("open %s device failed!\n", HWTIMER_DEV_NAME);
124+
return ret;
125+
}
126+
127+
/* 设置定时器超时值为5s并启动定时器 */
128+
timeout_s.sec = 5; /* 秒 */
129+
timeout_s.usec = 0; /* 微秒 */
130+
if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(rt_hwtimerval_t)) != sizeof(rt_hwtimerval_t))
131+
{
132+
ret = RT_ERROR;
133+
rt_kprintf("set timeout value failed\n");
134+
return ret;
135+
}
136+
#endif
137+
// 创建信号量
138+
sem1 = rt_sem_create("sem1", 1, RT_IPC_FLAG_FIFO); // 初始值为1
139+
sem2 = rt_sem_create("sem2", 0, RT_IPC_FLAG_FIFO); // 初始值为0
140+
if (sem1 == RT_NULL || sem2 == RT_NULL)
141+
{
142+
ret = RT_ERROR;
143+
rt_kprintf("Semaphore create failed!\n");
144+
return ret;
145+
}
146+
147+
// 创建线程1
148+
thread1 = rt_thread_create("thread1", thread1_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
149+
if (thread1 != RT_NULL)
150+
{
151+
rt_thread_startup(thread1);
152+
}
153+
// 创建线程2
154+
thread2 = rt_thread_create("thread2", thread2_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
155+
if (thread2 != RT_NULL)
156+
{
157+
rt_thread_startup(thread2);
158+
}
159+
return ret;
160+
}
161+
162+
#ifdef RT_USING_FINSH
163+
#include <finsh.h>
164+
MSH_CMD_EXPORT(context_switch_test, "Test context switch time");
165+
#endif

0 commit comments

Comments
 (0)