4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2008 Develer S.r.l. (http://www.develer.com/)
32 * \brief Semaphore test.
34 * For testing priority inversion (avoidance) a set of processes
35 * interacting among each others by means of two semaphores are
36 * disturbed by an unrelated process, i.e., a process not using
37 * any semaphore at all.
39 * In case of priority inversion, high priority processes
40 * are affected (delayed!) by such process, even it has lower
41 * priority, because of semaphores. On the other hand, when priority
42 * inheritance is enabled, non interacting low priority processes
43 * can't affect the execution of high priority ones.
45 * It all can be seen looking at the finishing time of the various
46 * processes involved in sem_inv_test (logged).
48 * Notice that priority inheritance makes sense iff priorities
49 * exist, so the whole test depends on CONFIG_KERN_PRI.
51 * \author Daniele Basile <asterix@develer.com>
52 * \author Stefano Fedrigo <aleph@develer.com>
53 * \author Dario Faggioli <raistlin@linux.it>
55 * $test$: cp bertos/cfg/cfg_proc.h $cfgdir/
56 * $test$: echo "#undef CONFIG_KERN" >> $cfgdir/cfg_proc.h
57 * $test$: echo "#define CONFIG_KERN 1" >> $cfgdir/cfg_proc.h
58 * $test$: echo "#undef CONFIG_KERN_PRI" >> $cfgdir/cfg_proc.h
59 * $test$: echo "#define CONFIG_KERN_PRI 1" >> $cfgdir/cfg_proc.h
60 * $test$: echo "#undef CONFIG_KERN_PRI_INHERIT" >> $cfgdir/cfg_proc.h
61 * $test$: echo "#define CONFIG_KERN_PRI_INHERIT 1" >> $cfgdir/cfg_proc.h
62 * $test$: cp bertos/cfg/cfg_sem.h $cfgdir/
63 * $test$: echo "#undef CONFIG_KERN_SEMAPHORES" >> $cfgdir/cfg_sem.h
64 * $test$: echo "#define CONFIG_KERN_SEMAPHORES 1" >> $cfgdir/cfg_sem.h
67 #include <cfg/debug.h>
71 #include <kern/proc.h>
74 #include <drv/timer.h>
76 // Global settings for the serialization test.
77 #define MAX_GLOBAL_COUNT 1024
78 #define TEST_TIME_OUT_MS 6000
81 // Settings for the test processes (serialization test).
84 #define DELAY_PROC_T1 INC_PROC_T1*DELAY
87 #define DELAY_PROC_T2 INC_PROC_T2*DELAY
90 #define DELAY_PROC_T3 INC_PROC_T3*DELAY
93 #define DELAY_PROC_T4 INC_PROC_T4*DELAY
95 #define INC_PROC_T5 11
96 #define DELAY_PROC_T5 INC_PROC_T5*DELAY
98 #define INC_PROC_T6 13
99 #define DELAY_PROC_T6 INC_PROC_T6*DELAY
101 #define INC_PROC_T7 17
102 #define DELAY_PROC_T7 INC_PROC_T7*DELAY
104 #define INC_PROC_T8 19
105 #define DELAY_PROC_T8 INC_PROC_T8*DELAY
108 unsigned int global_count = 0;
111 * These macros generate the code needed to create the test process functions.
113 #define PROC_TEST(num) static void proc_semTest##num(void) \
115 unsigned int local_count = 0; \
117 for (int i = 0; i < INC_PROC_T##num; ++i) \
120 kprintf("> test%d: Obtain semaphore.\n", num); \
121 local_count = global_count; \
122 kprintf("> test%d: Read global count [%d]\n", num, local_count); \
123 timer_delay(DELAY_PROC_T##num); \
124 local_count += INC_PROC_T##num; \
125 global_count = local_count; \
126 kprintf("> test%d: Update count g[%d] l[%d]\n", num, global_count, local_count); \
128 kprintf("> test%d: Relase semaphore.\n", num); \
132 #define PROC_TEST_STACK(num) PROC_DEFINE_STACK(proc_sem_test##num##_stack, KERN_MINSTACKSIZE * 2)
133 #define PROC_TEST_INIT(num) proc_new(proc_semTest##num, NULL, sizeof(proc_sem_test##num##_stack), proc_sem_test##num##_stack);
135 // Define processes for the serialization test.
147 // Global settings for the priority inversion test.
148 // 0.5 secs, enough for seeing the effects
152 unsigned int loops = 0; // For counting iterations
153 int finishing_time[8];
155 typedef enum ProcType {NONE, S1, S2, S1S2} ProcType;
157 * Macros for the processes of the priority inversion test.
159 #define PROC_INV_TEST(num) static void proc_semInvTest##num(void) \
161 ProcType p_type = (ProcType)((ssize_t) proc_currentUserData()); \
162 int mult = p_type == NONE ? 5 : 1; \
163 unsigned int i, local_count = 0; \
166 kprintf("> test%d(%d): Start.\n", num, proc_current()->link.pri); \
167 finishing_time[num-1] = timer_clock(); \
169 if (p_type == S1 || p_type == S1S2) { \
170 kprintf("> test%d(prio=%d): Obtain %p..\n", num, \
171 proc_current()->link.pri, &s1); \
173 kprintf("> test%d(prio=%d): Obtained %p.\n", num, \
174 proc_current()->link.pri, &s1); \
176 if (p_type == S2 || p_type == S1S2) { \
177 kprintf("> test%d(prio=%d): Obtain %p..\n", num, \
178 proc_current()->link.pri, &s2); \
180 kprintf("> test%d(prio=%d): Obtained %p.\n", num, \
181 proc_current()->link.pri, &s2); \
184 start = timer_clock(); \
185 for (i = 0; i < loops * mult && (((unsigned)timer_clock()-start) <= loops*mult); i++) { \
190 global_count += local_count; \
191 kprintf("> test%d(prio=%d): global_count=%u..\n", num, \
192 proc_current()->link.pri, global_count); \
195 if (p_type == S2 || p_type == S1S2) { \
196 kprintf("> test%d(prio=%d): Release %p..\n", num, \
197 proc_current()->link.pri, &s2); \
199 kprintf("> test%d(prio=%d): %p Released.\n", num, \
200 proc_current()->link.pri, &s2); \
202 if (p_type == S1 || p_type == S1S2) { \
203 kprintf("> test%d(prio=%d): Release %p..\n", num, \
204 proc_current()->link.pri, &s1); \
206 kprintf("> test%d(prio=%d): %p Released.\n", num, \
207 proc_current()->link.pri, &s1); \
210 finishing_time[num-1] = timer_clock() - finishing_time[num-1]; \
211 kprintf("> test%d(prio=%d): Exit.\n", num, proc_current()->link.pri); \
214 #define PROC_INV_TEST_INIT(num, pri, type) \
219 p = proc_new(proc_semInvTest##num, \
220 ((void*)type), sizeof(proc_sem_test##num##_stack), \
221 proc_sem_test##num##_stack); \
222 proc_setPri(p, pri); \
225 // Define processes for the priority inversion test.
235 #endif /* CONFIG_KERN_PRI */
237 // Define process stacks for both of the tests.
247 static int sem_ser_test(void)
249 ticks_t start_time = timer_clock();
254 kprintf("Run semaphore serialization test..\n");
256 // Initialize the processes.
265 kputs("> Main: Processes created\n");
268 * Wait until all processes exit, if something goes wrong we return an
269 * error after timeout_ms.
271 while((timer_clock() - start_time) < ms_to_ticks(TEST_TIME_OUT_MS))
273 if (sem_attempt(&sem))
275 kputs("> Main: Check if test has finished..\n");
276 if(global_count == MAX_GLOBAL_COUNT)
278 kputs("> Main: Test Finished..Ok!\n");
282 kputs("> Main: Test is still running..\n");
287 kputs("Semaphore serialization test failed..\n");
293 static int sem_inv_test(void)
295 int i, orig_pri = proc_current()->link.pri;
296 ticks_t fake, start_time;
305 kputs("> Main: calibration for the busy wait cycle..\n");
306 proc_setPri(proc_current(), 10);
308 fake = start_time = timer_clock();
309 while ((fake - start_time) < ms_to_ticks(BASETIME)) {
310 fake = timer_clock();
313 kprintf("> Main: calibration done, %dms equals to %u cycles!\n", BASETIME, loops);
315 kputs("> Main: Run Priority Inversion test...\n");
318 PROC_INV_TEST_INIT(1, 2, S2);
320 // 2 will block on s2; 3 will take s2 and still block on s2
321 PROC_INV_TEST_INIT(2, 3, S2);
322 PROC_INV_TEST_INIT(3, 4, S1S2);
324 // Will block on s1, nothing happens..
325 PROC_INV_TEST_INIT(4, 5, S1);
327 // No semaphore, without PI this will delay everyone!
328 PROC_INV_TEST_INIT(5, 6, NONE);
330 // Will block on s1 and boost
331 PROC_INV_TEST_INIT(6, 7, S1);
332 PROC_INV_TEST_INIT(7, 8, S1);
333 PROC_INV_TEST_INIT(8, 9, S1);
335 // All processes created, let them run.
336 proc_setPri(proc_current(), orig_pri);
337 while ((timer_clock() - start_time) < ms_to_ticks(TEST_TIME_OUT_MS*2)) {
338 if (sem_attempt(&sem)) {
339 if (global_count >= loops*7 + loops*5) {
340 for (i = 0; i < 8; i++)
341 kprintf("> Main: I-O latency of %d = %ldms\n", i+1, (long) ms_to_ticks(finishing_time[i]));
342 kputs("> Main: Test Finished..Ok!\n");
350 kputs("> Main: Priority Inversion Test failed..\n");
356 void sem_inv_test(void)
360 #endif /* CONFIG_KERN_PRI */
365 int sem_testRun(void)
368 sem_ser_test(); // Serialization
369 sem_inv_test(); // Priority Inversion
374 int sem_testSetup(void)
378 kprintf("Init Timer..");
382 kprintf("Init Process..");
389 int sem_testTearDown(void)
391 kputs("TearDown Semaphore test.\n");