|
| 1 | +#include <rtthread.h> |
| 2 | +#include <rthw.h> |
| 3 | +#include <rtdevice.h> |
| 4 | +#include <utest.h> |
| 5 | +#include <utest_assert.h> |
| 6 | + |
| 7 | +static rt_sem_t sem1, sem2; |
| 8 | +static rt_thread_t thread1, thread2; |
| 9 | +#define THREAD_STACK_SIZE 1024 |
| 10 | +#define THREAD_PRIORITY 10 |
| 11 | +#define THREAD_TIMESLICE 5 |
| 12 | + |
| 13 | +#define SWITCH_COUNT 1000 /* Number of context switches */ |
| 14 | + |
| 15 | +#ifdef USING_HWTIME_AS_TIME_REF |
| 16 | +static rt_device_t hw_dev = RT_NULL; |
| 17 | + |
| 18 | +static rt_size_t get_timer_us(rt_hwtimerval_t *timeout_s) |
| 19 | +{ |
| 20 | + if (hw_dev) |
| 21 | + return rt_device_read(hw_dev, 0, timeout_s, sizeof(rt_hwtimerval_t)); |
| 22 | + return 0; |
| 23 | +} |
| 24 | +#endif |
| 25 | + |
| 26 | +static void thread1_entry(void *parameter) |
| 27 | +{ |
| 28 | + while (1) |
| 29 | + { |
| 30 | + rt_sem_take(sem1, RT_WAITING_FOREVER); |
| 31 | + rt_sem_release(sem2); |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +static void thread2_entry(void *parameter) |
| 36 | +{ |
| 37 | + rt_uint32_t total_time = 0; |
| 38 | + rt_uint32_t sem_op_time = 0; |
| 39 | + rt_uint32_t i; |
| 40 | +#ifdef USING_HWTIME_AS_TIME_REF |
| 41 | + rt_hwtimerval_t start_time, end_time; |
| 42 | + rt_uint16_t ret; |
| 43 | + /* Getting Signal Time */ |
| 44 | + ret = get_timer_us(&start_time); |
| 45 | + for (i = 0; i < SWITCH_COUNT; i++) |
| 46 | + { |
| 47 | + rt_sem_take(sem2, RT_WAITING_FOREVER); |
| 48 | + rt_sem_release(sem2); |
| 49 | + } |
| 50 | + ret +=get_timer_us(&end_time); |
| 51 | + sem_op_time = (end_time.sec - start_time.sec) * 1000 + (end_time.usec - start_time.usec); |
| 52 | + |
| 53 | + ret += get_timer_us(&start_time); |
| 54 | + for (i = 0; i < SWITCH_COUNT; i++) |
| 55 | + { |
| 56 | + rt_sem_take(sem2, RT_WAITING_FOREVER); |
| 57 | + rt_sem_release(sem1); |
| 58 | + } |
| 59 | + ret +=get_timer_us(&end_time); |
| 60 | + total_time = (end_time.sec - start_time.sec) * 1000 + (end_time.usec - start_time.usec); |
| 61 | +#else |
| 62 | + rt_uint32_t start_time, end_time; |
| 63 | + /* Getting Signal Time */ |
| 64 | + start_time = rt_tick_get(); |
| 65 | + for (i = 0; i < SWITCH_COUNT; i++) |
| 66 | + { |
| 67 | + rt_sem_take(sem2, RT_WAITING_FOREVER); |
| 68 | + rt_sem_release(sem2); |
| 69 | + } |
| 70 | + end_time = rt_tick_get(); |
| 71 | + sem_op_time = (end_time - start_time) * (1000u / RT_TICK_PER_SECOND) * 1000u; |
| 72 | + |
| 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(sem1); |
| 78 | + } |
| 79 | + end_time = rt_tick_get(); |
| 80 | + total_time = (end_time - start_time) * (1000u / RT_TICK_PER_SECOND) * 1000u; |
| 81 | +#endif |
| 82 | + |
| 83 | + rt_uint32_t single_switch_time = total_time / SWITCH_COUNT; /* Total single switching time */ |
| 84 | + rt_uint32_t single_sem_op_time = sem_op_time / SWITCH_COUNT; /* Single semaphore operation time */ |
| 85 | + rt_uint32_t context_switch_time = single_switch_time - single_sem_op_time; /* Context switching time */ |
| 86 | + |
| 87 | + rt_kprintf("Total time for %d switches: %d us\n", SWITCH_COUNT, total_time); |
| 88 | + rt_kprintf("Single switch time (including semaphore): %d us\n", single_switch_time); |
| 89 | + rt_kprintf("Semaphore operation time: %d us\n", single_sem_op_time); |
| 90 | + rt_kprintf("Pure context switch time: %d us\n", context_switch_time); |
| 91 | +} |
| 92 | + |
| 93 | +void context_switch_test(void) |
| 94 | +{ |
| 95 | + |
| 96 | + thread1 = rt_thread_create("thread1", thread1_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); |
| 97 | + if (thread1 != RT_NULL) |
| 98 | + { |
| 99 | + rt_thread_startup(thread1); |
| 100 | + } |
| 101 | + |
| 102 | + thread2 = rt_thread_create("thread2", thread2_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); |
| 103 | + if (thread2 != RT_NULL) |
| 104 | + { |
| 105 | + rt_thread_startup(thread2); |
| 106 | + } |
| 107 | +} |
| 108 | + |
| 109 | +static rt_err_t utest_tc_init(void) |
| 110 | +{ |
| 111 | + int ret = RT_EOK; |
| 112 | +#ifdef USING_HWTIME_AS_TIME_REF |
| 113 | + rt_hwtimerval_t timeout_s; |
| 114 | + |
| 115 | + hw_dev = rt_device_find(UTEST_HWTIMER_DEV_NAME); |
| 116 | + if (hw_dev == RT_NULL) |
| 117 | + { |
| 118 | + ret = RT_ERROR; |
| 119 | + rt_kprintf("hwtimer sample run failed! can't find %s device!\n", UTEST_HWTIMER_DEV_NAME); |
| 120 | + return ret; |
| 121 | + } |
| 122 | + |
| 123 | + ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR); |
| 124 | + if (ret != RT_EOK) |
| 125 | + { |
| 126 | + rt_kprintf("open %s device failed!\n", UTEST_HWTIMER_DEV_NAME); |
| 127 | + return ret; |
| 128 | + } |
| 129 | + |
| 130 | + timeout_s.sec = 5; /* s */ |
| 131 | + timeout_s.usec = 0; /* us */ |
| 132 | + if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(rt_hwtimerval_t)) != sizeof(rt_hwtimerval_t)) |
| 133 | + { |
| 134 | + ret = RT_ERROR; |
| 135 | + rt_kprintf("set timeout value failed\n"); |
| 136 | + return ret; |
| 137 | + } |
| 138 | +#endif |
| 139 | + sem1 = rt_sem_create("sem1", 1, RT_IPC_FLAG_FIFO); |
| 140 | + sem2 = rt_sem_create("sem2", 0, RT_IPC_FLAG_FIFO); |
| 141 | + if (sem1 == RT_NULL || sem2 == RT_NULL) |
| 142 | + { |
| 143 | + ret = RT_ERROR; |
| 144 | + rt_kprintf("Semaphore create failed!\n"); |
| 145 | + return ret; |
| 146 | + } |
| 147 | + return ret; |
| 148 | +} |
| 149 | + |
| 150 | +static rt_err_t utest_tc_cleanup(void) |
| 151 | +{ |
| 152 | + if (thread1) rt_thread_delete(thread1); |
| 153 | + if(sem1) rt_sem_delete(sem1); |
| 154 | + if(sem2) rt_sem_delete(sem2); |
| 155 | +#ifdef USING_HWTIME_AS_TIME_REF |
| 156 | + if(hw_dev) rt_device_close(hw_dev); |
| 157 | +#endif |
| 158 | + return RT_EOK; |
| 159 | +} |
| 160 | + |
| 161 | +static void testcase(void) |
| 162 | +{ |
| 163 | + UTEST_UNIT_RUN(context_switch_test); |
| 164 | +} |
| 165 | + |
| 166 | +UTEST_TC_EXPORT(testcase, "testcase.pref.context", utest_tc_init, utest_tc_cleanup, 10); |
0 commit comments