summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author刘煜 <[email protected]>2024-06-18 08:40:56 +0000
committer刘煜 <[email protected]>2024-06-18 08:40:56 +0000
commitbfe41598d3f28e20360d79a8412f13c9da84b652 (patch)
tree72e4b9b63ea0032de78040d34a90340b569c8ee1
parente17067871a24932eb0473af9d3fb2682191c0516 (diff)
编码风格、测试用例完善
-rw-r--r--CMakeLists.txt2
-rw-r--r--bbq/CMakeLists.txt13
-rw-r--r--bbq/include/bbq.h322
-rw-r--r--bbq/src/bbq.c840
-rw-r--r--bbq/test.c54
-rw-r--r--bbq/tests/common/test_mix.c68
-rw-r--r--bbq/tests/common/test_mix.h87
-rw-r--r--bbq/tests/common/test_queue.c153
-rw-r--r--bbq/tests/common/test_queue.h18
-rw-r--r--bbq/tests/unittest/ut.h4
-rw-r--r--bbq/tests/unittest/ut_example.cc451
-rw-r--r--bbq/tests/unittest/ut_head_cursor.cc121
-rw-r--r--bbq/tests/unittest/ut_mix.cc60
-rw-r--r--bbq/tests/unittest/ut_multit.cc (renamed from bbq/tests/unittest/ut_data.cc)48
-rw-r--r--perf/CMakeLists.txt14
-rw-r--r--perf/benchmark/bcm_benchmark.c56
-rw-r--r--perf/benchmark/bcm_loadconfig.c34
-rw-r--r--perf/benchmark/bcm_queue.c8
-rwxr-xr-xperf/benchmark/benchmark.sh20
-rw-r--r--perf/benchmark/config/compare/case1_simple_spsc.ini (renamed from perf/benchmark/config/compare/general/case1_simple_spsc.ini)0
-rw-r--r--perf/benchmark/config/compare/case2_simple_spmc.ini (renamed from perf/benchmark/config/compare/general/case2_simple_spmc.ini)0
-rw-r--r--perf/benchmark/config/compare/case3_simple_mpsc.ini (renamed from perf/benchmark/config/compare/general/case3_simple_mpsc.ini)0
-rw-r--r--perf/benchmark/config/compare/case4_complex_spmc.ini (renamed from perf/benchmark/config/compare/general/case4_complex_spmc.ini)0
-rw-r--r--perf/benchmark/config/compare/case5_complex_mpsc.ini (renamed from perf/benchmark/config/compare/general/case5_complex_mpsc.ini)0
-rw-r--r--perf/benchmark/config/compare/case6_simple_mp0c.ini (renamed from perf/benchmark/config/compare/general/case6_simple_mp0c.ini)0
-rw-r--r--perf/benchmark/config/compare/case7_simple_0pmc.ini (renamed from perf/benchmark/config/compare/general/case7_simple_0pmc.ini)0
-rw-r--r--perf/benchmark/config/compare/case8_simple_mpmc.ini (renamed from perf/benchmark/config/compare/general/case8_simple_mpmc.ini)0
-rw-r--r--perf/benchmark/config/compare/case9_simple_mpmc_overcore.ini (renamed from perf/benchmark/config/compare/general/case9_simple_mpmc_overcore.ini)0
-rw-r--r--perf/benchmark/config/compare/perf/perf_case1_simple_spsc.ini14
-rw-r--r--perf/benchmark/config/compare/perf/perf_case2_simple_mpmc.ini14
-rw-r--r--perf/benchmark/config/compare/perf/perf_case3_simple_spmp.ini14
-rw-r--r--perf/benchmark/config/compare/perf/perf_case4_simple_mpsc.ini14
32 files changed, 1404 insertions, 1025 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 142785d..b185713 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,8 @@
cmake_minimum_required(VERSION 3.0)
project(BBQ_TOP)
+SET(OUTPUT_DIR ${PROJECT_SOURCE_DIR}/build/output)
+
# 添加子目录
add_subdirectory(bbq) # bbq库
add_subdirectory(perf)# perf目录用于各类消息队列的性能测试,需要依赖dpdk等环境 \ No newline at end of file
diff --git a/bbq/CMakeLists.txt b/bbq/CMakeLists.txt
index 1714295..77020a8 100644
--- a/bbq/CMakeLists.txt
+++ b/bbq/CMakeLists.txt
@@ -7,7 +7,18 @@ include_directories(
)
# 设置输出目录
-SET(OUTPUT_DIR ${PROJECT_SOURCE_DIR}/build/output)
+if(NOT DEFINED OUTPUT_DIR)
+ # 如果没有被设置,则设置一个默认值
+ SET(OUTPUT_DIR ${PROJECT_SOURCE_DIR}/build/output)
+endif()
+
+# 设置编译类型,默认Release
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
+endif()
+
+add_compile_options(-Wall -Wextra)
+
# 库生成的路径
set(LIB_PATH ${OUTPUT_DIR}/lib)
# 测试程序生成的路径
diff --git a/bbq/include/bbq.h b/bbq/include/bbq.h
index 7877cce..0b7921c 100644
--- a/bbq/include/bbq.h
+++ b/bbq/include/bbq.h
@@ -1,6 +1,6 @@
/*
* @Author: [email protected]
- * @LastEditTime: 2024-06-14 09:27:35
+ * @LastEditTime: 2024-06-18 14:16:54
* @Describe: bbq(Block-based Bounded Queue)头文件
* 参考:https://www.usenix.org/system/files/atc22-wang-jiawei.pdf
*/
@@ -12,9 +12,6 @@
#include <stdint.h>
#include <stdlib.h>
-// #define BBQ_MEMORY
-// #define BBQ_DEBUG
-
#ifndef __cplusplus
// C
#include <stdatomic.h>
@@ -30,168 +27,188 @@ using aotmic_uint64 = std::atomic<uint64_t>;
#define __BBQ_CACHE_ALIGNED __attribute__((__aligned__(64)))
-typedef struct {
+struct bbq_block_s {
bbq_cursor committed; // 已提交(version|offset)
bbq_cursor allocated; // 已分配(version|offset)
bbq_cursor reserved; // 已预留(version|offset)
- bbq_cursor consumed; // 已消费(version|offset), 在drop-old模式下没用
- char *entries;
-} __BBQ_CACHE_ALIGNED bbq_block_s;
-
-typedef enum {
- BBQ_SUCCESS = 0,
- BBQ_BLOCK_DONE, // 当前块已的entry已用完,需要移动到下一个块
- BBQ_NO_ENTRY, // 没有条目可以使用
- BBQ_NOT_AVAILABLE, // 当前块不可以用状态(将返回busy)
- BBQ_ALLOCATED, // 已分配,返回entry信息
- BBQ_RESERVED, // 已保留,返回entry信息
-} bbq_queue_state_e;
-
-typedef struct {
- uint64_t off; // entry在当前block的偏移(offset)
- uint64_t vsn; // allocated游标的版本(vsn)
- uint32_t actual_burst; // 实际出入队个数
- bbq_block_s *block; // 指向所在的block
-} bbq_entry_desc_s;
-
-typedef struct {
- bbq_queue_state_e state; // 队列状态
- union {
- uint64_t vsn; // reserve_entry state==BLOCK_DONE时生效
- bbq_entry_desc_s e; // state为ALLOCATED、RESERVED生效
- };
-} bbq_queue_state_s;
-
-#define BBQ_F_DEFAULT 0x0
-// flags 第一位控制入队策略,默认是retry new
-#define BBQ_F_POLICY_DROP_OLD 0x0001
-#define BBQ_F_POLICY_RETRY_NEW BBQ_F_DEFAULT
-#define BBQ_POLIC_DROP_OLD(flags) (flags & BBQ_F_POLICY_DROP_OLD)
-#define BBQ_POLIC_RETRY_NEW(flags) (!(flags & BBQ_F_POLICY_DROP_OLD))
-
-// flags 第二位控制入队时的数据拷贝策略,默认是copy pointer
-#define BBQ_F_COPY_VALUE 0x0002
-#define BBQ_F_COPY_POINTER BBQ_F_DEFAULT
-#define BBQ_COPY_VALUE(flags) (flags & BBQ_F_COPY_VALUE)
-#define BBQ_COPY_POINTER(flags) (!(flags & BBQ_F_COPY_VALUE))
-
-typedef struct {
- size_t bs; // 每个block里entries成员的大小
- size_t bn; // blocks个数
- size_t obj_size;
- size_t entry_size;
-
- int32_t socket_id; // 在哪个socket_id上使用libnuma分配内存,-1表示无效,使用malloc分配
- uint32_t flags;
- uint32_t idx_bits;
- uint32_t off_bits;
-
- uint64_t idx_mask;
- uint64_t off_mask;
- bbq_head phead; // 生产者头,指向块的索引(version|idx)
- bbq_head chead; // 消费者头,指向块的索引(version|idx)
-
- bbq_block_s *blocks; // bn大小的动态数组
-} bbq_queue_s;
-
-// -----------------------------对外接口-------------------------------
+ bbq_cursor consumed; // 已消费(version|offset)注:在drop-old模式下没用到
+ char *entries; // 存储大小可变的entry,分配空间大小:bs * entry_size
+} __BBQ_CACHE_ALIGNED;
+
+struct bbq_s {
+ size_t bs; // 每个block里entries成员的大小
+ size_t bn; // 块(blocks)的个数
+ size_t obj_size; // 入队数据的实际大小,int int* int**,都为sizeof(int)
+ size_t entry_size; // blocks.entries里每个entry的大小
+
+ int32_t socket_id; // 在哪个socket_id上使用libnuma分配内存,小于0将使用malloc分配
+ uint32_t flags; // 标记:retry new 模式,还是drop old模式
+ uint32_t idx_bits; // bbq_head里idx所占的位数
+ uint32_t off_bits; // bbq_cursor里offset所占的位数
+
+ uint64_t idx_mask; // idx_bits偏移后的掩码
+ uint64_t off_mask; // off_bits偏移后的掩码
+ bbq_head phead; // 生产者头,指向块的索引,分为两部分:version|idx
+ bbq_head chead; // 消费者头,指向块的索引,分为两部分:version|idx
+
+ struct bbq_block_s *blocks; // bn大小的数组
+};
+
+// 创建队列时flags可选参数
+// 第一位控制入队策略,默认是retry new
+#define BBQ_CREATE_F_DROP_OLD 0x0001 /**< 创建队列时设置为drop old模式(队列满时,覆盖旧数据,入队成功) */
+#define BBQ_CREATE_F_RETRY_NEW 0x0 /**< 默认为retry new模式(队列满时,当前入队失败) */
+
+// 第二位控制入队时的数据拷贝策略,默认是copy pointer
+#define BBQ_CREATE_F_COPY_VALUE 0x0002 /**< 创建队列时设置为拷贝数值 */
+#define BBQ_CREATE_F_COPY_PTR 0x0 /**< 默认为拷贝指针 */
+
/**
- * bbq_ring_create系列接口,用于创建并返回bbq队列结构体,功能类似,区别在于是否需要
- * 指定socket,是否手动手动指定块个数(bn),块的大小(bs),即每个块包含的条目数。
- * @param count
- * 队列所有条目的个数(总容量),必须大于1,且是2的N次方。将根据公式自动计算块的个数,以及块的大小。
- * 计算公式:log2(blocks) = max(1, ⌊log2(count)/4⌋) 注:⌊ ⌋代表向下取整。
- * @param flags
- * 第一位控制入队策略,默认是retry new模式,即队列满了当前入队失败。如果要设置为drop old模式,需要flags|BBQ_F_DROP_OLD
- * 第二位控制入队列时,传入的时候指针,还是指针指向的值。默认传入指针,如果要传入指向的值,需要设置flags|BBQ_F_COPY_VALUE
- * @param obj_size
- * 队列里每个成员的存储大小,如存储int类型数据:sizeof(int)
- * @param socket_id
- * socket ID,多numa架构下,队列里的空间将针对指定socket调用libnuma库函数分配内存。
- * 当检测到不支持多numa,将转为malloc分配内存。
+ * 创建并返回bbq队列结构指针
+ *
+ * @param[in] count
+ * 队列所有entry的个数(所有块下entry个数的总和),count必须大于1,且是2的N次方。
+ * 函数将会根据count自动计算出合理的块个数,并将entry平均分配到每个块里。
+ * 计算公式:log2(blocks) = max(1, ⌊log2(count)/4⌋) 注:⌊ ⌋代表向下取整。
+ * @param[in] obj_size
+ * 入队数据的实际大小,int int* int**,都为sizeof(int),因为在burst的时候会传入数组,
+ * 需要根据数据大小来计算偏移,请正确设置该值。
+ * @param[in] flags
+ * 设置入队策略,通过BBQ_CREATE_F_XX系列宏定义设置flags
+ * 1)第一位控制入队策略,默认是retry new模式(队列满了当前入队失败)。
+ * 如果要设置为drop old模式,需要flags|BBQ_CREATE_F_DROP_OLD
+ * 2)第二位控制数据入队列时,将"指针"入队,还是将"指针指向的数据"入队。默认入队"指针",
+ * 如果把"指针指向的数据"入队,需要设置flags|BBQ_CREATE_F_COPY_VALUE
+ * 3)可以同时设置多个flag,入BBQ_CREATE_F_DROP_OLD|BBQ_CREATE_F_COPY_VALUE
* @return
- * 非NULL:消息队列结构体指针,用于后续出队入队等操作。
+ * 非NULL:消息队列结构体指针,用于后续出队、入队等操作。
* NULL:创建失败。
*/
-extern bbq_queue_s *bbq_ring_create(uint32_t count, size_t obj_size, unsigned int flags);
-extern bbq_queue_s *bbq_ring_create_with_socket(uint32_t count, size_t obj_size, int socket_id, unsigned int flags);
-extern bbq_queue_s *bbq_ring_create_bnbs(uint32_t bn, uint32_t bs, size_t obj_size, unsigned int flags);
-extern bbq_queue_s *bbq_ring_create_bnbs_with_socket(uint32_t bn, uint32_t bs, size_t obj_size, int socket_id, unsigned int flags);
+extern struct bbq_s *bbq_create(uint32_t count, size_t obj_size, uint32_t flags);
/**
- * 用于释放消息队列,与bbq_ring_create系列函数成对。
- * @param q
- * 队列指针
+ * 创建并返回bbq队列结构指针,支持多numa
+ *
+ * @param[in] count
+ * 队列所有entry的个数(所有块下entry个数的总和),count必须大于1,且是2的N次方。
+ * 函数将会根据count自动计算出合理的块个数,并将entry平均分配到每个块里。
+ * 计算公式:log2(blocks) = max(1, ⌊log2(count)/4⌋) 注:⌊ ⌋代表向下取整。
+ * @param[in] flags
+ * 设置入队策略,通过BBQ_CREATE_F_XX系列宏定义设置flags
+ * 1)第一位控制入队策略,默认是retry new模式(队列满了当前入队失败)。
+ * 如果要设置为drop old模式,需要flags|BBQ_CREATE_F_DROP_OLD
+ * 2)第二位控制数据入队列时,将"指针"入队,还是将"指针指向的数据"入队。默认入队"指针",
+ * 如果把"指针指向的数据"入队,需要设置flags|BBQ_CREATE_F_COPY_VALUE
+ * 3)可以同时设置多个flag,入BBQ_CREATE_F_DROP_OLD|BBQ_CREATE_F_COPY_VALUE
+ * @param[in] obj_size
+ * 入队数据的实际大小,int int* int**,都为sizeof(int),因为在burst的时候会传入数组,
+ * 需要根据数据大小来计算偏移,请正确设置该值。
+ * @param[in] socket_id
+ * 多numa架构下,队列里的空间将针对指定socket调用libnuma库函数分配内存。
+ * 当检测到不支持多numa,将转为malloc分配内存。
+ * @return
+ * 非NULL:消息队列结构体指针,用于后续出队入队等操作。
+ * NULL:创建失败。
*/
-extern void bbq_ring_free(bbq_queue_s *q);
+extern struct bbq_s *bbq_create_with_socket(uint32_t count, size_t obj_size, int socket_id, uint32_t flags);
/**
- * 消息队列入队
- * @param q
- * 队列指针
- * @param data
- * void *类型,指针也要取地址后传入。例如int a 或 int *a 都传入 (void *)(&a)
+ * 用于释放消息队列,与bbq_create/bbq_create_with_socket函数成对。
+ *
+ * @param[in] q
+ * 队列指针
+ */
+extern void bbq_ring_free(struct bbq_s *q);
+
+/**
+ * 消息队列单个数据入队
+ *
+ * @param[in] q
+ * 队列指针
+ * @param[in] data
+ * 创建队列时:
+ * 1)如果flag设置了BBQ_CREATE_F_COPY_VALUE,则传入一维指针,如 int data,如:
+ * int data,传入&data
+ * int *data = malloc(sizeof(int));*data = 1; 传入data
+ * 2)如果flag设置了BBQ_CREATE_F_COPY_PTR,则传入二维指针,如 int *data,如:
+ * int *data = malloc(sizeof(int));*data = 1; 传入&data
* @return
- * BBQ_OK 0 :成功
- * BBQ_QUEUE_FULL -1001 : 失败,队列已满
- * BBQ_QUEUE_BUSY -1002 : 失败,队列忙碌中
- * BBQ_ERROR -1 :未知错误
- * BBQ_NULL_PTR -3 :传入空指针
+ * 成功返回0,失败返回小于0的错误码。
*/
-extern int bbq_enqueue(bbq_queue_s *q, void *data);
+extern int bbq_enqueue(struct bbq_s *q, void *data);
/**
- * 消息队列出队
- * @param q
+ * 消息队列批量入队(指针入队),尽可能一次入队n个数据,返回实际成功入队个数
+ *
+ * @param[in] q
+ * 队列指针
+ * @param[in] obj_table
+ * 即将入队的指针数组,将数组里的每个成员(指针)入队
+ * @param[in] n
+ * 尝试一次入队的个数
+ * @return
+ * 返回实际成功入队个数
+ */
+extern uint32_t bbq_enqueue_burst_ptr(struct bbq_s *q, void *const *obj_table, uint32_t n);
+
+/**
+ * 消息队列批量入队(数据入队),尽可能一次入队n个数据,返回实际成功入队个数
+ *
+ * @param[in] q
+ * 队列指针
+ * @param[in] obj_table
+ * 即将入队的数组,将数组里的每个成员入队
+ * @param[in] n
+ * 尝试一次入队的个数
+ * @return
+ * 返回实际成功入队个数
+ */
+extern uint32_t bbq_enqueue_burst_value(struct bbq_s *q, void const *obj_table, uint32_t n);
+
+/**
+ * 消息队列单个数据出队
+ * @param[in] q
* 队列指针
- * @param deq_data
- * 出队成功将复制数据到该参数。
- * 请不要以此判断是否出队列成功,应以return值作为判断依据。
+ * @param[in] data
+ * 创建队列时:
+ * 1)如果flag设置了BBQ_CREATE_F_COPY_VALUE,则传入一维指针,如:
+ * int data,传入&data
+ * int *data = malloc(sizeof(int)),传入data
+ * 2)如果flag设置了BBQ_CREATE_F_COPY_PTR,则传入二维指针,如:
+ * int *data = NULL; 传入&data
* @return
- * BBQ_OK 0 :成功
- * BBQ_QUEUE_BUSY -1002 : 失败,队列忙碌中
- * BBQ_QUEUE_EMPTY -1003 : 失败,队列已空(出队)
- * BBQ_ERROR -1 :未知错误
- * BBQ_NULL_PTR -3 :传入空指针
+ * 成功返回0,失败返回小于0的错误码。
*/
-extern int bbq_dequeue(bbq_queue_s *q, void *deq_data);
+extern int bbq_dequeue(struct bbq_s *q, void *data);
/**
- * 将多个对象从一个环形队列ring取出,直到达到最大数量,或是出队失败
- * @param q
+ * 消息队列批量出队(指针出队),尽可能一次出队n个数据,返回实际成功出队个数
+ *
+ * @param[in] q
* 队列指针
- * @param obj_table
- * @param n
- * obj_table的成员个数
+ * @param[out] obj_table
+ * 存储出队的数据(指针)
+ * @param[in] n
+ * 尝试一次出队的个数
* @return
- * 实际出队个数
+ * 返回实际成功出队个数
*/
-extern uint32_t bbq_dequeue_burst_one_dimensional(bbq_queue_s *q, void *obj_table, uint32_t n);
-extern uint32_t bbq_dequeue_burst_two_dimensional(bbq_queue_s *q, void **obj_table, uint32_t n);
+extern uint32_t bbq_dequeue_burst_ptr(struct bbq_s *q, void **obj_table, uint32_t n);
+
/**
- * 尝试一次入队多个数据,直到达到最大数量,或是入队失败
+ * 消息队列批量出队(数据出队),尽可能一次出队n个数据,返回实际成功出队个数
*
- * @param q
+ * @param[in] q
* 队列指针
- * @param obj_table
- * @param n
- * obj_table的成员个数
+ * @param[out] obj_table
+ * 存储出队的数据
+ * @param[in] n
+ * 尝试一次出队的个数
* @return
- * 实际入队个数
+ * 返回实际成功出队个数
*/
-extern uint32_t bbq_enqueue_burst_one_dimensional(bbq_queue_s *q, void *obj_table, uint32_t n);
-extern uint32_t bbq_enqueue_burst_two_dimensional(bbq_queue_s *q, void **obj_table, uint32_t n);
-
-// -----------------------------用于内存测试-------------------------------
-// 当BBQ_MEMORY宏定义开关打开,将对内存分配释放进行统计,方便排查内存泄漏
-typedef enum {
- BBQ_MODULE_QUEUE = 0,
- BBQ_MODULE_QUEUE_BLOCK_NB,
- BBQ_MODULE_QUEUE_BLOCK_ENTRY,
- BBQ_MODULE_MAX,
-} bbq_module_e;
-
-// -----------------------------错误码-------------------------------
+extern uint32_t bbq_dequeue_burst_value(struct bbq_s *q, void *obj_table, uint32_t n);
+
// 通用返回码
#define BBQ_OK 0 // 成功
#define BBQ_ERROR -1 // 通用错误
@@ -204,35 +221,4 @@ typedef enum {
#define BBQ_QUEUE_BUSY -1002 // 队列忙碌中(入队或出队失败)
#define BBQ_QUEUE_EMPTY -1003 // 队列已空(出队失败)
-// -----------------------------日志宏定义-------------------------------
-#ifdef BBQ_DEBUG
-#define BBQ_DBG_LOG(fmt, ...) \
- do { \
- printf("[DBG][%s:%d:%s]" fmt "\n", __func__, __LINE__, __FILE__, ##__VA_ARGS__); \
- } while (0)
-
-#else
-#define BBQ_DBG_LOG(fmt, ...) \
- do { \
- } while (0)
-#endif
-
-#define BBQ_ERR_LOG(fmt, ...) \
- do { \
- printf("\x1b[31m [ERR][%s:%d:%s]" fmt "\x1b[0m\n", __func__, __LINE__, __FILE__, ##__VA_ARGS__); \
- } while (0)
-
-#define BBQ_INFO_LOG(fmt, ...) \
- do { \
- printf("[INFO][%s:%d:%s]" fmt "\n", __func__, __LINE__, __FILE__, ##__VA_ARGS__); \
- } while (0)
-
-#define BBQ_COLOR_PRINT(fmt, ...) \
- do { \
- printf("\033[32m" fmt "\033[0m\n", ##__VA_ARGS__); \
- } while (0)
-
-// -----------------------------其他宏定义-------------------------------
-#define BBQ_INVALID_SOCKET -1
-
#endif \ No newline at end of file
diff --git a/bbq/src/bbq.c b/bbq/src/bbq.c
index cea7a54..cab4234 100644
--- a/bbq/src/bbq.c
+++ b/bbq/src/bbq.c
@@ -1,6 +1,6 @@
/*
* @Author: liuyu
- * @LastEditTime: 2024-06-13 23:11:20
+ * @LastEditTime: 2024-06-18 15:03:00
* @Describe: bbq(Block-based Bounded Queue)实现
* 参考:https://www.usenix.org/system/files/atc22-wang-jiawei.pdf
@@ -11,36 +11,135 @@
#include <stdio.h>
#include <string.h>
+// -----------------------------日志宏定义-------------------------------
+#define BBQ_ERR_LOG(fmt, ...) \
+ do { \
+ printf("\x1b[31m [ERR][%s:%d:%s]" fmt "\x1b[0m\n", __func__, __LINE__, __FILE__, ##__VA_ARGS__); \
+ } while (0)
+
+// -----------------------------其他宏定义-------------------------------
+#define AVOID_WARNING(param) ((void)param)
+#define BBQ_INVALID_SOCKET -1
+
+#define BBQ_POLIC_DROP_OLD(flags) (flags & BBQ_F_POLICY_DROP_OLD)
+#define BBQ_POLIC_RETRY_NEW(flags) (!(flags & BBQ_CREATE_F_DROP_OLD))
+
+#define BBQ_COPY_VALUE(flags) (flags & BBQ_F_COPY_VALUE)
+#define BBQ_COPY_POINTER(flags) (!(flags & BBQ_CREATE_F_COPY_VALUE))
+
+// -----------------------------用于内存测试-------------------------------
+// 当BBQ_MEMORY宏定义开关打开,将对内存分配释放进行统计,方便排查内存泄漏
+// #define BBQ_MEMORY
+enum bbq_module_e {
+ BBQ_MODULE_QUEUE = 0,
+ BBQ_MODULE_QUEUE_BLOCK_NB,
+ BBQ_MODULE_QUEUE_BLOCK_ENTRY,
+ BBQ_MODULE_MAX,
+};
+
struct bbq_status {
- int32_t status; // 返回状态
- uint32_t actual_burst; // 实际出/入队个数
+ int32_t status; // 返回状态
+ uint32_t actual_burst; // 实际出/入队个数
+};
+
+enum bbq_queue_state_e {
+ BBQ_SUCCESS = 0,
+ BBQ_BLOCK_DONE, // 当前块已的entry已用完,需要移动到下一个块
+ BBQ_NO_ENTRY, // 没有条目可以使用
+ BBQ_NOT_AVAILABLE, // 当前块不可以用状态(将返回busy)
+ BBQ_ALLOCATED, // 已分配,返回entry信息
+ BBQ_RESERVED, // 已保留,返回entry信息
+};
+
+struct bbq_entry_desc_s {
+ uint64_t off; // entry在当前block的偏移(offset)
+ uint64_t vsn; // allocated游标的版本(vsn)
+ uint32_t actual_burst; // 实际出入队个数
+ struct bbq_block_s *block; // 指向所在的block
+};
+
+struct bbq_queue_state_s {
+ enum bbq_queue_state_e state; // 队列状态
+ union {
+ uint64_t vsn; // reserve_entry state==BLOCK_DONE时生效
+ struct bbq_entry_desc_s e; // state为ALLOCATED、RESERVED生效
+ };
};
+extern inline uint64_t bbq_idx(struct bbq_s *q, uint64_t x) {
+ return x & q->idx_mask;
+}
+
+extern inline uint64_t bbq_off(struct bbq_s *q, uint64_t x) {
+ return x & q->off_mask;
+}
+
+extern inline uint64_t bbq_head_vsn(struct bbq_s *q, uint64_t x) {
+ return x >> q->idx_bits;
+}
+
+extern inline uint64_t bbq_cur_vsn(struct bbq_s *q, uint64_t x) {
+ return x >> q->off_bits;
+}
+
+extern inline uint64_t set_cur_vsn(struct bbq_s *q, uint64_t ver) {
+ return ver << q->off_bits;
+}
+
+#ifdef BBQ_MEMORY
#define BBQ_MEM_MAGIC 0xFF
+#endif
+
+#ifdef BBQ_MEMORY
+struct bbq_memory_s {
+ aotmic_uint64 malloc_cnt;
+ aotmic_uint64 malloc_size;
+ aotmic_uint64 free_cnt;
+ aotmic_uint64 free_size;
+};
+struct bbq_memory_s bbq_memory_g[BBQ_MODULE_MAX] = {0};
+#endif
+
+void *bbq_malloc(enum bbq_module_e module, int socket_id, size_t size) {
+ void *ptr = NULL;
+ if (socket_id >= 0) {
+ ptr = numa_alloc_onnode(size, 0);
+ } else {
+ ptr = malloc(size);
+ }
+#ifdef BBQ_MEMORY
+ if (ptr != NULL) {
+ atomic_fetch_add(&bbq_memory_g[module].malloc_cnt, 1);
+ atomic_fetch_add(&bbq_memory_g[module].malloc_size, size);
+ }
+#else
+ AVOID_WARNING(module);
+#endif
+ return ptr;
+}
+
+void bbq_free(enum bbq_module_e module, int socket_id, void *ptr, size_t size) {
+ if (socket_id >= 0) {
+ numa_free(ptr, size);
+ } else {
+ free(ptr);
+ }
-extern bbq_queue_state_s allocate_entry(bbq_queue_s* q, bbq_block_s* block, uint32_t n);
-extern bbq_queue_state_e advance_phead(bbq_queue_s* q, uint64_t ph);
-extern bbq_queue_state_s reserve_entry(bbq_queue_s* q, bbq_block_s* block, uint32_t n);
-extern bool consume_entry(bbq_queue_s* q, bbq_entry_desc_s* e, void* deq_data, uint32_t flag);
-extern bool advance_chead(bbq_queue_s* q, uint64_t ch, uint64_t ver);
-extern inline uint64_t bbq_idx(bbq_queue_s* q, uint64_t x);
-extern inline uint64_t bbq_off(bbq_queue_s* q, uint64_t x);
-extern inline uint64_t bbq_head_vsn(bbq_queue_s* q, uint64_t x);
-extern inline uint64_t bbq_cur_vsn(bbq_queue_s* q, uint64_t x);
-extern inline uint64_t set_cur_vsn(bbq_queue_s* q, uint64_t ver);
-extern void* bbq_memset(void* data, size_t size);
-extern void* bbq_malloc(bbq_module_e module, int socket_id, size_t size);
-extern void bbq_free(bbq_module_e module, int socket_id, void* ptr, size_t size);
-
-#ifdef BBQ_DEBUG
-extern void bbq_struct_print(bbq_queue_s* q);
+#ifdef BBQ_MEMORY
+ if (ptr != NULL) {
+ atomic_fetch_add(&bbq_memory_g[module].free_cnt, 1);
+ atomic_fetch_add(&bbq_memory_g[module].free_size, size);
+ }
+#else
+ AVOID_WARNING(module);
#endif
+}
/* 原子的比较两个值大小,并设置较大的值,成功则返回设置前的旧值 */
-uint64_t fetch_max(aotmic_uint64* atom, uint64_t upd) {
+uint64_t fetch_max(aotmic_uint64 *atom, uint64_t upd) {
uint64_t old_value;
do {
- old_value = atomic_load(atom); // 读取当前值
+ old_value = atomic_load(atom); // 读取当前值
} while (old_value < upd && !atomic_compare_exchange_weak(atom, &old_value, upd));
return old_value;
@@ -59,19 +158,19 @@ bool bbq_check_power_of_two(uint32_t n) {
* 计算公式:log2(blocks) = max(1, ⌊log2(count)/4⌋) 注:⌊ ⌋代表向下取整。*/
uint32_t bbq_blocks_calc(uint32_t entries) {
double log_entries = log2((double)entries);
- uint32_t over4 = (uint32_t)(log_entries / 4); // 向下取整
+ uint32_t over4 = (uint32_t)(log_entries / 4); // 向下取整
uint32_t max_value = (over4 > 1) ? over4 : 1;
uint32_t n = pow(2, max_value);
return n;
}
/* 块初始化 */
-int block_init(bbq_queue_s* q, bbq_block_s* block, bool cursor_init) {
+int block_init(struct bbq_s *q, struct bbq_block_s *block, bool cursor_init) {
#ifdef BBQ_MEMORY
// 末尾多分配一个entry(永远不应该被修改),以此检查是否存在写越界的问题
block->entries = bbq_malloc(BBQ_MODULE_QUEUE_BLOCK_ENTRY, q->socket_id,
(q->bs + 1) * q->entry_size);
- char* last_entry = block->entries + q->entry_size * q->bs;
+ char *last_entry = block->entries + q->entry_size * q->bs;
memset(last_entry, BBQ_MEM_MAGIC, q->entry_size);
#else
block->entries = bbq_malloc(BBQ_MODULE_QUEUE_BLOCK_ENTRY, q->socket_id,
@@ -104,7 +203,7 @@ int block_init(bbq_queue_s* q, bbq_block_s* block, bool cursor_init) {
}
/* 块清理函数,与block_init成对*/
-void block_cleanup(bbq_queue_s* q, bbq_block_s* block) {
+void block_cleanup(struct bbq_s *q, struct bbq_block_s *block) {
if (block->entries) {
#ifdef BBQ_MEMORY
bbq_free(BBQ_MODULE_QUEUE_BLOCK_ENTRY, q->socket_id,
@@ -137,17 +236,16 @@ unsigned ceil_log2(uint64_t x) {
}
/* 创建消息队列,bn和bs必须是2的N次幂,socket_id用于多numa分配内存,free_func先设置NULL */
-bbq_queue_s* bbq_ring_create_bnbs_with_socket(uint32_t bn, uint32_t bs, size_t obj_size, int socket_id, unsigned int flags) {
+struct bbq_s *bbq_ring_create_bnbs_with_socket(uint32_t bn, uint32_t bs, size_t obj_size, int socket_id, uint32_t flags) {
int ret = 0;
- bool numa_enable = true;
if (bbq_check_power_of_two(bn) == false) {
- BBQ_ERR_LOG("block number is not power of two, now is :%lu", bn);
+ BBQ_ERR_LOG("block number is not power of two, now is :%u", bn);
return NULL;
}
if (bbq_check_power_of_two(bs) == false) {
- BBQ_ERR_LOG("block size is not power of two, now is :%lu", bs);
+ BBQ_ERR_LOG("block size is not power of two, now is :%u", bs);
return NULL;
}
@@ -161,18 +259,18 @@ bbq_queue_s* bbq_ring_create_bnbs_with_socket(uint32_t bn, uint32_t bs, size_t o
socket_id = BBQ_INVALID_SOCKET;
}
- bbq_queue_s* q = bbq_malloc(BBQ_MODULE_QUEUE, socket_id, sizeof(*q));
+ struct bbq_s *q = bbq_malloc(BBQ_MODULE_QUEUE, socket_id, sizeof(*q));
if (q == NULL) {
BBQ_ERR_LOG("malloc for bbq queue error");
return NULL;
}
- bbq_memset(q, sizeof(*q));
+ memset(q, 0, sizeof(*q));
q->bn = bn;
q->bs = bs;
q->obj_size = obj_size;
if (BBQ_COPY_POINTER(flags)) {
- q->entry_size = sizeof(void*);
+ q->entry_size = sizeof(void *);
} else {
q->entry_size = obj_size;
}
@@ -186,7 +284,7 @@ bbq_queue_s* bbq_ring_create_bnbs_with_socket(uint32_t bn, uint32_t bs, size_t o
BBQ_ERR_LOG("bbq malloc for blocks error");
goto error;
}
- bbq_memset(q->blocks, sizeof(*q->blocks));
+ memset(q->blocks, 0, sizeof(*q->blocks));
for (uint32_t i = 0; i < bn; ++i) {
// 第一个block不需要设置cursor_init_flag
@@ -212,14 +310,14 @@ error:
}
/* 创建消息队列,bn和bs必须是2的N次幂,free_func先设置NULL */
-bbq_queue_s* bbq_ring_create_bnbs(uint32_t bn, uint32_t bs, size_t obj_size, unsigned int flags) {
+struct bbq_s *bbq_ring_create_bnbs(uint32_t bn, uint32_t bs, size_t obj_size, unsigned int flags) {
return bbq_ring_create_bnbs_with_socket(bn, bs, obj_size, BBQ_INVALID_SOCKET, flags);
}
/* 创建消息队列,count必须大于1,且是2的N次幂,bn和bs将根据count值自动计算,socket_id用于多numa分配内存,free_func先设置NULL */
-bbq_queue_s* bbq_ring_create_with_socket(uint32_t count, size_t obj_size, int socket_id, unsigned int flags) {
+struct bbq_s *bbq_create_with_socket(uint32_t count, size_t obj_size, int socket_id, unsigned int flags) {
if (bbq_check_power_of_two(count) == false || count == 1) {
- BBQ_ERR_LOG("bbq entries number must be power of two and greater than 1, now is :%lu", count);
+ BBQ_ERR_LOG("bbq entries number must be power of two and greater than 1, now is :%u", count);
return NULL;
}
@@ -229,13 +327,13 @@ bbq_queue_s* bbq_ring_create_with_socket(uint32_t count, size_t obj_size, int so
}
/* 创建消息队列,count必须大于1,且是2的N次幂,bn和bs将根据count值自动计算,free_func先设置NULL */
-bbq_queue_s* bbq_ring_create(uint32_t count, size_t obj_size, unsigned int flags) {
+struct bbq_s *bbq_create(uint32_t count, size_t obj_size, unsigned int flags) {
// 传入无效socket_id,将使用malloc分配内存
- return bbq_ring_create_with_socket(count, obj_size, BBQ_INVALID_SOCKET, flags);
+ return bbq_create_with_socket(count, obj_size, BBQ_INVALID_SOCKET, flags);
}
/* 释放消息队列,与bbq_ring_create系列接口成对*/
-void bbq_ring_free(bbq_queue_s* q) {
+void bbq_ring_free(struct bbq_s *q) {
if (q == NULL) {
return;
}
@@ -252,271 +350,62 @@ void bbq_ring_free(bbq_queue_s* q) {
#define BBQ_F_SINGLE 0x0
#define BBQ_F_ARRAY_1D 0x1
#define BBQ_F_ARRAY_2D 0x2
-void commit_entry(bbq_queue_s* q, bbq_entry_desc_s* e, void* data, uint32_t flag) {
+void commit_entry(struct bbq_s *q, struct bbq_entry_desc_s *e, void const *data, uint32_t flag) {
size_t idx = e->off * q->entry_size;
if (BBQ_COPY_POINTER(q->flags)) {
// 指针入队列
switch (flag) {
- case BBQ_F_ARRAY_1D:
- char* tmp = (char*)data;
- char* entry = &(e->block->entries[idx]);
- for (size_t i = 0; i < e->actual_burst; i++) {
- memcpy(entry, &tmp, q->entry_size);
- entry += q->entry_size;
- tmp += q->obj_size;
- }
- break;
- case BBQ_F_ARRAY_2D:
- case BBQ_F_SINGLE:
- // 二维数组名等于首成员的地址,这里data其实是void **data, &data等同于 &(data[0])
- memcpy(&(e->block->entries[idx]), data, q->entry_size * e->actual_burst);
-
- void** tmp3 = (void**)(e->block->entries);
- uint16_t* tmp2 = (uint16_t*)(tmp3[0]);
- break;
- default:
- break;
+ case BBQ_F_ARRAY_1D: {
+ char *tmp = (char *)data;
+ char *entry = &(e->block->entries[idx]);
+ for (size_t i = 0; i < e->actual_burst; i++) {
+ memcpy(entry, &tmp, q->entry_size);
+ entry += q->entry_size;
+ tmp += q->obj_size;
+ }
+ break;
+ }
+ case BBQ_F_ARRAY_2D:
+ case BBQ_F_SINGLE:
+ // 二维数组名等于首成员的地址,这里data其实是void **data, &data等同于 &(data[0])
+ memcpy(&(e->block->entries[idx]), data, q->entry_size * e->actual_burst);
+ break;
+ default:
+ break;
}
} else {
// 数据入队列
switch (flag) {
- case BBQ_F_ARRAY_1D:
- case BBQ_F_SINGLE:
- memcpy(&(e->block->entries[idx]), data, q->entry_size * e->actual_burst);
- break;
- case BBQ_F_ARRAY_2D:
- void** tmp = (void**)data;
- char* entry = &(e->block->entries[idx]);
- for (size_t i = 0; i < e->actual_burst; i++) {
- memcpy(entry, *tmp, q->entry_size);
- entry += q->entry_size;
- tmp++;
- }
- break;
- default:
- break;
- }
- }
- atomic_fetch_add(&e->block->committed, e->actual_burst);
-}
-
-/* 消息队列入队 */
-static struct bbq_status __bbq_enqueue(bbq_queue_s* q, void* data, uint32_t n, uint32_t flag) {
- struct bbq_status ret = {.status = 0, .actual_burst = 0};
-
- if (q == NULL || data == NULL) {
- ret.status = BBQ_NULL_PTR;
- return ret;
- }
-
- while (true) {
- // 获取当前phead,转为索引后获取到当前的blk
- uint64_t ph = atomic_load(&q->phead);
- bbq_block_s* blk = &(q->blocks[bbq_idx(q, ph)]);
- bbq_queue_state_s state = allocate_entry(q, blk, n);
-
- switch (state.state) {
- case BBQ_ALLOCATED:
- commit_entry(q, &state.e, data, flag);
- ret.actual_burst = state.e.actual_burst;
- ret.status = BBQ_OK;
- return ret;
- case BBQ_BLOCK_DONE:
- bbq_queue_state_e pstate = advance_phead(q, ph);
- switch (pstate) {
- case BBQ_NO_ENTRY:
- ret.status = BBQ_QUEUE_FULL;
- return ret;
- case BBQ_NOT_AVAILABLE:
- ret.status = BBQ_QUEUE_BUSY;
- return ret;
- case BBQ_SUCCESS:
- continue;
- }
- break;
- default:
- BBQ_DBG_LOG("Invalid QueueState in bbq_enqueue: %d", state.state);
- ret.status = BBQ_ERROR;
- return ret;
- }
- }
-}
-
-int bbq_enqueue(bbq_queue_s* q, void* data) {
- struct bbq_status ret = __bbq_enqueue(q, data, 1, BBQ_F_SINGLE);
- return ret.status;
-}
-
-/* 消息队列出队 */
-static struct bbq_status __bbq_dequeue(bbq_queue_s* q, void* deq_data, uint32_t n, uint32_t flag) {
- struct bbq_status ret = {.status = 0, .actual_burst = 0};
- if (q == NULL || deq_data == NULL) {
- ret.status = BBQ_NULL_PTR;
- return ret;
- }
-
- while (true) {
- uint64_t ch = atomic_load(&q->chead);
- bbq_block_s* blk = &(q->blocks[bbq_idx(q, ch)]);
-
- bbq_queue_state_s state;
- state = reserve_entry(q, blk, n);
-
- switch (state.state) {
- case BBQ_RESERVED:
- if (consume_entry(q, &state.e, deq_data, flag)) {
- ret.status = BBQ_OK;
- ret.actual_burst = state.e.actual_burst;
- return ret;
- } else {
- continue;
- }
- case BBQ_NO_ENTRY:
- ret.status = BBQ_QUEUE_EMPTY;
- return ret;
- case BBQ_NOT_AVAILABLE:
- ret.status = BBQ_QUEUE_BUSY;
- return ret;
- case BBQ_BLOCK_DONE:
- if (advance_chead(q, ch, state.vsn)) {
- continue;
- } else {
- ret.status = BBQ_QUEUE_EMPTY;
- return ret;
- }
- default:
- BBQ_DBG_LOG("Invalid QueueState in dequeue state: %d", state.state);
- ret.status = BBQ_ERROR;
- return ret;
- }
- }
-}
-
-int bbq_dequeue(bbq_queue_s* q, void* deq_data) {
- struct bbq_status ret = __bbq_dequeue(q, deq_data, 1, BBQ_F_SINGLE);
- return ret.status;
-}
-
-uint32_t bbq_max_burst(bbq_queue_s* q, uint32_t n) {
- uint32_t burst = n;
- if (burst > q->bs) {
- burst = q->bs;
- }
-
- return burst;
-}
-
-uint32_t bbq_dequeue_burst_one_dimensional(bbq_queue_s* q, void* obj_table, uint32_t n) {
- if (q == NULL || obj_table == NULL) {
- return BBQ_NULL_PTR;
- }
-
- uint32_t burst = 0;
- uint32_t ready = 0;
- void* obj = obj_table;
- struct bbq_status ret = {0};
-
- while (ready < n) {
- burst = bbq_max_burst(q, n - ready);
- ret = __bbq_dequeue(q, obj, burst, BBQ_F_ARRAY_1D);
- if (ret.status != BBQ_OK) {
+ case BBQ_F_ARRAY_1D:
+ case BBQ_F_SINGLE:
+ memcpy(&(e->block->entries[idx]), data, q->entry_size * e->actual_burst);
break;
- }
- obj += q->obj_size * ret.actual_burst;
- ready += ret.actual_burst;
-
- // bbq_struct_print(q);
- }
-
- return ready;
-}
-
-uint32_t bbq_dequeue_burst_two_dimensional(bbq_queue_s* q, void** obj_table, uint32_t n) {
- if (q == NULL || obj_table == NULL) {
- return BBQ_NULL_PTR;
- }
-
- uint32_t burst = 0;
- uint32_t ready = 0;
- void** obj_table_tmp = obj_table;
- struct bbq_status ret = {0};
-
- while (ready < n) {
- burst = bbq_max_burst(q, n - ready);
- ret = __bbq_dequeue(q, obj_table_tmp, burst, BBQ_F_ARRAY_2D);
- if (ret.status != BBQ_OK) {
+ case BBQ_F_ARRAY_2D: {
+ void **tmp = (void **)data;
+ char *entry = &(e->block->entries[idx]);
+ for (size_t i = 0; i < e->actual_burst; i++) {
+ memcpy(entry, *tmp, q->entry_size);
+ entry += q->entry_size;
+ tmp++;
+ }
break;
}
- obj_table_tmp += ret.actual_burst;
- ready += ret.actual_burst;
-
- // bbq_struct_print(q);
- }
-
- return ready;
-}
-
-/* 尝试一次入队多个数据,直到达到最大数量,或是入队失败 */
-uint32_t bbq_enqueue_burst_one_dimensional(bbq_queue_s* q, void* obj_table, uint32_t n) {
- if (q == NULL || obj_table == NULL) {
- return BBQ_NULL_PTR;
- }
-
- uint32_t burst = 0;
- uint32_t ready = 0;
- void* obj = obj_table;
- struct bbq_status ret = {0};
-
- while (ready < n) {
- burst = bbq_max_burst(q, n - ready);
- ret = __bbq_enqueue(q, obj, burst, BBQ_F_ARRAY_1D);
- if (ret.status != BBQ_OK) {
+ default:
break;
}
- obj += q->obj_size * ret.actual_burst;
- ready += ret.actual_burst;
-
- // bbq_struct_print(q);
}
-
- return ready;
-}
-
-/* 尝试一次入队多个数据,直到达到最大数量,或是入队失败 */
-uint32_t bbq_enqueue_burst_two_dimensional(bbq_queue_s* q, void** obj_table, uint32_t n) {
- if (q == NULL || obj_table == NULL) {
- return BBQ_NULL_PTR;
- }
-
- uint32_t burst = 0;
- uint32_t ready = 0;
- void** obj_table_tmp = obj_table;
- struct bbq_status ret = {0};
-
- while (ready < n) {
- burst = bbq_max_burst(q, n - ready);
- ret = __bbq_enqueue(q, obj_table_tmp, burst, BBQ_F_ARRAY_2D);
- if (ret.status != BBQ_OK) {
- break;
- }
- obj_table_tmp += ret.actual_burst;
- ready += ret.actual_burst;
-
- // bbq_struct_print(q);
- }
-
- return ready;
+ atomic_fetch_add(&e->block->committed, e->actual_burst);
}
-bbq_queue_state_s allocate_entry(bbq_queue_s* q, bbq_block_s* block, uint32_t n) {
- bbq_queue_state_s state = {0};
+struct bbq_queue_state_s allocate_entry(struct bbq_s *q, struct bbq_block_s *block, uint32_t n) {
+ struct bbq_queue_state_s state = {0};
if (bbq_off(q, atomic_load(&block->allocated)) >= q->bs) {
state.state = BBQ_BLOCK_DONE;
return state;
}
- uint64_t old = atomic_fetch_add(&block->allocated, n); // burst
+ uint64_t old = atomic_fetch_add(&block->allocated, n);
uint64_t committed_vsn = bbq_cur_vsn(q, atomic_load(&block->committed));
// committed_vsn在当前块被初始化后值是不变的,通过比较vsn值,来判断allocated的off是否溢出了,导致vsn+1
@@ -542,18 +431,22 @@ bbq_queue_state_s allocate_entry(bbq_queue_s* q, bbq_block_s* block, uint32_t n)
return state;
}
-bbq_queue_state_e advance_phead(bbq_queue_s* q, uint64_t ph) {
+enum bbq_queue_state_e advance_phead(struct bbq_s *q, uint64_t ph) {
// 获取下一个block
- bbq_block_s* n_blk;
- n_blk = &(q->blocks[(bbq_idx(q, ph) + 1) & q->idx_mask]);
+ uint64_t cur = 0;
+ struct bbq_block_s *n_blk = &(q->blocks[(bbq_idx(q, ph) + 1) & q->idx_mask]);
+ uint64_t ph_vsn = bbq_head_vsn(q, ph);
- uint64_t cur, reserved;
if (BBQ_POLIC_RETRY_NEW(q->flags)) {
cur = atomic_load(&n_blk->consumed);
- if (bbq_cur_vsn(q, cur) < bbq_head_vsn(q, ph) || // 生产者赶上了消费者
- (bbq_cur_vsn(q, cur) == bbq_head_vsn(q, ph) && bbq_off(q, cur) != q->bs)) {
+ uint64_t reserved;
+ uint64_t consumed_off = bbq_off(q, cur);
+ uint64_t consumed_vsn = bbq_cur_vsn(q, cur);
+
+ if (consumed_vsn < ph_vsn || // 生产者赶上了消费者
+ (consumed_vsn == ph_vsn && consumed_off != q->bs)) {
reserved = atomic_load(&n_blk->reserved);
- if (bbq_off(q, reserved) == bbq_off(q, cur)) {
+ if (bbq_off(q, reserved) == consumed_off) {
return BBQ_NO_ENTRY;
} else {
return BBQ_NOT_AVAILABLE;
@@ -562,22 +455,73 @@ bbq_queue_state_e advance_phead(bbq_queue_s* q, uint64_t ph) {
} else {
cur = atomic_load(&n_blk->committed);
// 生产者避免前进到上一轮中尚未完全提交的区块
- if (bbq_cur_vsn(q, cur) == bbq_head_vsn(q, ph) && bbq_off(q, cur) != q->bs) {
+ if (bbq_cur_vsn(q, cur) == ph_vsn && bbq_off(q, cur) != q->bs) {
return BBQ_NOT_AVAILABLE;
}
}
// 用head的version初始化下一个块,version在高位,version+1,idex/offset清零,如果没有被其他线程执行过,数值会高于旧值。多线程同时只更新一次。
- fetch_max(&n_blk->committed, set_cur_vsn(q, bbq_head_vsn(q, ph) + 1));
- fetch_max(&n_blk->allocated, set_cur_vsn(q, bbq_head_vsn(q, ph) + 1));
+ uint64_t new_vsn = set_cur_vsn(q, ph_vsn + 1);
+ fetch_max(&n_blk->committed, new_vsn);
+ fetch_max(&n_blk->allocated, new_vsn);
// 索引+1,当超过索引范围,也就是循环下一轮块时,version+1
fetch_max(&q->phead, ph + 1);
return BBQ_SUCCESS;
}
+/* 消息队列入队 */
+static struct bbq_status __bbq_enqueue(struct bbq_s *q, void const *data, uint32_t n, uint32_t flag) {
+ struct bbq_status ret = {.status = 0, .actual_burst = 0};
+
+ if (q == NULL || data == NULL) {
+ ret.status = BBQ_NULL_PTR;
+ return ret;
+ }
+
+ while (true) {
+ // 获取当前phead,转为索引后获取到当前的blk
+ uint64_t ph = atomic_load(&q->phead);
+ struct bbq_block_s *blk = &(q->blocks[bbq_idx(q, ph)]);
+ struct bbq_queue_state_s state = allocate_entry(q, blk, n);
+
+ switch (state.state) {
+ case BBQ_ALLOCATED:
+ commit_entry(q, &state.e, data, flag);
+ ret.actual_burst = state.e.actual_burst;
+ ret.status = BBQ_OK;
+ return ret;
+ case BBQ_BLOCK_DONE: {
+ enum bbq_queue_state_e pstate = advance_phead(q, ph);
+ switch (pstate) {
+ case BBQ_NO_ENTRY:
+ ret.status = BBQ_QUEUE_FULL;
+ return ret;
+ case BBQ_NOT_AVAILABLE:
+ ret.status = BBQ_QUEUE_BUSY;
+ return ret;
+ case BBQ_SUCCESS:
+ continue;
+ default:
+ ret.status = BBQ_ERROR;
+ return ret;
+ }
+ break;
+ }
+ default:
+ ret.status = BBQ_ERROR;
+ return ret;
+ }
+ }
+}
+
+int bbq_enqueue(struct bbq_s *q, void *data) {
+ struct bbq_status ret = __bbq_enqueue(q, data, 1, BBQ_F_SINGLE);
+ return ret.status;
+}
+
/* 更新成功 reserve成功的个数 */
-uint32_t reserve_update(bbq_cursor* aotmic, uint64_t reserved, uint32_t n) {
+uint32_t reserve_update(bbq_cursor *aotmic, uint64_t reserved, uint32_t n) {
if (n == 1) {
// fetch_max返回的是旧值,如果旧值等于局部变量reserved,则代表数据由当前线程更新
if (fetch_max(aotmic, reserved + 1) == reserved) {
@@ -591,9 +535,9 @@ uint32_t reserve_update(bbq_cursor* aotmic, uint64_t reserved, uint32_t n) {
}
}
-bbq_queue_state_s reserve_entry(bbq_queue_s* q, bbq_block_s* block, uint32_t n) {
+struct bbq_queue_state_s reserve_entry(struct bbq_s *q, struct bbq_block_s *block, uint32_t n) {
while (true) {
- bbq_queue_state_s state;
+ struct bbq_queue_state_s state;
uint64_t reserved = atomic_load(&block->reserved);
uint64_t reserved_off = bbq_off(q, reserved);
uint64_t reserved_svn = bbq_cur_vsn(q, reserved);
@@ -609,7 +553,7 @@ bbq_queue_state_s reserve_entry(bbq_queue_s* q, bbq_block_s* block, uint32_t n)
uint64_t committed = atomic_load(&block->committed);
uint64_t committed_off = bbq_off(q, committed);
- if (committed_off == reserved_off) { // TODO:多entry关注
+ if (committed_off == reserved_off) { // TODO:多entry关注
state.state = BBQ_NO_ENTRY;
return state;
}
@@ -623,9 +567,9 @@ bbq_queue_state_s reserve_entry(bbq_queue_s* q, bbq_block_s* block, uint32_t n)
}
}
- int32_t tmp = committed_off - reserved_off;
+ uint32_t tmp = committed_off - reserved_off;
uint32_t reserved_cnt = reserve_update(&block->reserved, reserved, tmp < n ? tmp : n);
- if (reserved_cnt > 0) { // TODO:多entry时关注
+ if (reserved_cnt > 0) { // TODO:多entry时关注
state.state = BBQ_RESERVED;
state.e.actual_burst = reserved_cnt;
state.e.block = block;
@@ -645,36 +589,37 @@ bbq_queue_state_s reserve_entry(bbq_queue_s* q, bbq_block_s* block, uint32_t n)
}
}
-bool consume_entry(bbq_queue_s* q, bbq_entry_desc_s* e, void* deq_data, uint32_t flag) {
+bool consume_entry(struct bbq_s *q, struct bbq_entry_desc_s *e, void *deq_data, uint32_t flag) {
size_t idx = e->off * q->entry_size;
if (BBQ_COPY_POINTER(q->flags)) {
switch (flag) {
- case BBQ_F_ARRAY_2D:
- case BBQ_F_SINGLE:
- memcpy(deq_data, &(e->block->entries[idx]), q->entry_size * e->actual_burst);
- break;
- case BBQ_F_ARRAY_1D:
- default:
- break;
+ case BBQ_F_ARRAY_2D:
+ case BBQ_F_SINGLE:
+ memcpy(deq_data, &(e->block->entries[idx]), q->entry_size * e->actual_burst);
+ break;
+ case BBQ_F_ARRAY_1D:
+ default:
+ break;
}
} else {
switch (flag) {
- case BBQ_F_ARRAY_1D:
- case BBQ_F_SINGLE:
- memcpy(deq_data, &(e->block->entries[idx]), q->entry_size * e->actual_burst);
- break;
- case BBQ_F_ARRAY_2D:
- void** tmp = (void**)deq_data;
- char* entry = &(e->block->entries[idx]);
- for (size_t i = 0; i < e->actual_burst; i++) {
- memcpy(*tmp, entry, q->entry_size);
- entry += q->entry_size;
- tmp++;
- }
- break;
- default:
- break;
+ case BBQ_F_ARRAY_1D:
+ case BBQ_F_SINGLE:
+ memcpy(deq_data, &(e->block->entries[idx]), q->entry_size * e->actual_burst);
+ break;
+ case BBQ_F_ARRAY_2D: {
+ void **tmp = (void **)deq_data;
+ char *entry = &(e->block->entries[idx]);
+ for (size_t i = 0; i < e->actual_burst; i++) {
+ memcpy(*tmp, entry, q->entry_size);
+ entry += q->entry_size;
+ tmp++;
+ }
+ break;
+ }
+ default:
+ break;
}
}
@@ -682,6 +627,7 @@ bool consume_entry(bbq_queue_s* q, bbq_entry_desc_s* e, void* deq_data, uint32_t
if (BBQ_POLIC_RETRY_NEW(q->flags)) {
atomic_fetch_add(&e->block->consumed, e->actual_burst);
} else {
+ // TODO:优化,考虑allocated vsn溢出?考虑判断如果生产满了,直接移动head?
allocated = atomic_load(&e->block->allocated);
// 预留的entry所在的块,已经被新生产的数据赶上了
if (bbq_cur_vsn(q, allocated) != e->vsn) {
@@ -692,95 +638,207 @@ bool consume_entry(bbq_queue_s* q, bbq_entry_desc_s* e, void* deq_data, uint32_t
return true;
}
-bool advance_chead(bbq_queue_s* q, uint64_t ch, uint64_t ver) {
- bbq_block_s* n_blk = &(q->blocks[(bbq_idx(q, ch) + 1) & q->idx_mask]);
+bool advance_chead(struct bbq_s *q, uint64_t ch, uint64_t ver) {
+ uint64_t ch_idx = bbq_idx(q, ch);
+ struct bbq_block_s *n_blk = &(q->blocks[(ch_idx + 1) & q->idx_mask]);
+ uint64_t ch_vsn = bbq_head_vsn(q, ch);
uint64_t committed = atomic_load(&n_blk->committed);
+ uint64_t committed_vsn = bbq_cur_vsn(q, committed);
if (BBQ_POLIC_RETRY_NEW(q->flags)) {
- if (bbq_cur_vsn(q, committed) != bbq_head_vsn(q, ch) + 1) {
+ if (committed_vsn != ch_vsn + 1) {
// 消费者追上了生产者,下一块还未开始生产
return false;
}
- fetch_max(&n_blk->consumed, set_cur_vsn(q, bbq_head_vsn(q, ch) + 1));
- fetch_max(&n_blk->reserved, set_cur_vsn(q, bbq_head_vsn(q, ch) + 1));
+ uint64_t new_vsn = set_cur_vsn(q, ch_vsn + 1);
+ fetch_max(&n_blk->consumed, new_vsn);
+ fetch_max(&n_blk->reserved, new_vsn);
} else {
// 通过检查下一个块的版本是否大于或等于当前块来保证 FIFO 顺序.
- // 第一个块是一个特殊情况,因为与其他块相比,它的版本总是相差一个。因此,如果 ch.bbq_idx == 0,我们在比较中加 1
- if (bbq_cur_vsn(q, committed) < ver + (bbq_idx(q, ch) == 0))
+ // 第一个块是一个特殊情况,因为与其他块相比,它的版本总是相差一个。因此,如果 ch_idx == 0,我们在比较中加 1
+ if (committed_vsn < ver + (ch_idx == 0))
return false;
- fetch_max(&n_blk->reserved, set_cur_vsn(q, bbq_cur_vsn(q, committed)));
+ fetch_max(&n_blk->reserved, set_cur_vsn(q, committed_vsn));
}
fetch_max(&q->chead, ch + 1);
return true;
}
-inline uint64_t bbq_idx(bbq_queue_s* q, uint64_t x) {
- return x & q->idx_mask;
-}
+/* 消息队列出队 */
+static struct bbq_status __bbq_dequeue(struct bbq_s *q, void *deq_data, uint32_t n, uint32_t flag) {
+ struct bbq_status ret = {.status = 0, .actual_burst = 0};
+ if (q == NULL || deq_data == NULL) {
+ ret.status = BBQ_NULL_PTR;
+ return ret;
+ }
-inline uint64_t bbq_off(bbq_queue_s* q, uint64_t x) {
- return x & q->off_mask;
-}
+ while (true) {
+ uint64_t ch = atomic_load(&q->chead);
+ struct bbq_block_s *blk = &(q->blocks[bbq_idx(q, ch)]);
-inline uint64_t bbq_head_vsn(bbq_queue_s* q, uint64_t x) {
- return x >> q->idx_bits;
+ struct bbq_queue_state_s state;
+ state = reserve_entry(q, blk, n);
+
+ switch (state.state) {
+ case BBQ_RESERVED:
+ if (consume_entry(q, &state.e, deq_data, flag)) {
+ ret.status = BBQ_OK;
+ ret.actual_burst = state.e.actual_burst;
+ return ret;
+ } else {
+ continue;
+ }
+ case BBQ_NO_ENTRY:
+ ret.status = BBQ_QUEUE_EMPTY;
+ return ret;
+ case BBQ_NOT_AVAILABLE:
+ ret.status = BBQ_QUEUE_BUSY;
+ return ret;
+ case BBQ_BLOCK_DONE:
+ if (advance_chead(q, ch, state.vsn)) {
+ continue;
+ } else {
+ ret.status = BBQ_QUEUE_EMPTY;
+ return ret;
+ }
+ default:
+ ret.status = BBQ_ERROR;
+ return ret;
+ }
+ }
}
-inline uint64_t bbq_cur_vsn(bbq_queue_s* q, uint64_t x) {
- return x >> q->off_bits;
+int bbq_dequeue(struct bbq_s *q, void *deq_data) {
+ struct bbq_status ret = __bbq_dequeue(q, deq_data, 1, BBQ_F_SINGLE);
+ return ret.status;
}
-inline uint64_t set_cur_vsn(bbq_queue_s* q, uint64_t ver) {
- return ver << q->off_bits;
+uint32_t bbq_max_burst(struct bbq_s *q, uint32_t n) {
+ uint32_t burst = n;
+ if (burst > q->bs) {
+ burst = q->bs;
+ }
+
+ return burst;
}
-void* bbq_memset(void* data, size_t size) {
- if (data != NULL && size > 0) {
- memset(data, 0, size);
+static uint32_t bbq_dequeue_burst_one_dimensional(struct bbq_s *q, void *obj_table, uint32_t n) {
+ if (q == NULL || obj_table == NULL) {
+ return BBQ_NULL_PTR;
+ }
+
+ uint32_t burst = 0;
+ uint32_t ready = 0;
+ void *obj = obj_table;
+ struct bbq_status ret = {0};
+
+ while (ready < n) {
+ burst = bbq_max_burst(q, n - ready);
+ ret = __bbq_dequeue(q, obj, burst, BBQ_F_ARRAY_1D);
+ if (ret.status != BBQ_OK) {
+ break;
+ }
+ obj += q->obj_size * ret.actual_burst;
+ ready += ret.actual_burst;
}
+
+ return ready;
}
-#ifdef BBQ_MEMORY
-typedef struct {
- aotmic_uint64 malloc_cnt;
- aotmic_uint64 malloc_size;
- aotmic_uint64 free_cnt;
- aotmic_uint64 free_size;
-} bbq_memory_s;
-bbq_memory_s bbq_memory_g[BBQ_MODULE_MAX] = {0};
-#endif
+static uint32_t bbq_dequeue_burst_two_dimensional(struct bbq_s *q, void **obj_table, uint32_t n) {
+ if (q == NULL || obj_table == NULL) {
+ return BBQ_NULL_PTR;
+ }
-void* bbq_malloc(bbq_module_e module, int socket_id, size_t size) {
- void* ptr = NULL;
- if (socket_id >= 0) {
- ptr = numa_alloc_onnode(size, 0);
- } else {
- ptr = malloc(size);
+ uint32_t burst = 0;
+ uint32_t ready = 0;
+ void **obj_table_tmp = obj_table;
+ struct bbq_status ret = {0};
+
+ while (ready < n) {
+ burst = bbq_max_burst(q, n - ready);
+ ret = __bbq_dequeue(q, obj_table_tmp, burst, BBQ_F_ARRAY_2D);
+ if (ret.status != BBQ_OK) {
+ break;
+ }
+ obj_table_tmp += ret.actual_burst;
+ ready += ret.actual_burst;
}
-#ifdef BBQ_MEMORY
- if (ptr != NULL) {
- atomic_fetch_add(&bbq_memory_g[module].malloc_cnt, 1);
- atomic_fetch_add(&bbq_memory_g[module].malloc_size, size);
+
+ return ready;
+}
+
+/* 尝试一次入队多个数据,直到达到最大数量,或是入队失败 */
+uint32_t bbq_enqueue_burst_one_dimensional(struct bbq_s *q, void const *obj_table, uint32_t n) {
+ if (q == NULL || obj_table == NULL) {
+ return BBQ_NULL_PTR;
}
-#endif
- return ptr;
+ uint32_t burst = 0;
+ uint32_t ready = 0;
+ void const *obj = obj_table;
+ struct bbq_status ret = {0};
+
+ while (ready < n) {
+ burst = bbq_max_burst(q, n - ready);
+ ret = __bbq_enqueue(q, obj, burst, BBQ_F_ARRAY_1D);
+ if (ret.status != BBQ_OK) {
+ break;
+ }
+ obj += q->obj_size * ret.actual_burst;
+ ready += ret.actual_burst;
+ }
+
+ return ready;
}
-void bbq_free(bbq_module_e module, int socket_id, void* ptr, size_t size) {
-#ifdef BBQ_MEMORY
- if (ptr != NULL) {
- atomic_fetch_add(&bbq_memory_g[module].free_cnt, 1);
- atomic_fetch_add(&bbq_memory_g[module].free_size, size);
+/* 尝试一次入队多个数据,直到达到最大数量,或是入队失败 */
+uint32_t bbq_enqueue_burst_two_dimensional(struct bbq_s *q, void *const *obj_table, uint32_t n) {
+ if (q == NULL || obj_table == NULL) {
+ return BBQ_NULL_PTR;
}
-#endif
- // free(ptr);
- if (socket_id >= 0) {
- numa_free(ptr, size);
- } else {
- free(ptr);
+
+ uint32_t burst = 0;
+ uint32_t ready = 0;
+ void *const *obj_table_tmp = obj_table;
+ struct bbq_status ret = {0};
+
+ while (ready < n) {
+ burst = bbq_max_burst(q, n - ready);
+ ret = __bbq_enqueue(q, obj_table_tmp, burst, BBQ_F_ARRAY_2D);
+ if (ret.status != BBQ_OK) {
+ break;
+ }
+ obj_table_tmp += ret.actual_burst;
+ ready += ret.actual_burst;
}
+
+ return ready;
+}
+
+uint32_t bbq_enqueue_burst_value(struct bbq_s *q, void const *obj_table, uint32_t n) {
+ return bbq_enqueue_burst_one_dimensional(q, obj_table, n);
+}
+
+uint32_t bbq_enqueue_burst_value_two_dimensional(struct bbq_s *q, void *const *obj_table, uint32_t n) {
+ return bbq_enqueue_burst_two_dimensional(q, obj_table, n);
+}
+
+uint32_t bbq_enqueue_burst_ptr(struct bbq_s *q, void *const *obj_table, uint32_t n) {
+ return bbq_enqueue_burst_two_dimensional(q, obj_table, n);
+}
+
+uint32_t bbq_enqueue_burst_ptr_one_dimensional(struct bbq_s *q, void const *obj_table, uint32_t n) {
+ return bbq_enqueue_burst_one_dimensional(q, obj_table, n);
+}
+
+uint32_t bbq_dequeue_burst_ptr(struct bbq_s *q, void **obj_table, uint32_t n) {
+ return bbq_dequeue_burst_two_dimensional(q, obj_table, n);
+}
+
+uint32_t bbq_dequeue_burst_value(struct bbq_s *q, void *obj_table, uint32_t n) {
+ return bbq_dequeue_burst_one_dimensional(q, obj_table, n);
}
bool bbq_malloc_free_equal() {
@@ -807,23 +865,25 @@ bool bbq_malloc_free_equal() {
#endif
}
-bool bbq_check_array_bounds(bbq_queue_s* q) {
+bool bbq_check_array_bounds(struct bbq_s *q) {
#ifdef BBQ_MEMORY
- void* value = malloc(q->entry_size);
+ void *value = malloc(q->entry_size);
memset(value, BBQ_MEM_MAGIC, q->entry_size);
for (size_t i = 0; i < q->bn; i++) {
// 针对内存检查版本,申请了bs+1个entry
- char* last_entry = q->blocks[i].entries + q->bs * q->entry_size;
+ char *last_entry = q->blocks[i].entries + q->bs * q->entry_size;
if (memcmp(last_entry, value, q->entry_size) != 0) {
return false;
}
}
+#else
+ AVOID_WARNING(q);
#endif
return true;
}
-void bbq_memory_info() {
+void bbq_memory_print() {
#ifdef BBQ_MEMORY
for (int i = 0; i < BBQ_MODULE_MAX; i++) {
uint64_t malloc_cnt = atomic_load(&bbq_memory_g[i].malloc_cnt);
@@ -832,21 +892,22 @@ void bbq_memory_info() {
continue;
}
- BBQ_INFO_LOG("[%d]bbq malloc:%lu free:%lu", i,
- atomic_load(&bbq_memory_g[i].malloc_cnt),
- atomic_load(&bbq_memory_g[i].free_cnt));
+ printf("[%d]bbq malloc:%lu free:%lu\n", i,
+ atomic_load(&bbq_memory_g[i].malloc_cnt),
+ atomic_load(&bbq_memory_g[i].free_cnt));
}
if (bbq_malloc_free_equal()) {
- BBQ_INFO_LOG("all memory free");
+ printf("all memory free\n");
} else {
BBQ_ERR_LOG("memory not all free");
}
#endif
}
-#ifdef BBQ_DEBUG
-void bbq_block_print(bbq_queue_s* q, bbq_block_s* block) {
+#if 1
+// 调试用
+void bbq_block_print(struct bbq_s *q, struct bbq_block_s *block) {
bbq_cursor allocated = atomic_load(&block->allocated);
bbq_cursor committed = atomic_load(&block->committed);
bbq_cursor reserved = atomic_load(&block->reserved);
@@ -857,11 +918,12 @@ void bbq_block_print(bbq_queue_s* q, bbq_block_s* block) {
printf(" consumed:%lu\n\n", bbq_off(q, consumed));
}
-void bbq_struct_print(bbq_queue_s* q) {
+void bbq_struct_print(struct bbq_s *q) {
+ printf("-------------\n");
printf("ph idx:%lu vsn:%lu\n", bbq_idx(q, q->phead), bbq_head_vsn(q, q->phead));
bbq_block_print(q, &(q->blocks[bbq_idx(q, q->phead)]));
- // printf("ch idx:%lu vsn:%lu", bbq_idx(q, q->chead), bbq_head_vsn(q, q->chead));
- // bbq_block_print(q, &(q->blocks[bbq_idx(q, q->chead)]));
+ printf("ch idx:%lu vsn:%lu", bbq_idx(q, q->chead), bbq_head_vsn(q, q->chead));
+ bbq_block_print(q, &(q->blocks[bbq_idx(q, q->chead)]));
}
#endif \ No newline at end of file
diff --git a/bbq/test.c b/bbq/test.c
new file mode 100644
index 0000000..7fa8ecf
--- /dev/null
+++ b/bbq/test.c
@@ -0,0 +1,54 @@
+/*
+ * @Description: 描述信息
+ * @Date: 2024-06-13 21:45:38
+ * @LastEditTime: 2024-06-17 18:28:18
+ */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// 假设我们有一些uint16_t的指针,并且我们想要复制它们的地址
+void copy_pointer_array(void **dest, uint16_t **src, size_t num_pointers) {
+ // 使用memcpy复制指针数组的内容
+ memcpy(dest, src, num_pointers * sizeof(uint16_t *));
+}
+
+// 一个简单的函数来展示如何使用这些指针
+void print_through_pointers(void *entries, size_t num_pointers) {
+ uint16_t **pointers = (uint16_t **)entries;
+ for (size_t i = 0; i < num_pointers; ++i) {
+ if (pointers[i]) {
+ printf("Pointer %zu points to %p, value: %u\n", i, (void *)pointers[i], *pointers[i]);
+ } else {
+ printf("Pointer %zu is NULL\n", i);
+ }
+ }
+}
+
+struct test_s {
+ void *entries;
+};
+
+int main() {
+ // 示例:创建一些uint16_t的指针和值
+ uint16_t val1 = 123, val2 = 456, val3 = 789;
+ uint16_t *ptrs[3] = {&val1, &val2, &val3};
+
+ printf("%p\n", ptrs[0]);
+ printf("%p\n", ptrs[1]);
+ printf("%p\n", ptrs[2]);
+
+ // 使用void指针进行复制
+ struct test_s tt;
+ tt.entries = malloc(3 * sizeof(uint16_t *));
+ copy_pointer_array(tt.entries, (uint16_t **)ptrs, 3);
+
+ // 通过void指针读取数据
+ print_through_pointers(tt.entries, 3);
+
+ // 清理内存
+ free(tt.entries);
+
+ return 0;
+} \ No newline at end of file
diff --git a/bbq/tests/common/test_mix.c b/bbq/tests/common/test_mix.c
index 1009c81..bcadaa5 100644
--- a/bbq/tests/common/test_mix.c
+++ b/bbq/tests/common/test_mix.c
@@ -1,7 +1,7 @@
/*
* @Description: 描述信息
* @Date: 2024-05-25 10:55:48
- * @LastEditTime: 2024-06-07 16:54:45
+ * @LastEditTime: 2024-06-17 17:14:16
*/
#define _GNU_SOURCE
#include "test_mix.h"
@@ -26,13 +26,6 @@ void *test_malloc(test_module_e module, size_t size) {
return ptr;
}
-void *test_calloc(test_module_e module, size_t size) {
- void *ptr = test_malloc(module, size);
- if (ptr != NULL) {
- memset(ptr, 0, size);
- }
-}
-
void test_free(test_module_e module, void *ptr) {
if (ptr != NULL) {
atomic_fetch_add(&test_memory_g[module].free_cnt, 1);
@@ -46,7 +39,7 @@ bool test_malloc_free_equal() {
uint64_t malloc_cnt = atomic_load(&test_memory_g[i].malloc_cnt);
uint64_t free_cnt = atomic_load(&test_memory_g[i].free_cnt);
if (malloc_cnt != free_cnt) {
- BBQ_ERR_LOG("[module:%d] malloc:%lu free:%lu, test malloc-free not equal\n", i, malloc_cnt, free_cnt);
+ TEST_ERR_LOG("[module:%d] malloc:%lu free:%lu, test malloc-free not equal\n", i, malloc_cnt, free_cnt);
ret = false;
}
}
@@ -57,7 +50,7 @@ void test_memory_counter_clear() {
memset(test_memory_g, 0, sizeof(test_memory_g));
}
-void test_memory_info() {
+void test_memory_counter_print() {
for (int i = 0; i < TEST_MODULE_MAX; i++) {
uint64_t malloc_cnt = atomic_load(&test_memory_g[i].malloc_cnt);
uint64_t free_cnt = atomic_load(&test_memory_g[i].free_cnt);
@@ -65,23 +58,20 @@ void test_memory_info() {
continue;
}
- BBQ_INFO_LOG("[%d]test malloc:%lu free:%lu", i,
- atomic_load(&test_memory_g[i].malloc_cnt),
- atomic_load(&test_memory_g[i].free_cnt));
+ TEST_INFO_LOG("[%d]test malloc:%lu free:%lu", i,
+ atomic_load(&test_memory_g[i].malloc_cnt),
+ atomic_load(&test_memory_g[i].free_cnt));
}
if (test_malloc_free_equal()) {
- BBQ_INFO_LOG("all memory free");
+ TEST_INFO_LOG("all memory free");
} else {
- BBQ_ERR_LOG("memory not all free");
+ TEST_ERR_LOG("memory not all free");
}
}
test_time_metric test_clock_time_get() {
test_time_metric metric = {0};
- struct timespec timestamp;
-
- // clock_gettime(CLOCK_MONOTONIC, &metric.timestamp); //从系统启动这一刻起开始计时,不受系统时间被用户改变的影响
clock_gettime(CLOCK_REALTIME, &metric.timestamp); // 系统实时时间,随系统实时时间改变而改变
return metric;
}
@@ -164,48 +154,6 @@ char *test_ring_type_enum2str(test_ring_type ring_type) {
}
}
-uint16_t **test_enqueue_table_create(uint32_t count) {
- uint16_t **table = test_malloc(TEST_MODULE_TABLE, sizeof(uint16_t **) * count);
- if (table == NULL) {
- return NULL;
- }
- memset(table, 0, sizeof(uint16_t **) * count);
-
- for (uint32_t i = 0; i < count; i++) {
- table[i] = test_malloc(TEST_MODULE_TABLE, sizeof(uint16_t));
- if (table[i] == NULL) {
- goto error;
- }
- *table[i] = TEST_TABLE_DATA_MAGIC;
- }
-
- return table;
-
-error:
- if (table) {
- for (uint32_t i = 0; i < count; i++) {
- if (table[i] != NULL) {
- test_free(TEST_MODULE_TABLE, table[i]);
- } else {
- break;
- }
- }
- test_free(TEST_MODULE_TABLE, table);
- }
- return NULL;
-}
-
-void test_enqueue_table_destory(uint16_t **table, uint32_t count) {
- if (table == NULL) {
- return;
- }
-
- for (uint32_t i = 0; i < count; i++) {
- test_free(TEST_MODULE_TABLE, table[i]);
- }
- test_free(TEST_MODULE_TABLE, table);
-}
-
int test_setaffinity(int core_id) {
cpu_set_t mask;
CPU_ZERO(&mask);
diff --git a/bbq/tests/common/test_mix.h b/bbq/tests/common/test_mix.h
index 82b3d7f..d2299fe 100644
--- a/bbq/tests/common/test_mix.h
+++ b/bbq/tests/common/test_mix.h
@@ -1,6 +1,6 @@
/*
* @Author: liuyu
- * @LastEditTime: 2024-06-11 11:48:13
+ * @LastEditTime: 2024-06-17 18:13:32
* @Describe: TODO
*/
@@ -18,8 +18,6 @@
#include <stdatomic.h>
#endif
-#define TEST_TABLE_DATA_MAGIC 12345
-
typedef enum {
TEST_THREAD_PRODUCER,
TEST_THREAD_CONSUMER,
@@ -110,6 +108,30 @@ typedef enum {
TEST_MODULE_MAX,
} test_module_e;
+#ifdef TEST_DEBUG
+#define TEST_DBG_LOG(fmt, ...) \
+ do { \
+ printf("[DBG][%s:%d:%s]" fmt "\n", __func__, __LINE__, __FILE__, ##__VA_ARGS__); \
+ } while (0)
+
+#else
+#define TEST_DBG_LOG(fmt, ...) \
+ do { \
+ } while (0)
+#endif
+
+#define TEST_ERR_LOG(fmt, ...) \
+ do { \
+ printf("\x1b[31m [ERR][%s:%d:%s]" fmt "\x1b[0m\n", __func__, __LINE__, __FILE__, ##__VA_ARGS__); \
+ } while (0)
+
+#define TEST_INFO_LOG(fmt, ...) \
+ do { \
+ printf("[INFO][%s:%d:%s]" fmt "\n", __func__, __LINE__, __FILE__, ##__VA_ARGS__); \
+ } while (0)
+
+#define TEST_AVOID_WARNING(param) ((void)param)
+
extern test_time_metric test_clock_time_get();
extern test_time_metric test_clock_time_sub(test_time_metric now, test_time_metric last);
extern int test_load_config(const char *config, const char *ring_type, uint32_t burst_cnt, test_cfg *cfg);
@@ -121,12 +143,63 @@ extern char *test_ring_type_enum2str(test_ring_type ring_type);
extern uint64_t test_clock_time_to_ns(test_time_metric *metric);
extern double test_clock_time_to_double(test_time_metric *metric);
extern void *test_malloc(test_module_e module, size_t size);
-extern void *test_calloc(test_module_e module, size_t size);
extern void test_free(test_module_e module, void *ptr);
-extern void test_memory_info();
+extern void test_memory_counter_print();
extern void test_memory_counter_clear();
extern bool test_malloc_free_equal();
-extern uint16_t **test_enqueue_table_create(uint32_t count);
-extern void test_enqueue_table_destory(uint16_t **table, uint32_t count);
extern int test_setaffinity(int core_id);
+
+#define TEST_PTR_ARRAY_DATA_INIT(table, t_type, t_count) \
+ do { \
+ if (table != NULL) { \
+ memset(table, 0, sizeof(t_type *) * t_count); \
+ for (uint32_t i = 0; i < t_count; i++) { \
+ table[i] = (t_type *)test_malloc(TEST_MODULE_TABLE, sizeof(t_type)); \
+ if (table[i] == NULL) { \
+ for (uint32_t j = 0; j < i; j++) { \
+ test_free(TEST_MODULE_TABLE, table[j]); \
+ table[j] = NULL; \
+ } \
+ test_free(TEST_MODULE_TABLE, table); \
+ break; \
+ } \
+ *table[i] = (t_type)TEST_DATA_MAGIC; \
+ } \
+ } \
+ } while (0)
+
+#define TEST_PTR_ARRAY_DATA_DESTORY(table, t_count) \
+ do { \
+ if (table != NULL) { \
+ for (uint32_t i = 0; i < t_count; i++) { \
+ test_free(TEST_MODULE_TABLE, table[i]); \
+ table[i] = NULL; \
+ } \
+ } \
+ } while (0)
+
+#define TEST_DOUBLE_PTR_DATA_INIT(table, t_type, t_count) \
+ do { \
+ table = (t_type **)test_malloc(TEST_MODULE_TABLE, sizeof(t_type *) * t_count); \
+ if (table != NULL) { \
+ TEST_PTR_ARRAY_DATA_INIT(table, t_type, t_count); \
+ } \
+ } while (0)
+
+#define TEST_DOUBLE_PTR_DATA_DESTORY(table, t_count) \
+ do { \
+ if (table != NULL) { \
+ TEST_PTR_ARRAY_DATA_DESTORY(table, t_count); \
+ test_free(TEST_MODULE_TABLE, table); \
+ table = NULL; \
+ } \
+ } while (0)
+
+#define TEST_ARRAY_DATA_INIT(table, t_count) \
+ do { \
+ for (int i = 0; i < t_count; i++) { \
+ table[i] = TEST_DATA_MAGIC; \
+ } \
+ } while (0)
+
#endif \ No newline at end of file
diff --git a/bbq/tests/common/test_queue.c b/bbq/tests/common/test_queue.c
index 6b57df7..9a96e33 100644
--- a/bbq/tests/common/test_queue.c
+++ b/bbq/tests/common/test_queue.c
@@ -1,69 +1,68 @@
/*
* @Author: liuyu
- * @LastEditTime: 2024-06-13 23:25:09
+ * @LastEditTime: 2024-06-18 04:11:12
* @Describe: TODO
*/
#include "test_queue.h"
-#include <sys/prctl.h>
-#include <unistd.h>
#include "bbq.h"
#include "test_mix.h"
-extern bool bbq_check_array_bounds(bbq_queue_s* q);
+#include <sys/prctl.h>
+#include <unistd.h>
+extern bool bbq_check_array_bounds(struct bbq_s *q);
+extern struct bbq_s *bbq_ring_create_bnbs(uint32_t bn, uint32_t bs, size_t obj_size, unsigned int flags);
+extern struct bbq_s *bbq_ring_create_bnbs_with_socket(uint32_t bn, uint32_t bs, size_t obj_size, int socket_id, unsigned int flags);
-uint32_t test_bbq_enqueue_burst(void* ring, void* obj_table, uint32_t n, uint16_t thread_idx) {
- return bbq_enqueue_burst_two_dimensional(ring, obj_table, n);
+uint32_t test_bbq_enqueue_burst(void *ring, void **obj_table, uint32_t n, uint16_t thread_idx) {
+ TEST_AVOID_WARNING(thread_idx);
+ return bbq_enqueue_burst_ptr(ring, obj_table, n);
}
-int test_queue_init_bbq(test_cfg* cfg, test_queue_s* q) {
- bbq_queue_s* ring;
+int test_queue_init_bbq(test_cfg *cfg, test_queue_s *q) {
size_t obj_size = sizeof(test_data);
if (cfg->ring.block_count == 0) {
- q->ring = bbq_ring_create_with_socket(cfg->ring.entries_cnt, obj_size, 0, BBQ_F_POLICY_RETRY_NEW | BBQ_F_COPY_POINTER);
+ q->ring = bbq_create_with_socket(cfg->ring.entries_cnt, obj_size, 0, BBQ_CREATE_F_RETRY_NEW | BBQ_CREATE_F_COPY_PTR);
} else {
q->ring = bbq_ring_create_bnbs_with_socket(cfg->ring.block_count,
cfg->ring.entries_cnt / cfg->ring.block_count,
obj_size,
- 0, BBQ_F_POLICY_RETRY_NEW | BBQ_F_COPY_POINTER);
+ 0, BBQ_CREATE_F_RETRY_NEW | BBQ_CREATE_F_COPY_PTR);
}
if (q->ring == NULL) {
- BBQ_ERR_LOG("bbq create queue failed");
+ TEST_ERR_LOG("bbq create queue failed");
return BBQ_NULL_PTR;
}
- bbq_queue_s* bbq_ring = (bbq_queue_s*)q->ring;
- BBQ_DBG_LOG("block number:%lu size:%lu", bbq_ring->bn, bbq_ring->bs);
-
q->ring_free_f = (test_ring_free_f)bbq_ring_free;
q->enqueue_f = (test_ring_enqueue_f)bbq_enqueue;
q->dequeue_f = (test_ring_dequeue_f)bbq_dequeue;
- q->dequeue_burst_f = (test_dequeue_burst_f)bbq_dequeue_burst_two_dimensional;
+ q->dequeue_burst_f = (test_dequeue_burst_f)bbq_dequeue_burst_ptr;
q->enqueue_burst_f = (test_enqueue_burst_f)test_bbq_enqueue_burst;
return 0;
}
-void test_queue_destory(test_queue_s* q) {
+void test_queue_destory(test_queue_s *q) {
if (q != NULL && q->ring_free_f != NULL) {
q->ring_free_f(q->ring);
}
}
-bool test_all_producer_exit(test_info_s* test_info) {
+bool test_all_producer_exit(test_info_s *test_info) {
return atomic_load(&test_info->ctl.producer_exit) == test_info->cfg.ring.producer_cnt;
}
-void test_wait_all_threads_ready(test_ctl* ctl) {
+void test_wait_all_threads_ready(test_ctl *ctl) {
pthread_barrier_wait(&ctl->all_threads_start);
- BBQ_DBG_LOG("thread init done!");
+ TEST_DBG_LOG("thread init done!");
}
-test_exit_data* test_exit_data_create(test_thread_arg_s* t_arg) {
- test_exit_data* exit_data = (test_exit_data*)test_malloc(TEST_MODULE_COMMON, sizeof(test_exit_data));
+test_exit_data *test_exit_data_create(test_thread_arg_s *t_arg) {
+ test_exit_data *exit_data = (test_exit_data *)test_malloc(TEST_MODULE_COMMON, sizeof(test_exit_data));
if (exit_data == NULL) {
- BBQ_ERR_LOG("malloc failed");
+ TEST_ERR_LOG("malloc failed");
exit(-1);
}
@@ -72,7 +71,7 @@ test_exit_data* test_exit_data_create(test_thread_arg_s* t_arg) {
exit_data->simple_data = test_data_create(size);
if (exit_data->simple_data == NULL) {
- BBQ_ERR_LOG("malloc failed");
+ TEST_ERR_LOG("malloc failed");
exit(-1);
}
exit_data->arg = t_arg;
@@ -83,14 +82,14 @@ test_exit_data* test_exit_data_create(test_thread_arg_s* t_arg) {
return exit_data;
}
-test_exit_data* test_exit_data_destory(test_exit_data* data) {
+void test_exit_data_destory(test_exit_data *data) {
test_data_destory(data->simple_data, data->simple_data_cnt);
test_free(TEST_MODULE_COMMON, data->arg);
test_free(TEST_MODULE_COMMON, data);
}
-test_data** test_data_create(size_t cnt) {
- test_data** simple_data = test_malloc(TEST_MODULE_DATA, sizeof(*simple_data) * cnt);
+test_data **test_data_create(size_t cnt) {
+ test_data **simple_data = test_malloc(TEST_MODULE_DATA, sizeof(*simple_data) * cnt);
test_time_metric enqueue_time = test_clock_time_get();
for (size_t i = 0; i < cnt; i++) {
simple_data[i] = test_malloc(TEST_MODULE_DATA, sizeof(*simple_data[i]));
@@ -101,42 +100,41 @@ test_data** test_data_create(size_t cnt) {
return simple_data;
}
-void test_data_destory(test_data** data, size_t cnt) {
+void test_data_destory(test_data **data, size_t cnt) {
for (size_t i = 0; i < cnt; i++) {
test_free(TEST_MODULE_DATA, data[i]);
}
test_free(TEST_MODULE_DATA, data);
}
-uint32_t test_exec_enqueue(test_queue_s* q, test_data** data, size_t burst_cnt, test_time_metric* op_use_diff, uint16_t thread_idx) {
+uint32_t test_exec_enqueue(test_queue_s *q, test_data **data, size_t burst_cnt, test_time_metric *op_use_diff, uint16_t thread_idx) {
uint32_t enqueue_cnt = 0;
test_time_metric op_use_start = test_clock_time_get();
- enqueue_cnt = q->enqueue_burst_f(q->ring, data, burst_cnt, thread_idx);
+ enqueue_cnt = q->enqueue_burst_f(q->ring, (void **)data, burst_cnt, thread_idx);
*op_use_diff = test_clock_time_sub(test_clock_time_get(), op_use_start);
return enqueue_cnt;
}
-uint32_t test_exec_dequeue(test_queue_s* q, test_data** data, size_t burst_cnt, test_time_metric* op_use_diff) {
+uint32_t test_exec_dequeue(test_queue_s *q, test_data **data, size_t burst_cnt, test_time_metric *op_use_diff) {
uint32_t dequeue_cnt = 0;
test_time_metric op_use_start = test_clock_time_get();
- dequeue_cnt = q->dequeue_burst_f(q->ring, (void**)data, burst_cnt);
+ dequeue_cnt = q->dequeue_burst_f(q->ring, (void **)data, burst_cnt);
*op_use_diff = test_clock_time_sub(test_clock_time_get(), op_use_start);
return dequeue_cnt;
}
-void* test_thread_producer_start(void* arg) {
- int ret = 0;
+void *test_thread_producer_start(void *arg) {
uint32_t enqueue_cnt = 0;
uint64_t ok_cnt = 0;
uint64_t run_times = 0;
- test_thread_arg_s* t_arg = (test_thread_arg_s*)arg;
- test_info_s* test_info = t_arg->test_info;
- test_cfg* cfg = &test_info->cfg;
- test_queue_s* q = t_arg->q;
- test_exit_data* exit_data = test_exit_data_create(t_arg);
+ test_thread_arg_s *t_arg = (test_thread_arg_s *)arg;
+ test_info_s *test_info = t_arg->test_info;
+ test_cfg *cfg = &test_info->cfg;
+ test_queue_s *q = t_arg->q;
+ test_exit_data *exit_data = test_exit_data_create(t_arg);
char thread_name[128] = {0};
uint64_t op_ok_latency_ns = 0;
@@ -144,10 +142,10 @@ void* test_thread_producer_start(void* arg) {
uint64_t run_ok_times = cfg->run.run_ok_times / cfg->ring.producer_cnt;
test_time_metric op_latency = {0};
- snprintf(thread_name, sizeof(thread_name), "producer:%x", exit_data->thread_id);
+ snprintf(thread_name, sizeof(thread_name), "producer:%lu", exit_data->thread_id);
prctl(PR_SET_NAME, thread_name);
if (test_setaffinity(t_arg->core) != BBQ_OK) {
- BBQ_ERR_LOG("test_setaffinity error");
+ TEST_ERR_LOG("test_setaffinity error");
exit(-1);
}
@@ -164,9 +162,9 @@ void* test_thread_producer_start(void* arg) {
enqueue_cnt = test_exec_enqueue(q, exit_data->simple_data, cfg->ring.burst_cnt, &op_latency, t_arg->thread_idx);
} else {
// 由于rmind不支持指定个数的批量出队列,为了兼容它,这里分配的空间位置entries大小。
- test_data** data = test_data_create(cfg->ring.entries_cnt);
+ test_data **data = test_data_create(cfg->ring.entries_cnt);
if (data == NULL) {
- BBQ_ERR_LOG("malloc falied");
+ TEST_ERR_LOG("malloc falied");
exit(-1);
}
enqueue_cnt = test_exec_enqueue(q, data, cfg->ring.burst_cnt, &op_latency, t_arg->thread_idx);
@@ -195,31 +193,31 @@ void* test_thread_producer_start(void* arg) {
exit_data->op_err_latency_ns = op_err_latency_ns;
atomic_fetch_add(&test_info->ctl.producer_exit, 1);
- BBQ_DBG_LOG("producer-----> en_ok:%lu", ok_cnt);
+ TEST_DBG_LOG("producer-----> en_ok:%lu", ok_cnt);
pthread_exit(exit_data);
}
-void* test_thread_consumer_start(void* arg) {
+void *test_thread_consumer_start(void *arg) {
uint32_t deq_cnt = -1;
uint64_t ok_cnt = 0;
uint64_t run_times = 0;
- test_thread_arg_s* t_arg = (test_thread_arg_s*)arg;
- test_info_s* test_info = t_arg->test_info;
- test_cfg* cfg = &test_info->cfg;
- test_queue_s* q = t_arg->q;
- test_exit_data* exit_data = test_exit_data_create(t_arg);
+ test_thread_arg_s *t_arg = (test_thread_arg_s *)arg;
+ test_info_s *test_info = t_arg->test_info;
+ test_cfg *cfg = &test_info->cfg;
+ test_queue_s *q = t_arg->q;
+ test_exit_data *exit_data = test_exit_data_create(t_arg);
uint64_t latency_ns = 0;
test_time_metric op_latency = {0};
- uint64_t op_ok_latency_ns;
+ uint64_t op_ok_latency_ns = 0;
uint64_t op_err_latency_ns = 0;
uint64_t data_error_cnt = 0;
char thread_name[128] = {0};
- test_data** deq_data = test_malloc(TEST_MODULE_DATA, sizeof(*deq_data) * cfg->ring.entries_cnt);
+ test_data **deq_data = test_malloc(TEST_MODULE_DATA, sizeof(*deq_data) * cfg->ring.entries_cnt);
- snprintf(thread_name, sizeof(thread_name), "consumer:%x", exit_data->thread_id);
+ snprintf(thread_name, sizeof(thread_name), "consumer:%lu", exit_data->thread_id);
prctl(PR_SET_NAME, thread_name);
if (test_setaffinity(t_arg->core) != BBQ_OK) {
- BBQ_ERR_LOG("test_setaffinity error");
+ TEST_ERR_LOG("test_setaffinity error");
exit(-1);
}
@@ -239,21 +237,21 @@ void* test_thread_consumer_start(void* arg) {
deq_cnt = test_exec_dequeue(q, deq_data, cfg->ring.burst_cnt, &op_latency);
if (deq_cnt > 0) {
for (uint32_t i = 0; i < deq_cnt; i++) {
- test_data* data = deq_data[i];
+ test_data *data = deq_data[i];
if (cfg->ring.workload == TEST_WORKLOAD_SIMPLE) {
if (data->data != TEST_DATA_MAGIC) {
- BBQ_ERR_LOG("the obtained data is not consistent with the expectation, expect:%u actual:%u", TEST_DATA_MAGIC, data->data);
+ TEST_ERR_LOG("the obtained data is not consistent with the expectation, expect:%u actual:%u", TEST_DATA_MAGIC, data->data);
exit_data->data_error_cnt += 1;
}
} else {
test_time_metric latency = test_clock_time_sub(test_clock_time_get(), data->enqueue_time);
if (test_clock_time_is_zero(&data->enqueue_time)) {
- BBQ_ERR_LOG("enqueue_time is 0");
+ TEST_ERR_LOG("enqueue_time is 0");
exit(-1);
}
if (data->data != TEST_DATA_MAGIC) {
- BBQ_ERR_LOG("the obtained data is not consistent with the expectation, expect:%u actual:%u", TEST_DATA_MAGIC, data->data);
+ TEST_ERR_LOG("the obtained data is not consistent with the expectation, expect:%u actual:%u", TEST_DATA_MAGIC, data->data);
data_error_cnt += 1;
}
@@ -279,26 +277,24 @@ void* test_thread_consumer_start(void* arg) {
exit_data->data_error_cnt = data_error_cnt;
test_free(TEST_MODULE_DATA, deq_data);
- BBQ_DBG_LOG("consumer-----> de_ok:%lu", ok_cnt);
+ TEST_DBG_LOG("consumer-----> de_ok:%lu", ok_cnt);
pthread_exit(exit_data);
}
-void test_wait_all_threads_exit(test_info_s* test_info, uint32_t thread_cnt, pthread_t* threads, test_exit_data** exit_data) {
+void test_wait_all_threads_exit(test_info_s *test_info, uint32_t thread_cnt, pthread_t *threads, test_exit_data **exit_data) {
if (test_info->cfg.run.run_time > 0) {
- BBQ_DBG_LOG("sleep %lus, and notify all threads to exit...", test_info->cfg.run.run_time);
+ TEST_DBG_LOG("sleep %lus, and notify all threads to exit...", test_info->cfg.run.run_time);
sleep(test_info->cfg.run.run_time);
test_info->ctl.running = false;
}
for (uint32_t i = 0; i < thread_cnt; i++) {
- pthread_join(threads[i], (void**)(&exit_data[i])); // 等待每个线程结束
+ pthread_join(threads[i], (void **)(&exit_data[i])); // 等待每个线程结束
}
}
-
-pthread_t*
-test_one_thread_create(test_info_s* test_info, test_queue_s* q, test_thread_type_e ttype, int core, uint16_t thread_id, pthread_t* thread) {
- BBQ_DBG_LOG("thread type:%d core:%d", ttype, core);
- test_thread_arg_s* arg = (test_thread_arg_s*)test_malloc(TEST_MODULE_COMMON, sizeof(test_thread_arg_s)); // 线程回收时free
+void test_one_thread_create(test_info_s *test_info, test_queue_s *q, test_thread_type_e ttype, int core, uint16_t thread_id, pthread_t *thread) {
+ TEST_DBG_LOG("thread type:%d core:%d", ttype, core);
+ test_thread_arg_s *arg = (test_thread_arg_s *)test_malloc(TEST_MODULE_COMMON, sizeof(test_thread_arg_s)); // 线程回收时free
arg->test_info = test_info;
arg->q = q;
arg->ttype = ttype;
@@ -317,14 +313,13 @@ test_one_thread_create(test_info_s* test_info, test_queue_s* q, test_thread_type
core_id = (core_id + 1) < max_id ? (core_id + 1) : core_id; \
} while (0)
-pthread_t* test_threads_create(test_info_s* test_info, test_queue_s* q) {
+pthread_t *test_threads_create(test_info_s *test_info, test_queue_s *q) {
// 创建生产者消费者线程
- int ret;
uint16_t thread_id = 0;
int core_id = 0;
- test_cfg* cfg = &test_info->cfg;
+ test_cfg *cfg = &test_info->cfg;
size_t thread_cnt = cfg->ring.producer_cnt + cfg->ring.consumer_cnt;
- pthread_t* threads = (pthread_t*)test_malloc(TEST_MODULE_COMMON, sizeof(pthread_t) * thread_cnt); // 存储所有线程ID的数组
+ pthread_t *threads = (pthread_t *)test_malloc(TEST_MODULE_COMMON, sizeof(pthread_t) * thread_cnt); // 存储所有线程ID的数组
pthread_barrier_init(&test_info->ctl.all_threads_start, NULL, thread_cnt);
test_info->ctl.running = true;
@@ -337,7 +332,7 @@ pthread_t* test_threads_create(test_info_s* test_info, test_queue_s* q) {
// SPMC,第一个核心给生产者,其他分配给消费者
test_one_thread_create(test_info, q, TEST_THREAD_PRODUCER, core_id, thread_id, &(threads[thread_id]));
thread_id++;
- for (int i = 0; i < cfg->ring.consumer_cnt; i++) {
+ for (uint32_t i = 0; i < cfg->ring.consumer_cnt; i++) {
CORE_ID_CHK_SET(core_id, cfg->base.cores_cnt);
test_one_thread_create(test_info, q, TEST_THREAD_CONSUMER, core_id, thread_id, &(threads[thread_id]));
thread_id++;
@@ -346,15 +341,15 @@ pthread_t* test_threads_create(test_info_s* test_info, test_queue_s* q) {
// MPSC,第一个核心给消费者,其他分配给生产者
test_one_thread_create(test_info, q, TEST_THREAD_CONSUMER, core_id, thread_id, &(threads[thread_id]));
thread_id++;
- for (int i = 0; i < cfg->ring.producer_cnt; i++) {
+ for (uint32_t i = 0; i < cfg->ring.producer_cnt; i++) {
CORE_ID_CHK_SET(core_id, cfg->base.cores_cnt);
test_one_thread_create(test_info, q, TEST_THREAD_PRODUCER, core_id, thread_id, &(threads[thread_id]));
thread_id++;
}
} else {
// MPMC 或 只有生产者 或这有消费者,核心交错分配
- uint32_t pcnt = cfg->ring.producer_cnt; // 生产者个数
- uint32_t ccnt = cfg->ring.consumer_cnt; // 消费者个数
+ uint32_t pcnt = cfg->ring.producer_cnt; // 生产者个数
+ uint32_t ccnt = cfg->ring.consumer_cnt; // 消费者个数
for (core_id = 0; core_id < cfg->base.cores_cnt && pcnt > 0 && ccnt > 0;) {
if ((core_id & 1) == 0) {
// 偶数
@@ -369,13 +364,13 @@ pthread_t* test_threads_create(test_info_s* test_info, test_queue_s* q) {
CORE_ID_CHK_SET(core_id, cfg->base.cores_cnt);
}
- for (int i = 0; i < pcnt; i++) {
+ for (uint32_t i = 0; i < pcnt; i++) {
test_one_thread_create(test_info, q, TEST_THREAD_PRODUCER, core_id, thread_id, &(threads[thread_id]));
thread_id++;
CORE_ID_CHK_SET(core_id, cfg->base.cores_cnt);
}
- for (int i = 0; i < ccnt; i++) {
+ for (uint32_t i = 0; i < ccnt; i++) {
test_one_thread_create(test_info, q, TEST_THREAD_CONSUMER, core_id, thread_id, &(threads[thread_id]));
thread_id++;
CORE_ID_CHK_SET(core_id, cfg->base.cores_cnt);
@@ -385,12 +380,12 @@ pthread_t* test_threads_create(test_info_s* test_info, test_queue_s* q) {
return threads;
}
-void test_threads_destory(test_info_s* test_info, pthread_t* threads) {
+void test_threads_destory(test_info_s *test_info, pthread_t *threads) {
pthread_barrier_destroy(&test_info->ctl.all_threads_start);
test_free(TEST_MODULE_COMMON, threads);
}
-void test_merge_data_detail(test_merge_data* merge, test_exit_data* exit_data) {
+void test_merge_data_detail(test_merge_data *merge, test_exit_data *exit_data) {
merge->run_times += exit_data->run_times;
merge->ok_cnt += exit_data->ok_cnt;
merge->latency_ns += exit_data->latency_ns;
@@ -399,7 +394,7 @@ void test_merge_data_detail(test_merge_data* merge, test_exit_data* exit_data) {
merge->data_error_cnt += exit_data->data_error_cnt;
}
-void test_merge_all_data(test_exit_data** exit_data, uint32_t thread_cnt, test_merge_s* merge) {
+void test_merge_all_data(test_exit_data **exit_data, uint32_t thread_cnt, test_merge_s *merge) {
test_time_metric p_start = {0};
test_time_metric p_end = {0};
test_time_metric c_start = {0};
diff --git a/bbq/tests/common/test_queue.h b/bbq/tests/common/test_queue.h
index 22bce92..723f0b3 100644
--- a/bbq/tests/common/test_queue.h
+++ b/bbq/tests/common/test_queue.h
@@ -1,6 +1,6 @@
/*
* @Author: liuyu
- * @LastEditTime: 2024-06-13 18:59:37
+ * @LastEditTime: 2024-06-17 18:17:24
* @Describe: TODO
*/
@@ -10,12 +10,12 @@
#include "test_mix.h"
#include <pthread.h>
-#define TEST_DATA_MAGIC 1234567890
+#define TEST_DATA_MAGIC 0x1F // 为了兼容所有类型的数据,存储1字节大小的数据
typedef void (*test_ring_free_f)(void *ring);
typedef int (*test_ring_enqueue_f)(void *ring, void *obj);
typedef int (*test_ring_dequeue_f)(void *ring, void *obj);
-typedef uint32_t (*test_enqueue_burst_f)(void *ring, void *obj_table, uint32_t n, uint16_t thread_idx);
+typedef uint32_t (*test_enqueue_burst_f)(void *ring, void **obj_table, uint32_t n, uint16_t thread_idx);
typedef uint32_t (*test_dequeue_burst_f)(void *ring, void **obj_table, uint32_t n);
typedef bool (*test_ring_empty_f)(void *ring);
@@ -79,22 +79,22 @@ typedef struct {
extern void test_threads_destory(test_info_s *test_info, pthread_t *threads);
extern pthread_t *test_threads_create(test_info_s *test_info, test_queue_s *q);
-extern pthread_t *test_one_thread_create(test_info_s *test_info, test_queue_s *q, test_thread_type_e ttype, int core, uint16_t thread_id, pthread_t *thread);
+extern void test_one_thread_create(test_info_s *test_info, test_queue_s *q, test_thread_type_e ttype, int core, uint16_t thread_id, pthread_t *thread);
extern void test_wait_all_threads_exit(test_info_s *test_info, uint32_t thread_cnt, pthread_t *threads, test_exit_data **exit_data);
extern void *test_thread_consumer_start(void *arg);
extern void *test_thread_producer_start(void *arg);
extern uint32_t test_exec_dequeue(test_queue_s *q, test_data **data, size_t burst_cnt, test_time_metric *op_use_diff);
extern uint32_t test_exec_enqueue(test_queue_s *q, test_data **data, size_t burst_cnt, test_time_metric *op_use_diff, uint16_t thread_idx);
-extern test_exit_data *test_exit_data_destory(test_exit_data *data);
+extern void test_exit_data_destory(test_exit_data *data);
extern test_exit_data *test_exit_data_create(test_thread_arg_s *t_arg);
extern void test_wait_all_threads_ready(test_ctl *ctl);
extern void test_queue_destory(test_queue_s *q);
extern int test_queue_init_bbq(test_cfg *cfg, test_queue_s *q);
extern void test_merge_all_data(test_exit_data **exit_data, uint32_t thread_cnt, test_merge_s *merge);
-extern uint64_t bbq_idx(bbq_queue_s *q, uint64_t x);
-extern uint64_t bbq_off(bbq_queue_s *q, uint64_t x);
-extern uint64_t bbq_head_vsn(bbq_queue_s *q, uint64_t x);
-extern uint64_t bbq_cur_vsn(bbq_queue_s *q, uint64_t x);
+extern uint64_t bbq_idx(struct bbq_s *q, uint64_t x);
+extern uint64_t bbq_off(struct bbq_s *q, uint64_t x);
+extern uint64_t bbq_head_vsn(struct bbq_s *q, uint64_t x);
+extern uint64_t bbq_cur_vsn(struct bbq_s *q, uint64_t x);
extern test_data **test_data_create(size_t cnt);
extern void test_data_destory(test_data **data, size_t cnt);
#endif \ No newline at end of file
diff --git a/bbq/tests/unittest/ut.h b/bbq/tests/unittest/ut.h
index b733c9f..b36c2ee 100644
--- a/bbq/tests/unittest/ut.h
+++ b/bbq/tests/unittest/ut.h
@@ -1,6 +1,6 @@
/*
* @Author: liuyu
- * @LastEditTime: 2024-05-31 17:33:50
+ * @LastEditTime: 2024-06-14 15:56:17
* @Describe: TODO
*/
@@ -17,7 +17,7 @@ typedef struct {
} testdata_s;
typedef struct {
- bbq_queue_s *q;
+ struct bbq_s *q;
uint32_t usleep; // 该线程每次执行间隔睡眠时间
bool until_end; // 循环读取,直到队列空或满
uint64_t thread_exec_times; // 每个线程生产/消费次数
diff --git a/bbq/tests/unittest/ut_example.cc b/bbq/tests/unittest/ut_example.cc
index 943aeb8..fe78e03 100644
--- a/bbq/tests/unittest/ut_example.cc
+++ b/bbq/tests/unittest/ut_example.cc
@@ -1,14 +1,8 @@
/*
* @Author: liuyu
- * @LastEditTime: 2024-06-13 23:28:23
+ * @LastEditTime: 2024-06-18 15:11:23
- * @Describe: TODO
- */
-/*
- * @Author: liuyu
- * @LastEditTime: 2024-06-04 18:16:51
- * @Email: [email protected]
- * @Describe: 简单的测试用例,测试基本功能,同时让调用者快速上手
+ * @Describe: 简单的测试用例,测试基本功能
*/
#include "gtest/gtest.h"
@@ -17,154 +11,403 @@ extern "C" {
#include "test_queue.h"
#include "ut.h"
extern bool bbq_malloc_free_equal();
-extern void bbq_memory_info();
-extern bool bbq_check_array_bounds(bbq_queue_s* q);
+extern void bbq_memory_print();
+extern bool bbq_check_array_bounds(struct bbq_s *q);
+extern void bbq_struct_print(struct bbq_s *q);
+extern uint32_t bbq_enqueue_burst_ptr_one_dimensional(struct bbq_s *q, void const *obj_table, uint32_t n);
+extern uint32_t bbq_enqueue_burst_value_two_dimensional(struct bbq_s *q, void *const *obj_table, uint32_t n);
}
#define BUF_CNT 4096
-#define ENQ_TABLE1_CNT 4000
-#define ENQ_TABLE2_CNT 90
-#define ENQ_TABLE3_CNT 10
-TEST(burst, retry_new_cp_value) {
- test_memory_counter_clear();
- uint32_t ret1 = 0;
- uint32_t ret2 = 0;
- uint32_t ret3 = 0;
- bbq_queue_s* q;
+class bbq_example : public testing::Test {
+ protected:
+ virtual void SetUp() override {
+ // 1.清空内存malloc/free统计
+ test_memory_counter_clear();
+
+ // 2.入队空间初始化
+ TEST_DOUBLE_PTR_DATA_INIT(enq_table1, uint16_t, BUF_CNT);
+ TEST_PTR_ARRAY_DATA_INIT(enq_table2, uint16_t, BUF_CNT);
+ TEST_ARRAY_DATA_INIT(enq_table3, BUF_CNT);
+ }
+
+ virtual void TearDown() override {
+ // 1.释放测试数据
+ TEST_DOUBLE_PTR_DATA_DESTORY(enq_table1, BUF_CNT);
+ TEST_PTR_ARRAY_DATA_DESTORY(enq_table2, BUF_CNT);
+
+ // 2.内存泄漏检测
+ EXPECT_TRUE(bbq_malloc_free_equal());
+ EXPECT_TRUE(test_malloc_free_equal());
+ }
+
+ // 入队数据
+ uint16_t **enq_table1;
+ uint16_t *enq_table2[BUF_CNT];
+ uint16_t enq_table3[BUF_CNT];
+};
+
+TEST_F(bbq_example, single_retry_new_cp_ptr) {
+ int ret = 0;
+ uint64_t cnt = 0;
+ uint16_t *deq_data = NULL;
+
+ // 创建队列
+ struct bbq_s *q = bbq_create(BUF_CNT, sizeof(uint16_t), BBQ_CREATE_F_RETRY_NEW | BBQ_CREATE_F_COPY_PTR);
+ EXPECT_TRUE(q);
+
+ // 空队出队失败
+ EXPECT_EQ(bbq_dequeue(q, &deq_data), BBQ_QUEUE_EMPTY);
+
+ // 全部入队成功
+ for (uint32_t i = 0; i < 4000; i++) {
+ if (bbq_enqueue(q, &enq_table1[i]) == 0) {
+ cnt++;
+ }
+ }
- // 创建测试数据,3种数据类型,均将数据值入队列
- uint16_t** enq_table1 = test_enqueue_table_create(ENQ_TABLE1_CNT);
- uint16_t* enq_table2[ENQ_TABLE2_CNT] = {0};
- for (int i = 0; i < ENQ_TABLE2_CNT; i++) {
- enq_table2[i] = (uint16_t*)test_malloc(TEST_MODULE_DATA, sizeof(uint16_t));
- *enq_table2[i] = TEST_TABLE_DATA_MAGIC;
+ // 部分入队成功
+ for (uint32_t i = 0; i < 4000; i++) {
+ if (bbq_enqueue(q, &enq_table2[i]) == 0) {
+ cnt++;
+ }
}
- uint16_t enq_table3[ENQ_TABLE3_CNT];
- for (int i = 0; i < ENQ_TABLE3_CNT; i++) {
- enq_table3[i] = TEST_TABLE_DATA_MAGIC;
+
+ // 入队成功个数等于队列总数
+ EXPECT_EQ(cnt, BUF_CNT);
+
+ cnt = 0;
+ for (uint32_t i = 0; i < BUF_CNT; i++) {
+ ret = bbq_dequeue(q, &deq_data);
+ if (ret == 0) {
+ EXPECT_EQ(*deq_data, TEST_DATA_MAGIC);
+ cnt++;
+ }
}
+ // 全部出队成功
+ EXPECT_EQ(cnt, BUF_CNT);
+
+ // 空队出队失败
+ EXPECT_EQ(bbq_dequeue(q, &deq_data), BBQ_QUEUE_EMPTY);
+}
- uint16_t deq_table1[ENQ_TABLE1_CNT] = {0};
- uint16_t* deq_table2 = (uint16_t*)test_malloc(TEST_MODULE_DATA, sizeof(uint16_t) * BUF_CNT);
+TEST_F(bbq_example, single_retry_new_cp_value) {
+ int ret = 0;
+ uint64_t cnt = 0;
+ uint16_t deq_data;
// 创建队列
- q = bbq_ring_create(BUF_CNT, sizeof(uint16_t), BBQ_F_POLICY_RETRY_NEW | BBQ_F_COPY_VALUE);
+ struct bbq_s *q = bbq_create(BUF_CNT, sizeof(uint16_t), BBQ_CREATE_F_RETRY_NEW | BBQ_CREATE_F_COPY_VALUE);
EXPECT_TRUE(q);
- // 批量入队(全成功)
- ret1 = bbq_enqueue_burst_two_dimensional(q, (void**)enq_table1, ENQ_TABLE1_CNT);
- EXPECT_EQ(ret1, ENQ_TABLE1_CNT);
+ // 空队出队失败
+ EXPECT_EQ(bbq_dequeue(q, &deq_data), BBQ_QUEUE_EMPTY);
+
+ // 全部入队成功
+ for (uint32_t i = 0; i < 4000; i++) {
+ if (bbq_enqueue(q, enq_table1[i]) == 0) {
+ cnt++;
+ }
+ }
+
+ // 部分入队成功
+ for (uint32_t i = 0; i < 4000; i++) {
+ if (bbq_enqueue(q, enq_table2[i]) == 0) {
+ cnt++;
+ }
+ }
+
+ // 入队成功个数等于队列总数
+ EXPECT_EQ(cnt, BUF_CNT);
+
+ cnt = 0;
+ for (uint32_t i = 0; i < BUF_CNT; i++) {
+ ret = bbq_dequeue(q, &deq_data);
+ if (ret == 0) {
+ EXPECT_EQ(deq_data, TEST_DATA_MAGIC);
+ cnt++;
+ }
+ }
+ // 全部出队成功
+ EXPECT_EQ(cnt, BUF_CNT);
- // 批量入队(全成功)
- ret2 = bbq_enqueue_burst_two_dimensional(q, (void**)enq_table2, ENQ_TABLE2_CNT);
- EXPECT_EQ(ret2, ENQ_TABLE2_CNT);
+ // 空队出队失败
+ EXPECT_EQ(bbq_dequeue(q, &deq_data), BBQ_QUEUE_EMPTY);
+}
+
+TEST_F(bbq_example, single_drop_old_cp_pointer) {
+ int ret = 0;
+ uint64_t cnt = 0;
+ uint16_t *deq_data = NULL;
+ uint64_t first_cnt = BUF_CNT;
+ uint64_t second_cnt = 1000;
+
+ // 创建队列
+ struct bbq_s *q = bbq_create(BUF_CNT, sizeof(uint16_t), BBQ_CREATE_F_DROP_OLD | BBQ_CREATE_F_COPY_PTR);
+ EXPECT_TRUE(q);
+ EXPECT_LT(second_cnt, q->bs * q->bn);
+
+ // 空队出队失败
+ EXPECT_EQ(bbq_dequeue(q, &deq_data), BBQ_QUEUE_EMPTY);
+
+ // 全部入队成功,入队个数是BUF_CNT的整数倍,因此到了一个边界,刚好与消费者位置一致(套了loop圈)
+ uint32_t loop = 3;
+ for (uint32_t n = 0; n < loop; n++) {
+ for (uint32_t i = 0; i < first_cnt; i++) {
+ ret = bbq_enqueue(q, &enq_table1[i]);
+ if (ret == 0) {
+ cnt++;
+ }
+ }
+ }
+ EXPECT_EQ(cnt, first_cnt * loop);
+
+ // 全部入队成功
+ cnt = 0;
+ for (uint32_t i = 0; i < second_cnt; i++) {
+ if (bbq_enqueue(q, &enq_table2[i]) == 0) {
+ cnt++;
+ }
+ }
+ EXPECT_EQ(cnt, second_cnt);
+
+ cnt = 0;
+ for (uint32_t i = 0; i < BUF_CNT; i++) {
+ ret = bbq_dequeue(q, &deq_data);
+ if (ret == 0) {
+ EXPECT_EQ(*deq_data, TEST_DATA_MAGIC);
+ cnt++;
+ }
+ }
+
+ // 一旦生产者追上了消费者,之前未消费的,以及当前块的数据全都作废了。
+ EXPECT_EQ(cnt, second_cnt - q->bs);
+
+ // 空队出队失败
+ EXPECT_EQ(bbq_dequeue(q, &deq_data), BBQ_QUEUE_EMPTY);
+}
+
+TEST_F(bbq_example, single_drop_old_cp_value) {
+ int ret = 0;
+ uint64_t cnt = 0;
+ uint16_t deq_data;
+ uint64_t first_cnt = BUF_CNT;
+ uint64_t second_cnt = 1000;
+
+ // 创建队列
+ struct bbq_s *q = bbq_create(BUF_CNT, sizeof(uint16_t), BBQ_CREATE_F_DROP_OLD | BBQ_CREATE_F_COPY_VALUE);
+ EXPECT_TRUE(q);
+ EXPECT_LT(second_cnt, q->bs * q->bn);
+
+ // 空队出队失败
+ EXPECT_EQ(bbq_dequeue(q, &deq_data), BBQ_QUEUE_EMPTY);
+
+ // 全部入队成功,入队个数是BUF_CNT的整数倍,因此到了一个边界,刚好与消费者位置一致(套了loop圈)
+ uint32_t loop = 3;
+ for (uint32_t n = 0; n < loop; n++) {
+ for (uint32_t i = 0; i < first_cnt; i++) {
+ ret = bbq_enqueue(q, enq_table1[i]);
+ if (ret == 0) {
+ cnt++;
+ }
+ }
+ }
+ EXPECT_EQ(cnt, first_cnt * loop);
+
+ // 全部入队成功
+ cnt = 0;
+ for (uint32_t i = 0; i < second_cnt; i++) {
+ if (bbq_enqueue(q, enq_table2[i]) == 0) {
+ cnt++;
+ }
+ }
+ EXPECT_EQ(cnt, second_cnt);
+
+ cnt = 0;
+ for (uint32_t i = 0; i < BUF_CNT; i++) {
+ ret = bbq_dequeue(q, &deq_data);
+ if (ret == 0) {
+ EXPECT_EQ(deq_data, TEST_DATA_MAGIC);
+ cnt++;
+ }
+ }
+
+ // 一旦生产者追上了消费者,之前未消费的,以及当前块的数据全都作废了。
+ EXPECT_EQ(cnt, second_cnt - q->bs);
+
+ // 空队出队失败
+ EXPECT_EQ(bbq_dequeue(q, &deq_data), BBQ_QUEUE_EMPTY);
+}
+
+TEST_F(bbq_example, burst_retry_new_cp_value) {
+ struct bbq_s *q;
+ uint32_t ret1 = 0;
+ uint32_t ret2 = 0;
+ uint64_t first_cnt = 4000;
+ uint64_t second_cnt = 1000;
+
+ uint16_t deq_table1[BUF_CNT] = {0};
+ uint16_t *deq_table2 = (uint16_t *)test_malloc(TEST_MODULE_DATA, sizeof(uint16_t) * BUF_CNT);
+
+ // 创建队列
+ q = bbq_create(BUF_CNT, sizeof(uint16_t), BBQ_CREATE_F_RETRY_NEW | BBQ_CREATE_F_COPY_VALUE);
+ EXPECT_TRUE(q);
+ EXPECT_LT(first_cnt, q->bn * q->bs);
+
+ // 批量入队(全部成功)
+ // 推荐的函数,传入的数组地址连续,内部可以memcpy批量拷贝,速度快
+ ret1 = bbq_enqueue_burst_value(q, (void const *)enq_table3, first_cnt);
+ EXPECT_EQ(ret1, first_cnt);
// 批量入队(部分成功)
- ret3 = bbq_enqueue_burst_one_dimensional(q, (void*)enq_table3, ENQ_TABLE3_CNT);
- EXPECT_EQ(ret3, BUF_CNT - ret1 - ret2);
+ // 不推荐,但可用于特殊场景。由于需要将最终的值入队列,二维数组里的值不连续,需要循环赋值。
+ ret2 = bbq_enqueue_burst_value_two_dimensional(q, (void *const *)enq_table2, second_cnt);
+ EXPECT_EQ(ret2, BUF_CNT - ret1);
- /*------------------------------------------------------------------*/
- // 出队列(全成功)
- ret1 = bbq_dequeue_burst_one_dimensional(q, (void*)deq_table1, ENQ_TABLE1_CNT);
- EXPECT_EQ(ret1, ENQ_TABLE1_CNT);
+ // 出队列(全部成功)
+ ret1 = bbq_dequeue_burst_value(q, (void *)deq_table1, first_cnt);
+ EXPECT_EQ(ret1, first_cnt);
// 出队列(部分成功)
- ret2 = bbq_dequeue_burst_one_dimensional(q, (void*)deq_table2, BUF_CNT);
+ ret2 = bbq_dequeue_burst_value(q, (void *)deq_table2, second_cnt);
EXPECT_EQ(ret2, BUF_CNT - ret1);
// 验证数据
for (uint32_t i = 0; i < ret1; i++) {
- EXPECT_EQ(deq_table1[i], TEST_TABLE_DATA_MAGIC) << "i :" << i;
+ EXPECT_EQ(deq_table1[i], TEST_DATA_MAGIC) << "i :" << i;
}
for (uint32_t i = 0; i < ret2; i++) {
- EXPECT_EQ(deq_table2[i], TEST_TABLE_DATA_MAGIC) << "i :" << i;
+ EXPECT_EQ(deq_table2[i], TEST_DATA_MAGIC) << "i :" << i;
}
+
EXPECT_TRUE(bbq_check_array_bounds(q));
bbq_ring_free(q);
-
- // 释放测试数据
- test_enqueue_table_destory(enq_table1, ENQ_TABLE1_CNT);
- for (int i = 0; i < ENQ_TABLE2_CNT; i++) {
- test_free(TEST_MODULE_DATA, enq_table2[i]);
- }
test_free(TEST_MODULE_DATA, deq_table2);
- // 内存泄漏检测
- EXPECT_TRUE(bbq_malloc_free_equal());
- EXPECT_TRUE(test_malloc_free_equal());
}
-TEST(burst, retry_new_cp_pointer) {
- test_memory_counter_clear();
+TEST_F(bbq_example, burst_retry_new_cp_pointer) {
+ struct bbq_s *q;
uint32_t ret1 = 0;
uint32_t ret2 = 0;
- uint32_t ret3 = 0;
- bbq_queue_s* q;
-
- // 创建测试数据,3种数据类型,均将数据值入队列
- uint16_t** enq_table1 = test_enqueue_table_create(ENQ_TABLE1_CNT);
- uint16_t* enq_table2[ENQ_TABLE2_CNT] = {0};
- for (int i = 0; i < ENQ_TABLE2_CNT; i++) {
- enq_table2[i] = (uint16_t*)test_malloc(TEST_MODULE_DATA, sizeof(uint16_t));
- *enq_table2[i] = TEST_TABLE_DATA_MAGIC;
- }
- uint16_t enq_table3[ENQ_TABLE3_CNT];
- for (int i = 0; i < ENQ_TABLE3_CNT; i++) {
- enq_table3[i] = TEST_TABLE_DATA_MAGIC;
- }
+ uint64_t first_cnt = 4000;
+ uint64_t second_cnt = 1000;
- uint16_t* deq_table1[BUF_CNT] = {0};
- uint16_t* deq_table2[BUF_CNT] = {0};
- uint16_t** deq_table3 = (uint16_t**)malloc(sizeof(uint16_t*) * BUF_CNT);
+ uint16_t *deq_table1[BUF_CNT] = {0};
+ uint16_t **deq_table2 = (uint16_t **)test_malloc(TEST_MODULE_DATA, sizeof(uint16_t *) * BUF_CNT);
// 创建队列
- q = bbq_ring_create(BUF_CNT, sizeof(uint16_t), BBQ_F_POLICY_RETRY_NEW | BBQ_F_COPY_POINTER);
+ q = bbq_create(BUF_CNT, sizeof(uint16_t), BBQ_CREATE_F_RETRY_NEW | BBQ_CREATE_F_COPY_PTR);
EXPECT_TRUE(q);
+ EXPECT_LT(first_cnt, q->bn * q->bs);
- ret1 = bbq_enqueue_burst_two_dimensional(q, (void**)enq_table1, ENQ_TABLE1_CNT);
- EXPECT_EQ(ret1, ENQ_TABLE1_CNT);
+ // 批量入队(全部成功)
+ // 推荐的函数,传入的数组地址连续,内部可以memcpy批量拷贝,速度快
+ ret1 = bbq_enqueue_burst_ptr(q, (void *const *)enq_table1, first_cnt);
+ EXPECT_EQ(ret1, first_cnt);
- ret2 = bbq_enqueue_burst_two_dimensional(q, (void**)enq_table2, ENQ_TABLE2_CNT);
- EXPECT_EQ(ret2, ENQ_TABLE2_CNT);
-
- ret3 = bbq_enqueue_burst_one_dimensional(q, (void*)enq_table3, ENQ_TABLE3_CNT);
- EXPECT_EQ(ret3, BUF_CNT - ret1 - ret2);
-
- /*------------------------------------------------------------------*/
- ret1 = bbq_dequeue_burst_two_dimensional(q, (void**)deq_table1, ENQ_TABLE1_CNT);
- EXPECT_EQ(ret1, ENQ_TABLE1_CNT);
+ // 批量入队(部分成功)
+ // 不推荐,但可用于特殊场景。将数组成员的每个地址入队,需要循环取成员地址。
+ ret2 = bbq_enqueue_burst_ptr_one_dimensional(q, (const void *)enq_table3, second_cnt);
+ EXPECT_EQ(ret2, BUF_CNT - ret1);
- ret2 = bbq_dequeue_burst_two_dimensional(q, (void**)deq_table2, ENQ_TABLE2_CNT);
- EXPECT_EQ(ret2, ENQ_TABLE2_CNT);
+ // 出队列(全部成功)
+ ret1 = bbq_dequeue_burst_ptr(q, (void **)deq_table1, first_cnt);
+ EXPECT_EQ(ret1, first_cnt);
- ret3 = bbq_dequeue_burst_two_dimensional(q, (void**)deq_table3, ENQ_TABLE3_CNT);
- EXPECT_EQ(ret3, BUF_CNT - ret1 - ret2);
+ // 出队列(部分成功)
+ ret2 = bbq_dequeue_burst_ptr(q, (void **)deq_table2, second_cnt);
+ EXPECT_EQ(ret2, BUF_CNT - ret1);
// 验证数据
for (uint32_t i = 0; i < ret1; i++) {
- EXPECT_TRUE(deq_table1[i]);
- EXPECT_EQ(*deq_table1[i], TEST_TABLE_DATA_MAGIC) << "i :" << i;
+ EXPECT_EQ(*deq_table1[i], TEST_DATA_MAGIC) << "i :" << i;
}
for (uint32_t i = 0; i < ret2; i++) {
- EXPECT_TRUE(deq_table2[i]);
- EXPECT_EQ(*deq_table2[i], TEST_TABLE_DATA_MAGIC) << "i :" << i;
+ EXPECT_EQ(*deq_table2[i], TEST_DATA_MAGIC) << "i :" << i;
}
- for (uint32_t i = 0; i < ret3; i++) {
- EXPECT_TRUE(deq_table3[i]);
- EXPECT_EQ(*deq_table3[i], TEST_TABLE_DATA_MAGIC) << "i :" << i;
+ EXPECT_TRUE(bbq_check_array_bounds(q));
+ bbq_ring_free(q);
+ test_free(TEST_MODULE_DATA, deq_table2);
+}
+
+TEST_F(bbq_example, burst_drop_old_cp_pointer) {
+ struct bbq_s *q;
+ uint32_t ret1 = 0;
+ uint32_t ret2 = 0;
+ uint64_t first_cnt = BUF_CNT;
+ uint64_t second_cnt = 1000;
+
+ uint16_t *deq_table1[BUF_CNT] = {0};
+ uint16_t **deq_table2 = (uint16_t **)test_malloc(TEST_MODULE_DATA, sizeof(uint16_t *) * BUF_CNT);
+
+ // 创建队列
+ q = bbq_create(BUF_CNT, sizeof(uint16_t), BBQ_CREATE_F_DROP_OLD | BBQ_CREATE_F_COPY_PTR);
+ EXPECT_TRUE(q);
+ EXPECT_LT(second_cnt, q->bs * q->bn);
+
+ // 批量入队(全部成功)
+ // 推荐的函数,传入的数组地址连续,内部可以memcpy批量拷贝,速度快
+ ret1 = bbq_enqueue_burst_ptr(q, (void *const *)enq_table1, first_cnt);
+ EXPECT_EQ(ret1, first_cnt);
+
+ // 批量入队(全部成功),覆盖了旧数据
+ // 不推荐,但可用于特殊场景。将数组成员的每个地址入队,需要循环取成员地址。
+ ret2 = bbq_enqueue_burst_ptr_one_dimensional(q, (const void *)enq_table3, second_cnt);
+ EXPECT_EQ(ret2, second_cnt);
+
+ // 出队列(部分成功)
+ // 一旦生产者追上了消费者,之前未消费的,以及当前块的数据全都作废了。
+ ret1 = bbq_dequeue_burst_ptr(q, (void **)deq_table1, BUF_CNT);
+ EXPECT_EQ(ret1, second_cnt - q->bs);
+
+ // 验证数据
+ for (uint32_t i = 0; i < ret1; i++) {
+ EXPECT_EQ(*deq_table1[i], TEST_DATA_MAGIC) << "i :" << i;
}
+
EXPECT_TRUE(bbq_check_array_bounds(q));
bbq_ring_free(q);
+ test_free(TEST_MODULE_DATA, deq_table2);
+}
- // 释放测试数据
- test_enqueue_table_destory(enq_table1, ENQ_TABLE1_CNT);
- for (int i = 0; i < ENQ_TABLE2_CNT; i++) {
- test_free(TEST_MODULE_DATA, enq_table2[i]);
+TEST_F(bbq_example, burst_drop_old_cp_value) {
+ struct bbq_s *q;
+ uint32_t ret1 = 0;
+ uint32_t ret2 = 0;
+ uint64_t first_cnt = BUF_CNT;
+ uint64_t second_cnt = 1000;
+
+ uint16_t deq_table1[BUF_CNT] = {0};
+
+ // 创建队列
+ q = bbq_create(BUF_CNT, sizeof(uint16_t), BBQ_CREATE_F_DROP_OLD | BBQ_CREATE_F_COPY_VALUE);
+ EXPECT_TRUE(q);
+ EXPECT_LT(second_cnt, q->bs * q->bn);
+
+ // 批量入队(全部成功)
+ // 推荐的函数,传入的数组地址连续,内部可以memcpy批量拷贝,速度快
+ ret1 = bbq_enqueue_burst_value(q, (void const *)enq_table3, first_cnt);
+ EXPECT_EQ(ret1, first_cnt);
+
+ // 批量入队(全部成功),覆盖了旧数据
+ // 不推荐,但可用于特殊场景。将数组成员的每个地址入队,需要循环取成员地址。
+ ret2 = bbq_enqueue_burst_value_two_dimensional(q, (void *const *)enq_table1, second_cnt);
+ EXPECT_EQ(ret2, second_cnt);
+
+ // 出队列(部分成功)
+ // 一旦生产者追上了消费者,之前未消费的,以及当前块的数据全都作废了。
+ ret1 = bbq_dequeue_burst_value(q, (void *)deq_table1, BUF_CNT);
+ EXPECT_EQ(ret1, second_cnt - q->bs);
+
+ // 验证数据
+ for (uint32_t i = 0; i < ret1; i++) {
+ EXPECT_EQ(deq_table1[i], TEST_DATA_MAGIC) << "i :" << i;
}
- // 内存泄漏检测
- EXPECT_TRUE(bbq_malloc_free_equal());
- EXPECT_TRUE(test_malloc_free_equal());
+
+ EXPECT_TRUE(bbq_check_array_bounds(q));
+ bbq_ring_free(q);
} \ No newline at end of file
diff --git a/bbq/tests/unittest/ut_head_cursor.cc b/bbq/tests/unittest/ut_head_cursor.cc
index 6f6a42c..dd95e7e 100644
--- a/bbq/tests/unittest/ut_head_cursor.cc
+++ b/bbq/tests/unittest/ut_head_cursor.cc
@@ -1,6 +1,6 @@
/*
* @Author: liuyu
- * @LastEditTime: 2024-06-13 23:26:11
+ * @LastEditTime: 2024-06-17 11:15:19
* @Describe: TODO
*/
@@ -9,51 +9,66 @@ extern "C" {
#include "test_queue.h"
#include "ut.h"
extern bool bbq_malloc_free_equal();
-extern void bbq_memory_info();
-bool bbq_check_array_bounds(bbq_queue_s* q);
+extern void bbq_memory_print();
+extern bool bbq_check_array_bounds(struct bbq_s *q);
+extern struct bbq_s *bbq_ring_create_bnbs(uint32_t bn, uint32_t bs, size_t obj_size, unsigned int flags);
+extern struct bbq_s *bbq_ring_create_bnbs_with_socket(uint32_t bn, uint32_t bs, size_t obj_size, int socket_id, unsigned int flags);
}
-void expect_phead(bbq_queue_s* q, uint64_t idx, uint64_t vsn, int line) {
+class bbq_head_cursor : public testing::Test { // 继承了 testing::Test
+ protected:
+ virtual void SetUp() override {
+ // std::cout << "enter into SetUp()" << std::endl;
+ // 清空内存泄漏统计
+ test_memory_counter_clear();
+ }
+
+ virtual void TearDown() override {
+ // std::cout << "exit from TearDown" << std::endl;
+ // 内存泄漏检测
+ EXPECT_TRUE(bbq_malloc_free_equal());
+ EXPECT_TRUE(test_malloc_free_equal());
+ }
+};
+
+void expect_phead(struct bbq_s *q, uint64_t idx, uint64_t vsn, int line) {
EXPECT_EQ(bbq_idx(q, q->phead), idx) << "line: " << line;
EXPECT_EQ(bbq_head_vsn(q, q->phead), vsn) << "line: " << line;
}
-void expect_chead(bbq_queue_s* q, uint64_t idx, uint64_t vsn, int line) {
+void expect_chead(struct bbq_s *q, uint64_t idx, uint64_t vsn, int line) {
EXPECT_EQ(bbq_idx(q, q->chead), idx) << "line: " << line;
EXPECT_EQ(bbq_head_vsn(q, q->chead), vsn) << "line: " << line;
}
-void expect_eq_allocated(bbq_queue_s* q, bbq_block_s* block, uint64_t off, uint64_t vsn, int line) {
+void expect_eq_allocated(struct bbq_s *q, bbq_block_s *block, uint64_t off, uint64_t vsn, int line) {
EXPECT_EQ(bbq_off(q, block->allocated), off) << "line: " << line;
EXPECT_EQ(bbq_cur_vsn(q, block->allocated), vsn) << "line: " << line;
}
-void expect_eq_committed(bbq_queue_s* q, bbq_block_s* block, uint64_t off, uint64_t vsn, int line) {
+void expect_eq_committed(struct bbq_s *q, bbq_block_s *block, uint64_t off, uint64_t vsn, int line) {
EXPECT_EQ(bbq_off(q, block->committed), off) << "line: " << line;
EXPECT_EQ(bbq_cur_vsn(q, block->committed), vsn) << "line: " << line;
}
-void expect_eq_consumed(bbq_queue_s* q, bbq_block_s* block, uint64_t off, uint64_t vsn, int line) {
+void expect_eq_consumed(struct bbq_s *q, bbq_block_s *block, uint64_t off, uint64_t vsn, int line) {
EXPECT_EQ(bbq_off(q, block->consumed), off) << "line: " << line;
EXPECT_EQ(bbq_cur_vsn(q, block->consumed), vsn) << "line: " << line;
}
-void expect_eq_reserved(bbq_queue_s* q, bbq_block_s* block, uint64_t off, uint64_t vsn, int line) {
+void expect_eq_reserved(struct bbq_s *q, bbq_block_s *block, uint64_t off, uint64_t vsn, int line) {
EXPECT_EQ(bbq_off(q, block->reserved), off) << "line: " << line;
EXPECT_EQ(bbq_cur_vsn(q, block->reserved), vsn) << "line: " << line;
}
// 初始化状态
-TEST(head_cursor, init) {
+TEST_F(bbq_head_cursor, init) {
test_memory_counter_clear();
- int ret = 0;
- bbq_queue_s* q;
+ struct bbq_s *q;
uint32_t bn = 2;
uint32_t bs = 4;
- int enqueue_data = TEST_DATA_MAGIC;
-
- q = bbq_ring_create_bnbs(bn, bs, sizeof(int), BBQ_F_COPY_VALUE | BBQ_F_POLICY_RETRY_NEW);
+ q = bbq_ring_create_bnbs(bn, bs, sizeof(int), BBQ_CREATE_F_COPY_VALUE | BBQ_CREATE_F_RETRY_NEW);
EXPECT_TRUE(q);
// 1.初始化状态,除了第一个block外其他块的4个游标都指向最后一个条目
@@ -78,7 +93,7 @@ TEST(head_cursor, init) {
void ut_produce_something(uint32_t produce_cnt) {
int ret = 0;
- bbq_queue_s* q;
+ struct bbq_s *q;
uint32_t bn = 8;
uint32_t bs = 4096;
int enqueue_data = TEST_DATA_MAGIC;
@@ -87,7 +102,7 @@ void ut_produce_something(uint32_t produce_cnt) {
EXPECT_GT(produce_cnt, 0);
EXPECT_LE(produce_cnt, bs);
- q = bbq_ring_create_bnbs(bn, bs, sizeof(int), BBQ_F_COPY_VALUE | BBQ_F_POLICY_RETRY_NEW);
+ q = bbq_ring_create_bnbs(bn, bs, sizeof(int), BBQ_CREATE_F_COPY_VALUE | BBQ_CREATE_F_RETRY_NEW);
EXPECT_TRUE(q);
// 生产produce_cnt
@@ -127,7 +142,7 @@ void ut_produce_something(uint32_t produce_cnt) {
bbq_ring_free(q);
}
// 在第一块内生产,然后被消费完
-TEST(head_cursor, produce_something) {
+TEST_F(bbq_head_cursor, produce_something) {
test_memory_counter_clear();
ut_produce_something(1);
@@ -140,7 +155,7 @@ TEST(head_cursor, produce_something) {
void ut_produce_next_block(uint32_t over) {
int ret = 0;
- bbq_queue_s* q;
+ struct bbq_s *q;
uint32_t bn = 8;
uint32_t bs = 4096;
uint32_t produce_cnt = bs + over;
@@ -150,7 +165,7 @@ void ut_produce_next_block(uint32_t over) {
EXPECT_GT(over, 0);
EXPECT_LT(over, bs);
- q = bbq_ring_create_bnbs(bn, bs, sizeof(int), BBQ_F_COPY_VALUE | BBQ_F_POLICY_RETRY_NEW);
+ q = bbq_ring_create_bnbs(bn, bs, sizeof(int), BBQ_CREATE_F_COPY_VALUE | BBQ_CREATE_F_RETRY_NEW);
EXPECT_TRUE(q);
// 生产至第二块的第一个entry
@@ -195,7 +210,7 @@ void ut_produce_next_block(uint32_t over) {
}
// 第一块生产完毕,第二块生产了若干,然后被消费完
-TEST(head_cursor, produce_next_block) {
+TEST_F(bbq_head_cursor, produce_next_block) {
test_memory_counter_clear();
ut_produce_next_block(1);
@@ -208,14 +223,14 @@ TEST(head_cursor, produce_next_block) {
void ut_produce_all_loop(uint32_t loop) {
int ret = 0;
- bbq_queue_s* q;
+ struct bbq_s *q;
uint32_t bn = 8;
uint32_t bs = 4096;
uint32_t produce_cnt = bn * bs;
int enqueue_data = TEST_DATA_MAGIC;
int dequeue_data = 0;
- q = bbq_ring_create_bnbs(bn, bs, sizeof(int), BBQ_F_COPY_VALUE | BBQ_F_POLICY_RETRY_NEW);
+ q = bbq_ring_create_bnbs(bn, bs, sizeof(int), BBQ_CREATE_F_COPY_VALUE | BBQ_CREATE_F_RETRY_NEW);
EXPECT_TRUE(q);
for (uint32_t cnt = 0; cnt < loop; cnt++) {
@@ -253,7 +268,7 @@ void ut_produce_all_loop(uint32_t loop) {
}
// 完成多轮的满生产和满消费
-TEST(head_cursor, produce_all_loop) {
+TEST_F(bbq_head_cursor, produce_all_loop) {
test_memory_counter_clear();
ut_produce_all_loop(1);
@@ -264,22 +279,20 @@ TEST(head_cursor, produce_all_loop) {
EXPECT_TRUE(test_malloc_free_equal());
}
-TEST(boundary, retry_new_full_empty) {
+TEST_F(bbq_head_cursor, retry_new_full_empty) {
test_memory_counter_clear();
int ret = 0;
uint32_t entries_cnt = 4096;
uint32_t loop = 1000;
- bbq_queue_s* q;
+ struct bbq_s *q;
- int* data = (int*)test_malloc(TEST_MODULE_UTEST, sizeof(*data) * entries_cnt);
+ int *data = (int *)test_malloc(TEST_MODULE_UTEST, sizeof(*data) * entries_cnt);
int tmp_data = 0;
EXPECT_TRUE(data);
- q = bbq_ring_create(entries_cnt, sizeof(int), BBQ_F_COPY_VALUE | BBQ_F_POLICY_RETRY_NEW);
+ q = bbq_create(entries_cnt, sizeof(int), BBQ_CREATE_F_COPY_VALUE | BBQ_CREATE_F_RETRY_NEW);
EXPECT_TRUE(q);
- bool test = bbq_check_array_bounds(q);
-
for (uint32_t i = 0; i < loop; i++) {
// 入满队
for (uint32_t j = 0; j < entries_cnt; j++) {
@@ -333,12 +346,14 @@ TEST(boundary, retry_new_full_empty) {
EXPECT_TRUE(test_malloc_free_equal());
}
-TEST(boundary, mpsc_faa) {
+TEST_F(bbq_head_cursor, mpsc_faa) {
test_memory_counter_clear();
test_info_s test_info = {
.cfg = {
.base = {
+ .name = {},
+ .introduce = {},
.cores_cnt = 4,
},
.ring = {
@@ -351,10 +366,15 @@ TEST(boundary, mpsc_faa) {
.burst_cnt = 1,
},
.run = {
+ .run_ok_times = 0,
.run_time = 5,
},
},
- .ctl = {.running = true},
+ .ctl = {
+ .running = true,
+ .all_threads_start = {},
+ .producer_exit = {},
+ },
};
// 队列初始化
@@ -364,18 +384,20 @@ TEST(boundary, mpsc_faa) {
ASSERT_TRUE(ret == 0);
// 创建线程
- pthread_t* threads = test_threads_create(&test_info, &q);
+ pthread_t *threads = test_threads_create(&test_info, &q);
ASSERT_TRUE(threads);
// 等待所有线程完成,回收数据
uint32_t thread_cnt = test_info.cfg.ring.producer_cnt + test_info.cfg.ring.consumer_cnt;
- test_exit_data** exit_data = (test_exit_data**)test_malloc(TEST_MODULE_UTEST, sizeof(test_exit_data**) * (thread_cnt));
+ test_exit_data **exit_data = (test_exit_data **)test_malloc(TEST_MODULE_UTEST, sizeof(test_exit_data **) * (thread_cnt));
uint32_t i = 0;
test_wait_all_threads_exit(&test_info, thread_cnt, threads, exit_data);
// 比较数据
- test_merge_s merge = {0};
+ test_merge_s merge;
+ memset(&merge, 0, sizeof(merge));
+
test_merge_all_data(exit_data, thread_cnt, &merge);
EXPECT_EQ(merge.consumer.data_error_cnt, 0);
EXPECT_EQ(merge.consumer.ok_cnt, merge.producer.ok_cnt);
@@ -386,37 +408,22 @@ TEST(boundary, mpsc_faa) {
}
test_free(TEST_MODULE_UTEST, exit_data);
test_threads_destory(&test_info, threads);
- EXPECT_TRUE(bbq_check_array_bounds((bbq_queue_s*)q.ring));
+ EXPECT_TRUE(bbq_check_array_bounds((struct bbq_s *)q.ring));
test_queue_destory(&q);
EXPECT_TRUE(bbq_malloc_free_equal());
EXPECT_TRUE(test_malloc_free_equal());
}
-void debug_head_print(bbq_queue_s* q) {
- printf("phead vsn:%d idx:%d\n", bbq_head_vsn(q, q->phead), bbq_idx(q, q->phead));
- printf("chead vsn:%d idx:%d\n", bbq_head_vsn(q, q->chead), bbq_idx(q, q->chead));
-}
-
-void debug_block_print(bbq_queue_s* q) {
- for (int i = 0; i < q->bn; i++) {
- printf("[%d]zzzz allocated:vsn:%d off:%d\n", i, bbq_cur_vsn(q, q->blocks[i].allocated.load()), bbq_off(q, q->blocks[i].allocated.load()));
- printf("[%d]zzzz committed:%d off:%d\n", i, bbq_cur_vsn(q, q->blocks[i].committed.load()), bbq_off(q, q->blocks[i].committed.load()));
- printf("[%d]zzzz reserved:%d off:%d\n", i, bbq_cur_vsn(q, q->blocks[i].reserved.load()), bbq_off(q, q->blocks[i].reserved.load()));
- printf("[%d]zzzz consumed:%d off:%d\n\n", i, bbq_cur_vsn(q, q->blocks[i].consumed.load()), bbq_off(q, q->blocks[i].consumed.load()));
- }
-}
-
-TEST(boundary, drop_old_full_empty1) {
+TEST_F(bbq_head_cursor, drop_old_full_empty1) {
test_memory_counter_clear();
int ret = 0;
uint32_t bn = 2;
uint32_t bs = 4;
- uint32_t over_cnt = 3;
uint32_t loop = 1000;
- bbq_queue_s* q;
+ struct bbq_s *q;
int tmp_data = 0;
- q = bbq_ring_create_bnbs(bn, bs, sizeof(int), BBQ_F_COPY_VALUE | BBQ_F_POLICY_DROP_OLD);
+ q = bbq_ring_create_bnbs(bn, bs, sizeof(int), BBQ_CREATE_F_COPY_VALUE | BBQ_CREATE_F_DROP_OLD);
EXPECT_TRUE(q);
for (uint32_t j = 0; j < loop; j++) {
@@ -455,19 +462,19 @@ TEST(boundary, drop_old_full_empty1) {
EXPECT_TRUE(test_malloc_free_equal());
}
-TEST(boundary, drop_old_full_empty2) {
+TEST_F(bbq_head_cursor, drop_old_full_empty2) {
test_memory_counter_clear();
int ret = 0;
uint32_t bn = 2;
uint32_t bs = 4;
uint32_t loop = 1000;
uint32_t over_cnt = bs + 2;
- bbq_queue_s* q;
+ struct bbq_s *q;
EXPECT_EQ(over_cnt / bs, 1);
int tmp_data = 0;
- q = bbq_ring_create_bnbs(bn, bs, sizeof(int), BBQ_F_COPY_VALUE | BBQ_F_POLICY_DROP_OLD);
+ q = bbq_ring_create_bnbs(bn, bs, sizeof(int), BBQ_CREATE_F_COPY_VALUE | BBQ_CREATE_F_DROP_OLD);
EXPECT_TRUE(q);
// 入满队列,再入over_cnt
diff --git a/bbq/tests/unittest/ut_mix.cc b/bbq/tests/unittest/ut_mix.cc
index b279234..cb7c12a 100644
--- a/bbq/tests/unittest/ut_mix.cc
+++ b/bbq/tests/unittest/ut_mix.cc
@@ -1,22 +1,37 @@
/*
* @Author: liuyu
- * @LastEditTime: 2024-06-13 23:13:00
+ * @LastEditTime: 2024-06-17 11:14:19
* @Describe: bbq除了队列操作外,其他函数的测试
*/
#include "gtest/gtest.h"
extern "C" {
-#include <math.h>
#include "test_mix.h"
#include "ut.h"
+#include <math.h>
extern bool bbq_check_power_of_two(int n);
extern uint32_t bbq_blocks_calc(uint32_t entries);
extern unsigned ceil_log2(uint64_t x);
-extern uint64_t fetch_max(aotmic_uint64* atom, uint64_t upd);
+extern uint64_t fetch_max(aotmic_uint64 *atom, uint64_t upd);
extern bool bbq_malloc_free_equal();
extern bool test_malloc_free_equal();
}
-namespace {
+
+class bbq_mix : public testing::Test { // 继承了 testing::Test
+ protected:
+ virtual void SetUp() override {
+ // std::cout << "enter into SetUp()" << std::endl;
+ // 清空内存泄漏统计
+ test_memory_counter_clear();
+ }
+
+ virtual void TearDown() override {
+ // std::cout << "exit from TearDown" << std::endl;
+ // 内存泄漏检测
+ EXPECT_TRUE(bbq_malloc_free_equal());
+ EXPECT_TRUE(test_malloc_free_equal());
+ }
+};
typedef struct {
uint64_t thread_cnt;
@@ -24,43 +39,43 @@ typedef struct {
aotmic_uint64 ready_thread_cnt;
} ut_fetch_arg;
-void* fetch_max_thread_func(void* arg) {
- ut_fetch_arg* fetch_arg = (ut_fetch_arg*)arg;
+void *fetch_max_thread_func(void *arg) {
+ ut_fetch_arg *fetch_arg = (ut_fetch_arg *)arg;
fetch_arg->ready_thread_cnt.fetch_add(1);
while (fetch_arg->ready_thread_cnt.load() != fetch_arg->thread_cnt) {
}
- uint64_t* ret = (uint64_t*)test_malloc(TEST_MODULE_UTEST, sizeof(*ret));
+ uint64_t *ret = (uint64_t *)test_malloc(TEST_MODULE_UTEST, sizeof(*ret));
// 不同线程写入不同的>3的数
*ret = fetch_max(&fetch_arg->data, pthread_self() + 3);
pthread_exit(ret);
}
-TEST(bbq_mix, fetch_max) {
+TEST_F(bbq_mix, fetch_max) {
test_memory_counter_clear();
uint64_t ret = 0;
- ut_fetch_arg arg = {0};
- arg.data.store(1); // 初始化1
+ ut_fetch_arg arg = {};
+ arg.data.store(1); // 初始化1
arg.thread_cnt = 50;
- ret = fetch_max(&arg.data, 2); // max比较后设置为2
+ ret = fetch_max(&arg.data, 2); // max比较后设置为2
EXPECT_EQ(arg.data.load(), 2);
EXPECT_EQ(ret, 1);
- pthread_t* threads = (pthread_t*)test_malloc(TEST_MODULE_UTEST, sizeof(*threads) * arg.thread_cnt);
+ pthread_t *threads = (pthread_t *)test_malloc(TEST_MODULE_UTEST, sizeof(*threads) * arg.thread_cnt);
for (uint64_t i = 0; i < arg.thread_cnt; i++) {
// 多个线程同时fetch_max,输入 > 3的数据
- pthread_create(&threads[i], NULL, fetch_max_thread_func, (void*)&arg);
+ pthread_create(&threads[i], NULL, fetch_max_thread_func, (void *)&arg);
}
int eq_cnt = 0;
- for (int i = 0; i < arg.thread_cnt; i++) {
- uint64_t* tret;
- pthread_join(threads[i], (void**)&tret); // 等待每个线程结束
+ for (uint64_t i = 0; i < arg.thread_cnt; i++) {
+ uint64_t *tret;
+ pthread_join(threads[i], (void **)&tret); // 等待每个线程结束
if (*tret == 2) {
- eq_cnt++; // 统计返回2的个数
+ eq_cnt++; // 统计返回2的个数
}
test_free(TEST_MODULE_UTEST, tret);
}
@@ -71,7 +86,7 @@ TEST(bbq_mix, fetch_max) {
EXPECT_TRUE(test_malloc_free_equal());
}
-TEST(bbq_mix, power_of_two) {
+TEST_F(bbq_mix, power_of_two) {
test_memory_counter_clear();
uint32_t tmp = 0;
@@ -83,7 +98,7 @@ TEST(bbq_mix, power_of_two) {
for (uint32_t val = 5; val < max; val *= tmp) {
EXPECT_FALSE(bbq_check_power_of_two(val));
if (val >= max / tmp) {
- break; // 即将越界
+ break; // 即将越界
}
}
@@ -98,7 +113,7 @@ TEST(bbq_mix, power_of_two) {
EXPECT_TRUE(test_malloc_free_equal());
}
-TEST(bbq_mix, bbq_blocks_calc) {
+TEST_F(bbq_mix, bbq_blocks_calc) {
test_memory_counter_clear();
uint32_t tmp = 0;
@@ -121,7 +136,7 @@ TEST(bbq_mix, bbq_blocks_calc) {
} else if (val <= 2147483648) {
EXPECT_TRUE(bbq_blocks_calc(val) == 128);
} else {
- EXPECT_TRUE(0); // 异常
+ EXPECT_TRUE(0); // 异常
}
if (val >= max / tmp) {
@@ -132,7 +147,7 @@ TEST(bbq_mix, bbq_blocks_calc) {
EXPECT_TRUE(test_malloc_free_equal());
}
-TEST(bbq_mix, ceil_log2) {
+TEST_F(bbq_mix, ceil_log2) {
test_memory_counter_clear();
uint32_t tmp = 0;
@@ -149,4 +164,3 @@ TEST(bbq_mix, ceil_log2) {
EXPECT_TRUE(bbq_malloc_free_equal());
EXPECT_TRUE(test_malloc_free_equal());
}
-} // namespace \ No newline at end of file
diff --git a/bbq/tests/unittest/ut_data.cc b/bbq/tests/unittest/ut_multit.cc
index 74ed0e2..8ab7276 100644
--- a/bbq/tests/unittest/ut_data.cc
+++ b/bbq/tests/unittest/ut_multit.cc
@@ -1,6 +1,6 @@
/*
* @Author: liuyu
- * @LastEditTime: 2024-06-13 23:25:39
+ * @LastEditTime: 2024-06-17 11:07:02
* @Describe: TODO
*/
@@ -12,22 +12,38 @@ extern "C" {
#include "ut.h"
extern bool bbq_malloc_free_equal();
extern bool test_malloc_free_equal();
-extern void bbq_memory_info();
-bool bbq_check_array_bounds(bbq_queue_s* q);
+extern void bbq_memory_print();
+bool bbq_check_array_bounds(struct bbq_s *q);
}
-TEST(data, correct) {
- test_memory_counter_clear();
+class multit : public testing::Test { // 继承了 testing::Test
+ protected:
+ virtual void SetUp() override {
+ // std::cout << "enter into SetUp()" << std::endl;
+ // 清空内存泄漏统计
+ test_memory_counter_clear();
+ }
+
+ virtual void TearDown() override {
+ // std::cout << "exit from TearDown" << std::endl;
+ // 内存泄漏检测
+ EXPECT_TRUE(bbq_malloc_free_equal());
+ EXPECT_TRUE(test_malloc_free_equal());
+ }
+};
+TEST_F(multit, mpmc) {
test_info_s test_info{
.cfg = {
.base = {
+ .name = {},
+ .introduce = {},
.cores_cnt = 4,
},
.ring = {
.ring_type = TEST_RING_TYPE_BBQ,
- .producer_cnt = 1,
- .consumer_cnt = 1,
+ .producer_cnt = 4,
+ .consumer_cnt = 4,
.workload = TEST_WORKLOAD_SIMPLE,
.entries_cnt = 4096,
.block_count = 0,
@@ -35,9 +51,14 @@ TEST(data, correct) {
},
.run = {
.run_ok_times = 50000,
+ .run_time = 0,
},
},
- .ctl = {.running = true},
+ .ctl = {
+ .running = true,
+ .all_threads_start = {},
+ .producer_exit = {},
+ },
};
// 队列初始化
@@ -47,16 +68,17 @@ TEST(data, correct) {
ASSERT_TRUE(ret == 0);
// 创建线程
- pthread_t* threads = test_threads_create(&test_info, &q);
+ pthread_t *threads = test_threads_create(&test_info, &q);
ASSERT_TRUE(threads);
// 等待所有线程完成,回收数据
uint32_t thread_cnt = test_info.cfg.ring.producer_cnt + test_info.cfg.ring.consumer_cnt;
- test_exit_data** exit_data = (test_exit_data**)test_malloc(TEST_MODULE_UTEST, sizeof(test_exit_data**) * (thread_cnt));
+ test_exit_data **exit_data = (test_exit_data **)test_malloc(TEST_MODULE_UTEST, sizeof(test_exit_data **) * (thread_cnt));
test_wait_all_threads_exit(&test_info, thread_cnt, threads, exit_data);
// 比较数据
- test_merge_s merge = {0};
+ test_merge_s merge;
+ memset(&merge, 0, sizeof(merge));
test_merge_all_data(exit_data, thread_cnt, &merge);
EXPECT_EQ(merge.consumer.data_error_cnt, 0);
EXPECT_EQ(merge.consumer.ok_cnt, merge.producer.ok_cnt);
@@ -67,8 +89,6 @@ TEST(data, correct) {
}
test_free(TEST_MODULE_UTEST, exit_data);
test_threads_destory(&test_info, threads);
- EXPECT_TRUE(bbq_check_array_bounds((bbq_queue_s*)q.ring));
+ EXPECT_TRUE(bbq_check_array_bounds((struct bbq_s *)q.ring));
test_queue_destory(&q);
- EXPECT_TRUE(bbq_malloc_free_equal());
- EXPECT_TRUE(test_malloc_free_equal());
}
diff --git a/perf/CMakeLists.txt b/perf/CMakeLists.txt
index a361c80..54801b1 100644
--- a/perf/CMakeLists.txt
+++ b/perf/CMakeLists.txt
@@ -10,12 +10,22 @@ include_directories(
/home/admin/test/dpdk-23.07/build/install/include
)
-
# 将bbq单元测试里的公共文件,添加到perf里。
SET(TEST_COMMON_DIR ${PROJECT_SOURCE_DIR}/../bbq/tests/common)
# 设置输出目录
-SET(OUTPUT_DIR ${PROJECT_SOURCE_DIR}/build/output)
+if(NOT DEFINED OUTPUT_DIR)
+ # 如果没有被设置,则设置一个默认值
+ SET(OUTPUT_DIR ${PROJECT_SOURCE_DIR}/build/output)
+endif()
+
+# 设置编译类型,默认Release
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
+endif()
+
+add_compile_options(-Wall -Wextra)
+
# 库生成的路径
set(LIB_PATH ${OUTPUT_DIR}/lib)
# 测试程序生成的路径
diff --git a/perf/benchmark/bcm_benchmark.c b/perf/benchmark/bcm_benchmark.c
index 6cbbdfa..923fa1f 100644
--- a/perf/benchmark/bcm_benchmark.c
+++ b/perf/benchmark/bcm_benchmark.c
@@ -1,6 +1,6 @@
/*
* @Author: liuyu
- * @LastEditTime: 2024-06-13 16:32:40
+ * @LastEditTime: 2024-06-14 17:34:15
* @Describe: TODO
*/
@@ -16,7 +16,7 @@
#include <sys/prctl.h>
#include <unistd.h>
-extern void bbq_memory_info();
+extern void bbq_memory_print();
extern bool bbq_malloc_free_equal();
void bcm_report_printf(test_cfg *cfg, test_merge_data *data, test_exit_data **raw_data, uint32_t thread_cnt, test_thread_type_e ttype) {
@@ -24,17 +24,17 @@ void bcm_report_printf(test_cfg *cfg, test_merge_data *data, test_exit_data **ra
double latency_ns = 0;
double throughput = 0;
- BBQ_COLOR_PRINT("\n---------%s---------", ttype == TEST_THREAD_PRODUCER ? "生产者" : "消费者");
+ printf("\n---------%s---------\n", ttype == TEST_THREAD_PRODUCER ? "生产者" : "消费者");
double use_time = test_clock_time_to_double(&data->use_time);
- BBQ_COLOR_PRINT("执行时间 : %lf 秒", use_time);
- BBQ_COLOR_PRINT("执行次数 : %lu (burst=%u)", data->run_times, cfg->ring.burst_cnt);
- BBQ_COLOR_PRINT("成功%s : %lu", ttype == TEST_THREAD_PRODUCER ? "入队" : "出队", data->ok_cnt);
- BBQ_COLOR_PRINT("数据错误次数 : %lu", data->data_error_cnt);
+ printf("执行时间 : %lf 秒\n", use_time);
+ printf("执行次数 : %lu (burst=%u)\n", data->run_times, cfg->ring.burst_cnt);
+ printf("成功%s : %lu\n", ttype == TEST_THREAD_PRODUCER ? "入队" : "出队", data->ok_cnt);
+ printf("数据错误次数 : %lu\n", data->data_error_cnt);
// 同时有生产者、消费者时才输出
if (cfg->ring.producer_cnt > 0 && cfg->ring.consumer_cnt > 0) {
throughput = data->ok_cnt / use_time;
- BBQ_COLOR_PRINT("吞吐 :%.0lf/s (%e/s)", throughput, throughput);
+ printf("吞吐 :%.0lf/s (%e/s)\n", throughput, throughput);
// 多生产者单消费者 或 单生产者多消费才输出
if ((cfg->ring.producer_cnt == 1 && cfg->ring.consumer_cnt > 1) ||
@@ -43,7 +43,7 @@ void bcm_report_printf(test_cfg *cfg, test_merge_data *data, test_exit_data **ra
if (raw_data[i]->arg->ttype == ttype) {
test_time_metric tmp_time = test_clock_time_sub(raw_data[i]->metric_end, raw_data[i]->metric_start);
throughput = raw_data[i]->ok_cnt / test_clock_time_to_double(&tmp_time);
- BBQ_COLOR_PRINT(" %s-%d 吞吐 :%.0lf/s (%e/s)", name, bbq_idx, throughput, throughput);
+ printf(" %s-%d 吞吐 :%.0lf/s (%e/s)", name, bbq_idx, throughput, throughput);
bbq_idx++;
}
}
@@ -51,17 +51,17 @@ void bcm_report_printf(test_cfg *cfg, test_merge_data *data, test_exit_data **ra
if (ttype == TEST_THREAD_CONSUMER && cfg->ring.workload == TEST_WORKLOAD_COMPLEX) {
latency_ns = data->latency_ns * 1.0 / data->ok_cnt;
- BBQ_COLOR_PRINT("数据延迟 :%.0lf 纳秒 (%e)", latency_ns, latency_ns);
+ printf("数据延迟 :%.0lf 纳秒 (%e)\n", latency_ns, latency_ns);
}
latency_ns = data->op_ok_latency_ns * 1.0 / data->ok_cnt;
- BBQ_COLOR_PRINT("操作延迟 :%.0lf 纳秒 (%e)", latency_ns, latency_ns);
+ printf("操作延迟 :%.0lf 纳秒 (%e)\n", latency_ns, latency_ns);
} else {
latency_ns = data->op_err_latency_ns * 1.0 / (data->run_times - data->ok_cnt);
if (ttype == TEST_THREAD_PRODUCER) {
- BBQ_COLOR_PRINT("满队入队操作延迟 :%.0lf 纳秒 (%e)", latency_ns, latency_ns);
+ printf("满队入队操作延迟 :%.0lf 纳秒 (%e)\n", latency_ns, latency_ns);
} else {
- BBQ_COLOR_PRINT("空队出队操作延迟 :%.0lf 纳秒 (%e)", latency_ns, latency_ns);
+ printf("空队出队操作延迟 :%.0lf 纳秒 (%e)\n", latency_ns, latency_ns);
}
}
}
@@ -72,9 +72,9 @@ void bcm_report_generate(test_cfg *cfg, test_exit_data **exit_data, uint32_t thr
test_merge_s merge = {0};
test_merge_all_data(exit_data, thread_cnt, &merge);
- BBQ_COLOR_PRINT("ring类型: %s", test_ring_type_enum2str(cfg->ring.ring_type));
- BBQ_COLOR_PRINT("简介: %s", cfg->base.introduce);
- BBQ_COLOR_PRINT("配置: %s", cfg->base.name);
+ printf("ring类型: %s\n", test_ring_type_enum2str(cfg->ring.ring_type));
+ printf("简介: %s\n", cfg->base.introduce);
+ printf("配置: %s\n", cfg->base.name);
if (cfg->ring.producer_cnt > 0) {
bcm_report_printf(cfg, &merge.producer, exit_data, thread_cnt, TEST_THREAD_PRODUCER);
}
@@ -84,7 +84,7 @@ void bcm_report_generate(test_cfg *cfg, test_exit_data **exit_data, uint32_t thr
}
if (cfg->ring.producer_cnt > 0 && cfg->ring.consumer_cnt > 0) {
- BBQ_COLOR_PRINT("生产消费个数验证: %s", merge.consumer.ok_cnt == merge.producer.ok_cnt ? "相等" : "不等!!!!!!!!!");
+ printf("生产消费个数验证: %s\n", merge.consumer.ok_cnt == merge.producer.ok_cnt ? "相等" : "不等!!!!!!!!!");
}
}
@@ -101,22 +101,20 @@ int main(int argc, char *argv[]) {
burst_cnt = 1;
}
} else {
- config = "/root/code/c/bbq-ly/perf/benchmark/config/compare/perf/perf_case2_simple_mpmc.ini";
- // ring_type = "rmind";
- // ring_type = "dpdk";
- ring_type = "bbq";
- burst_cnt = 1;
- BBQ_ERR_LOG("use default config, ringt_type:%s burst:%u config:%s argc:%d", ring_type, burst_cnt, config, argc);
+ config = "/root/code/c/bbq-ly/perf/benchmark/config/compare/case1_simple_spsc.ini";
+ ring_type = "rmind";
+ burst_cnt = 16;
+ TEST_ERR_LOG("use default config, ringt_type:%s burst:%u config:%s argc:%d", ring_type, burst_cnt, config, argc);
}
char thread_name[128] = {0};
- snprintf(thread_name, sizeof(thread_name), "main:%x", pthread_self());
+ snprintf(thread_name, sizeof(thread_name), "main:%lu", pthread_self());
prctl(PR_SET_NAME, thread_name);
// 加载配置
test_info_s test_info;
if (test_load_config(config, ring_type, burst_cnt, &test_info.cfg) != 0) {
- BBQ_ERR_LOG("load config error");
+ TEST_ERR_LOG("load config error");
return -1;
}
@@ -125,14 +123,14 @@ int main(int argc, char *argv[]) {
test_queue_s q;
ret = bcm_queue_init(&test_info.cfg, &q);
if (ret != 0) {
- BBQ_ERR_LOG("init failed :%d", ret);
+ TEST_ERR_LOG("init failed :%d", ret);
return ret;
}
// 创建线程
pthread_t *threads = test_threads_create(&test_info, &q);
if (threads == NULL) {
- BBQ_ERR_LOG("pthread_arr is NULL");
+ TEST_ERR_LOG("pthread_arr is NULL");
return ret;
}
@@ -153,8 +151,8 @@ int main(int argc, char *argv[]) {
test_free(TEST_MODULE_BCM, exit_data);
test_threads_destory(&test_info, threads);
test_queue_destory(&q);
- bbq_memory_info();
- test_memory_info();
+ bbq_memory_print();
+ test_memory_counter_print();
return 0;
} \ No newline at end of file
diff --git a/perf/benchmark/bcm_loadconfig.c b/perf/benchmark/bcm_loadconfig.c
index f285747..53dbc6a 100644
--- a/perf/benchmark/bcm_loadconfig.c
+++ b/perf/benchmark/bcm_loadconfig.c
@@ -1,6 +1,6 @@
/*
* @Author: liuyu
- * @LastEditTime: 2024-06-11 18:05:56
+ * @LastEditTime: 2024-06-14 16:48:29
* @Describe: TODO
*/
@@ -11,7 +11,7 @@
int test_load_config(const char *config, const char *ring_type, uint32_t burst_cnt, test_cfg *cfg) {
// 加载配置
- BBQ_INFO_LOG("load config:%s", config);
+ TEST_INFO_LOG("load config:%s", config);
dictionary *ini = iniparser_load(config);
if (ini == NULL) {
return -1;
@@ -37,7 +37,7 @@ int test_load_config(const char *config, const char *ring_type, uint32_t burst_c
// 设置ring_type
cfg->ring.ring_type = test_ring_type_str2enum(ring_type);
if (cfg->ring.ring_type >= TEST_RING_TYPE_MAX) {
- BBQ_ERR_LOG("unknown ring type:%d", cfg->ring.ring_type);
+ TEST_ERR_LOG("unknown ring type:%d", cfg->ring.ring_type);
return -1;
}
cfg->ring.burst_cnt = burst_cnt;
@@ -45,32 +45,32 @@ int test_load_config(const char *config, const char *ring_type, uint32_t burst_c
if (cfg->ring.ring_type == TEST_RING_TYPE_RMIND) {
// rmind仅支持1个消费者,仅支持burst方式
if (cfg->ring.consumer_cnt > 1) {
- BBQ_ERR_LOG("ring type:%s only support single consumer", TEST_RING_TYPE_RMIND_STR);
+ TEST_ERR_LOG("ring type:%s only support single consumer", TEST_RING_TYPE_RMIND_STR);
return -1;
}
if (cfg->ring.burst_cnt <= 1) {
- BBQ_ERR_LOG("ring type:%s only support burst_cnt > 1 !", TEST_RING_TYPE_RMIND_STR);
+ TEST_ERR_LOG("ring type:%s only support burst_cnt > 1 !", TEST_RING_TYPE_RMIND_STR);
return -1;
}
}
if (cfg->run.run_time == 0 && cfg->run.run_ok_times == 0) {
- BBQ_ERR_LOG("At least one of run_time or run_ok_times is not 0", TEST_RING_TYPE_RMIND_STR);
+ TEST_ERR_LOG("At least one of run_time or run_ok_times is not 0");
return -1;
}
- BBQ_INFO_LOG("introduce:%s", cfg->base.introduce);
- BBQ_INFO_LOG("cores_cnt:%u", cfg->base.cores_cnt);
- BBQ_INFO_LOG("workload:%s(%u)", workload, cfg->ring.workload);
- BBQ_INFO_LOG("entries_cnt:%u", cfg->ring.entries_cnt);
- BBQ_INFO_LOG("producer_cnt:%u", cfg->ring.producer_cnt);
- BBQ_INFO_LOG("consumer_cnt:%u", cfg->ring.consumer_cnt);
- BBQ_INFO_LOG("block_count:%u", cfg->ring.block_count);
- BBQ_INFO_LOG("run_ok_times:%lu", cfg->run.run_ok_times);
- BBQ_INFO_LOG("run_time:%lu", cfg->run.run_time);
- BBQ_INFO_LOG("ring_type:%s(%u)", ring_type, cfg->ring.ring_type);
- BBQ_INFO_LOG("burst_cnt:%u", burst_cnt);
+ TEST_INFO_LOG("introduce:%s", cfg->base.introduce);
+ TEST_INFO_LOG("cores_cnt:%u", cfg->base.cores_cnt);
+ TEST_INFO_LOG("workload:%s(%u)", workload, cfg->ring.workload);
+ TEST_INFO_LOG("entries_cnt:%lu", cfg->ring.entries_cnt);
+ TEST_INFO_LOG("producer_cnt:%u", cfg->ring.producer_cnt);
+ TEST_INFO_LOG("consumer_cnt:%u", cfg->ring.consumer_cnt);
+ TEST_INFO_LOG("block_count:%u", cfg->ring.block_count);
+ TEST_INFO_LOG("run_ok_times:%lu", cfg->run.run_ok_times);
+ TEST_INFO_LOG("run_time:%lu", cfg->run.run_time);
+ TEST_INFO_LOG("ring_type:%s(%u)", ring_type, cfg->ring.ring_type);
+ TEST_INFO_LOG("burst_cnt:%u", burst_cnt);
// 释放dictionary对象
iniparser_freedict(ini);
diff --git a/perf/benchmark/bcm_queue.c b/perf/benchmark/bcm_queue.c
index 9eec4f2..0cd09e8 100644
--- a/perf/benchmark/bcm_queue.c
+++ b/perf/benchmark/bcm_queue.c
@@ -1,6 +1,6 @@
/*
* @Author: liuyu
- * @LastEditTime: 2024-06-13 18:58:20
+ * @LastEditTime: 2024-06-14 17:31:56
* @Describe: TODO
*/
@@ -8,7 +8,8 @@
#include "ringbuf.h"
static __rte_always_inline unsigned int
-bcm_dpdk_ring_enqueue_burst(struct rte_ring *r, void **obj_table, size_t n, uint16_t thread_idx) {
+bcm_dpdk_ring_enqueue_burst(struct rte_ring *r, void **obj_table, uint32_t n, uint16_t thread_idx) {
+ TEST_AVOID_WARNING(thread_idx);
return rte_ring_enqueue_burst(r, (void *const *)obj_table, n, NULL);
}
@@ -67,7 +68,7 @@ void test_queue_free_rmind(void *ring) {
test_free(TEST_MODULE_RMIND, ring);
}
-uint32_t test_enqueue_burst_rmind(void *ring, void **obj_table, size_t n, unsigned int flags, uint16_t thread_idx) {
+uint32_t test_enqueue_burst_rmind(void *ring, void **obj_table, uint32_t n, uint16_t thread_idx) {
uint32_t cnt = 0;
int ret = 0;
size_t off = 0;
@@ -92,6 +93,7 @@ uint32_t test_enqueue_burst_rmind(void *ring, void **obj_table, size_t n, unsign
}
uint32_t test_dequeue_burst_rmind(void *ring, void *obj_table, uint32_t n) {
+ TEST_AVOID_WARNING(n);
size_t len = 0;
size_t off = 0;
size_t per_size = sizeof(void *);
diff --git a/perf/benchmark/benchmark.sh b/perf/benchmark/benchmark.sh
index 272b6d6..6889de3 100755
--- a/perf/benchmark/benchmark.sh
+++ b/perf/benchmark/benchmark.sh
@@ -1,9 +1,9 @@
#!/bin/bash
###
# @Author: liuyu
-# @LastEditTime: 2024-06-14 10:19:30
+# @LastEditTime: 2024-06-14 14:37:48
-# @Describe: TODO
+# @Describe: 运行性能测试的脚本
###
ring_type_arr=("bbq" "dpdk" "rmind")
@@ -11,7 +11,7 @@ burst_arr=("32" "16" "8" "1")
# 检查参数数量
if [ "$#" -ne 3 ]; then
- echo "Usage: $0 <path_to_benchmark> <path_to_config_directory> <ring_type>"
+ echo "Usage: $0 <path to benchmark> <path to config file or directory> <ring type>"
exit 1
fi
@@ -24,6 +24,7 @@ function exec_benchmark_ring_type() {
local ini="$1"
local ring="$2"
local log_file=$3
+ local burst=$4
# 如果以perf开头的配置文件,还要执行perf统计
if [[ $(basename "$ini") == perf* ]]; then
@@ -31,7 +32,7 @@ function exec_benchmark_ring_type() {
# echo perf stat -a -e L1-dcache-loads,L1-dcache-load-misses,cache-references,cache-misses "$BENCHMARK_PATH" "$ini" "$ring" "$BURST_CNT"
# perf stat -a -e L1-dcache-loads,L1-dcache-load-misses,cache-references,cache-misses "$BENCHMARK_PATH" "$ini" "$ring" "$BURST_CNT"
else
- "$BENCHMARK_PATH" "$ini" "$ring" "$BURST_CNT" 2>&1 | tee -a "$log_file"
+ "$BENCHMARK_PATH" "$ini" "$ring" "$burst" 2>&1 | tee -a "$log_file"
fi
}
@@ -73,6 +74,9 @@ folder_path="/tmp/bbq/$timestamp"
rm -rf "$folder_path"
mkdir -p "$folder_path"
+# 开始时间
+start_time=$(date +%s)
+
for burst in "${burst_arr[@]}"; do
burst_dir="$folder_path"/burst_"$burst"
mkdir -p "$burst_dir"
@@ -94,4 +98,10 @@ for burst in "${burst_arr[@]}"; do
sleep 1
done
done
-echo "done......."
+
+# 结束时间
+end_time=$(date +%s)
+# 计算时间差(秒)
+runtime=$((end_time - start_time))
+# 输出运行时间
+echo "done, use $runtime second"
diff --git a/perf/benchmark/config/compare/general/case1_simple_spsc.ini b/perf/benchmark/config/compare/case1_simple_spsc.ini
index de92814..de92814 100644
--- a/perf/benchmark/config/compare/general/case1_simple_spsc.ini
+++ b/perf/benchmark/config/compare/case1_simple_spsc.ini
diff --git a/perf/benchmark/config/compare/general/case2_simple_spmc.ini b/perf/benchmark/config/compare/case2_simple_spmc.ini
index 4d1d06e..4d1d06e 100644
--- a/perf/benchmark/config/compare/general/case2_simple_spmc.ini
+++ b/perf/benchmark/config/compare/case2_simple_spmc.ini
diff --git a/perf/benchmark/config/compare/general/case3_simple_mpsc.ini b/perf/benchmark/config/compare/case3_simple_mpsc.ini
index 89af5fc..89af5fc 100644
--- a/perf/benchmark/config/compare/general/case3_simple_mpsc.ini
+++ b/perf/benchmark/config/compare/case3_simple_mpsc.ini
diff --git a/perf/benchmark/config/compare/general/case4_complex_spmc.ini b/perf/benchmark/config/compare/case4_complex_spmc.ini
index 6fcd711..6fcd711 100644
--- a/perf/benchmark/config/compare/general/case4_complex_spmc.ini
+++ b/perf/benchmark/config/compare/case4_complex_spmc.ini
diff --git a/perf/benchmark/config/compare/general/case5_complex_mpsc.ini b/perf/benchmark/config/compare/case5_complex_mpsc.ini
index faeee45..faeee45 100644
--- a/perf/benchmark/config/compare/general/case5_complex_mpsc.ini
+++ b/perf/benchmark/config/compare/case5_complex_mpsc.ini
diff --git a/perf/benchmark/config/compare/general/case6_simple_mp0c.ini b/perf/benchmark/config/compare/case6_simple_mp0c.ini
index f2d6952..f2d6952 100644
--- a/perf/benchmark/config/compare/general/case6_simple_mp0c.ini
+++ b/perf/benchmark/config/compare/case6_simple_mp0c.ini
diff --git a/perf/benchmark/config/compare/general/case7_simple_0pmc.ini b/perf/benchmark/config/compare/case7_simple_0pmc.ini
index f4273ea..f4273ea 100644
--- a/perf/benchmark/config/compare/general/case7_simple_0pmc.ini
+++ b/perf/benchmark/config/compare/case7_simple_0pmc.ini
diff --git a/perf/benchmark/config/compare/general/case8_simple_mpmc.ini b/perf/benchmark/config/compare/case8_simple_mpmc.ini
index 0ed2a25..0ed2a25 100644
--- a/perf/benchmark/config/compare/general/case8_simple_mpmc.ini
+++ b/perf/benchmark/config/compare/case8_simple_mpmc.ini
diff --git a/perf/benchmark/config/compare/general/case9_simple_mpmc_overcore.ini b/perf/benchmark/config/compare/case9_simple_mpmc_overcore.ini
index bbbb46d..bbbb46d 100644
--- a/perf/benchmark/config/compare/general/case9_simple_mpmc_overcore.ini
+++ b/perf/benchmark/config/compare/case9_simple_mpmc_overcore.ini
diff --git a/perf/benchmark/config/compare/perf/perf_case1_simple_spsc.ini b/perf/benchmark/config/compare/perf/perf_case1_simple_spsc.ini
deleted file mode 100644
index e45848a..0000000
--- a/perf/benchmark/config/compare/perf/perf_case1_simple_spsc.ini
+++ /dev/null
@@ -1,14 +0,0 @@
-[base]
- introduce = "perf case1 简单负载下,单生产者、单消费者" ;测试配置说明
- cores_cnt = 8 ;测试用核心个数
-
-[ring]
- workload = "simple" ;负载模式 simple/complex
- entries_cnt = 4096 ;ring初始化时分配entry的个数
- block_count = 0 ;bbq配置,等于0则表示根据entries_cnt自动计算
- producer_cnt = 1 ;生产者个数
- consumer_cnt = 1 ;消费者个数
-
-[run]
- run_time = 10 ; 整体运行的秒数,大于0生效
- run_ok_times = 0 ;成功入队/出队次数,大于0生效。 \ No newline at end of file
diff --git a/perf/benchmark/config/compare/perf/perf_case2_simple_mpmc.ini b/perf/benchmark/config/compare/perf/perf_case2_simple_mpmc.ini
deleted file mode 100644
index eee9566..0000000
--- a/perf/benchmark/config/compare/perf/perf_case2_simple_mpmc.ini
+++ /dev/null
@@ -1,14 +0,0 @@
-[base]
- introduce = "perf case2 简单负载下,多生产者、多消费者" ;测试配置说明
- cores_cnt = 8 ;测试用核心个数
-
-[ring]
- workload = "simple" ;负载模式 simple/complex
- entries_cnt = 4096 ;ring初始化时分配entry的个数
- block_count = 0 ;bbq配置,等于0则表示根据entries_cnt自动计算
- producer_cnt = 4 ;生产者个数
- consumer_cnt = 4 ;消费者个数
-
-[run]
- run_time = 10 ; 整体运行的秒数,大于0生效
- run_ok_times = 0 ;成功入队/出队次数,大于0生效。 \ No newline at end of file
diff --git a/perf/benchmark/config/compare/perf/perf_case3_simple_spmp.ini b/perf/benchmark/config/compare/perf/perf_case3_simple_spmp.ini
deleted file mode 100644
index 8356282..0000000
--- a/perf/benchmark/config/compare/perf/perf_case3_simple_spmp.ini
+++ /dev/null
@@ -1,14 +0,0 @@
-[base]
- introduce = "perf case3 简单负载下,单生产者、多消费者" ;测试配置说明
- cores_cnt = 8 ;测试用核心个数
-
-[ring]
- workload = "simple" ;负载模式 simple/complex
- entries_cnt = 4096 ;ring初始化时分配entry的个数
- block_count = 0 ;bbq配置,等于0则表示根据entries_cnt自动计算
- producer_cnt = 1 ;生产者个数
- consumer_cnt = 4 ;消费者个数
-
-[run]
- run_time = 10 ; 整体运行的秒数,大于0生效
- run_ok_times = 0 ;成功入队/出队次数,大于0生效。 \ No newline at end of file
diff --git a/perf/benchmark/config/compare/perf/perf_case4_simple_mpsc.ini b/perf/benchmark/config/compare/perf/perf_case4_simple_mpsc.ini
deleted file mode 100644
index edc0001..0000000
--- a/perf/benchmark/config/compare/perf/perf_case4_simple_mpsc.ini
+++ /dev/null
@@ -1,14 +0,0 @@
-[base]
- introduce = "perf case4 简单负载下,多生产者、单消费者" ;测试配置说明
- cores_cnt = 8 ;测试用核心个数
-
-[ring]
- workload = "simple" ;负载模式 simple/complex
- entries_cnt = 4096 ;ring初始化时分配entry的个数
- block_count = 0 ;bbq配置,等于0则表示根据entries_cnt自动计算
- producer_cnt = 4 ;生产者个数
- consumer_cnt = 1 ;消费者个数
-
-[run]
- run_time = 10 ; 整体运行的秒数,大于0生效
- run_ok_times = 0 ;成功入队/出队次数,大于0生效。 \ No newline at end of file