summaryrefslogtreecommitdiff
path: root/perf/benchmark
diff options
context:
space:
mode:
Diffstat (limited to 'perf/benchmark')
-rw-r--r--perf/benchmark/CMakeLists.txt21
-rw-r--r--perf/benchmark/bcm_benchmark.c153
-rw-r--r--perf/benchmark/bcm_loadconfig.c91
-rw-r--r--perf/benchmark/bcm_queue.c187
-rw-r--r--perf/benchmark/bcm_queue.h10
-rwxr-xr-xperf/benchmark/benchmark.sh107
-rw-r--r--perf/benchmark/config/bbq_debug/debug.ini15
-rw-r--r--perf/benchmark/config/compare/case1_simple_spsc.ini14
-rw-r--r--perf/benchmark/config/compare/case2_simple_spmc.ini14
-rw-r--r--perf/benchmark/config/compare/case3_simple_mpsc.ini14
-rw-r--r--perf/benchmark/config/compare/case4_complex_spmc.ini14
-rw-r--r--perf/benchmark/config/compare/case5_complex_mpsc.ini14
-rw-r--r--perf/benchmark/config/compare/case6_simple_mp0c.ini14
-rw-r--r--perf/benchmark/config/compare/case7_simple_0pmc.ini14
-rw-r--r--perf/benchmark/config/compare/case8_simple_mpmc.ini14
-rw-r--r--perf/benchmark/config/compare/case9_simple_mpmc_overcore.ini14
16 files changed, 710 insertions, 0 deletions
diff --git a/perf/benchmark/CMakeLists.txt b/perf/benchmark/CMakeLists.txt
new file mode 100644
index 0000000..323240b
--- /dev/null
+++ b/perf/benchmark/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.0)
+project(BBQ_BENCHMARK)
+
+# 搜索当前cmake文件所在目录下的c文件
+file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
+file(GLOB SRC_BBQ_UT_FUNC_LIST "${UT_BBQ_FUNC_DIR}/*.c")
+list(APPEND SRC_LIST ${SRC_BBQ_UT_FUNC_LIST})
+
+# 指定可执行文件输出路径
+set(EXECUTABLE_OUTPUT_PATH ${EXEC_PATH})
+
+add_executable(benchmark ${SRC_LIST}) # 添加可执行程序
+target_link_libraries(benchmark dl iniparser pthread rte_ring rte_eal rte_kvargs rte_telemetry rmind_ringbuf bbq m) # 链接库
+#target_link_libraries(benchmark dl iniparser pthread dpdk rmind_ringbuf bbq m) # 链接库
+
+add_custom_command(
+ TARGET benchmark POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_SOURCE_DIR}/benchmark.sh
+ ${EXECUTABLE_OUTPUT_PATH}/benchmark.sh
+)
diff --git a/perf/benchmark/bcm_benchmark.c b/perf/benchmark/bcm_benchmark.c
new file mode 100644
index 0000000..5a7db7a
--- /dev/null
+++ b/perf/benchmark/bcm_benchmark.c
@@ -0,0 +1,153 @@
+/*
+ * @Author: liuyu
+ * @LastEditTime: 2024-07-07 21:19:02
+ * @Email: [email protected]
+ * @Describe: TODO
+ */
+#include "bbq.h"
+#include "bcm_queue.h"
+#include "iniparser.h"
+#include "ut_bbq_func.h"
+#include <pthread.h>
+#include <stdatomic.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+void bcm_report_printf(struct ut_cfg *cfg, struct ut_merge_data *data, struct ut_exit_data **raw_data, uint32_t thread_cnt, enum ut_thread_type ttype) {
+ char name[10] = {0};
+ double latency_ns = 0;
+ double throughput = 0;
+
+ printf("\n---------%s---------\n", ttype == UT_THREAD_PRODUCER ? "生产者" : "消费者");
+ double use_time = ut_clock_time_to_double(&data->use_time);
+ printf("执行时间 : %lf 秒\n", use_time);
+ printf("执行次数 : %lu (burst=%u)\n", data->run_times, cfg->ring.burst_cnt);
+ printf("成功%s : %lu\n", ttype == UT_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;
+ printf("吞吐 :%.0lf/s (%e/s)\n", throughput, throughput);
+
+ // 多生产者单消费者 或 单生产者多消费才输出
+ if ((cfg->ring.producer_cnt == 1 && cfg->ring.consumer_cnt > 1) ||
+ (cfg->ring.producer_cnt > 1 && cfg->ring.consumer_cnt == 1)) {
+ for (uint32_t i = 0, bbq_head_idx = 1; i < thread_cnt; i++) {
+ if (raw_data[i]->arg->ttype == ttype) {
+ struct ut_metric tmp_time = ut_clock_time_sub(raw_data[i]->metric_end, raw_data[i]->metric_start);
+ throughput = raw_data[i]->ok_cnt / ut_clock_time_to_double(&tmp_time);
+ printf(" %s-%d 吞吐 :%.0lf/s (%e/s)", name, bbq_head_idx, throughput, throughput);
+ bbq_head_idx++;
+ }
+ }
+ }
+
+ if (ttype == UT_THREAD_CONSUMER && cfg->ring.workload == UT_WORKLOAD_COMPLEX) {
+ latency_ns = data->latency_ns * 1.0 / data->ok_cnt;
+ printf("数据延迟 :%.0lf 纳秒 (%e)\n", latency_ns, latency_ns);
+ }
+
+ latency_ns = data->op_ok_latency_ns * 1.0 / data->ok_cnt;
+ 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 == UT_THREAD_PRODUCER) {
+ printf("满队入队操作延迟 :%.0lf 纳秒 (%e)\n", latency_ns, latency_ns);
+ } else {
+ printf("空队出队操作延迟 :%.0lf 纳秒 (%e)\n", latency_ns, latency_ns);
+ }
+ }
+}
+
+void bcm_report_generate(struct ut_cfg *cfg, struct ut_exit_data **exit_data, uint32_t thread_cnt) {
+ // ut_report report;
+
+ struct ut_merge_s merge = {0};
+ ut_merge_all_data(exit_data, thread_cnt, &merge);
+
+ printf("ring类型: %s\n", ut_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, UT_THREAD_PRODUCER);
+ }
+
+ if (cfg->ring.consumer_cnt > 0) {
+ bcm_report_printf(cfg, &merge.consumer, exit_data, thread_cnt, UT_THREAD_CONSUMER);
+ }
+
+ if (cfg->ring.producer_cnt > 0 && cfg->ring.consumer_cnt > 0) {
+ printf("生产消费个数验证: %s\n", merge.consumer.ok_cnt == merge.producer.ok_cnt ? "相等" : "不等!!!!!!!!!");
+ }
+}
+
+int main(int argc, char *argv[]) {
+ char *config;
+ char *ring_type;
+ uint32_t burst_cnt = 0;
+
+ if (argc == 4) {
+ config = argv[1];
+ ring_type = argv[2];
+ burst_cnt = strtoul(argv[3], NULL, 0);
+ if (burst_cnt <= 0) {
+ burst_cnt = 1;
+ }
+ } else {
+ config = "/root/code/c/bbq/perf/benchmark/config/compare/case1_simple_spsc.ini";
+ ring_type = "dpdk";
+ burst_cnt = 16;
+ UT_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:%lu", pthread_self());
+ prctl(PR_SET_NAME, thread_name);
+
+ // 加载配置
+ struct ut_info_s info;
+ if (ut_load_config(config, ring_type, burst_cnt, &info.cfg) != 0) {
+ UT_ERR_LOG("load config error");
+ return -1;
+ }
+
+ // 队列初始化
+ int ret = -1;
+ struct ut_queue q;
+ ret = bcm_queue_init(&info.cfg, &q);
+ if (ret != 0) {
+ UT_ERR_LOG("init failed :%d", ret);
+ return ret;
+ }
+
+ // 创建线程
+ pthread_t *threads = ut_threads_create(&info, &q);
+ if (threads == NULL) {
+ UT_ERR_LOG("pthread_arr is NULL");
+ return ret;
+ }
+
+ // 等待所有线程完成,回收数据
+ uint32_t thread_cnt = info.cfg.ring.producer_cnt + info.cfg.ring.consumer_cnt;
+ struct ut_exit_data **exit_data = (struct ut_exit_data **)ut_malloc(UT_MODULE_BCM, sizeof(struct ut_exit_data **) * (thread_cnt));
+ uint32_t i = 0;
+
+ ut_wait_all_threads_exit(&info, thread_cnt, threads, exit_data);
+
+ // 生成benchmark报告
+ bcm_report_generate(&info.cfg, exit_data, thread_cnt);
+
+ // 回收、释放数据
+ for (i = 0; i < thread_cnt; i++) {
+ ut_exit_data_destory(exit_data[i]);
+ }
+ ut_free(UT_MODULE_BCM, exit_data);
+ ut_threads_destory(&info, threads);
+ ut_queue_destory(&q);
+ ut_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
new file mode 100644
index 0000000..68f7bcc
--- /dev/null
+++ b/perf/benchmark/bcm_loadconfig.c
@@ -0,0 +1,91 @@
+/*
+ * @Author: liuyu
+ * @LastEditTime: 2024-07-07 22:13:33
+ * @Email: [email protected]
+ * @Describe: TODO
+ */
+#include "bbq.h"
+#include "iniparser.h"
+#include "ut_bbq_func.h"
+
+#include <string.h>
+
+int ut_load_config(const char *config, const char *ring_type, uint32_t burst_cnt, struct ut_cfg *cfg) {
+ int ret = 0;
+ // 加载配置
+ UT_INFO_LOG("load config:%s", config);
+ dictionary *ini = iniparser_load(config);
+ if (ini == NULL) {
+ return -1;
+ }
+
+ strncpy(cfg->base.name, config, sizeof(cfg->base.name) - 1);
+ cfg->base.name[sizeof(cfg->base.name) - 1] = '\0';
+
+ // 获取键值
+ const char *introduce = iniparser_getstring(ini, "base:introduce", "none");
+ strncpy(cfg->base.introduce, introduce, sizeof(cfg->base.introduce) - 1);
+ cfg->base.introduce[sizeof(cfg->base.introduce) - 1] = '\0'; // 手工写上 \0
+ const char *cores = iniparser_getstring(ini, "base:cores", "unknown");
+ ret = sscanf(cores, "%hu-%hu", &cfg->base.core_begin, &cfg->base.core_end);
+ if (ret != 2) {
+ UT_ERR_LOG("cores error: %s", cores);
+ return -1;
+ }
+
+ const char *workload = iniparser_getstring(ini, "ring:workload", "unknown");
+ cfg->ring.workload = ut_workload_str2enum(workload);
+ cfg->ring.entries_cnt = iniparser_getuint64(ini, "ring:entries_cnt", 0);
+ cfg->ring.producer_cnt = iniparser_getint(ini, "ring:producer_cnt", 0);
+ cfg->ring.consumer_cnt = iniparser_getint(ini, "ring:consumer_cnt", 0);
+ cfg->ring.block_count = iniparser_getint(ini, "ring:block_count", 0);
+ cfg->run.run_ok_times = iniparser_getint(ini, "run:run_ok_times", 0);
+ cfg->run.run_time = iniparser_getuint64(ini, "run:run_time", 0);
+
+ // 设置ring_type
+ cfg->ring.ring_type = ut_ring_type_str2enum(ring_type);
+ if (cfg->ring.ring_type >= UT_RING_TYPE_MAX) {
+ UT_ERR_LOG("unknown ring type:%d", cfg->ring.ring_type);
+ return -1;
+ }
+ cfg->ring.burst_cnt = burst_cnt;
+
+ if (cfg->ring.ring_type == UT_RING_TYPE_RMIND) {
+ // rmind仅支持1个消费者,仅支持burst方式
+ if (cfg->ring.consumer_cnt > 1) {
+ UT_ERR_LOG("ring type:%s only support single consumer", UT_RING_TYPE_RMIND_STR);
+ return -1;
+ }
+
+ if (cfg->ring.burst_cnt <= 1) {
+ UT_ERR_LOG("ring type:%s only support burst_cnt > 1 !", UT_RING_TYPE_RMIND_STR);
+ return -1;
+ }
+
+ if (cfg->ring.workload == UT_WORKLOAD_COMPLEX) {
+ UT_ERR_LOG("ring type:%s only support simple workload !", UT_RING_TYPE_RMIND_STR);
+ return -1;
+ }
+ }
+
+ if (cfg->run.run_time == 0 && cfg->run.run_ok_times == 0) {
+ UT_ERR_LOG("At least one of run_time or run_ok_times is not 0");
+ return -1;
+ }
+
+ UT_INFO_LOG("introduce:%s", cfg->base.introduce);
+ UT_INFO_LOG("cores:%u-%u", cfg->base.core_begin, cfg->base.core_end);
+ UT_INFO_LOG("workload:%s(%u)", workload, cfg->ring.workload);
+ UT_INFO_LOG("entries_cnt:%lu", cfg->ring.entries_cnt);
+ UT_INFO_LOG("producer_cnt:%u", cfg->ring.producer_cnt);
+ UT_INFO_LOG("consumer_cnt:%u", cfg->ring.consumer_cnt);
+ UT_INFO_LOG("block_count:%u", cfg->ring.block_count);
+ UT_INFO_LOG("run_ok_times:%lu", cfg->run.run_ok_times);
+ UT_INFO_LOG("run_time:%lu", cfg->run.run_time);
+ UT_INFO_LOG("ring_type:%s(%u)", ring_type, cfg->ring.ring_type);
+ UT_INFO_LOG("burst_cnt:%u", burst_cnt);
+
+ // 释放dictionary对象
+ iniparser_freedict(ini);
+ return 0;
+} \ No newline at end of file
diff --git a/perf/benchmark/bcm_queue.c b/perf/benchmark/bcm_queue.c
new file mode 100644
index 0000000..b116f25
--- /dev/null
+++ b/perf/benchmark/bcm_queue.c
@@ -0,0 +1,187 @@
+/*
+ * @Author: liuyu
+ * @LastEditTime: 2024-07-07 20:52:05
+ * @Email: [email protected]
+ * @Describe: TODO
+ */
+#include "bcm_queue.h"
+#include "ringbuf.h"
+
+static __rte_always_inline unsigned int
+bcm_dpdk_ring_enqueue_burst(struct rte_ring *r, void **obj_table, uint32_t n, uint16_t thread_idx, uint32_t *wait_consumed) {
+ UT_AVOID_WARNING(thread_idx);
+ int ret = 0;
+
+ if (wait_consumed) {
+ unsigned int free_space = 0;
+ ret = rte_ring_enqueue_burst(r, (void *const *)obj_table, n, &free_space);
+ *wait_consumed = r->size - free_space - 1;
+ } else {
+ ret = rte_ring_enqueue_burst(r, (void *const *)obj_table, n, NULL);
+ }
+
+ return ret;
+}
+
+int ut_queue_init_dpdk(struct ut_cfg *cfg, struct ut_queue *q) {
+ /* generate eal parameters */
+ const char *eal_args[] = {"bcm_dpdk", "-n", "4", "--proc-type", "auto", "--no-huge", "-m", "2048"};
+ if (rte_eal_init(RTE_DIM(eal_args), (char **)eal_args) < 0) {
+ return -1;
+ }
+
+ q->ring_type = UT_RING_TYPE_DPDK;
+ unsigned int flags = 0;
+ if (cfg->ring.producer_cnt <= 1) {
+ flags |= RING_F_SP_ENQ;
+ } else {
+ flags |= RING_F_MP_RTS_ENQ;
+ }
+
+ if (cfg->ring.consumer_cnt <= 1) {
+ flags |= RING_F_SC_DEQ;
+ } else {
+ flags |= RING_F_MC_RTS_DEQ;
+ }
+
+ q->ring = (void *)rte_ring_create("dpdk_ring", cfg->ring.entries_cnt, rte_socket_id(), flags);
+ if (q->ring == NULL) {
+ return BBQ_ERR_INPUT_NULL;
+ }
+
+ q->ring_free_f = (ut_ring_free_f)rte_ring_free;
+ q->enqueue_f = (ut_ring_enqueue_f)rte_ring_enqueue;
+ q->dequeue_f = (ut_ring_dequeue_f)rte_ring_dequeue;
+ q->enqueue_burst_f = (ut_enqueue_burst_f)bcm_dpdk_ring_enqueue_burst;
+ q->dequeue_burst_f = (ut_dequeue_burst_f)rte_ring_dequeue_burst;
+
+ return BBQ_OK;
+}
+
+unsigned char *rmind_buf;
+uint16_t worker_cnt;
+ringbuf_worker_t **rmind_workers;
+
+void ut_queue_free_rmind(void *ring) {
+ for (uint16_t i = 0; i < worker_cnt; i++) {
+ ringbuf_unregister((ringbuf_t *)ring, rmind_workers[i]);
+ }
+
+ ut_free(UT_MODULE_RMIND, rmind_workers);
+ ut_free(UT_MODULE_RMIND, rmind_buf);
+ ut_free(UT_MODULE_RMIND, ring);
+}
+
+uint32_t ut_enqueue_burst_rmind(void *ring, void **obj_table, uint32_t n, uint16_t thread_idx, uint32_t *wait_consumed) {
+ UT_AVOID_WARNING(wait_consumed);
+ uint32_t cnt = 0;
+ int ret = 0;
+ size_t off = 0;
+ void *obj = NULL;
+ ringbuf_worker_t *w = (ringbuf_worker_t *)rmind_workers[thread_idx];
+ size_t len = sizeof(uintptr_t);
+
+ for (cnt = 0; cnt < n; cnt++) {
+ obj = obj_table[cnt];
+ uintptr_t uptr = (uintptr_t)obj;
+
+ if ((ret = ringbuf_acquire(ring, w, len)) != -1) {
+ off = (size_t)ret;
+ memcpy(&rmind_buf[off], &uptr, len);
+ ringbuf_produce(ring, w);
+ } else {
+ break;
+ }
+ }
+
+ return cnt;
+}
+
+uint32_t ut_dequeue_burst_rmind(void *ring, void *obj_table, uint32_t n, uint32_t *wait_consumed) {
+ UT_AVOID_WARNING(n);
+ UT_AVOID_WARNING(wait_consumed);
+ size_t len = 0;
+ size_t off = 0;
+ size_t per_size = sizeof(void *);
+ void **table = (void **)obj_table;
+
+ if ((len = ringbuf_consume(ring, &off)) != 0) {
+ size_t rem = len;
+ size_t i = 0;
+
+ while (rem) {
+ uintptr_t *data = (uintptr_t *)(&rmind_buf[off]);
+ table[i] = (void *)(*data);
+ i++;
+ off += per_size;
+ rem -= sizeof(void *);
+ }
+ ringbuf_release(ring, len);
+ return i;
+ }
+
+ return 0;
+}
+
+int ut_queue_init_rmind(struct ut_cfg *cfg, struct ut_queue *q) {
+ static size_t ringbuf_obj_size;
+ worker_cnt = cfg->ring.producer_cnt + cfg->ring.consumer_cnt;
+
+ ringbuf_get_sizes(worker_cnt, &ringbuf_obj_size, NULL);
+ ringbuf_t *r = ut_malloc(UT_MODULE_RMIND, ringbuf_obj_size);
+ if (r == NULL) {
+ exit(-1);
+ }
+
+ size_t buf_size = sizeof(void *) * cfg->ring.entries_cnt;
+ rmind_buf = ut_malloc(UT_MODULE_RMIND, buf_size);
+ if (rmind_buf == NULL) {
+ exit(-1);
+ }
+ ringbuf_setup(r, worker_cnt, buf_size);
+
+ rmind_workers = ut_malloc(UT_MODULE_RMIND, sizeof(*rmind_workers) * worker_cnt);
+ if (rmind_workers == NULL) {
+ exit(-1);
+ }
+ for (uint32_t i = 0; i < worker_cnt; i++) {
+ rmind_workers[i] = ringbuf_register(r, i);
+ if (rmind_workers[i] == NULL) {
+ exit(-1);
+ }
+ }
+
+ q->ring = r;
+ q->ring_free_f = (ut_ring_free_f)ut_queue_free_rmind;
+ q->enqueue_f = NULL;
+ q->dequeue_f = NULL;
+ q->enqueue_burst_f = (ut_enqueue_burst_f)ut_enqueue_burst_rmind;
+ q->dequeue_burst_f = (ut_dequeue_burst_f)ut_dequeue_burst_rmind;
+
+ return 0;
+}
+
+int bcm_queue_init(struct ut_cfg *cfg, struct ut_queue *q) {
+ if (cfg == NULL || q == NULL) {
+ return BBQ_ERR_INPUT_NULL;
+ }
+
+ memset(q, 0, sizeof(*q));
+ int ret = -1;
+ q->ring_type = cfg->ring.ring_type;
+ switch (q->ring_type) {
+ case UT_RING_TYPE_DPDK:
+ ret = ut_queue_init_dpdk(cfg, q);
+ break;
+ case UT_RING_TYPE_BBQ:
+ ret = ut_queue_init_bbq(cfg, q);
+ break;
+ case UT_RING_TYPE_RMIND:
+ ret = ut_queue_init_rmind(cfg, q);
+ break;
+ default:
+ return BBQ_ERR;
+ }
+
+ return ret;
+}
diff --git a/perf/benchmark/bcm_queue.h b/perf/benchmark/bcm_queue.h
new file mode 100644
index 0000000..11006e4
--- /dev/null
+++ b/perf/benchmark/bcm_queue.h
@@ -0,0 +1,10 @@
+/*
+ * @Author: liuyu
+ * @LastEditTime: 2024-07-07 21:18:56
+ * @Email: [email protected]
+ * @Describe: TODO
+ */
+#include "rte_ring.h"
+#include "ut_bbq_func.h"
+
+extern int bcm_queue_init(struct ut_cfg *cfg, struct ut_queue *q); \ No newline at end of file
diff --git a/perf/benchmark/benchmark.sh b/perf/benchmark/benchmark.sh
new file mode 100755
index 0000000..abde645
--- /dev/null
+++ b/perf/benchmark/benchmark.sh
@@ -0,0 +1,107 @@
+#!/bin/bash
+###
+# @Author: liuyu
+ # @LastEditTime: 2024-06-30 21:43:01
+# @Describe: 运行性能测试的脚本
+###
+
+ring_type_arr=("bbq" "dpdk" "rmind")
+burst_arr=("32" "16" "8" "1")
+
+# 检查参数数量
+if [ "$#" -ne 3 ]; then
+ echo "Usage: $0 <path to benchmark> <path to config file or directory> <ring type>"
+ exit 1
+fi
+
+# 获取参数值
+BENCHMARK_PATH=$1
+CONFIG_DIR=$2
+RING_TYPE=$3
+
+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
+ echo "skip perf*"
+ # echo perf stat -e L1-dcache-loads,L1-dcache-load-misses "$BENCHMARK_PATH" "$ini" "$ring" "$BURST_CNT"
+ # perf stat -e L1-dcache-loads,L1-dcache-load-misses "$BENCHMARK_PATH" "$ini" "$ring" "$BURST_CNT"
+ else
+ "$BENCHMARK_PATH" "$ini" "$ring" "$burst" 2>&1 | tee -a "$log_file"
+ fi
+}
+
+function exec_benchmark() {
+ # 提取配置文件名(不带路径)
+ local INI_FILE=$1
+ local log_file=$2
+ local burst=$3
+
+ # 执行benchmark命令并传递配置文件作为参数
+ echo "Executing benchmark with $INI_FILE"
+
+ # 使用所有ring_type
+ if [ "$RING_TYPE" == "all" ]; then
+ for ring_type_tmp in "${ring_type_arr[@]}"; do
+ echo start ring:"$ring_type_tmp"
+ exec_benchmark_ring_type "$INI_FILE" "$ring_type_tmp" "$log_file" "$burst"
+ done
+ else
+ exec_benchmark_ring_type "$INI_FILE" "$RING_TYPE" "$log_file" "$burst"
+ fi
+}
+
+# 检查benchmark文件是否存在且可执行
+if [ ! -x "$BENCHMARK_PATH" ]; then
+ echo "Error: Benchmark executable '$BENCHMARK_PATH' does not exist or is not executable."
+ exit 1
+fi
+
+# 检查配置文件目录是否存在
+if [ ! -e "$CONFIG_DIR" ]; then
+ echo "Error: Config directory '$CONFIG_DIR' does not exist."
+ exit 1
+fi
+
+# 创建报告目录
+timestamp=$(date +"%Y%m%d_%H%M%S")
+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"
+ for i in {1..3}; do
+ echo ======"$i"========
+ report_path="$burst_dir"/report_"$i".txt
+ if [[ -f "$CONFIG_DIR" ]]; then
+ # 如果是文件,直接执行
+ exec_benchmark "$CONFIG_DIR" "$report_path" "$burst"
+ else
+ # 使用 find 命令递归地搜索所有的 .ini 文件,并按文件名排序
+ find "$CONFIG_DIR" -type f -name "*.ini" -print0 | sort -z | while IFS= read -r -d '' INI_FILE; do
+ if [ -f "$INI_FILE" ]; then
+ exec_benchmark "$INI_FILE" "$report_path" "$burst"
+ fi
+ done
+ fi
+
+ sleep 1
+ done
+done
+
+# 结束时间
+end_time=$(date +%s)
+# 计算时间差(秒)
+runtime=$((end_time - start_time))
+# 输出运行时间
+echo "done, use $runtime second"
diff --git a/perf/benchmark/config/bbq_debug/debug.ini b/perf/benchmark/config/bbq_debug/debug.ini
new file mode 100644
index 0000000..cead690
--- /dev/null
+++ b/perf/benchmark/config/bbq_debug/debug.ini
@@ -0,0 +1,15 @@
+[base]
+ introduce = "bbq简单负载下,多生产者、单消费者 block=0" ;测试配置说明
+ cores = "20-27" ;测试用核心起止范围
+
+[ring]
+ workload = "simple" ;负载模式 simple/complex
+ entries_cnt = 8 ;ring初始化时分配entry的个数
+ block_count = 2 ;bbq配置,等于0则表示根据entries_cnt自动计算
+ producer_cnt = 4 ;生产者个数
+ consumer_cnt = 1 ;消费者个数
+
+[run]
+ run_time = 10 ; 整体运行的秒数,大于0生效
+ enqueue_cnt = 0 ;每个线程入队次数,大于0生效
+ dequeue_cnt = 0 ;每个线程出队次数,大于0生效 \ No newline at end of file
diff --git a/perf/benchmark/config/compare/case1_simple_spsc.ini b/perf/benchmark/config/compare/case1_simple_spsc.ini
new file mode 100644
index 0000000..e1ee087
--- /dev/null
+++ b/perf/benchmark/config/compare/case1_simple_spsc.ini
@@ -0,0 +1,14 @@
+[base]
+ introduce = "general case1 简单负载下,单生产者、单消费者 吞吐测试" ;测试配置说明
+ cores = "20-27" ;测试用核心起止范围
+
+[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 = 15 ; 整体运行的秒数,大于0生效
+ run_ok_times = 0 ;成功入队/出队次数,大于0生效。 \ No newline at end of file
diff --git a/perf/benchmark/config/compare/case2_simple_spmc.ini b/perf/benchmark/config/compare/case2_simple_spmc.ini
new file mode 100644
index 0000000..8216381
--- /dev/null
+++ b/perf/benchmark/config/compare/case2_simple_spmc.ini
@@ -0,0 +1,14 @@
+[base]
+ introduce = "general case2 简单负载下,单生产者、多消费者 吞吐测试" ;测试配置说明
+ cores = "20-27" ;测试用核心起止范围
+
+[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 = 15 ; 整体运行的秒数,大于0生效
+ run_ok_times = 0 ;成功入队/出队次数,大于0生效。
diff --git a/perf/benchmark/config/compare/case3_simple_mpsc.ini b/perf/benchmark/config/compare/case3_simple_mpsc.ini
new file mode 100644
index 0000000..3476774
--- /dev/null
+++ b/perf/benchmark/config/compare/case3_simple_mpsc.ini
@@ -0,0 +1,14 @@
+[base]
+ introduce = "general case3 简单负载下,多生产者、单消费者 吞吐测试" ;测试配置说明
+ cores = "20-27" ;测试用核心起止范围
+
+[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 = 15 ; 整体运行的秒数,大于0生效
+ run_ok_times = 0 ;成功入队/出队次数,大于0生效。 \ No newline at end of file
diff --git a/perf/benchmark/config/compare/case4_complex_spmc.ini b/perf/benchmark/config/compare/case4_complex_spmc.ini
new file mode 100644
index 0000000..64e3e41
--- /dev/null
+++ b/perf/benchmark/config/compare/case4_complex_spmc.ini
@@ -0,0 +1,14 @@
+[base]
+ introduce = "general case4 复杂负载下,单生产者、多消费者 吞吐测试" ;测试配置说明
+ cores = "20-27" ;测试用核心起止范围
+
+[ring]
+ workload = "complex" ;负载模式 simple/complex
+ entries_cnt = 4096 ;ring初始化时分配entry的个数
+ block_count = 0 ;bbq配置,等于0则表示根据entries_cnt自动计算
+ producer_cnt = 1 ;生产者个数
+ consumer_cnt = 4 ;消费者个数
+
+[run]
+ run_time = 15 ; 整体运行的秒数,大于0生效
+ run_ok_times = 0 ;成功入队/出队次数,大于0生效。 \ No newline at end of file
diff --git a/perf/benchmark/config/compare/case5_complex_mpsc.ini b/perf/benchmark/config/compare/case5_complex_mpsc.ini
new file mode 100644
index 0000000..2404649
--- /dev/null
+++ b/perf/benchmark/config/compare/case5_complex_mpsc.ini
@@ -0,0 +1,14 @@
+[base]
+ introduce = "general case5 复杂负载下,多生产者、单消费者 吞吐测试" ;测试配置说明
+ cores = "20-27" ;测试用核心起止范围
+
+[ring]
+ workload = "complex" ;负载模式 simple/complex
+ entries_cnt = 4096 ;ring初始化时分配entry的个数
+ block_count = 0 ;bbq配置,等于0则表示根据entries_cnt自动计算
+ producer_cnt = 4 ;生产者个数
+ consumer_cnt = 1 ;消费者个数
+
+[run]
+ run_time = 15 ; 整体运行的秒数,大于0生效
+ run_ok_times = 0 ;成功入队/出队次数,大于0生效。 \ No newline at end of file
diff --git a/perf/benchmark/config/compare/case6_simple_mp0c.ini b/perf/benchmark/config/compare/case6_simple_mp0c.ini
new file mode 100644
index 0000000..62325e4
--- /dev/null
+++ b/perf/benchmark/config/compare/case6_simple_mp0c.ini
@@ -0,0 +1,14 @@
+[base]
+ introduce = "general case6 简单负载下,多生产者、无消费者,测试满队入队操作时延" ;测试配置说明
+ cores = "20-27" ;测试用核心起止范围
+
+[ring]
+ workload = "simple" ;负载模式 simple/complex
+ entries_cnt = 4096 ;ring初始化时分配entry的个数
+ block_count = 0 ;bbq配置,等于0则表示根据entries_cnt自动计算
+ producer_cnt = 4 ;生产者个数
+ consumer_cnt = 0 ;消费者个数
+
+[run]
+ run_time = 15 ; 整体运行的秒数,大于0生效
+ run_ok_times = 0 ;成功入队/出队次数,大于0生效。 \ No newline at end of file
diff --git a/perf/benchmark/config/compare/case7_simple_0pmc.ini b/perf/benchmark/config/compare/case7_simple_0pmc.ini
new file mode 100644
index 0000000..1c5ed2c
--- /dev/null
+++ b/perf/benchmark/config/compare/case7_simple_0pmc.ini
@@ -0,0 +1,14 @@
+[base]
+ introduce = "general case7 简单负载下,无生产者、多消费者,测试空队出队操作时延" ;测试配置说明
+ cores = "20-27" ;测试用核心起止范围
+
+[ring]
+ workload = "simple" ;负载模式 simple/complex
+ entries_cnt = 4096 ;ring初始化时分配entry的个数
+ block_count = 0 ;bbq配置,等于0则表示根据entries_cnt自动计算
+ producer_cnt = 0 ;生产者个数
+ consumer_cnt = 4 ;消费者个数
+
+[run]
+ run_time = 15 ; 整体运行的秒数,大于0生效
+ run_ok_times = 0 ;成功入队/出队次数,大于0生效。 \ No newline at end of file
diff --git a/perf/benchmark/config/compare/case8_simple_mpmc.ini b/perf/benchmark/config/compare/case8_simple_mpmc.ini
new file mode 100644
index 0000000..b5026bb
--- /dev/null
+++ b/perf/benchmark/config/compare/case8_simple_mpmc.ini
@@ -0,0 +1,14 @@
+[base]
+ introduce = "general case8 简单负载下,多生产者、多消费者 吞吐测试" ;测试配置说明
+ cores = "20-27" ;测试用核心起止范围
+
+[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 = 15 ; 整体运行的秒数,大于0生效
+ run_ok_times = 0 ;成功入队/出队次数,大于0生效。 \ No newline at end of file
diff --git a/perf/benchmark/config/compare/case9_simple_mpmc_overcore.ini b/perf/benchmark/config/compare/case9_simple_mpmc_overcore.ini
new file mode 100644
index 0000000..b4b304a
--- /dev/null
+++ b/perf/benchmark/config/compare/case9_simple_mpmc_overcore.ini
@@ -0,0 +1,14 @@
+[base]
+ introduce = "general case9 简单负载下,多生产者、多消费者 线程核心超过已有核心时的吞吐测试" ;测试配置说明
+ cores = "20-27" ;测试用核心起止范围
+
+[ring]
+ workload = "simple" ;负载模式 simple/complex
+ entries_cnt = 4096 ;ring初始化时分配entry的个数
+ block_count = 0 ;bbq配置,等于0则表示根据entries_cnt自动计算
+ producer_cnt = 16 ;生产者个数
+ consumer_cnt = 16 ;消费者个数
+
+[run]
+ run_time = 15 ; 整体运行的秒数,大于0生效
+ run_ok_times = 0 ;成功入队/出队次数,大于0生效。 \ No newline at end of file