chore(perf): 性能测试新增run_count并用测试ringbuf和segarray的性能,直观看出差异。

This commit is contained in:
建峰 2026-05-21 16:33:58 +08:00
parent 18c67dacb3
commit 97c403b636
14 changed files with 259 additions and 117 deletions

View File

@ -1,71 +0,0 @@
# performance
## 性能对比
### 测试环境
| 测试环境 | 详细信息 |
| --------| -----|
| CPU | Intel(R) Pentium(R) G4560 @ 3.50GHz |
| 内存 | 16GB |
| OS | win10 22H2 |
| gcc | mingw (x86_64-posix-seh-rev0, Built by MinGW-Builds project) 13.2.0 |
### 测试方案
```
T0: capacity = 1024, obj_size = 256
T1: capacity = 4096, obj_size = 256
T2: capacity = 8192, obj_size = 256
T3: capacity = 1024, obj_size = 4096
T4: capacity = 4096, obj_size = 4096
T5: capacity = 8192, obj_size = 4096
```
### 测试对比
> 这里是总时间,对比意义不大。而且目前都未使用扩容
1. 链表实现的栈和队列
```bash
function T0 (ms) T1 (ms) T2 (ms) T3 (ms) T4 (ms) T5 (ms)
-------------------- --------- --------- --------- --------- --------- ---------
perf_deque_new() 0.013 0.011 0.008 0.008 0.013 0.014
perf_deque_push_back() 0.161 0.520 1.011 0.626 2.934 7.444
perf_deque_pop_back() 0.032 0.172 0.329 0.236 1.478 2.728
perf_deque_push_front() 0.038 0.162 0.369 0.175 1.019 2.050
perf_deque_pop_front() 0.037 0.146 0.305 0.220 2.061 2.628
perf_deque_free() 0.001 0.092 0.187 0.357 1.287 2.694
perf_stack_new() 0.002 0.001 0.002 0.001 0.001 0.001
perf_stack_push() 0.271 1.003 1.941 1.967 8.882 16.369
perf_stack_pop() 0.164 1.183 1.893 0.965 3.717 8.114
perf_stack_free() 0.000 0.001 0.001 0.002 0.001 0.001
perf_queue_new() 0.018 0.000 0.000 0.000 0.001 0.002
perf_queue_push() 0.258 1.020 1.947 1.537 7.774 15.220
perf_queue_pop() 0.162 0.613 1.050 0.811 3.590 7.070
perf_queue_free() 0.000 0.000 0.000 0.001 0.001 0.001
```
2. 动态数组实现的栈和队列(这里还不涉及到扩容)
```bash
function T0 (ms) T1 (ms) T2 (ms) T3 (ms) T4 (ms) T5 (ms)
-------------------- --------- --------- --------- --------- --------- ---------
perf_deque_new() 0.011 0.018 0.015 0.033 0.017 0.017
perf_deque_push_back() 0.187 0.650 1.216 1.692 2.852 6.202
perf_deque_pop_back() 0.052 0.219 0.468 0.685 1.332 2.295
perf_deque_push_front() 0.058 0.262 0.536 0.290 1.155 1.845
perf_deque_pop_front() 0.055 0.239 0.438 0.427 1.398 2.398
perf_deque_free() 0.002 0.151 0.286 0.361 2.695 3.049
perf_stack_new() 0.224 0.013 0.013 0.010 0.014 0.014
perf_stack_push() 0.036 0.388 0.745 0.801 2.890 6.183
perf_stack_pop() 0.035 0.244 0.318 0.236 1.109 3.167
perf_stack_free() 0.002 0.113 0.177 0.408 1.272 2.578
perf_queue_new() 0.010 0.012 0.007 0.008 0.012 0.014
perf_queue_push() 0.148 0.377 0.701 0.737 2.955 6.273
perf_queue_pop() 0.030 0.149 0.271 0.230 1.173 2.338
perf_queue_free() 0.001 0.094 0.154 0.350 1.273 2.556
```

46
doc/perf.md Normal file
View File

