1 /*
2 * Copyright (c) 2006-2025, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2025-07-03 rcitach test case for irq latency
9 */
10
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include <rtservice.h>
14 #include <utest.h>
15 #include <utest_assert.h>
16 #include <perf_tc.h>
17
18 #define RET_INT 0
19 #define RET_DECIMALS 1
20
21 #define GET_INT(num) split_double(num, RET_INT)
22 #define GET_DECIMALS(num) split_double(num, RET_DECIMALS)
23
24 static rt_device_t hw_dev = RT_NULL;
25 static rt_hwtimerval_t timeout_s = {0};
26
27 typedef rt_err_t (*testcase_function)(rt_perf_t *perf);
28 testcase_function test_func_ptrs[] =
29 {
30 context_switch_test,
31 rt_perf_thread_sem,
32 rt_perf_thread_event,
33 rt_perf_thread_mq,
34 rt_perf_thread_mbox,
35 rt_perf_irq_latency, /* Timer Interrupt Source */
36 RT_NULL
37 };
38
rt_perf_get_timer_us(void)39 static rt_uint32_t rt_perf_get_timer_us(void)
40 {
41 rt_hwtimerval_t timer_val = {0};
42 if (hw_dev && rt_device_read(hw_dev, 0, &timer_val, sizeof(rt_hwtimerval_t)))
43 {
44 return (rt_uint32_t)(timer_val.sec * 1000000u + timer_val.usec); /* return us */
45 }
46 return 0;
47 }
48
rt_perf_start_impl(rt_perf_t * perf,rt_hwtimerval_t * timeout)49 void rt_perf_start_impl(rt_perf_t *perf, rt_hwtimerval_t *timeout)
50 {
51 if (hw_dev)
52 {
53 if (timeout == RT_NULL)
54 timeout = &timeout_s;
55 rt_device_write(hw_dev, 0, timeout, sizeof(rt_hwtimerval_t));
56 }
57 perf->begin_time = rt_perf_get_timer_us();
58 }
59
rt_perf_stop(rt_perf_t * perf)60 void rt_perf_stop(rt_perf_t *perf)
61 {
62 perf->real_time = rt_perf_get_timer_us() - perf->begin_time;
63
64 if(perf->local_modify) perf->local_modify(perf);
65 if (perf->real_time > perf->max_time)
66 {
67 perf->max_time = perf->real_time;
68 }
69
70 if (perf->real_time < perf->min_time)
71 {
72 perf->min_time = perf->real_time;
73 }
74
75 perf->count++;
76 perf->tot_time += perf->real_time;
77
78 if(hw_dev)
79 rt_device_control(hw_dev, HWTIMER_CTRL_STOP, NULL);
80 }
81
split_double(double num,rt_uint32_t type)82 static rt_int32_t split_double(double num, rt_uint32_t type)
83 {
84 if (type == RET_INT)
85 {
86 return (rt_int32_t)num;
87 }
88 else if (type == RET_DECIMALS)
89 {
90 return (rt_int32_t)((num - (rt_int32_t)num) * 10000);
91 }
92 else
93 {
94 return (-1);
95 }
96
97 return (-1);
98 }
99
rt_perf_dump(rt_perf_t * perf)100 void rt_perf_dump( rt_perf_t *perf)
101 {
102 static rt_uint32_t test_index = 1;
103 char avg_str[10] = {0};
104 if(perf->dump_head)
105 {
106 rt_kprintf("Test No | Test Name | Count | Total Time (us) | Max Time (us) | Min Time (us) | Avg Time (us)\n");
107 rt_kprintf("--------|----------------------|-------|-----------------|---------------|---------------|--------------\n");
108 perf->dump_head = RT_FALSE;
109 }
110
111 if (perf->count)
112 perf->avg_time = (double)perf->tot_time / perf->count;
113 else
114 perf->avg_time = 0.0;
115
116 rt_sprintf(avg_str, "%u.%04u", GET_INT(perf->avg_time), GET_DECIMALS(perf->avg_time));
117
118 rt_kprintf("%7u | %-20s | %5u | %15u | %13u | %13u | %12s\n",
119 test_index++,
120 perf->name,
121 perf->count,
122 perf->tot_time,
123 perf->max_time,
124 perf->min_time,
125 avg_str);
126 }
127
rt_perf_clear(rt_perf_t * perf)128 static void rt_perf_clear(rt_perf_t *perf)
129 {
130 perf->local_modify = NULL;
131 perf->begin_time = 0;
132 perf->real_time = 0;
133 perf->tot_time = 0;
134 perf->max_time = 0;
135 perf->min_time = RT_UINT32_MAX;
136 perf->count = 0;
137 perf->avg_time = 0;
138 perf->tmp_time = 0;
139 }
140
rt_perf_all_test(void)141 static void rt_perf_all_test(void)
142 {
143
144 rt_perf_t *perf_data = rt_malloc(sizeof(rt_perf_t));
145 if (perf_data == RT_NULL)
146 {
147 return;
148 }
149 perf_data->lock = rt_mutex_create("perf", RT_IPC_FLAG_PRIO);
150 perf_data->dump_head = RT_TRUE;
151 rt_kprintf("\n === Performance Test Results Start ===\n");
152 for (int i = 0; test_func_ptrs[i] != RT_NULL; i++)
153 {
154 rt_perf_clear(perf_data);
155 if (test_func_ptrs[i](perf_data) != RT_EOK)
156 {
157 LOG_E("%s test fail",perf_data->name);
158 continue;
159 }
160 }
161 rt_kprintf("\n === Performance Test Results End ===\n");
162 rt_mutex_delete(perf_data->lock);
163 rt_free(perf_data);
164 }
165
utest_tc_init(void)166 static rt_err_t utest_tc_init(void)
167 {
168 int ret = RT_EOK;
169
170 hw_dev = rt_device_find(UTEST_HWTIMER_DEV_NAME);
171 if (hw_dev == RT_NULL)
172 {
173 ret = RT_ERROR;
174 LOG_E("hwtimer sample run failed! can't find %s device!", UTEST_HWTIMER_DEV_NAME);
175 return ret;
176 }
177 ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
178 if (ret != RT_EOK)
179 {
180 LOG_E("open %s device failed!", UTEST_HWTIMER_DEV_NAME);
181 return ret;
182 }
183
184 timeout_s.sec = 10; /* No modification is necessary here, use the fixed value */
185 timeout_s.usec = 0;
186
187 return ret;
188 }
189
utest_tc_cleanup(void)190 static rt_err_t utest_tc_cleanup(void)
191 {
192 if(hw_dev) rt_device_close(hw_dev);
193 return RT_EOK;
194 }
195
testcase(void)196 static void testcase(void)
197 {
198 UTEST_UNIT_RUN(rt_perf_all_test);
199 }
200
201 UTEST_TC_EXPORT(testcase, "testcase.pref.all", utest_tc_init, utest_tc_cleanup, 10);
202
203