diff --git a/CMakeLists.txt b/CMakeLists.txt index 9946420..1d3c6a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,3 +23,4 @@ add_subdirectory(src) add_subdirectory(demo) add_subdirectory(3rdparty) add_subdirectory(test) +add_subdirectory(perf) diff --git a/perf/CMakeLists.txt b/perf/CMakeLists.txt new file mode 100644 index 0000000..b939890 --- /dev/null +++ b/perf/CMakeLists.txt @@ -0,0 +1,22 @@ + +# set the name of project +project(perf) + +# include +include_directories(.) + +# add src +aux_source_directory(. SRCS) + +# generate target +add_executable(${PROJECT_NAME} ${SRCS}) + +# link libary +target_link_libraries( + ${PROJECT_NAME} + unicstl + unity +) + +# install +install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/perf/main.c b/perf/main.c new file mode 100644 index 0000000..f50a286 --- /dev/null +++ b/perf/main.c @@ -0,0 +1,21 @@ +/** + * @file main.c + * @author wenjf (Orig5826@163.com) + * @brief + * @version 0.1 + * @date 2026-05-12 + * + * @copyright Copyright (c) 2026 + * + */ +#include "perf.h" + + +int main(int argc, char *argv[]) +{ + PERF_INIT(); + + perf_deque(); + + return 0; +} diff --git a/perf/perf.c b/perf/perf.c new file mode 100644 index 0000000..07af57e --- /dev/null +++ b/perf/perf.c @@ -0,0 +1,79 @@ +/** + * @file main.c + * @author wenjf (Orig5826@163.com) + * @brief + * @version 0.1 + * @date 2026-05-12 + * + * @copyright Copyright (c) 2026 + * + */ +#include "perf.h" + +#define PERF_FORMAT_HEAD "%-24s %-4s %-6s %-12s\n" +#define PERF_FORMAT_DATA "%-24s T%-3d %-6d %8.3f ms\n" + +void perf_init(void) +{ + printf(PERF_FORMAT_HEAD, "function", " id ", " loop", " time(ms)"); + printf(PERF_FORMAT_HEAD, "--------", "----", "------", "------------"); +} + +void perf_begin(struct _perf_args* args) +{ + timespec_get(&args->start, TIME_UTC); +} + +double calc_elapsed(struct timespec start, struct timespec end) +{ + return (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9; +} + +void perf_end(struct _perf_args* args) +{ + timespec_get(&args->end, TIME_UTC); + + args->elapsed = calc_elapsed(args->start, args->end); + printf(PERF_FORMAT_DATA, args->name, args->id, 1, 1000 * args->elapsed); +} + +void perf_print(struct _perf_args* args) +{ + +} + + + +#if 0 +void perf_run_avg(perf_func_t perf_func, const char *func_name, size_t count) +{ + double time_used = 0; + double time_total = 0; + + for(size_t i = 0; i < count; i++) + { + perf_start(); + perf_func(); + perf_end(); + + time_used = (time_end.tv_sec - time_start.tv_sec) + (time_end.tv_nsec - time_start.tv_nsec) / 1e9; + time_total += time_used; + } + printf(PERF_FORMAT_DATA, func_name, "AVG", 1, 1000 * time_total/count); +} + +void perf_run_loop(perf_func_t perf_func, const char *func_name, size_t loop) +{ + double time_used = 0; + + perf_start(); + for(size_t i = 0; i < loop; i++) + { + perf_func(); + } + perf_end(); + + time_used = (time_end.tv_sec - time_start.tv_sec) + (time_end.tv_nsec - time_start.tv_nsec) / 1e9; + printf(PERF_FORMAT_DATA, func_name, "LOOP", loop, 1000 * time_used); +} +#endif diff --git a/perf/perf.h b/perf/perf.h new file mode 100644 index 0000000..bf11ad0 --- /dev/null +++ b/perf/perf.h @@ -0,0 +1,70 @@ +/** + * @file perf.h + * @author wenjf (Orig5826@163.com) + * @brief + * @version 0.1 + * @date 2026-05-12 + * + * @copyright Copyright (c) 2026 + * + */ +#ifndef _PERF_H_ +#define _PERF_H_ + +#include "unicstl.h" +#include + +typedef void (*perf_func_t)(void); + +struct _perf_args +{ + size_t id; + + const char *name; + struct timespec start; // [C11] + struct timespec end; // [C11] + double elapsed; +}; + +/** + * @brief initialize the performance test + * + */ +#define PERF_INIT() perf_init() + +/** + * @brief run the performance test function + * + */ +#define RUN_PERF(ID, func) do{\ + struct _perf_args args = {\ + .id = ID, \ + .name = #func, \ + .start = {0}, \ + .end = {0}, \ + .elapsed = 0, \ + };\ + perf_begin(&args); \ + (func); \ + perf_end(&args); \ +}while(0) + +#define RUN_PERF_T1(func) RUN_PERF(1, func) +#define RUN_PERF_T2(func) RUN_PERF(2, func) +#define RUN_PERF_T3(func) RUN_PERF(3, func) + +/** + * @brief print the performance test result + * + */ +void perf_init(void); +void perf_begin(struct _perf_args* args); +void perf_end(struct _perf_args* args); + +/** + * @brief perf test items + * + */ +void perf_deque(void); + +#endif // !_PERF_H_ diff --git a/perf/perf_deque.c b/perf/perf_deque.c new file mode 100644 index 0000000..f7d5531 --- /dev/null +++ b/perf/perf_deque.c @@ -0,0 +1,313 @@ +/** + * @file perf_deque.c + * @author wenjf (Orig5826@163.com) + * @brief + * @version 0.1 + * @date 2026-05-12 + * + * @copyright Copyright (c) 2026 + * + */ +#include "perf.h" + +#if 0 +static void demo_deque_num(void) +{ + size_t i = 0; + int data[] = { 1,2,3,4,5,6,7,8,9,10 }; + int temp = 0; + size_t len = sizeof(data) / sizeof(data[0]); + + deque_t deque = deque_new(sizeof(int), len); + deque->print_obj = print_num; + + printf("\n\n----- demo_deque_num -----\n"); + + printf("----- after push_back -----\n"); + for (i = 0; i < len; i++) + { + deque->push_back(deque, &data[i]); + + deque->front(deque, &temp); + printf("front = "); + deque->print_obj(&temp); + + deque->back(deque, &temp); + printf("\tback = "); + deque->print_obj(&temp); + + printf("\tsize = %2d\n", deque->size(deque)); + } + printf("----- print -----\n"); + deque->print(deque); + printf("\n"); + + deque->clear(deque); + if (deque->empty(deque)) + { + printf("----- empty -----\n"); + } + + printf("----- push_back -----\n"); + for (i = 0; i < len; i++) + { + deque->push_back(deque, &data[i]); + } + + printf("----- after pop_back -----\n"); + for (i = 0; i < len + 1; i++) + { + if (true == deque->pop_back(deque, &temp)) + { + printf("pop = "); + deque->print_obj(&temp); + + if (true == deque->front(deque, &temp)) + { + printf("front = "); + deque->print_obj(&temp); + } + + if (deque->back(deque, &temp)) + { + printf("back = "); + deque->print_obj(&temp); + } + + printf("size = %2d\n", deque->size(deque)); + } + else + { + printf("pop failed! because it is empty\n"); + } + + if (deque->empty(deque)) + { + printf("----- empty -----\n"); + } + } + + printf("----- after push_front -----\n"); + for (i = 0; i < len; i++) + { + deque->push_front(deque, &data[i]); + + deque->front(deque, &temp); + printf("front = "); + deque->print_obj(&temp); + + deque->back(deque, &temp); + printf("\tback = "); + deque->print_obj(&temp); + + printf("\tsize = %2d\n", deque->size(deque)); + } + printf("----- print -----\n"); + deque->print(deque); + printf("\n"); + + deque->clear(deque); + if (deque->empty(deque)) + { + printf("----- empty -----\n"); + } + + printf("----- push_front -----\n"); + for (i = 0; i < len; i++) + { + deque->push_front(deque, &data[i]); + } + + for (i = 0; i < len + 1; i++) + { + if (true == deque->pop_front(deque, &temp)) + { + printf("pop = "); + deque->print_obj(&temp); + + if (true == deque->front(deque, &temp)) + { + printf("front = "); + deque->print_obj(&temp); + } + + if (deque->back(deque, &temp)) + { + printf("back = "); + deque->print_obj(&temp); + } + + printf("size = %2d\n", deque->size(deque)); + } + } + +#if 0 + printf("----- push_front -----\n"); + for (i = 0; i < len; i++) + { + deque->push_front(deque, &data[i]); + } + printf("----- print -----\n"); + deque->print(deque); + printf("\n"); + + printf("----- set -----\n"); + temp = 11; + deque->set(deque, 0, &temp); + + temp = 22; + deque->set(deque, len/2, &temp); + + temp = 33; + deque->set(deque, len - 1, &temp); + + printf("----- print -----\n"); + deque->print(deque); + printf("\n"); + + printf("----- get -----\n"); + for (i = 0; i < len; i++) + { + if (true == deque->get(deque, i, &temp)) + { + printf("deque[%2d] = ", i); + deque->print_obj(&temp); + printf("\n"); + } + } +#endif + + deque_free(&deque); +} +#endif + +#define CAPACITY_T1 1024 +#define OBJ_SIZE_T1 256 + +#define CAPACITY_T2 1024 +#define OBJ_SIZE_T2 4096 + +#define CAPACITY_T3 8192 +#define OBJ_SIZE_T3 4096 + +struct _test_obj +{ + void *obj; + size_t obj_size; + size_t capacity; +}test_obj; + +static deque_t deque = NULL; + +void perf_deque_new(void) +{ + deque = deque_new(test_obj.obj_size, test_obj.capacity); +} + +void perf_deque_push_back(void) +{ + for (size_t i = 0; i < test_obj.capacity; i++) + { + deque->push_back(deque, &test_obj.obj); + } +} + +void perf_deque_pop_back(void) +{ + for (size_t i = 0; i < test_obj.capacity; i++) + { + deque->pop_back(deque, &test_obj.obj); + } +} + +void perf_deque_push_front(void) +{ + for (size_t i = 0; i < test_obj.capacity; i++) + { + deque->push_front(deque, &test_obj.obj); + } +} + +void perf_deque_pop_front(void) +{ + for (size_t i = 0; i < test_obj.capacity; i++) + { + deque->pop_front(deque, &test_obj.obj); + } +} + +void perf_deque_free(void) +{ + deque_free(&deque); +} + + +void perf_deque_t1(void) +{ + test_obj.capacity = CAPACITY_T1; + test_obj.obj_size = OBJ_SIZE_T1; + test_obj.obj = malloc(test_obj.capacity); + if(test_obj.obj == NULL) + { + printf( __FUNCTION__, "malloc failed"); + return; + } + + RUN_PERF_T1( perf_deque_new() ); + RUN_PERF_T1( perf_deque_push_back() ); + RUN_PERF_T1( perf_deque_pop_back() ); + RUN_PERF_T1( perf_deque_push_front() ); + RUN_PERF_T1( perf_deque_pop_front() ); + RUN_PERF_T1( perf_deque_free() ); + + free(test_obj.obj); +} + +void perf_deque_t2(void) +{ + test_obj.capacity = CAPACITY_T2; + test_obj.obj_size = OBJ_SIZE_T2; + test_obj.obj = malloc(test_obj.capacity); + if(test_obj.obj == NULL) + { + printf( __FUNCTION__, "malloc failed"); + return; + } + + RUN_PERF_T2( perf_deque_new() ); + RUN_PERF_T2( perf_deque_push_back() ); + RUN_PERF_T2( perf_deque_pop_back() ); + RUN_PERF_T2( perf_deque_push_front() ); + RUN_PERF_T2( perf_deque_pop_front() ); + RUN_PERF_T2( perf_deque_free() ); + + free(test_obj.obj); +} + +void perf_deque_t3(void) +{ + test_obj.capacity = CAPACITY_T3; + test_obj.obj_size = OBJ_SIZE_T3; + test_obj.obj = malloc(test_obj.capacity); + if(test_obj.obj == NULL) + { + printf( __FUNCTION__, "malloc failed"); + return; + } + + RUN_PERF_T3( perf_deque_new() ); + RUN_PERF_T3( perf_deque_push_back() ); + RUN_PERF_T3( perf_deque_pop_back() ); + RUN_PERF_T3( perf_deque_push_front() ); + RUN_PERF_T3( perf_deque_pop_front() ); + RUN_PERF_T3( perf_deque_free() ); + + free(test_obj.obj); +} + +void perf_deque(void) +{ + perf_deque_t1(); + perf_deque_t2(); + perf_deque_t3(); +} diff --git a/run.bat b/run.bat index e15252c..42cc3f8 100644 --- a/run.bat +++ b/run.bat @@ -1 +1,2 @@ -start /b /wait build/release/bin/demo.exe +@REM start /b /wait build/release/bin/demo.exe +start /b /wait build/release/bin/perf.exe