@ -0,0 +1,46 @@
# performance
## 性能对比
### 测试环境
| 测试环境 | 详细信息 |
| --------| -----|
| CPU | Intel(R) Pentium(R) G4560 @ 3.50GHz |
| 内存 | 16GB |
| OS | win10 22H2 |
| gcc | mingw (x86_64-posix-seh-rev0, Built by MinGW-Builds project) 13.2.0 |
### 测试结果
1. ringbuf和segarray的性能对比
```
T0: obj_size=256, capacity=1024, run_count=1024
T1: obj_size=256, capacity=8192, run_count=8192
T2: obj_size=4096, capacity=1024, run_count=1024
T3: obj_size=4096, capacity=8192, run_count=8192
T4: obj_size=256, capacity=1024, run_count=100000
T5: obj_size=256, capacity=8192, run_count=100000
T6: obj_size=4096, capacity=1024, run_count=100000
T7: obj_size=4096, capacity=8192, run_count=100000
function T0 (us) T1 (us) T2 (us) T3 (us) T4 (us) T5 (us) T6 (us) T7 (us)
-------------------- --------- --------- --------- --------- --------- --------- --------- ---------
perf_segarray_new() 0.008 0.000 0.000 0.000 0.000 0.000 0.000 0.000
perf_segarray_push_back() 0.215 0.316 0.658 1.038 0.182 0.158 0.795 0.978
perf_segarray_pop_back() 0.058 0.060 0.231 0.497 0.054 0.056 0.328 0.327
perf_segarray_free() 0.037 0.026 0.332 0.335 0.022 0.024 0.337 0.308
perf_segarray_new() 0.001 0.000 0.001 0.000 0.000 0.000 0.000 0.000
perf_segarray_push_front() 0.180 0.148 1.569 1.952 0.172 0.147 1.685 1.942
perf_segarray_pop_front() 0.051 0.060 0.242 0.342 0.062 0.061 0.348 0.368
perf_segarray_free() 0.034 0.023 0.325 0.342 0.026 0.021 0.369 0.306
perf_ringbuf_new() 0.006 0.002 0.019 0.003 0.000 0.000 0.000 0.000
perf_ringbuf_push_back() 0.153 0.096 0.983 0.866 0.854 1.060 13.849 14.344
perf_ringbuf_pop_back() 0.030 0.037 0.273 0.275 0.049 0.054 0.344 0.317
perf_ringbuf_free() 0.032 0.018 0.393 0.371 0.019 0.026 0.340 0.307
perf_ringbuf_new() 0.006 0.001 0.022 0.003 0.000 0.000 0.000 0.000
perf_ringbuf_push_front() 0.138 0.135 2.114 1.941 0.990 1.252 14.603 13.887
perf_ringbuf_pop_front() 0.039 0.065 0.292 0.365 0.045 0.044 0.516 0.309
perf_ringbuf_free() 0.000 0.024 0.407 0.408 0.025 0.023 0.605 0.301
```

View File

@ -16,7 +16,7 @@
#include "segarray.h"
// 0.rinfbuf 1.segarray
#define DEQUE_DEFAULT_SELECT 1
#define DEQUE_DEFAULT_SELECT 0
#if DEQUE_DEFAULT_SELECT == 1
#define DEQUE_RINGBUF 0

View File

