Skip to content

Commit ef759b9

Browse files
committed
[utest] add scheduler test
Signed-off-by: Shell <smokewood@qq.com>
1 parent d92d2b6 commit ef759b9

9 files changed

Lines changed: 818 additions & 2 deletions

File tree

examples/utest/testcases/kernel/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,8 @@ config UTEST_MTSAFE_KPRINT_TC
6969
bool "mtsafe kprint test"
7070
default n
7171

72+
config UTEST_SCHEDULER_TC
73+
bool "scheduler test"
74+
default n
75+
7276
endmenu

examples/utest/testcases/kernel/SConscript

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ if GetDepend(['UTEST_HOOKLIST_TC']):
5050
if GetDepend(['UTEST_MTSAFE_KPRINT_TC']):
5151
src += ['mtsafe_kprint_tc.c']
5252

53+
# Stressful testcase for scheduler (MP/UP)
54+
if GetDepend(['UTEST_SCHEDULER_TC']):
55+
src += ['sched_timed_sem_tc.c']
56+
src += ['sched_timed_mtx_tc.c']
57+
src += ['sched_mtx_tc.c']
58+
src += ['sched_sem_tc.c', 'sched_thread_tc.c']
59+
5360
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
5461

5562
Return('group')

examples/utest/testcases/kernel/mutex_tc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* 2021-09.01 luckyzjq the first version
99
* 2023-09-15 xqyjlj change stack size in cpu64
1010
*/
11-
#define __RTT_IPC_SOURCE__
11+
#define __RT_IPC_SOURCE__
1212

