From 74997901401df476d4b73b34ea3de945916a904f Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Sat, 11 Oct 2025 16:07:08 +0800 Subject: utest: core: move perf testcase from example to src Also: - Add "RT_" prefix for the UTEST config options. - Follow the naming rules to update the case name. Signed-off-by: Chen Wang --- Kconfig.utestcases | 1 - examples/utest/testcases/perf/Kconfig | 24 --- examples/utest/testcases/perf/README.md | 12 -- examples/utest/testcases/perf/SConscript | 10 -- examples/utest/testcases/perf/context_switch_tc.c | 106 ------------ examples/utest/testcases/perf/irq_latency_tc.c | 80 --------- examples/utest/testcases/perf/perf_tc.c | 202 ---------------------- examples/utest/testcases/perf/perf_tc.h | 55 ------ examples/utest/testcases/perf/thread_event_tc.c | 112 ------------ examples/utest/testcases/perf/thread_mbox_tc.c | 110 ------------ examples/utest/testcases/perf/thread_mq_tc.c | 109 ------------ examples/utest/testcases/perf/thread_sem_tc.c | 121 ------------- src/utest/Kconfig | 2 + src/utest/perf/Kconfig | 15 ++ src/utest/perf/README.md | 12 ++ src/utest/perf/SConscript | 10 ++ src/utest/perf/context_switch_tc.c | 106 ++++++++++++ src/utest/perf/irq_latency_tc.c | 80 +++++++++ src/utest/perf/perf_tc.c | 202 ++++++++++++++++++++++ src/utest/perf/perf_tc.h | 55 ++++++ src/utest/perf/thread_event_tc.c | 112 ++++++++++++ src/utest/perf/thread_mbox_tc.c | 110 ++++++++++++ src/utest/perf/thread_mq_tc.c | 109 ++++++++++++ src/utest/perf/thread_sem_tc.c | 121 +++++++++++++ 24 files changed, 934 insertions(+), 942 deletions(-) delete mode 100644 examples/utest/testcases/perf/Kconfig delete mode 100644 examples/utest/testcases/perf/README.md delete mode 100644 examples/utest/testcases/perf/SConscript delete mode 100644 examples/utest/testcases/perf/context_switch_tc.c delete mode 100644 examples/utest/testcases/perf/irq_latency_tc.c delete mode 100644 examples/utest/testcases/perf/perf_tc.c delete mode 100644 examples/utest/testcases/perf/perf_tc.h delete mode 100644 examples/utest/testcases/perf/thread_event_tc.c delete mode 100644 examples/utest/testcases/perf/thread_mbox_tc.c delete mode 100644 examples/utest/testcases/perf/thread_mq_tc.c delete mode 100644 examples/utest/testcases/perf/thread_sem_tc.c create mode 100644 src/utest/perf/Kconfig create mode 100644 src/utest/perf/README.md create mode 100644 src/utest/perf/SConscript create mode 100644 src/utest/perf/context_switch_tc.c create mode 100644 src/utest/perf/irq_latency_tc.c create mode 100644 src/utest/perf/perf_tc.c create mode 100644 src/utest/perf/perf_tc.h create mode 100644 src/utest/perf/thread_event_tc.c create mode 100644 src/utest/perf/thread_mbox_tc.c create mode 100644 src/utest/perf/thread_mq_tc.c create mode 100644 src/utest/perf/thread_sem_tc.c diff --git a/Kconfig.utestcases b/Kconfig.utestcases index 2221228b4b..29980bed84 100644 --- a/Kconfig.utestcases +++ b/Kconfig.utestcases @@ -14,7 +14,6 @@ rsource "examples/utest/testcases/drivers/ipc/Kconfig" rsource "examples/utest/testcases/posix/Kconfig" rsource "examples/utest/testcases/mm/Kconfig" rsource "examples/utest/testcases/tmpfs/Kconfig" -rsource "examples/utest/testcases/perf/Kconfig" rsource "src/klibc/utest/Kconfig" diff --git a/examples/utest/testcases/perf/Kconfig b/examples/utest/testcases/perf/Kconfig deleted file mode 100644 index e25b919df2..0000000000 --- a/examples/utest/testcases/perf/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -menu "SyStem Performance Testcase" - -config UTEST_SYS_PERF_TC - bool "SyStem Performance test" - default n - -config UTEST_SYS_PERF_TC_COUNT - int "Test the number of cycles" - default 1000 - depends on UTEST_SYS_PERF_TC - -config UTEST_HWTIMER_DEV_NAME - string "Hardware timer device name" - default "timer0" - depends on RT_USING_HWTIMER && UTEST_SYS_PERF_TC - help - Specify the hardware timer device name used for context switch testing (e.g., timer0). - -config UTEST_SYS_IRQ_LATENCY - bool "SyStem IRQ LATENCY test" - default n - depends on RT_USING_HWTIMER && UTEST_SYS_PERF_TC - -endmenu diff --git a/examples/utest/testcases/perf/README.md b/examples/utest/testcases/perf/README.md deleted file mode 100644 index 0c10dff139..0000000000 --- a/examples/utest/testcases/perf/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# testcases 说明 - -## 一、测试用例说明 - -| 文件 | 说明 | -|--------|--------| -| context_switch.c | 上下文切换测试代码 | -| irq_latency.c | 中断延时测试代码 | -| rt_perf_thread_event.c | 线程事件性能测试 | -| rt_perf_thread_mbox.c | 线程邮箱性能测试 | -| rt_perf_thread_mq.c | 线程消息队列性能测试 | -| rt_perf_thread_sem.c | 线程信号量性能测试 | diff --git a/examples/utest/testcases/perf/SConscript b/examples/utest/testcases/perf/SConscript deleted file mode 100644 index c1ac0cff98..0000000000 --- a/examples/utest/testcases/perf/SConscript +++ /dev/null @@ -1,10 +0,0 @@ -Import('rtconfig') -from building import * - -cwd = GetCurrentDir() -src = Glob('*.c') -CPPPATH = [cwd] - -group = DefineGroup('utestcases', src, depend = ['UTEST_SYS_PERF_TC'], CPPPATH = CPPPATH) - -Return('group') diff --git a/examples/utest/testcases/perf/context_switch_tc.c b/examples/utest/testcases/perf/context_switch_tc.c deleted file mode 100644 index 074447303f..0000000000 --- a/examples/utest/testcases/perf/context_switch_tc.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2006-2025, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2025-07-03 rcitach test case for context_switch - */ - -#include -#include -#include -#include -#include -#include - -static rt_sem_t sem1, sem2; -static rt_sem_t complete_sem = RT_NULL; - -static void local_modify_time(rt_perf_t *perf) -{ - if(perf) - perf->real_time = perf->real_time - perf->tmp_time; -} - -static void perf_thread_event1(void *parameter) -{ - while (1) - { - rt_sem_take(sem1, RT_WAITING_FOREVER); - rt_sem_release(sem2); - } -} - -static void perf_thread_event2(void *parameter) -{ - rt_perf_t *perf = (rt_perf_t *)parameter; - - for (rt_uint32_t i = 0; i < UTEST_SYS_PERF_TC_COUNT; i++) - { - perf->tmp_time = 0; - rt_perf_start(perf); - rt_sem_take(sem2, RT_WAITING_FOREVER); - rt_sem_release(sem2); - rt_perf_stop(perf); - - rt_mutex_take(perf->lock,RT_WAITING_FOREVER); - perf->count -= 1; - perf->tmp_time = perf->real_time; - rt_mutex_release(perf->lock); - - rt_perf_start(perf); - rt_sem_take(sem2, RT_WAITING_FOREVER); - rt_sem_release(sem1); - rt_perf_stop(perf); - } - rt_sem_release(complete_sem); -} - -rt_err_t context_switch_test(rt_perf_t *perf) -{ - rt_thread_t thread1 = RT_NULL; - rt_thread_t thread2 = RT_NULL; - -# if __STDC_VERSION__ >= 199901L - rt_strcpy(perf->name,__func__); -#else - rt_strcpy(perf->name,"context_switch_test"); -#endif - - perf->local_modify = local_modify_time; - sem1 = rt_sem_create("sem1", 1, RT_IPC_FLAG_FIFO); - sem2 = rt_sem_create("sem2", 0, RT_IPC_FLAG_FIFO); - complete_sem = rt_sem_create("complete_sem", 0, RT_IPC_FLAG_FIFO); - - thread1 = rt_thread_create("perf_thread_event1", perf_thread_event1, perf, - THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); - if (thread1 == RT_NULL) - { - LOG_E("perf_thread_event1 create failed."); - return -RT_ERROR; - } - - thread2 = rt_thread_create("perf_thread_event2", perf_thread_event2, perf, - THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); - if (thread2 == RT_NULL) - { - LOG_E("perf_thread_event2 create failed."); - return -RT_ERROR; - } - - rt_thread_startup(thread1); - rt_thread_startup(thread2); - - rt_sem_take(complete_sem, RT_WAITING_FOREVER); - - rt_perf_dump(perf); - rt_thread_delete(thread1); - rt_sem_delete(complete_sem); - rt_sem_delete(sem1); - rt_sem_delete(sem2); - - return RT_EOK; -} - diff --git a/examples/utest/testcases/perf/irq_latency_tc.c b/examples/utest/testcases/perf/irq_latency_tc.c deleted file mode 100644 index 20d2c2d01a..0000000000 --- a/examples/utest/testcases/perf/irq_latency_tc.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2006-2025, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2025-07-03 rcitach test case for irq latency - */ - -#include -#include -#include -#include -#include - -static rt_device_t hw_dev = RT_NULL; -static rt_sem_t complete_sem = RT_NULL; -static rt_hwtimerval_t timeout = {0}; -static rt_perf_t *perf_local = RT_NULL; - -static void modify_time(rt_perf_t *perf) -{ - if(perf) - perf->real_time = perf->real_time - perf->tmp_time; -} - -static rt_err_t timer_callback(rt_device_t dev, rt_size_t size) -{ - rt_perf_stop(perf_local); - if (perf_local->count >= UTEST_SYS_PERF_TC_COUNT) - { - rt_sem_release(complete_sem); - return RT_EOK; - } - rt_perf_start_impl(perf_local, &timeout); - return RT_EOK; -} - -rt_err_t rt_perf_irq_latency(rt_perf_t *perf) -{ -# if __STDC_VERSION__ >= 199901L - rt_strcpy(perf->name,__func__); -#else - rt_strcpy(perf->name,"rt_perf_irq_latency"); -#endif - int ret = RT_EOK; - rt_hwtimer_mode_t mode = HWTIMER_MODE_PERIOD; - - perf_local = perf; - hw_dev = rt_device_find(UTEST_HWTIMER_DEV_NAME); - if (hw_dev == RT_NULL) - { - ret = RT_ERROR; - LOG_E("hwtimer sample run failed! can't find %s device!", UTEST_HWTIMER_DEV_NAME); - return ret; - } - - complete_sem = rt_sem_create("complete", 0, RT_IPC_FLAG_FIFO); - timeout.sec = 0; - timeout.usec = 50; /* No modification is necessary here, use the fixed value */ - - rt_mutex_take(perf->lock,RT_WAITING_FOREVER); - perf_local->tmp_time = (rt_uint32_t)(timeout.sec * 1000000u + timeout.usec); - perf_local->local_modify = modify_time; - rt_mutex_release(perf->lock); - - rt_device_set_rx_indicate(hw_dev, timer_callback); - rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, (void *)&mode); - - rt_perf_start_impl(perf_local, &timeout); - - rt_sem_take(complete_sem, RT_WAITING_FOREVER); - rt_perf_dump(perf_local); - rt_sem_delete(complete_sem); - rt_device_close(hw_dev); - - return RT_EOK; -} - diff --git a/examples/utest/testcases/perf/perf_tc.c b/examples/utest/testcases/perf/perf_tc.c deleted file mode 100644 index 489624e5c7..0000000000 --- a/examples/utest/testcases/perf/perf_tc.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2006-2025, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2025-07-03 rcitach test case for irq latency - */ - -#include -#include -#include -#include -#include -#include - -#define RET_INT 0 -#define RET_DECIMALS 1 - -#define GET_INT(num) split_double(num, RET_INT) -#define GET_DECIMALS(num) split_double(num, RET_DECIMALS) - -static rt_device_t hw_dev = RT_NULL; -static rt_hwtimerval_t timeout_s = {0}; - -typedef rt_err_t (*testcase_function)(rt_perf_t *perf); -testcase_function test_func_ptrs[] = -{ - context_switch_test, - rt_perf_thread_sem, - rt_perf_thread_event, - rt_perf_thread_mq, - rt_perf_thread_mbox, - rt_perf_irq_latency, /* Timer Interrupt Source */ - RT_NULL -}; - -static rt_uint32_t rt_perf_get_timer_us(void) -{ - rt_hwtimerval_t timer_val = {0}; - if (hw_dev && rt_device_read(hw_dev, 0, &timer_val, sizeof(rt_hwtimerval_t))) - { - return (rt_uint32_t)(timer_val.sec * 1000000u + timer_val.usec); /* return us */ - } - return 0; -} - -void rt_perf_start_impl(rt_perf_t *perf, rt_hwtimerval_t *timeout) -{ - if (hw_dev) - { - if (timeout == RT_NULL) - timeout = &timeout_s; - rt_device_write(hw_dev, 0, timeout, sizeof(rt_hwtimerval_t)); - } - perf->begin_time = rt_perf_get_timer_us(); -} - -void rt_perf_stop(rt_perf_t *perf) -{ - perf->real_time = rt_perf_get_timer_us() - perf->begin_time; - - if(perf->local_modify) perf->local_modify(perf); - if (perf->real_time > perf->max_time) - { - perf->max_time = perf->real_time; - } - - if (perf->real_time < perf->min_time) - { - perf->min_time = perf->real_time; - } - - perf->count++; - perf->tot_time += perf->real_time; - - if(hw_dev) - rt_device_control(hw_dev, HWTIMER_CTRL_STOP, NULL); -} - -static rt_int32_t split_double(double num, rt_uint32_t type) -{ - if (type == RET_INT) - { - return (rt_int32_t)num; - } - else if (type == RET_DECIMALS) - { - return (rt_int32_t)((num - (rt_int32_t)num) * 10000); - } - else - { - return (-1); - } - - return (-1); -} - -void rt_perf_dump( rt_perf_t *perf) -{ - static rt_uint32_t test_index = 1; - char avg_str[10] = {0}; - if(perf->dump_head) - { - rt_kprintf("Test No | Test Name | Count | Total Time (us) | Max Time (us) | Min Time (us) | Avg Time (us)\n"); - rt_kprintf("--------|----------------------|-------|-----------------|---------------|---------------|--------------\n"); - perf->dump_head = RT_FALSE; - } - - if (perf->count) - perf->avg_time = (double)perf->tot_time / perf->count; - else - perf->avg_time = 0.0; - - rt_sprintf(avg_str, "%u.%04u", GET_INT(perf->avg_time), GET_DECIMALS(perf->avg_time)); - - rt_kprintf("%7u | %-20s | %5u | %15u | %13u | %13u | %12s\n", - test_index++, - perf->name, - perf->count, - perf->tot_time, - perf->max_time, - perf->min_time, - avg_str); -} - -static void rt_perf_clear(rt_perf_t *perf) -{ - perf->local_modify = NULL; - perf->begin_time = 0; - perf->real_time = 0; - perf->tot_time = 0; - perf->max_time = 0; - perf->min_time = RT_UINT32_MAX; - perf->count = 0; - perf->avg_time = 0; - perf->tmp_time = 0; -} - -static void rt_perf_all_test(void) -{ - - rt_perf_t *perf_data = rt_malloc(sizeof(rt_perf_t)); - if (perf_data == RT_NULL) - { - return; - } - perf_data->lock = rt_mutex_create("perf", RT_IPC_FLAG_PRIO); - perf_data->dump_head = RT_TRUE; - rt_kprintf("\n === Performance Test Results Start ===\n"); - for (int i = 0; test_func_ptrs[i] != RT_NULL; i++) - { - rt_perf_clear(perf_data); - if (test_func_ptrs[i](perf_data) != RT_EOK) - { - LOG_E("%s test fail",perf_data->name); - continue; - } - } - rt_kprintf("\n === Performance Test Results End ===\n"); - rt_mutex_delete(perf_data->lock); - rt_free(perf_data); -} - -static rt_err_t utest_tc_init(void) -{ - int ret = RT_EOK; - - hw_dev = rt_device_find(UTEST_HWTIMER_DEV_NAME); - if (hw_dev == RT_NULL) - { - ret = RT_ERROR; - LOG_E("hwtimer sample run failed! can't find %s device!", UTEST_HWTIMER_DEV_NAME); - return ret; - } - ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR); - if (ret != RT_EOK) - { - LOG_E("open %s device failed!", UTEST_HWTIMER_DEV_NAME); - return ret; - } - - timeout_s.sec = 10; /* No modification is necessary here, use the fixed value */ - timeout_s.usec = 0; - - return ret; -} - -static rt_err_t utest_tc_cleanup(void) -{ - if(hw_dev) rt_device_close(hw_dev); - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(rt_perf_all_test); -} - -UTEST_TC_EXPORT(testcase, "testcase.pref.all", utest_tc_init, utest_tc_cleanup, 10); - diff --git a/examples/utest/testcases/perf/perf_tc.h b/examples/utest/testcases/perf/perf_tc.h deleted file mode 100644 index 06aeb5214e..0000000000 --- a/examples/utest/testcases/perf/perf_tc.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2006-2025, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2025-07-03 rcitach test case - */ - -#ifndef PERF_TC_H__ -#define PERF_TC_H__ - -#include -#include -#include -#include - -#define THREAD_STACK_SIZE 2048 -#define THREAD_PRIORITY 10 -#define THREAD_TIMESLICE 5 -typedef struct rt_perf -{ - char name[64]; - volatile rt_uint32_t begin_time; - volatile rt_uint32_t real_time; - volatile rt_uint32_t tot_time; - volatile rt_uint32_t max_time; - volatile rt_uint32_t min_time; - volatile rt_uint32_t count; - volatile double avg_time; - volatile rt_uint32_t tmp_time; /* Temporary data */ - rt_mutex_t lock; - void (*local_modify)(struct rt_perf *perf); - rt_bool_t dump_head; -} rt_perf_t; - -void rt_perf_start_impl(rt_perf_t *perf, rt_hwtimerval_t *timeout); -void rt_perf_stop(rt_perf_t *perf); -void rt_perf_dump( rt_perf_t *perf); - -static inline void rt_perf_start(rt_perf_t *perf) -{ - rt_perf_start_impl(perf, RT_NULL); -} - -rt_err_t context_switch_test(rt_perf_t *perf); -rt_err_t rt_perf_irq_latency(rt_perf_t *perf); -rt_err_t rt_perf_thread_sem(rt_perf_t *perf); -rt_err_t rt_perf_thread_event(rt_perf_t *perf); -rt_err_t rt_perf_thread_mq(rt_perf_t *perf); -rt_err_t rt_perf_thread_mbox(rt_perf_t *perf); - -#endif /* PERF_TC_H__ */ - diff --git a/examples/utest/testcases/perf/thread_event_tc.c b/examples/utest/testcases/perf/thread_event_tc.c deleted file mode 100644 index bff7bd919c..0000000000 --- a/examples/utest/testcases/perf/thread_event_tc.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2006-2025, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2025-07-03 rcitach test case for event - */ - -#include -#include -#include -#include -#include -#include - -#define EVENT_FLAG (1 << 0) -static rt_event_t perf_thread_event = RT_NULL; -static rt_sem_t sem1 = RT_NULL; -static rt_sem_t complete_sem = RT_NULL; - -static void perf_thread_event1(void *parameter) -{ - rt_err_t ret = RT_EOK; - rt_uint32_t recv = 0; - rt_perf_t *perf = (rt_perf_t *)parameter; - while (1) - { - ret = rt_event_recv(perf_thread_event, EVENT_FLAG, - (RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR), - RT_WAITING_FOREVER, &recv); - rt_perf_stop(perf); - if (ret != RT_EOK) - { - LOG_E("event recv error!"); - rt_event_delete(perf_thread_event); - return; - } - - if (perf->count >= UTEST_SYS_PERF_TC_COUNT) - { - rt_event_delete(perf_thread_event); - rt_sem_delete(sem1); - return; - } - rt_sem_release(sem1); - } -} - -static void perf_thread_event2(void *parameter) -{ - rt_perf_t *perf = (rt_perf_t *)parameter; - while (1) - { - if (perf->count >= UTEST_SYS_PERF_TC_COUNT) - { - rt_sem_release(complete_sem); - return; - } - rt_sem_take(sem1, RT_WAITING_FOREVER); - rt_perf_start(perf); - rt_event_send(perf_thread_event, EVENT_FLAG); - } -} - -rt_err_t rt_perf_thread_event(rt_perf_t *perf) -{ - rt_thread_t thread1 = RT_NULL; - rt_thread_t thread2 = RT_NULL; - -# if __STDC_VERSION__ >= 199901L - rt_strcpy(perf->name,__func__); -#else - rt_strcpy(perf->name,"rt_perf_thread_event"); -#endif - - perf_thread_event = rt_event_create("perf_thread_event", RT_IPC_FLAG_PRIO); - if (perf_thread_event == RT_NULL) - { - LOG_E("perf_thread_event create failed."); - return -RT_ERROR; - } - - sem1 = rt_sem_create("sem1", 1, RT_IPC_FLAG_FIFO); - complete_sem = rt_sem_create("complete", 0, RT_IPC_FLAG_FIFO); - - thread1 = rt_thread_create("perf_thread_event1", perf_thread_event1, perf, - THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); - if (thread1 == RT_NULL) - { - LOG_E("perf_thread_event1 create failed."); - return -RT_ERROR; - } - - thread2 = rt_thread_create("perf_thread_event2", perf_thread_event2, perf, - THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); - if (thread2 == RT_NULL) - { - LOG_E("perf_thread_event2 create failed."); - return -RT_ERROR; - } - - rt_thread_startup(thread1); - rt_thread_startup(thread2); - - rt_sem_take(complete_sem, RT_WAITING_FOREVER); - rt_perf_dump(perf); - rt_sem_delete(complete_sem); - return RT_EOK; -} - diff --git a/examples/utest/testcases/perf/thread_mbox_tc.c b/examples/utest/testcases/perf/thread_mbox_tc.c deleted file mode 100644 index 4ea58bce2e..0000000000 --- a/examples/utest/testcases/perf/thread_mbox_tc.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2006-2025, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2025-07-03 rcitach test case for mbox - */ - -#include -#include -#include -#include -#include -#include - -static rt_sem_t sem1 = RT_NULL; -static rt_sem_t complete_sem = RT_NULL; -static rt_mailbox_t perf_thread_mbox = RT_NULL; - -static void perf_thread_mbox1(void *parameter) -{ - rt_ubase_t recv = 0; - rt_err_t ret = RT_EOK; - rt_perf_t *perf = (rt_perf_t *)parameter; - while (1) - { - ret = rt_mb_recv(perf_thread_mbox, &recv, RT_WAITING_FOREVER); - rt_perf_stop(perf); - if (ret != RT_EOK) - { - LOG_E("mbox recv value error!\n"); - rt_mb_delete(perf_thread_mbox); - return; - } - - if (perf->count >= UTEST_SYS_PERF_TC_COUNT) - { - rt_mb_delete(perf_thread_mbox); - rt_sem_delete(sem1); - return; - } - rt_sem_release(sem1); - } -} - -static void perf_thread_mbox2(void *parameter) -{ - rt_perf_t *perf = (rt_perf_t *)parameter; - rt_err_t ret = RT_EOK; - while (1) - { - if (perf->count >= UTEST_SYS_PERF_TC_COUNT) - { - rt_sem_release(complete_sem); - return; - } - rt_sem_take(sem1, RT_WAITING_FOREVER); - rt_perf_start(perf); - rt_mb_send(perf_thread_mbox, 1); - } -} - -rt_err_t rt_perf_thread_mbox(rt_perf_t *perf) -{ - rt_thread_t thread1 = RT_NULL; - rt_thread_t thread2 = RT_NULL; - -# if __STDC_VERSION__ >= 199901L - rt_strcpy(perf->name,__func__); -#else - rt_strcpy(perf->name,"rt_perf_thread_mbox"); -#endif - - perf_thread_mbox = rt_mb_create("perf_thread_mbox", 1, RT_IPC_FLAG_PRIO); - if (perf_thread_mbox == RT_NULL) - { - LOG_E("perf thread mbox create failed."); - return -RT_ERROR; - } - - sem1 = rt_sem_create("sem1", 1, RT_IPC_FLAG_FIFO); - complete_sem = rt_sem_create("complete", 0, RT_IPC_FLAG_FIFO); - - thread1 = rt_thread_create("perf_thread_mbox1", perf_thread_mbox1, perf, - THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); - if (thread1 == RT_NULL) - { - LOG_E("perf_thread_mbox1 create failed."); - return -RT_ERROR; - } - - thread2 = rt_thread_create("perf_thread_mbox2", perf_thread_mbox2, perf, - THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); - if (thread2 == RT_NULL) - { - LOG_E("perf_thread_mbox2 create failed."); - return -RT_ERROR; - } - - rt_thread_startup(thread1); - rt_thread_startup(thread2); - - rt_sem_take(complete_sem, RT_WAITING_FOREVER); - rt_perf_dump(perf); - rt_sem_delete(complete_sem); - return RT_EOK; -} - diff --git a/examples/utest/testcases/perf/thread_mq_tc.c b/examples/utest/testcases/perf/thread_mq_tc.c deleted file mode 100644 index 6258ee72bc..0000000000 --- a/examples/utest/testcases/perf/thread_mq_tc.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2006-2025, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2025-07-03 rcitach test case for messagequeue - */ - -#include -#include -#include -#include -#include -#include - -static rt_sem_t sem1 = RT_NULL; -static rt_sem_t complete_sem = RT_NULL; -static rt_mq_t perf_thread_mq = RT_NULL; - -static void perf_thread_mq1(void *parameter) -{ - char recv = 0; - rt_perf_t *perf = (rt_perf_t *)parameter; - while (1) - { - rt_mq_recv(perf_thread_mq, &recv, 1, RT_WAITING_FOREVER); - rt_perf_stop(perf); - if (recv != 'A') - { - LOG_E("mq recv value error!"); - rt_mq_delete(perf_thread_mq); - return; - } - - if (perf->count >= UTEST_SYS_PERF_TC_COUNT) - { - rt_mq_delete(perf_thread_mq); - rt_sem_delete(sem1); - return; - } - rt_sem_release(sem1); - } -} - -static void perf_thread_mq2(void *parameter) -{ - rt_perf_t *perf = (rt_perf_t *)parameter; - char send = 'A'; - while (1) - { - if (perf->count >= UTEST_SYS_PERF_TC_COUNT) - { - rt_sem_release(complete_sem); - return; - } - rt_sem_take(sem1, RT_WAITING_FOREVER); - rt_perf_start(perf); - rt_mq_send(perf_thread_mq, &send, 1); - } -} - -rt_err_t rt_perf_thread_mq(rt_perf_t *perf) -{ - rt_thread_t thread1 = RT_NULL; - rt_thread_t thread2 = RT_NULL; - -# if __STDC_VERSION__ >= 199901L - rt_strcpy(perf->name,__func__); -#else - rt_strcpy(perf->name,"rt_perf_thread_mq"); -#endif - - perf_thread_mq = rt_mq_create("perf_thread_mq", 1, 1, RT_IPC_FLAG_PRIO); - if (perf_thread_mq == RT_NULL) - { - LOG_E("perf_thread_mq create failed."); - return -RT_ERROR; - } - - sem1 = rt_sem_create("sem1", 1, RT_IPC_FLAG_FIFO); - complete_sem = rt_sem_create("complete", 0, RT_IPC_FLAG_FIFO); - - thread1 = rt_thread_create("perf_thread_mq1", perf_thread_mq1, perf, - THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); - if (thread1 == RT_NULL) - { - LOG_E("perf_thread_mq1 create failed."); - return -RT_ERROR; - } - - thread2 = rt_thread_create("perf_thread_mq2", perf_thread_mq2, perf, - THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); - if (thread2 == RT_NULL) - { - LOG_E("perf_thread_mq2 create failed."); - return -RT_ERROR; - } - - rt_thread_startup(thread1); - rt_thread_startup(thread2); - - rt_sem_take(complete_sem, RT_WAITING_FOREVER); - rt_perf_dump(perf); - rt_sem_delete(complete_sem); - return RT_EOK; -} - diff --git a/examples/utest/testcases/perf/thread_sem_tc.c b/examples/utest/testcases/perf/thread_sem_tc.c deleted file mode 100644 index c120631be0..0000000000 --- a/examples/utest/testcases/perf/thread_sem_tc.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2006-2025, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2025-07-03 rcitach test case for semaphore - */ - -#include -#include -#include -#include -#include -#include - -static rt_sem_t perf_thread_sem = RT_NULL; -static rt_event_t perf_thread_event = RT_NULL; -static rt_sem_t complete_sem = RT_NULL; - -#define EVENT_FLAG (1 << 0) -static void perf_thread_sem1(void *parameter) -{ - rt_err_t ret = RT_EOK; - rt_perf_t *perf = (rt_perf_t *)parameter; - rt_event_send(perf_thread_event, EVENT_FLAG); - while (1) - { - ret = rt_sem_take(perf_thread_sem, RT_WAITING_FOREVER); - rt_perf_stop(perf); - if(ret != RT_EOK) - { - LOG_E("Sem recv error!"); - rt_sem_delete(perf_thread_sem); - return; - } - - if (perf->count >= UTEST_SYS_PERF_TC_COUNT) - { - rt_event_delete(perf_thread_event); - rt_sem_delete(perf_thread_sem); - return; - } - rt_event_send(perf_thread_event, EVENT_FLAG); - } -} - -static void perf_thread_sem2(void *parameter) -{ - rt_err_t ret = RT_EOK; - rt_perf_t *perf = (rt_perf_t *)parameter; - rt_uint32_t recv = 0; - while (1) - { - if (perf->count >= UTEST_SYS_PERF_TC_COUNT) - { - rt_sem_release(complete_sem); - return; - } - ret = rt_event_recv(perf_thread_event, EVENT_FLAG, - (RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR), - RT_WAITING_FOREVER, &recv); - if(ret != RT_EOK) - { - LOG_E("Event reception failed"); - rt_event_delete(perf_thread_event); - rt_sem_release(complete_sem); - return; - } - rt_perf_start(perf); - rt_sem_release(perf_thread_sem); - } -} - -rt_err_t rt_perf_thread_sem(rt_perf_t *perf) -{ - rt_thread_t thread1 = RT_NULL; - rt_thread_t thread2 = RT_NULL; - -# if __STDC_VERSION__ >= 199901L - rt_strcpy(perf->name,__func__); -#else - rt_strcpy(perf->name,"rt_perf_thread_sem"); -#endif - - perf_thread_sem = rt_sem_create("perf_thread_sem", 0, RT_IPC_FLAG_FIFO); - if (perf_thread_sem == RT_NULL) - { - LOG_E("perf_thread_sem create failed."); - return -RT_ERROR; - } - - perf_thread_event = rt_event_create("perf_thread_event", RT_IPC_FLAG_PRIO); - complete_sem = rt_sem_create("complete", 0, RT_IPC_FLAG_FIFO); - - thread1 = rt_thread_create("perf_thread_sem1", perf_thread_sem1, perf, - THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); - if (thread1 == RT_NULL) - { - LOG_E("perf_thread_sem1 create failed."); - return -RT_ERROR; - } - - thread2 = rt_thread_create("perf_thread_sem2", perf_thread_sem2, perf, - THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); - if (thread2 == RT_NULL) - { - LOG_E("perf_thread_sem2 create failed."); - return -RT_ERROR; - } - - rt_thread_startup(thread1); - rt_thread_startup(thread2); - - rt_sem_take(complete_sem, RT_WAITING_FOREVER); - rt_perf_dump(perf); - rt_sem_delete(complete_sem); - return RT_EOK; -} - diff --git a/src/utest/Kconfig b/src/utest/Kconfig index 58f275bc2a..c9580f099f 100644 --- a/src/utest/Kconfig +++ b/src/utest/Kconfig @@ -84,6 +84,8 @@ config UTEST_MEMPOOL_TC default n depends on RT_USING_MEMPOOL +rsource "perf/Kconfig" + if RT_USING_SMP rsource "smp/Kconfig" endif diff --git a/src/utest/perf/Kconfig b/src/utest/perf/Kconfig new file mode 100644 index 0000000000..fe6ee640ce --- /dev/null +++ b/src/utest/perf/Kconfig @@ -0,0 +1,15 @@ +config RT_UTEST_SYS_PERF + bool "Performance Test" + default n + +config RT_UTEST_SYS_PERF_TC_COUNT + int "PerfTest: Number of cycles" + default 1000 + depends on RT_UTEST_SYS_PERF + +config RT_UTEST_HWTIMER_DEV_NAME + string "PerfTest: Hardware timer device name" + default "timer0" + depends on RT_USING_HWTIMER && RT_UTEST_SYS_PERF + help + Specify the hardware timer device name used for context switch testing (e.g., timer0). diff --git a/src/utest/perf/README.md b/src/utest/perf/README.md new file mode 100644 index 0000000000..0c10dff139 --- /dev/null +++ b/src/utest/perf/README.md @@ -0,0 +1,12 @@ +# testcases 说明 + +## 一、测试用例说明 + +| 文件 | 说明 | +|--------|--------| +| context_switch.c | 上下文切换测试代码 | +| irq_latency.c | 中断延时测试代码 | +| rt_perf_thread_event.c | 线程事件性能测试 | +| rt_perf_thread_mbox.c | 线程邮箱性能测试 | +| rt_perf_thread_mq.c | 线程消息队列性能测试 | +| rt_perf_thread_sem.c | 线程信号量性能测试 | diff --git a/src/utest/perf/SConscript b/src/utest/perf/SConscript new file mode 100644 index 0000000000..22b74b9b5d --- /dev/null +++ b/src/utest/perf/SConscript @@ -0,0 +1,10 @@ +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +group = DefineGroup('utestcases', src, depend = ['RT_UTEST_SYS_PERF'], CPPPATH = CPPPATH) + +Return('group') diff --git a/src/utest/perf/context_switch_tc.c b/src/utest/perf/context_switch_tc.c new file mode 100644 index 0000000000..ee42bc554c --- /dev/null +++ b/src/utest/perf/context_switch_tc.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2025-07-03 rcitach test case for context_switch + */ + +#include +#include +#include +#include +#include +#include + +static rt_sem_t sem1, sem2; +static rt_sem_t complete_sem = RT_NULL; + +static void local_modify_time(rt_perf_t *perf) +{ + if(perf) + perf->real_time = perf->real_time - perf->tmp_time; +} + +static void perf_thread_event1(void *parameter) +{ + while (1) + { + rt_sem_take(sem1, RT_WAITING_FOREVER); + rt_sem_release(sem2); + } +} + +static void perf_thread_event2(void *parameter) +{ + rt_perf_t *perf = (rt_perf_t *)parameter; + + for (rt_uint32_t i = 0; i < RT_UTEST_SYS_PERF_TC_COUNT; i++) + { + perf->tmp_time = 0; + rt_perf_start(perf); + rt_sem_take(sem2, RT_WAITING_FOREVER); + rt_sem_release(sem2); + rt_perf_stop(perf); + + rt_mutex_take(perf->lock,RT_WAITING_FOREVER); + perf->count -= 1; + perf->tmp_time = perf->real_time; + rt_mutex_release(perf->lock); + + rt_perf_start(perf); + rt_sem_take(sem2, RT_WAITING_FOREVER); + rt_sem_release(sem1); + rt_perf_stop(perf); + } + rt_sem_release(complete_sem); +} + +rt_err_t context_switch_test(rt_perf_t *perf) +{ + rt_thread_t thread1 = RT_NULL; + rt_thread_t thread2 = RT_NULL; + +# if __STDC_VERSION__ >= 199901L + rt_strcpy(perf->name,__func__); +#else + rt_strcpy(perf->name,"context_switch_test"); +#endif + + perf->local_modify = local_modify_time; + sem1 = rt_sem_create("sem1", 1, RT_IPC_FLAG_FIFO); + sem2 = rt_sem_create("sem2", 0, RT_IPC_FLAG_FIFO); + complete_sem = rt_sem_create("complete_sem", 0, RT_IPC_FLAG_FIFO); + + thread1 = rt_thread_create("perf_thread_event1", perf_thread_event1, perf, + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + if (thread1 == RT_NULL) + { + LOG_E("perf_thread_event1 create failed."); + return -RT_ERROR; + } + + thread2 = rt_thread_create("perf_thread_event2", perf_thread_event2, perf, + THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); + if (thread2 == RT_NULL) + { + LOG_E("perf_thread_event2 create failed."); + return -RT_ERROR; + } + + rt_thread_startup(thread1); + rt_thread_startup(thread2); + + rt_sem_take(complete_sem, RT_WAITING_FOREVER); + + rt_perf_dump(perf); + rt_thread_delete(thread1); + rt_sem_delete(complete_sem); + rt_sem_delete(sem1); + rt_sem_delete(sem2); + + return RT_EOK; +} + diff --git a/src/utest/perf/irq_latency_tc.c b/src/utest/perf/irq_latency_tc.c new file mode 100644 index 0000000000..785151fc66 --- /dev/null +++ b/src/utest/perf/irq_latency_tc.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2025-07-03 rcitach test case for irq latency + */ + +#include +#include +#include +#include +#include + +static rt_device_t hw_dev = RT_NULL; +static rt_sem_t complete_sem = RT_NULL; +static rt_hwtimerval_t timeout = {0}; +static rt_perf_t *perf_local = RT_NULL; + +static void modify_time(rt_perf_t *perf) +{ + if(perf) + perf->real_time = perf->real_time - perf->tmp_time; +} + +static rt_err_t timer_callback(rt_device_t dev, rt_size_t size) +{ + rt_perf_stop(perf_local); + if (perf_local->count >= RT_UTEST_SYS_PERF_TC_COUNT) + { + rt_sem_release(complete_sem); + return RT_EOK; + } + rt_perf_start_impl(perf_local, &timeout); + return RT_EOK; +} + +rt_err_t rt_perf_irq_latency(rt_perf_t *perf) +{ +# if __STDC_VERSION__ >= 199901L + rt_strcpy(perf->name,__func__); +#else + rt_strcpy(perf->name,"rt_perf_irq_latency"); +#endif + int ret = RT_EOK; + rt_hwtimer_mode_t mode = HWTIMER_MODE_PERIOD; + + perf_local = perf; + hw_dev = rt_device_find(RT_UTEST_HWTIMER_DEV_NAME); + if (hw_dev == RT_NULL) + { + ret = RT_ERROR; + LOG_E("hwtimer sample run failed! can't find %s device!", RT_UTEST_HWTIMER_DEV_NAME); + return ret; + } + + complete_sem = rt_sem_create("complete", 0, RT_IPC_FLAG_FIFO); + timeout.sec = 0; + timeout.usec = 50; /* No modification is necessary here, use the fixed value */ + + rt_mutex_take(perf->lock,RT_WAITING_FOREVER); + perf_local->tmp_time = (rt_uint32_t)(timeout.sec * 1000000u + timeout.usec); + perf_local->local_modify = modify_time; + rt_mutex_release(perf->lock); + + rt_device_set_rx_indicate(hw_dev, timer_callback); + rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, (void *)&mode); + + rt_perf_start_impl(perf_local, &timeout); + + rt_sem_take(complete_sem, RT_WAITING_FOREVER); + rt_perf_dump(perf_local); + rt_sem_delete(complete_sem); + rt_device_close(hw_dev); + + return RT_EOK; +} + diff --git a/src/utest/perf/perf_tc.c b/src/utest/perf/perf_tc.c new file mode 100644 index 0000000000..56b3b8dfa6 --- /dev/null +++ b/src/utest/perf/perf_tc.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2025-07-03 rcitach test case for irq latency + */ + +#include +#include +#include +#include +#include +#include + +#define RET_INT 0 +#define RET_DECIMALS 1 + +#define GET_INT(num) split_double(num, RET_INT) +#define GET_DECIMALS(num) split_double(num, RET_DECIMALS) + +static rt_device_t hw_dev = RT_NULL; +static rt_hwtimerval_t timeout_s = {0}; + +typedef rt_err_t (*testcase_function)(rt_perf_t *perf); +testcase_function test_func_ptrs[] = +{ + context_switch_test, + rt_perf_thread_sem, + rt_perf_thread_event, + rt_perf_thread_mq, + rt_perf_thread_mbox, + rt_perf_irq_latency, /* Timer Interrupt Source */ + RT_NULL +}; + +static rt_uint32_t rt_perf_get_timer_us(void) +{ + rt_hwtimerval_t timer_val = {0}; + if (hw_dev && rt_device_read(hw_dev, 0, &timer_val, sizeof(rt_hwtimerval_t))) + { + return (rt_uint32_t)(timer_val.sec * 1000000u + timer_val.usec); /* return us */ + } + return 0; +} + +void rt_perf_start_impl(rt_perf_t *perf, rt_hwtimerval_t *timeout) +{ + if (hw_dev) + { + if (timeout == RT_NULL) + timeout = &timeout_s; + rt_device_write(hw_dev, 0, timeout, sizeof(rt_hwtimerval_t)); + } + perf->begin_time = rt_perf_get_timer_us(); +} + +void rt_perf_stop(rt_perf_t *perf) +{ + perf->real_time = rt_perf_get_timer_us() - perf->begin_time; + + if(perf->local_modify) perf->local_modify(perf); + if (perf->real_time > perf->max_time) + { + perf->max_time = perf->real_time; + } + + if (perf->real_time < perf->min_time) + { + perf->min_time = perf->real_time; + } + + perf->count++; + perf->tot_time += perf->real_time; + + if(hw_dev) + rt_device_control(hw_dev, HWTIMER_CTRL_STOP, NULL); +} + +static rt_int32_t split_double(double num, rt_uint32_t type) +{ + if (type == RET_INT) + { + return (rt_int32_t)num; + } + else if (type == RET_DECIMALS) + { + return (rt_int32_t)((num - (rt_int32_t)num) * 10000); + } + else + { + return (-1); + } + + return (-1); +} + +void rt_perf_dump( rt_perf_t *perf) +{ + static rt_uint32_t test_index = 1; + char avg_str[10] = {0}; + if(perf->dump_head) + { + rt_kprintf("Test No | Test Name | Count | Total Time (us) | Max Time (us) | Min Time (us) | Avg Time (us)\n"); + rt_kprintf("--------|----------------------|-------|-----------------|---------------|---------------|--------------\n"); + perf->dump_head = RT_FALSE; + } + + if (perf->count) + perf->avg_time = (double)perf->tot_time / perf->count; + else + perf->avg_time = 0.0; + + rt_sprintf(avg_str, "%u.%04u", GET_INT(perf->avg_time), GET_DECIMALS(perf->avg_time)); + + rt_kprintf("%7u | %-20s | %5u | %15u | %13u | %13u | %12s\n", + test_index++, + perf->name, + perf->count, + perf->tot_time, + perf->max_time, + perf->min_time, + avg_str); +} + +static void rt_perf_clear(rt_perf_t *perf) +{ + perf->local_modify = NULL; + perf->begin_time = 0; + perf->real_time = 0; + perf->tot_time = 0; + perf->max_time = 0; + perf->min_time = RT_UINT32_MAX; + perf->count = 0; + perf->avg_time = 0; + perf->tmp_time = 0; +} + +static void rt_perf_all_test(void) +{ + + rt_perf_t *perf_data = rt_malloc(sizeof(rt_perf_t)); + if (perf_data == RT_NULL) + { + return; + } + perf_data->lock = rt_mutex_create("perf", RT_IPC_FLAG_PRIO); + perf_data->dump_head = RT_TRUE; + rt_kprintf("\n === Performance Test Results Start ===\n"); + for (int i = 0; test_func_ptrs[i] != RT_NULL; i++) + { + rt_perf_clear(perf_data); + if (test_func_ptrs[i](perf_data) != RT_EOK) + { + LOG_E("%s test fail",perf_data->name); + continue; + } + } + rt_kprintf("\n === Performance Test Results End ===\n"); + rt_mutex_delete(perf_data->lock); + rt_free(perf_data); +} + +static rt_err_t utest_tc_init(void) +{ + int ret = RT_EOK; + + hw_dev = rt_device_find(RT_UTEST_HWTIMER_DEV_NAME); + if (hw_dev == RT_NULL) + { + ret = RT_ERROR; + LOG_E("hwtimer sample run failed! can't find %s device!", RT_UTEST_HWTIMER_DEV_NAME); + return ret; + } + ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR); + if (ret != RT_EOK) + { + LOG_E("open %s device failed!", RT_UTEST_HWTIMER_DEV_NAME); + return ret; + } + + timeout_s.sec = 10; /* No modification is necessary here, use the fixed value */ + timeout_s.usec = 0; + + return ret; +} + +static rt_err_t utest_tc_cleanup(void) +{ + if(hw_dev) rt_device_close(hw_dev); + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(rt_perf_all_test); +} + +UTEST_TC_EXPORT(testcase, "core.pref_test", utest_tc_init, utest_tc_cleanup, 10); + diff --git a/src/utest/perf/perf_tc.h b/src/utest/perf/perf_tc.h new file mode 100644 index 0000000000..06aeb5214e --- /dev/null +++ b/src/utest/perf/perf_tc.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2025-07-03 rcitach test case + */ + +#ifndef PERF_TC_H__ +#define PERF_TC_H__ + +#include +#include +#include +#include + +#define THREAD_STACK_SIZE 2048 +#define THREAD_PRIORITY 10 +#define THREAD_TIMESLICE 5 +typedef struct rt_perf +{ + char name[64]; + volatile rt_uint32_t begin_time; + volatile rt_uint32_t real_time; + volatile rt_uint32_t tot_time; + volatile rt_uint32_t max_time; + volatile rt_uint32_t min_time; + volatile rt_uint32_t count; + volatile double avg_time; + volatile rt_uint32_t tmp_time; /* Temporary data */ + rt_mutex_t lock; + void (*local_modify)(struct rt_perf *perf); + rt_bool_t dump_head; +} rt_perf_t; + +void rt_perf_start_impl(rt_perf_t *perf, rt_hwtimerval_t *timeout); +void rt_perf_stop(rt_perf_t *perf); +void rt_perf_dump( rt_perf_t *perf); + +static inline void rt_perf_start(rt_perf_t *perf) +{ + rt_perf_start_impl(perf, RT_NULL); +} + +rt_err_t context_switch_test(rt_perf_t *perf); +rt_err_t rt_perf_irq_latency(rt_perf_t *perf); +rt_err_t rt_perf_thread_sem(rt_perf_t *perf); +rt_err_t rt_perf_thread_event(rt_perf_t *perf); +rt_err_t rt_perf_thread_mq(rt_perf_t *perf); +rt_err_t rt_perf_thread_mbox(rt_perf_t *perf); + +#endif /* PERF_TC_H__ */ + diff --git a/src/utest/perf/thread_event_tc.c b/src/utest/perf/thread_event_tc.c new file mode 100644 index 0000000000..2d9b0ef932 --- /dev/null +++ b/src/utest/perf/thread_event_tc.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2025-07-03 rcitach test case for event + */ + +#include +#include +#include +#include +#include +#include + +#define EVENT_FLAG (1 << 0) +static rt_event_t perf_thread_event = RT_NULL; +static rt_sem_t sem1 = RT_NULL; +static rt_sem_t complete_sem = RT_NULL; + +static void perf_thread_event1(void *parameter) +{ + rt_err_t ret = RT_EOK; + rt_uint32_t recv = 0; + rt_perf_t *perf = (rt_perf_t *)parameter; + while (1) + { + ret = rt_event_recv(perf_thread_event, EVENT_FLAG, + (RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR), + RT_WAITING_FOREVER, &recv); + rt_perf_stop(perf); + if (ret != RT_EOK) + { + LOG_E("event recv error!"); + rt_event_delete(perf_thread_event); + return; + } + + if (perf->count >= RT_UTEST_SYS_PERF_TC_COUNT) + { + rt_event_delete(perf_thread_event); + rt_sem_delete(sem1); + return; + } + rt_sem_release(sem1); + } +} + +static void perf_thread_event2(void *parameter) +{ + rt_perf_t *perf = (rt_perf_t *)parameter; + while (1) + { + if (perf->count >= RT_UTEST_SYS_PERF_TC_COUNT) + { + rt_sem_release(complete_sem); + return; + } + rt_sem_take(sem1, RT_WAITING_FOREVER); + rt_perf_start(perf); + rt_event_send(perf_thread_event, EVENT_FLAG); + } +} + +rt_err_t rt_perf_thread_event(rt_perf_t *perf) +{ + rt_thread_t thread1 = RT_NULL; + rt_thread_t thread2 = RT_NULL; + +# if __STDC_VERSION__ >= 199901L + rt_strcpy(perf->name,__func__); +#else + rt_strcpy(perf->name,"rt_perf_thread_event"); +#endif + + perf_thread_event = rt_event_create("perf_thread_event", RT_IPC_FLAG_PRIO); + if (perf_thread_event == RT_NULL) + { + LOG_E("perf_thread_event create failed."); + return -RT_ERROR; + } + + sem1 = rt_sem_create("sem1", 1, RT_IPC_FLAG_FIFO); + complete_sem = rt_sem_create("complete", 0, RT_IPC_FLAG_FIFO); + + thread1 = rt_thread_create("perf_thread_event1", perf_thread_event1, perf, + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + if (thread1 == RT_NULL) + { + LOG_E("perf_thread_event1 create failed."); + return -RT_ERROR; + } + + thread2 = rt_thread_create("perf_thread_event2", perf_thread_event2, perf, + THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); + if (thread2 == RT_NULL) + { + LOG_E("perf_thread_event2 create failed."); + return -RT_ERROR; + } + + rt_thread_startup(thread1); + rt_thread_startup(thread2); + + rt_sem_take(complete_sem, RT_WAITING_FOREVER); + rt_perf_dump(perf); + rt_sem_delete(complete_sem); + return RT_EOK; +} + diff --git a/src/utest/perf/thread_mbox_tc.c b/src/utest/perf/thread_mbox_tc.c new file mode 100644 index 0000000000..f07dab21d4 --- /dev/null +++ b/src/utest/perf/thread_mbox_tc.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2025-07-03 rcitach test case for mbox + */ + +#include +#include +#include +#include +#include +#include + +static rt_sem_t sem1 = RT_NULL; +static rt_sem_t complete_sem = RT_NULL; +static rt_mailbox_t perf_thread_mbox = RT_NULL; + +static void perf_thread_mbox1(void *parameter) +{ + rt_ubase_t recv = 0; + rt_err_t ret = RT_EOK; + rt_perf_t *perf = (rt_perf_t *)parameter; + while (1) + { + ret = rt_mb_recv(perf_thread_mbox, &recv, RT_WAITING_FOREVER); + rt_perf_stop(perf); + if (ret != RT_EOK) + { + LOG_E("mbox recv value error!\n"); + rt_mb_delete(perf_thread_mbox); + return; + } + + if (perf->count >= RT_UTEST_SYS_PERF_TC_COUNT) + { + rt_mb_delete(perf_thread_mbox); + rt_sem_delete(sem1); + return; + } + rt_sem_release(sem1); + } +} + +static void perf_thread_mbox2(void *parameter) +{ + rt_perf_t *perf = (rt_perf_t *)parameter; + rt_err_t ret = RT_EOK; + while (1) + { + if (perf->count >= RT_UTEST_SYS_PERF_TC_COUNT) + { + rt_sem_release(complete_sem); + return; + } + rt_sem_take(sem1, RT_WAITING_FOREVER); + rt_perf_start(perf); + rt_mb_send(perf_thread_mbox, 1); + } +} + +rt_err_t rt_perf_thread_mbox(rt_perf_t *perf) +{ + rt_thread_t thread1 = RT_NULL; + rt_thread_t thread2 = RT_NULL; + +# if __STDC_VERSION__ >= 199901L + rt_strcpy(perf->name,__func__); +#else + rt_strcpy(perf->name,"rt_perf_thread_mbox"); +#endif + + perf_thread_mbox = rt_mb_create("perf_thread_mbox", 1, RT_IPC_FLAG_PRIO); + if (perf_thread_mbox == RT_NULL) + { + LOG_E("perf thread mbox create failed."); + return -RT_ERROR; + } + + sem1 = rt_sem_create("sem1", 1, RT_IPC_FLAG_FIFO); + complete_sem = rt_sem_create("complete", 0, RT_IPC_FLAG_FIFO); + + thread1 = rt_thread_create("perf_thread_mbox1", perf_thread_mbox1, perf, + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + if (thread1 == RT_NULL) + { + LOG_E("perf_thread_mbox1 create failed."); + return -RT_ERROR; + } + + thread2 = rt_thread_create("perf_thread_mbox2", perf_thread_mbox2, perf, + THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); + if (thread2 == RT_NULL) + { + LOG_E("perf_thread_mbox2 create failed."); + return -RT_ERROR; + } + + rt_thread_startup(thread1); + rt_thread_startup(thread2); + + rt_sem_take(complete_sem, RT_WAITING_FOREVER); + rt_perf_dump(perf); + rt_sem_delete(complete_sem); + return RT_EOK; +} + diff --git a/src/utest/perf/thread_mq_tc.c b/src/utest/perf/thread_mq_tc.c new file mode 100644 index 0000000000..df4ac1ca2b --- /dev/null +++ b/src/utest/perf/thread_mq_tc.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2025-07-03 rcitach test case for messagequeue + */ + +#include +#include +#include +#include +#include +#include + +static rt_sem_t sem1 = RT_NULL; +static rt_sem_t complete_sem = RT_NULL; +static rt_mq_t perf_thread_mq = RT_NULL; + +static void perf_thread_mq1(void *parameter) +{ + char recv = 0; + rt_perf_t *perf = (rt_perf_t *)parameter; + while (1) + { + rt_mq_recv(perf_thread_mq, &recv, 1, RT_WAITING_FOREVER); + rt_perf_stop(perf); + if (recv != 'A') + { + LOG_E("mq recv value error!"); + rt_mq_delete(perf_thread_mq); + return; + } + + if (perf->count >= RT_UTEST_SYS_PERF_TC_COUNT) + { + rt_mq_delete(perf_thread_mq); + rt_sem_delete(sem1); + return; + } + rt_sem_release(sem1); + } +} + +static void perf_thread_mq2(void *parameter) +{ + rt_perf_t *perf = (rt_perf_t *)parameter; + char send = 'A'; + while (1) + { + if (perf->count >= RT_UTEST_SYS_PERF_TC_COUNT) + { + rt_sem_release(complete_sem); + return; + } + rt_sem_take(sem1, RT_WAITING_FOREVER); + rt_perf_start(perf); + rt_mq_send(perf_thread_mq, &send, 1); + } +} + +rt_err_t rt_perf_thread_mq(rt_perf_t *perf) +{ + rt_thread_t thread1 = RT_NULL; + rt_thread_t thread2 = RT_NULL; + +# if __STDC_VERSION__ >= 199901L + rt_strcpy(perf->name,__func__); +#else + rt_strcpy(perf->name,"rt_perf_thread_mq"); +#endif + + perf_thread_mq = rt_mq_create("perf_thread_mq", 1, 1, RT_IPC_FLAG_PRIO); + if (perf_thread_mq == RT_NULL) + { + LOG_E("perf_thread_mq create failed."); + return -RT_ERROR; + } + + sem1 = rt_sem_create("sem1", 1, RT_IPC_FLAG_FIFO); + complete_sem = rt_sem_create("complete", 0, RT_IPC_FLAG_FIFO); + + thread1 = rt_thread_create("perf_thread_mq1", perf_thread_mq1, perf, + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + if (thread1 == RT_NULL) + { + LOG_E("perf_thread_mq1 create failed."); + return -RT_ERROR; + } + + thread2 = rt_thread_create("perf_thread_mq2", perf_thread_mq2, perf, + THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); + if (thread2 == RT_NULL) + { + LOG_E("perf_thread_mq2 create failed."); + return -RT_ERROR; + } + + rt_thread_startup(thread1); + rt_thread_startup(thread2); + + rt_sem_take(complete_sem, RT_WAITING_FOREVER); + rt_perf_dump(perf); + rt_sem_delete(complete_sem); + return RT_EOK; +} + diff --git a/src/utest/perf/thread_sem_tc.c b/src/utest/perf/thread_sem_tc.c new file mode 100644 index 0000000000..e05430c257 --- /dev/null +++ b/src/utest/perf/thread_sem_tc.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2025-07-03 rcitach test case for semaphore + */ + +#include +#include +#include +#include +#include +#include + +static rt_sem_t perf_thread_sem = RT_NULL; +static rt_event_t perf_thread_event = RT_NULL; +static rt_sem_t complete_sem = RT_NULL; + +#define EVENT_FLAG (1 << 0) +static void perf_thread_sem1(void *parameter) +{ + rt_err_t ret = RT_EOK; + rt_perf_t *perf = (rt_perf_t *)parameter; + rt_event_send(perf_thread_event, EVENT_FLAG); + while (1) + { + ret = rt_sem_take(perf_thread_sem, RT_WAITING_FOREVER); + rt_perf_stop(perf); + if(ret != RT_EOK) + { + LOG_E("Sem recv error!"); + rt_sem_delete(perf_thread_sem); + return; + } + + if (perf->count >= RT_UTEST_SYS_PERF_TC_COUNT) + { + rt_event_delete(perf_thread_event); + rt_sem_delete(perf_thread_sem); + return; + } + rt_event_send(perf_thread_event, EVENT_FLAG); + } +} + +static void perf_thread_sem2(void *parameter) +{ + rt_err_t ret = RT_EOK; + rt_perf_t *perf = (rt_perf_t *)parameter; + rt_uint32_t recv = 0; + while (1) + { + if (perf->count >= RT_UTEST_SYS_PERF_TC_COUNT) + { + rt_sem_release(complete_sem); + return; + } + ret = rt_event_recv(perf_thread_event, EVENT_FLAG, + (RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR), + RT_WAITING_FOREVER, &recv); + if(ret != RT_EOK) + { + LOG_E("Event reception failed"); + rt_event_delete(perf_thread_event); + rt_sem_release(complete_sem); + return; + } + rt_perf_start(perf); + rt_sem_release(perf_thread_sem); + } +} + +rt_err_t rt_perf_thread_sem(rt_perf_t *perf) +{ + rt_thread_t thread1 = RT_NULL; + rt_thread_t thread2 = RT_NULL; + +# if __STDC_VERSION__ >= 199901L + rt_strcpy(perf->name,__func__); +#else + rt_strcpy(perf->name,"rt_perf_thread_sem"); +#endif + + perf_thread_sem = rt_sem_create("perf_thread_sem", 0, RT_IPC_FLAG_FIFO); + if (perf_thread_sem == RT_NULL) + { + LOG_E("perf_thread_sem create failed."); + return -RT_ERROR; + } + + perf_thread_event = rt_event_create("perf_thread_event", RT_IPC_FLAG_PRIO); + complete_sem = rt_sem_create("complete", 0, RT_IPC_FLAG_FIFO); + + thread1 = rt_thread_create("perf_thread_sem1", perf_thread_sem1, perf, + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + if (thread1 == RT_NULL) + { + LOG_E("perf_thread_sem1 create failed."); + return -RT_ERROR; + } + + thread2 = rt_thread_create("perf_thread_sem2", perf_thread_sem2, perf, + THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); + if (thread2 == RT_NULL) + { + LOG_E("perf_thread_sem2 create failed."); + return -RT_ERROR; + } + + rt_thread_startup(thread1); + rt_thread_startup(thread2); + + rt_sem_take(complete_sem, RT_WAITING_FOREVER); + rt_perf_dump(perf); + rt_sem_delete(complete_sem); + return RT_EOK; +} + -- cgit v1.3.1