@ -74,7 +74,7 @@
* LOG_ERROR
* LOG_NONE
*/
#define LOG_LEVEL LOG_DEBUG
#define LOG_LEVEL LOG_NONE
/**
* @brief

View File

@ -1,24 +1,29 @@
/**
* @file main.c
* @author wenjf (Orig5826@163.com)
* @brief
* @brief
* @version 0.1
* @date 2026-05-12
*
*
* @copyright Copyright (c) 2026
*
*
*/
#include "perf.h"
#include "perf_log.h"
// clang-format off
test_obj_t test_plans[PERF_TEST_TIEMS] = {
{.capacity = 1024, .obj_size = 256}, // 1. 小对象 + 少量数据
{.capacity = 4096, .obj_size = 256}, // 2. 小对象 + 中等数据
{.capacity = 8192, .obj_size = 256}, // 3. 小对象 + 大量数据
{.capacity = 1024, .obj_size = 4096}, // 4. 大对象 + 少量数据
{.capacity = 4096, .obj_size = 4096}, // 5. 大对象 + 中等数据
{.capacity = 8192, .obj_size = 4096} // 6. 大对象 + 大量数据
{.obj_size = 256, .capacity = 1024, .run_count = 1024, }, // 1. 小对象 + 少量数据
{.obj_size = 256, .capacity = 8192, .run_count = 8192, }, // 2. 小对象 + 大量数据
{.obj_size = 4096, .capacity = 1024, .run_count = 1024, }, // 3. 大对象 + 少量数据
{.obj_size = 4096, .capacity = 8192, .run_count = 8192, }, // 4. 大对象 + 大量数据
{.obj_size = 256, .capacity = 1024, .run_count = 100000, }, // 1. 小对象 + 少量数据 + 扩容
{.obj_size = 256, .capacity = 8192, .run_count = 100000, }, // 2. 小对象 + 大量数据 + 扩容
{.obj_size = 4096, .capacity = 1024, .run_count = 100000, }, // 3. 大对象 + 少量数据 + 扩容
{.obj_size = 4096, .capacity = 8192, .run_count = 100000, }, // 4. 大对象 + 大量数据 + 扩容
};
// clang-format on
test_obj_t g_test_obj;
@ -37,17 +42,19 @@ void perf_deinit(void)
perf_log_free();
}
void perf_begin(struct _perf_args* args)
void perf_begin(struct _perf_args *args)
{
timespec_get(&args->start, TIME_UTC);
}
void perf_end(struct _perf_args* args)
void perf_end(struct _perf_args *args)
{
timespec_get(&args->end, TIME_UTC);
args->elapsed = calc_elapsed(args->start, args->end);
perf_log_append(args->name, args->id, args->elapsed * 1000);
// printf("run_count = %zu, elapsed = %.3f ms\n", args->run_count, args->elapsed * 1000);
// perf_log_append(args->name, args->id, args->elapsed * 1000);
perf_log_append(args->name, args->id, args->elapsed * 1000*1000 / args->run_count);
}
void perf_run_start(size_t id)
@ -56,9 +63,10 @@ void perf_run_start(size_t id)
g_test_obj.capacity = test_plans[id].capacity;
g_test_obj.obj_size = test_plans[id].obj_size;
g_test_obj.run_count = test_plans[id].run_count;
g_test_obj.obj = unicstl_malloc(g_test_obj.capacity);
if(g_test_obj.obj == NULL)
if (g_test_obj.obj == NULL)
{
log_debug("unicstl_malloc failed");
return;
@ -72,9 +80,10 @@ void perf_run_end(size_t id)
void perf_print(void)
{
for(size_t i = 0; i < PERF_TEST_TIEMS; i++)
for (size_t i = 0; i < PERF_TEST_TIEMS; i++)
{
printf("T%d: capacity = %zu, obj_size = %zu\n", i, test_plans[i].capacity, test_plans[i].obj_size);
printf("T%d: obj_size=%zu, capacity=%zu, run_count=%zu\n", i,
test_plans[i].obj_size, test_plans[i].capacity, test_plans[i].run_count);
}
printf("\n");
perf_log_print();
@ -85,9 +94,12 @@ int main(int argc, char *argv[])
{
perf_init();
perf_test_deque();
perf_test_stack();
perf_test_queue();
perf_test_segarray();
perf_test_ringbuf();
// perf_test_deque();
// perf_test_stack();
// perf_test_queue();
perf_print();
perf_deinit();

View File

@ -24,8 +24,17 @@ struct _perf_args
struct timespec start; // [C11]
struct timespec end; // [C11]
double elapsed;
size_t run_count;
};
typedef struct _test_obj
{
void *obj;
size_t obj_size;
size_t capacity;
size_t run_count;
}test_obj_t;
/**
* @brief run the performance test function
*
@ -37,6 +46,7 @@ struct _perf_args
.start = {0}, \
.end = {0}, \
.elapsed = 0, \
.run_count = g_test_obj.run_count,\
};\
perf_begin(&args); \
(func); \
@ -49,16 +59,7 @@ struct _perf_args
perf_run_end(ID); \
}while(0)
typedef struct _test_obj
{
void *obj;
size_t obj_size;
size_t capacity;
}test_obj_t;
#define PERF_TEST_TIEMS 6
#define PERF_TEST_TIEMS 8
extern test_obj_t g_test_obj;
/**
@ -80,6 +81,9 @@ void perf_print(void);
* @brief perf test items
*
*/
void perf_test_segarray(void);
void perf_test_ringbuf(void);
void perf_test_deque(void);
void perf_test_stack(void);
void perf_test_queue(void);

View File

@ -19,7 +19,7 @@ void perf_deque_new(void)
void perf_deque_push_back(void)
{
for (size_t i = 0; i < g_test_obj.capacity; i++)
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
deque->push_back(deque, &g_test_obj.obj);
}
@ -27,7 +27,7 @@ void perf_deque_push_back(void)
void perf_deque_pop_back(void)
{
for (size_t i = 0; i < g_test_obj.capacity; i++)
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
deque->pop_back(deque, &g_test_obj.obj);
}
@ -35,7 +35,7 @@ void perf_deque_pop_back(void)
void perf_deque_push_front(void)
{
for (size_t i = 0; i < g_test_obj.capacity; i++)
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
deque->push_front(deque, &g_test_obj.obj);
}
@ -43,7 +43,7 @@ void perf_deque_push_front(void)
void perf_deque_pop_front(void)
{
for (size_t i = 0; i < g_test_obj.capacity; i++)
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
deque->pop_front(deque, &g_test_obj.obj);
}
@ -59,6 +59,9 @@ void perf_deque(size_t id)
RUN_PERF(id, perf_deque_new());
RUN_PERF(id, perf_deque_push_back() );
RUN_PERF(id, perf_deque_pop_back() );
RUN_PERF(id, perf_deque_free() );
RUN_PERF(id, perf_deque_new());
RUN_PERF(id, perf_deque_push_front() );
RUN_PERF(id, perf_deque_pop_front() );
RUN_PERF(id, perf_deque_free() );

View File

@ -123,7 +123,7 @@ static void perf_log_print_header(void)
printf(PERF_FORMAT_FUNC, " function ");
for(size_t i = 0; i < count; ++i)
{
printf(" T%-2d(ms)", i);
printf(" T%-2d(us)", i);
}
printf("\n");

View File

@ -19,7 +19,7 @@ void perf_queue_new(void)
void perf_queue_push(void)
{
for (size_t i = 0; i < g_test_obj.capacity; i++)
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
queue->push(queue, &g_test_obj.obj);
}
@ -27,7 +27,7 @@ void perf_queue_push(void)
void perf_queue_pop(void)
{
for (size_t i = 0; i < g_test_obj.capacity; i++)
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
queue->pop(queue, &g_test_obj.obj);
}

76
perf/perf_ringbuf.c Normal file
View File

@ -0,0 +1,76 @@
/**
* @file perf_ringbuf.c
* @author wenjf (orig5826@163.com)
* @brief
* @version 0.1
* @date 2026-05-21
*
* @copyright Copyright (c) 2026
*
*/
#include "perf.h"
static ringbuf_t ringbuf = NULL;
void perf_ringbuf_new(void)
{
ringbuf = ringbuf_new(g_test_obj.obj_size, g_test_obj.capacity);
}
void perf_ringbuf_push_back(void)
{
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
ringbuf->push_back(ringbuf, &g_test_obj.obj);
}
}
void perf_ringbuf_pop_back(void)
{
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
ringbuf->pop_back(ringbuf, &g_test_obj.obj);
}
}
void perf_ringbuf_push_front(void)
{
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
ringbuf->push_front(ringbuf, &g_test_obj.obj);
}
}
void perf_ringbuf_pop_front(void)
{
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
ringbuf->pop_front(ringbuf, &g_test_obj.obj);
}
}
void perf_ringbuf_free(void)
{
ringbuf_free(&ringbuf);
}
void perf_ringbuf(size_t id)
{
RUN_PERF(id, perf_ringbuf_new());
RUN_PERF(id, perf_ringbuf_push_back() );
RUN_PERF(id, perf_ringbuf_pop_back() );
RUN_PERF(id, perf_ringbuf_free() );
RUN_PERF(id, perf_ringbuf_new());
RUN_PERF(id, perf_ringbuf_push_front() );
RUN_PERF(id, perf_ringbuf_pop_front() );
RUN_PERF(id, perf_ringbuf_free() );
}
void perf_test_ringbuf(void)
{
for(size_t i = 0; i < PERF_TEST_TIEMS; i++)
{
PERF_ADD(i, perf_ringbuf);
}
}