1313
#include <rtthread.h>
1414
#include <stdlib.h>
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright (c) 2006-2024, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
* 2024-01-17 Shell the first version
9+
*/
10+
#include <rtthread.h>
11+
#include <stdlib.h>
12+
#include "utest.h"
13+
14+
/**
15+
* Stressful Test for Mutex
16+
*/
17+
18+
#define TEST_SECONDS 30
19+
#define TEST_LOOP_TICKS (TEST_SECONDS * RT_TICK_PER_SECOND)
20+
#define TEST_THREAD_COUNTS (RT_CPUS_NR)
21+
#define TEST_PROGRESS_COUNTS (36)
22+
#define TEST_PROGRESS_ON (TEST_LOOP_TICKS/TEST_PROGRESS_COUNTS)
23+
#define TEST_PRIORITY_HIGHEST (UTEST_THR_PRIORITY+1)
24+
#define TEST_RANDOM_LATENCY_MAX (1000 * 1000)
25+
26+
static struct rt_semaphore _thr_exit_sem;
27+
static rt_atomic_t _progress_counter;
28+
static rt_atomic_t _exit_flag;
29+
static struct rt_mutex _racing_lock;
30+
31+
static void test_thread_entry(void *param)
32+
{
33+
while (1)
34+
{
35+
rt_mutex_take(&_racing_lock, RT_WAITING_FOREVER);
36+
rt_mutex_release(&_racing_lock);
37+
38+
if (rt_atomic_load(&_exit_flag))
39+
{
40+
break;
41+
}
42+
}
43+
44+
rt_sem_release(&_thr_exit_sem);
45+
}
46+
47+
static void mutex_stress_tc(void)
48+
{
49+
rt_err_t error;
50+
rt_thread_t tester;
51+
const rt_base_t priority_base = TEST_PRIORITY_HIGHEST;
52+
53+
for (size_t i = 0; i < TEST_THREAD_COUNTS; i++)
54+
{
55+
tester = rt_thread_create(
56+
"tester",
57+
test_thread_entry,
58+
(void *)0,
59+
UTEST_THR_STACK_SIZE,
60+
priority_base + (i % (RT_THREAD_PRIORITY_MAX - TEST_PRIORITY_HIGHEST)),
61+
1);
62+
63+
rt_thread_startup(tester);
64+
}
65+
66+
for (size_t i = 0; i < TEST_LOOP_TICKS; i++)
67+
{
68+
rt_thread_delay(1);
69+
70+
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
71+
uassert_true(1);
72+
}
73+
74+
/* trigger exit request for all sub-threads */
75+
rt_atomic_store(&_exit_flag, 1);
76+
77+
/* waiting for sub-threads to exit */
78+
for (size_t i = 0; i < TEST_THREAD_COUNTS; i++)
79+
{
80+
error = rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
81+
uassert_int_equal(error, RT_EOK);
82+
}
83+
}
84+
85+
static rt_err_t utest_tc_init(void)
86+
{
87+
int *pseed = rt_malloc(sizeof(int));
88+
srand(*(int *)pseed);
89+
rt_free(pseed);
90+
91+
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
92+
rt_mutex_init(&_racing_lock, "ipc", RT_IPC_FLAG_PRIO);
93+
return RT_EOK;
94+
}
95+
96+
static rt_err_t utest_tc_cleanup(void)
97+
{
98+
rt_sem_detach(&_thr_exit_sem);
99+
rt_mutex_detach(&_racing_lock);
100+
return RT_EOK;
101+
}
102+
103+
static void testcase(void)
104+
{
105+
UTEST_UNIT_RUN(mutex_stress_tc);
106+
}
107+
UTEST_TC_EXPORT(testcase, "testcases.kernel.scheduler.mutex", utest_tc_init, utest_tc_cleanup, TEST_SECONDS);
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
* Copyright (c) 2006-2024, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
* 2024-01-17 Shell the first version
9+
*/
10+
#define __RT_IPC_SOURCE__
11+
12+
#include <rtthread.h>
13+
#include "rthw.h"
14+
#include "utest.h"
15+
16+
#define KERN_TEST_CONFIG_LOOP_TIMES 160
17+
#define KERN_TEST_CONCURRENT_THREADS (RT_CPUS_NR * 2)
18+
#define KERN_TEST_CONFIG_HIGHEST_PRIO 3
19+
#define KERN_TEST_CONFIG_LOWEST_PRIO (RT_THREAD_PRIORITY_MAX - 2)
20+
21+
#define TEST_LEVEL_COUNTS (KERN_TEST_CONFIG_LOWEST_PRIO - KERN_TEST_CONFIG_HIGHEST_PRIO + 1)
22+
#if TEST_LEVEL_COUNTS <= RT_CPUS_NR
23+
#warning for the best of this test, TEST_LEVEL_COUNTS should greater than RT_CPUS_NR
24+
#endif
25+
#if KERN_TEST_CONCURRENT_THREADS < RT_CPUS_NR
26+
#warning for the best of this test, KERN_TEST_CONCURRENT_THREADS should greater than RT_CPUS_NR
27+
#endif
28+
#if KERN_TEST_CONFIG_LOWEST_PRIO >= RT_THREAD_PRIORITY_MAX - 1
29+
#error the thread priority should at least be greater than idle
30+
#endif
31+
32+
static rt_atomic_t _star_counter = 1;
33+
static struct rt_semaphore _thr_exit_sem;
34+
static struct rt_semaphore _level_waiting[TEST_LEVEL_COUNTS];
35+
static rt_thread_t _thread_matrix[TEST_LEVEL_COUNTS][KERN_TEST_CONCURRENT_THREADS];
36+
static rt_atomic_t _load_average[RT_CPUS_NR];
37+
38+
static void _print_char(rt_thread_t thr_self, int character)
39+
{
40+
rt_base_t current_counter;
41+
42+
#ifdef RT_USING_SMP
43+
rt_kprintf("%c%d", character, SCHED_CTX(thr_self).oncpu);
44+
#else
45+
rt_kprintf("%c0", character);
46+
#endif /* RT_USING_SMP */
47+
48+
current_counter = rt_atomic_add(&_star_counter, 1);
49+
if (current_counter % 30 == 0)
50+
{
51+
rt_kprintf("\n");
52+
}
53+
}
54+
55+
static void _stats_load_avg_inc(void)
56+
{
57+
int cpuid;
58+
59+
cpuid = rt_hw_cpu_id();
60+
rt_atomic_add(&_load_average[cpuid], 1);
61+
}
62+
63+
static void _stats_load_avg_print(void)
64+
{
65+
rt_base_t counts = 0;
66+
const rt_base_t total_test_counts = KERN_TEST_CONFIG_LOOP_TIMES * TEST_LEVEL_COUNTS * KERN_TEST_CONCURRENT_THREADS;
67+
68+
for (size_t i = 0; i < RT_CPUS_NR; i++)
69+
{
70+
rt_kprintf("%ld ", _load_average[i]);
71+
counts += _load_average[i];
72+
}
73+
74+
rt_kprintf("\n");
75+
uassert_int_equal(counts, total_test_counts);
76+
}
77+
78+
static void _thread_entry(void *param)
79+
{
80+
int level = (rt_ubase_t)param;
81+
rt_thread_t thr_self = rt_thread_self();
82+
83+
if (level == 0)
84+
{
85+
/* always the first to execute among other working threads */
86+
for (size_t i = 0; i < KERN_TEST_CONFIG_LOOP_TIMES; i++)
87+
{
88+
/* notify our consumer */
89+
rt_sem_release(&_level_waiting[level + 1]);
90+
91+
_stats_load_avg_inc();
92+
93+
/* waiting for resource of ours */
94+
rt_sem_take(&_level_waiting[level], RT_WAITING_FOREVER);
95+
}
96+
}
97+
else if (level == TEST_LEVEL_COUNTS - 1)
98+
{
99+
100+
for (size_t i = 0; i < KERN_TEST_CONFIG_LOOP_TIMES; i++)
101+
{
102+
/* waiting for our resource first */
103+
rt_sem_take(&_level_waiting[level], RT_WAITING_FOREVER);
104+
105+
_stats_load_avg_inc();
106+
107+
_print_char(thr_self, '*');
108+
109+
rt_thread_delay(1);
110+
111+
/* produce for level 0 worker */
112+
rt_sem_release(&_level_waiting[0]);
113+
}
114+
}
115+
else
116+
{
117+
for (size_t i = 0; i < KERN_TEST_CONFIG_LOOP_TIMES; i++)
118+
{
119+
/* waiting for resource of ours */
120+
rt_sem_take(&_level_waiting[level], RT_WAITING_FOREVER);
121+
122+
_stats_load_avg_inc();
123+
124+
/* notify our consumer */
125+
rt_sem_release(&_level_waiting[level + 1]);
126+
}
127+
}
128+
129+
uassert_true(1);
130+
rt_sem_release(&_thr_exit_sem);
131+
132+
return;
133+
}
134+
135+
static void scheduler_tc(void)
136+
{
137+
LOG_I("Test starts...");
138+
for (size_t i = 0; i < TEST_LEVEL_COUNTS; i++)
139+
{
140+
for (size_t j = 0; j < KERN_TEST_CONCURRENT_THREADS; j++)
141+
{
142+
rt_thread_startup(_thread_matrix[i][j]);
143+
}
144+
}
145+
LOG_I("%d threads startup...", TEST_LEVEL_COUNTS * KERN_TEST_CONCURRENT_THREADS);
146+
147+
/* waiting for sub-threads to exit */
148+
for (size_t i = 0; i < TEST_LEVEL_COUNTS * KERN_TEST_CONCURRENT_THREADS; i++)
149+
{
150+
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
151+
}
152+
153+
/* print load average */
154+
_stats_load_avg_print();
155+
}
156+
157+
static rt_err_t utest_tc_init(void)
158+
{
159+
LOG_I("Setup environment...");
160+
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
161+
162+
for (size_t i = 0; i < TEST_LEVEL_COUNTS; i++)
163+
{
164+
rt_sem_init(&_level_waiting[i], "test", 0, RT_IPC_FLAG_PRIO);
165+
166+
for (size_t j = 0; j < KERN_TEST_CONCURRENT_THREADS; j++)
167+
{
168+
_thread_matrix[i][j] =
169+
rt_thread_create("test",
170+
_thread_entry,
171+
(void *)i,
172+
UTEST_THR_STACK_SIZE,
173+
KERN_TEST_CONFIG_HIGHEST_PRIO+i,
174+
5);
175+
if (!_thread_matrix[i][j])
176+
uassert_not_null(_thread_matrix[i][j]);
177+
}
178+
}
179+
return RT_EOK;
180+
}
181+
182+
static rt_err_t utest_tc_cleanup(void)
183+
{
184+
rt_sem_detach(&_thr_exit_sem);
185+
for (size_t i = 0; i < TEST_LEVEL_COUNTS; i++)
186+
{
187+
rt_sem_detach(&_level_waiting[i]);
188+
}
189+
return RT_EOK;
190+
}
191+
192+
static void testcase(void)
193+
{
194+
UTEST_UNIT_RUN(scheduler_tc);
195+
}
196+
UTEST_TC_EXPORT(testcase, "testcases.kernel.scheduler.sem", utest_tc_init, utest_tc_cleanup, 10);

0 commit comments

Comments
 (0)