Skip to content

Commit 3659f5e

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

File tree

4 files changed

+209
-0
lines changed

4 files changed

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

0 commit comments

Comments
 (0)