76
perf/perf_segarray.c Normal file
View File

@ -0,0 +1,76 @@
/**
* @file perf_segarray.c
* @author wenjf (orig5826@163.com)
* @brief
* @version 0.1
* @date 2026-05-21
*
* @copyright Copyright (c) 2026
*
*/
#include "perf.h"
static segarray_t segarray = NULL;
void perf_segarray_new(void)
{
segarray = segarray_new(g_test_obj.obj_size, g_test_obj.capacity);
}
void perf_segarray_push_back(void)
{
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
segarray->push_back(segarray, &g_test_obj.obj);
}
}
void perf_segarray_pop_back(void)
{
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
segarray->pop_back(segarray, &g_test_obj.obj);
}
}
void perf_segarray_push_front(void)
{
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
segarray->push_front(segarray, &g_test_obj.obj);
}
}
void perf_segarray_pop_front(void)
{
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
segarray->pop_front(segarray, &g_test_obj.obj);
}
}
void perf_segarray_free(void)
{
segarray_free(&segarray);
}
void perf_segarray(size_t id)
{
RUN_PERF(id, perf_segarray_new());
RUN_PERF(id, perf_segarray_push_back() );
RUN_PERF(id, perf_segarray_pop_back() );
RUN_PERF(id, perf_segarray_free() );
RUN_PERF(id, perf_segarray_new());
RUN_PERF(id, perf_segarray_push_front() );
RUN_PERF(id, perf_segarray_pop_front() );
RUN_PERF(id, perf_segarray_free() );
}
void perf_test_segarray(void)
{
for(size_t i = 0; i < PERF_TEST_TIEMS; i++)
{
PERF_ADD(i, perf_segarray);
}
}

View File

@ -19,7 +19,7 @@ void perf_stack_new(void)
void perf_stack_push(void)
{
for (size_t i = 0; i < g_test_obj.capacity; i++)
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
stack->push(stack, &g_test_obj.obj);
}
@ -27,7 +27,7 @@ void perf_stack_push(void)
void perf_stack_pop(void)
{
for (size_t i = 0; i < g_test_obj.capacity; i++)
for (size_t i = 0; i < g_test_obj.run_count; i++)
{
stack->pop(stack, &g_test_obj.obj);
}

View File

@ -1,2 +1,2 @@
start /b /wait build/release/bin/demo.exe
@REM start /b /wait build/release/bin/perf.exe
@REM start /b /wait build/release/bin/demo.exe
start /b /wait build/release/bin/perf.exe

View File

@ -60,8 +60,6 @@ static void heap_fixed_up(struct _heap* self, size_t i)
}
obj_swap(base, i, p, obj_size);
i = p;
self->print(self);
}
}
else /* if(self->_type == HEAP_MIN) */
@ -78,8 +76,6 @@ static void heap_fixed_up(struct _heap* self, size_t i)
}
obj_swap(base, i, p, obj_size);
i = p;
self->print(self);
}
}
}
@ -170,7 +166,7 @@ static bool heap_pop(struct _heap* self, void* obj)
return true;
}
static size_t heap_reserve(struct _heap* self, size_t capacity)
static bool heap_reserve(struct _heap* self, size_t capacity)
{
unicstl_assert(self != NULL);
unicstl_assert(self->_darray != NULL);