From 760fa10061e702d428e9f4aa73f9a53056c8e6a7 Mon Sep 17 00:00:00 2001 From: Zelong Yue Date: Fri, 11 Jul 2025 13:33:03 +0800 Subject: [PATCH] Perftest: Add support for Send with Immediate verb Currently, perftest supports RDMA Write / Write-with-Immediate / Send / Read and Atomic operations, but lacks Send-with-Immediate support. This commit adds Send-with-Immediate functionality, allowing users to test it via ib_send_bw with --send_with_imm flag. Additionally, to verify the completion logic for operations with immediate data is correct, completion events are now validated to ensure the IBV_WC_WITH_IMM flag is set. Signed-off-by: Zelong Yue --- src/perftest_parameters.c | 88 ++++++++++++------- src/perftest_parameters.h | 3 +- src/perftest_resources.c | 179 +++++++++++++++++++++++++++++--------- src/perftest_resources.h | 10 +++ 4 files changed, 210 insertions(+), 70 deletions(-) diff --git a/src/perftest_parameters.c b/src/perftest_parameters.c index 1b8739ba..b70c7cc6 100755 --- a/src/perftest_parameters.c +++ b/src/perftest_parameters.c @@ -31,7 +31,7 @@ #define HEX_BASE (16) #define DEFAULT_JSON_FILE_NAME "perftest_out.json" static const char *connStr[] = {"RC","UC","UD","RawEth","XRC","DC","SRD"}; -static const char *testsStr[] = {"Send","RDMA_Write","RDMA_Write_imm","RDMA_Read","Atomic"}; +static const char *testsStr[] = {"Send", "Send_imm", "RDMA_Write","RDMA_Write_imm","RDMA_Read","Atomic"}; static const char *portStates[] = {"Nop","Down","Init","Armed","","Active Defer"}; static const char *qp_state[] = {"OFF","ON"}; static const char *exchange_state[] = {"Ethernet","rdma_cm"}; @@ -283,7 +283,7 @@ static void usage(const char *argv0, VerbType verb, TestType tst, int connection } if (connection_type != RawEth) { - if (verb == SEND) { + if (verb == SEND || verb == SEND_IMM) { printf(" -c, --connection= "); printf(" Connection type RC/XRC/UC/UD/DC/SRD (default RC) (SYMMETRIC)\n"); } else if (verb == WRITE || verb == WRITE_IMM) { @@ -417,7 +417,7 @@ static void usage(const char *argv0, VerbType verb, TestType tst, int connection printf(" Generate Cqe only after <--cq-mod> completion\n"); } - if ((verb == SEND || verb == WRITE_IMM) && tst != FS_RATE) { + if ((verb == SEND || verb == SEND_IMM || verb == WRITE_IMM) && tst != FS_RATE) { printf(" -r, --rx-depth= "); printf(" Rx queue size (default %d).",DEF_RX_SEND); printf(" If using srq, rx-depth controls max-wr size of the srq\n"); @@ -527,7 +527,7 @@ static void usage(const char *argv0, VerbType verb, TestType tst, int connection printf(" Force the link(s) to a specific type: IB or Ethernet.\n"); } - if (verb == SEND) { + if (verb == SEND || verb == SEND_IMM) { printf(" --use-srq "); printf(" Use a Shared Receive Queue. --rx-depth controls max-wr size of the SRQ \n"); } @@ -755,6 +755,11 @@ static void usage(const char *argv0, VerbType verb, TestType tst, int connection #endif } + if ((tst == LAT || tst == BW) && verb == SEND) { + printf(" --send_with_imm "); + printf(" Use send-with-immediate verb instead of send\n"); + } + putchar('\n'); } /****************************************************************************** @@ -877,8 +882,11 @@ static void init_perftest_params(struct perftest_parameters *user_param) user_param->use_mcg = OFF; user_param->use_rdma_cm = OFF; user_param->work_rdma_cm = OFF; - user_param->rx_depth = (user_param->verb == SEND || user_param->verb == WRITE || user_param->verb == WRITE_IMM) - ? DEF_RX_SEND : DEF_RX_RDMA; + user_param->rx_depth = (user_param->verb == SEND || + user_param->verb == SEND_IMM || + user_param->verb == WRITE || + user_param->verb == WRITE_IMM) + ? DEF_RX_SEND : DEF_RX_RDMA; user_param->duplex = OFF; user_param->noPeak = OFF; user_param->req_cq_mod = 0; @@ -995,9 +1003,10 @@ static void init_perftest_params(struct perftest_parameters *user_param) user_param->perform_warm_up = 0; user_param->use_ooo = 0; user_param->disable_pcir = 0; - user_param->source_ip = NULL; - user_param->has_source_ip = 0; - user_param->use_write_with_imm = 0; + user_param->source_ip = NULL; + user_param->has_source_ip = 0; + user_param->use_write_with_imm = 0; + user_param->use_send_with_imm = 0; user_param->use_unsolicited_write = 0; user_param->congest_type = OFF; user_param->no_lock = OFF; @@ -1071,7 +1080,7 @@ static void change_conn_type(int *cptr, VerbType verb, const char *optarg) } else if (strcmp(connStr[2], optarg)==0) { *cptr = UD; - if (verb != SEND) { + if (verb != SEND && verb != SEND_IMM) { fprintf(stderr," UD connection only possible in SEND verb\n"); exit(1); } @@ -1253,7 +1262,7 @@ static void force_dependecies(struct perftest_parameters *user_param) user_param->tx_depth = user_param->iters; } - if ((user_param->verb == SEND || user_param->verb == WRITE_IMM) && + if ((user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) && user_param->rx_depth > user_param->iters) { user_param->rx_depth = user_param->iters; } @@ -1316,9 +1325,9 @@ static void force_dependecies(struct perftest_parameters *user_param) exit (1); } - if (user_param->use_srq && user_param->verb != SEND) { + if (user_param->use_srq && user_param->verb != SEND && user_param->verb != SEND_IMM) { printf(RESULT_LINE); - printf(" Using SRQ only avavilible in SEND tests.\n"); + printf(" Using SRQ only avavilible in SEND / SEND_IMM tests.\n"); exit (1); } @@ -1346,8 +1355,9 @@ static void force_dependecies(struct perftest_parameters *user_param) if (user_param->connection_type == DC && !user_param->use_srq) user_param->use_srq = ON; - if (user_param->use_srq && user_param->verb == SEND && - user_param->num_of_qps > user_param->rx_depth) { + if (user_param->use_srq + && (user_param->verb == SEND || user_param->verb == SEND_IMM) + && (user_param->num_of_qps > user_param->rx_depth)) { printf(RESULT_LINE); printf(" Using SRQ depth should be greater than number of QPs.\n"); exit (1); @@ -1600,8 +1610,8 @@ static void force_dependecies(struct perftest_parameters *user_param) } } - if ((user_param->verb == SEND || user_param->verb == WRITE_IMM) && user_param->tst == BW - && user_param->machine == SERVER && !user_param->duplex ) { + if ((user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) + && user_param->tst == BW && user_param->machine == SERVER && !user_param->duplex ) { if (user_param->noPeak == OFF) printf(" WARNING: BW peak won't be measured in this run.\n"); user_param->noPeak = ON; @@ -1626,9 +1636,10 @@ static void force_dependecies(struct perftest_parameters *user_param) } - if (user_param->duplex && (user_param->verb == SEND || user_param->verb == WRITE_IMM)) { + if (user_param->duplex && + (user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM)) { printf(RESULT_LINE); - fprintf(stderr," run_infinitely mode is not supported in SEND or WRITE_IMM " + fprintf(stderr," run_infinitely mode is not supported in SEND, SEND_IMM or WRITE_IMM " "Bidirectional BW test\n"); exit(1); } @@ -1820,9 +1831,10 @@ static void force_dependecies(struct perftest_parameters *user_param) } if (user_param->rate_limit_type == SW_RATE_LIMIT) { - if (user_param->tst != BW || user_param->verb == ATOMIC || (user_param->verb == SEND && user_param->duplex)) { + if (user_param->tst != BW || user_param->verb == ATOMIC + || ((user_param->verb == SEND || user_param->verb == SEND_IMM) && user_param->duplex)) { printf(RESULT_LINE); - fprintf(stderr,"SW Rate limiter cann't be executed on non-BW, ATOMIC or bidirectional SEND tests\n"); + fprintf(stderr,"SW Rate limiter cann't be executed on non-BW, ATOMIC or bidirectional SEND / SEND_IMM tests\n"); exit(1); } } else if (user_param->rate_limit_type == HW_RATE_LIMIT) { @@ -1973,7 +1985,8 @@ static void force_dependecies(struct perftest_parameters *user_param) } /* WA for a bug when rx_depth is odd in SEND */ - if ((user_param->verb == SEND || user_param->verb == WRITE_IMM) && (user_param->rx_depth % 2 == 1) && user_param->test_method == RUN_REGULAR) + if ((user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) + && (user_param->rx_depth % 2 == 1) && user_param->test_method == RUN_REGULAR) user_param->rx_depth += 1; if (user_param->test_type == ITERATIONS && user_param->iters > 20000 && user_param->noPeak == OFF && user_param->tst == BW) { @@ -2460,6 +2473,7 @@ static void ctx_set_max_inline(struct ibv_context *context,struct perftest_param switch(user_param->verb) { case WRITE_IMM: case WRITE: user_param->inline_size = (user_param->connection_type == DC)? DEF_INLINE_DC : DEF_INLINE_WRITE; break; + case SEND_IMM: case SEND : user_param->inline_size = (user_param->connection_type == DC)? DEF_INLINE_DC : (user_param->connection_type == UD)? DEF_INLINE_SEND_UD : DEF_INLINE_SEND_RC_UC_XRC ; break; default : user_param->inline_size = 0; @@ -2607,6 +2621,7 @@ int parser(struct perftest_parameters *user_param,char *argv[], int argc) static int recv_post_list_flag = 0; static int payload_flag = 0; static int use_write_with_imm_flag = 0; + static int use_send_with_imm_flag = 0; #ifdef HAVE_SRD_WITH_UNSOLICITED_WRITE_RECV static int unsolicited_write_flag = 0; #endif @@ -2812,6 +2827,7 @@ int parser(struct perftest_parameters *user_param,char *argv[], int argc) #endif {.name = "bind_source_ip", .has_arg = 1, .flag = &source_ip_flag, .val = 1}, {.name = "write_with_imm", .has_arg = 0, .flag = &use_write_with_imm_flag, .val = 1 }, + {.name = "send_with_imm", .has_arg = 0, .flag = &use_send_with_imm_flag, .val = 1 }, #ifdef HAVE_OOO_RECV_WRS { .name = "no_enhanced_reorder", .has_arg = 0, .flag = &no_enhanced_reorder_flag, .val = 1}, #endif @@ -2909,7 +2925,8 @@ int parser(struct perftest_parameters *user_param,char *argv[], int argc) break; case 'M': GET_STRING(user_param->user_mgid,strdupa(optarg)); break; case 'r': CHECK_VALUE_IN_RANGE(user_param->rx_depth,int,MIN_RX,MAX_RX," Rx depth",not_int_ptr); - if (user_param->verb != SEND && user_param->verb != WRITE && user_param->verb != WRITE_IMM && user_param->rx_depth > DEF_RX_RDMA) { + if (user_param->verb != SEND && user_param->verb != SEND_IMM && + user_param->verb != WRITE && user_param->verb != WRITE_IMM && user_param->rx_depth > DEF_RX_RDMA) { fprintf(stderr," On RDMA verbs rx depth can be only 1\n"); free(duplicates_checker); return FAILURE; @@ -3575,6 +3592,14 @@ int parser(struct perftest_parameters *user_param,char *argv[], int argc) user_param->verb = WRITE_IMM; use_write_with_imm_flag = 0; } + if (use_send_with_imm_flag) { + if ((user_param->tst != LAT && user_param->tst != BW) || user_param->verb != SEND) { + fprintf(stderr, "Send_with_imm can only be used with send_lat and send_bw tests\n"); + return FAILURE; + } + user_param->verb = SEND_IMM; + use_send_with_imm_flag = 0; + } #ifdef HAVE_SRD_WITH_UNSOLICITED_WRITE_RECV if (unsolicited_write_flag) { user_param->use_unsolicited_write = 1; @@ -4041,7 +4066,8 @@ void ctx_print_test_info(struct perftest_parameters *user_param) if (user_param->recv_post_list > 1) printf(" Recv Post List : %d\n", user_param->recv_post_list); - if ((user_param->verb == SEND || user_param->verb == WRITE_IMM) && (user_param->machine == SERVER || user_param->duplex)) { + if ((user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) + && (user_param->machine == SERVER || user_param->duplex)) { printf(" RX depth : %d\n",user_param->rx_depth); } @@ -4189,7 +4215,7 @@ void print_report_bw (struct perftest_parameters *user_param, struct bw_report_d exit(1); } - run_inf_bi_factor = (user_param->duplex && user_param->test_method == RUN_INFINITELY) ? (user_param->verb == SEND ? 1 : 2) : 1 ; + run_inf_bi_factor = (user_param->duplex && user_param->test_method == RUN_INFINITELY) ? ((user_param->verb == SEND || user_param->verb == SEND_IMM) ? 1 : 2) : 1 ; tsize = run_inf_bi_factor * user_param->size; num_of_calculated_iters *= (user_param->test_type == DURATION) ? 1 : num_of_qps; location_arr = (user_param->noPeak) ? 0 : num_of_calculated_iters - 1; @@ -4227,8 +4253,9 @@ void print_report_bw (struct perftest_parameters *user_param, struct bw_report_d my_bw_rep->msgRate_avg_p2 = msgRate_avg_p2; my_bw_rep->sl = user_param->sl; - if (!user_param->duplex || ((user_param->verb == SEND || user_param->verb == WRITE_IMM) && user_param->test_type == DURATION) - || user_param->test_method == RUN_INFINITELY || user_param->connection_type == RawEth) + if (!user_param->duplex + || ((user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) && user_param->test_type == DURATION) + || user_param->test_method == RUN_INFINITELY || user_param->connection_type == RawEth) print_full_bw_report(user_param, my_bw_rep, NULL); if (free_my_bw_rep == 1) { @@ -4300,8 +4327,8 @@ static void write_test_info_to_file(int out_json_fds, struct perftest_parameters if (user_param->recv_post_list > 1) dprintf(out_json_fds, "\"Recv_Post_List\": %d,\n", user_param->recv_post_list); - if ((user_param->verb == SEND || user_param->verb == WRITE_IMM) && - (user_param->machine == SERVER || user_param->duplex)) { + if ((user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) && + (user_param->machine == SERVER || user_param->duplex)) { dprintf(out_json_fds, "\"RX_depth\": %d,\n",user_param->rx_depth); } @@ -4397,7 +4424,8 @@ void print_full_bw_report (struct perftest_parameters *user_param, struct bw_rep msgRate_avg_p2 += rem_bw_rep->msgRate_avg_p2; } - if ( (user_param->duplex && rem_bw_rep != NULL) || (!user_param->duplex && rem_bw_rep == NULL) || (user_param->duplex && user_param->verb == SEND)) { + if ((user_param->duplex && rem_bw_rep != NULL) || (!user_param->duplex && rem_bw_rep == NULL) + || (user_param->duplex && (user_param->verb == SEND || user_param->verb == SEND_IMM))) { /* Verify Limits */ if ( ((user_param->is_limit_bw == ON )&& (user_param->limit_bw > bw_avg)) ) user_param->is_bw_limit_passed |= 0; diff --git a/src/perftest_parameters.h b/src/perftest_parameters.h index 84d96e45..47156853 100755 --- a/src/perftest_parameters.h +++ b/src/perftest_parameters.h @@ -324,7 +324,7 @@ } while (0) /* The Verb of the benchmark. */ -typedef enum { SEND , WRITE, WRITE_IMM, READ, ATOMIC } VerbType; +typedef enum { SEND, SEND_IMM, WRITE, WRITE_IMM, READ, ATOMIC } VerbType; /* The type of the test */ typedef enum { LAT , BW , LAT_BY_BW, FS_RATE } TestType; @@ -673,6 +673,7 @@ struct perftest_parameters { int has_source_ip; int ah_allocated; int use_write_with_imm; + int use_send_with_imm; int use_unsolicited_write; int use_enhanced_reorder; int no_enhanced_reorder; diff --git a/src/perftest_resources.c b/src/perftest_resources.c index 580e2403..9f0fd533 100755 --- a/src/perftest_resources.c +++ b/src/perftest_resources.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -29,7 +30,7 @@ #include "perftest_resources.h" #include "raw_ethernet_resources.h" -static enum ibv_wr_opcode opcode_verbs_array[] = {IBV_WR_SEND,IBV_WR_RDMA_WRITE,IBV_WR_RDMA_WRITE_WITH_IMM,IBV_WR_RDMA_READ}; +static enum ibv_wr_opcode opcode_verbs_array[] = {IBV_WR_SEND,IBV_WR_SEND_WITH_IMM,IBV_WR_RDMA_WRITE,IBV_WR_RDMA_WRITE_WITH_IMM,IBV_WR_RDMA_READ}; static enum ibv_wr_opcode opcode_atomic_array[] = {IBV_WR_ATOMIC_CMP_AND_SWP,IBV_WR_ATOMIC_FETCH_AND_ADD}; #define CPU_UTILITY "/proc/stat" @@ -413,6 +414,10 @@ static inline int _new_post_send(struct pingpong_context *ctx, case IBV_WR_SEND: ibv_wr_send(ctx->qpx[index]); break; + case IBV_WR_SEND_WITH_IMM: + ibv_wr_send_imm( + ctx->qpx[index], 0); + break; case IBV_WR_RDMA_WRITE: ibv_wr_rdma_write( ctx->qpx[index], @@ -564,13 +569,13 @@ static int new_post_read_sge_dc(struct pingpong_context *ctx, int index, static int new_post_send_sge_dc(struct pingpong_context *ctx, int index, struct perftest_parameters *user_param) { - return _new_post_send(ctx, user_param, 0, index, IBV_QPT_DRIVER, IBV_WR_SEND, DC, 0); + return _new_post_send(ctx, user_param, 0, index, IBV_QPT_DRIVER, opcode_verbs_array[user_param->verb], DC, 0); } static int new_post_send_inl_dc(struct pingpong_context *ctx, int index, struct perftest_parameters *user_param) { - return _new_post_send(ctx, user_param, 1, index, IBV_QPT_DRIVER, IBV_WR_SEND, DC, 0); + return _new_post_send(ctx, user_param, 1, index, IBV_QPT_DRIVER, opcode_verbs_array[user_param->verb], DC, 0); } static int new_post_atomic_fa_sge_dc(struct pingpong_context *ctx, int index, @@ -588,19 +593,19 @@ static int new_post_atomic_cs_sge_dc(struct pingpong_context *ctx, int index, static int new_post_send_sge_rc(struct pingpong_context *ctx, int index, struct perftest_parameters *user_param) { - return _new_post_send(ctx, user_param, 0, index, IBV_QPT_RC, IBV_WR_SEND, RC, 0); + return _new_post_send(ctx, user_param, 0, index, IBV_QPT_RC, opcode_verbs_array[user_param->verb], RC, 0); } static int new_post_send_sge_enc_rc(struct pingpong_context *ctx, int index, struct perftest_parameters *user_param) { - return _new_post_send(ctx, user_param, 0, index, IBV_QPT_RC, IBV_WR_SEND, RC, 1); + return _new_post_send(ctx, user_param, 0, index, IBV_QPT_RC, opcode_verbs_array[user_param->verb], RC, 1); } static int new_post_send_inl_rc(struct pingpong_context *ctx, int index, struct perftest_parameters *user_param) { - return _new_post_send(ctx, user_param, 1, index, IBV_QPT_RC, IBV_WR_SEND, RC, 0); + return _new_post_send(ctx, user_param, 1, index, IBV_QPT_RC, opcode_verbs_array[user_param->verb], RC, 0); } static int new_post_write_sge_rc(struct pingpong_context *ctx, int index, @@ -648,25 +653,25 @@ static int new_post_atomic_cs_sge_rc(struct pingpong_context *ctx, int index, static int new_post_send_sge_ud(struct pingpong_context *ctx, int index, struct perftest_parameters *user_param) { - return _new_post_send(ctx, user_param, 0, index, IBV_QPT_UD, IBV_WR_SEND, UD, 0); + return _new_post_send(ctx, user_param, 0, index, IBV_QPT_UD, opcode_verbs_array[user_param->verb], UD, 0); } static int new_post_send_inl_ud(struct pingpong_context *ctx, int index, struct perftest_parameters *user_param) { - return _new_post_send(ctx, user_param, 1, index, IBV_QPT_UD, IBV_WR_SEND, UD, 0); + return _new_post_send(ctx, user_param, 1, index, IBV_QPT_UD, opcode_verbs_array[user_param->verb], UD, 0); } static int new_post_send_sge_uc(struct pingpong_context *ctx, int index, struct perftest_parameters *user_param) { - return _new_post_send(ctx, user_param, 0, index, IBV_QPT_UC, IBV_WR_SEND, UC, 0); + return _new_post_send(ctx, user_param, 0, index, IBV_QPT_UC, opcode_verbs_array[user_param->verb], UC, 0); } static int new_post_send_inl_uc(struct pingpong_context *ctx, int index, struct perftest_parameters *user_param) { - return _new_post_send(ctx, user_param, 1, index, IBV_QPT_UC, IBV_WR_SEND, UC, 0); + return _new_post_send(ctx, user_param, 1, index, IBV_QPT_UC, opcode_verbs_array[user_param->verb], UC, 0); } static int new_post_write_sge_uc(struct pingpong_context *ctx, int index, @@ -715,13 +720,13 @@ static int new_post_write_inl_srd(struct pingpong_context *ctx, int index, static int new_post_send_sge_xrc(struct pingpong_context *ctx, int index, struct perftest_parameters *user_param) { - return _new_post_send(ctx, user_param, 0, index, IBV_QPT_XRC_SEND, IBV_WR_SEND, XRC, 0); + return _new_post_send(ctx, user_param, 0, index, IBV_QPT_XRC_SEND, opcode_verbs_array[user_param->verb], XRC, 0); } static int new_post_send_inl_xrc(struct pingpong_context *ctx, int index, struct perftest_parameters *user_param) { - return _new_post_send(ctx, user_param, 1, index, IBV_QPT_XRC_SEND, IBV_WR_SEND, XRC, 0); + return _new_post_send(ctx, user_param, 1, index, IBV_QPT_XRC_SEND, opcode_verbs_array[user_param->verb], XRC, 0); } static int new_post_write_sge_xrc(struct pingpong_context *ctx, int index, @@ -830,7 +835,7 @@ static int ctx_xrc_srq_create(struct pingpong_context *ctx, srq_init_attr.srq_type = IBV_SRQT_XRC; srq_init_attr.xrcd = ctx->xrc_domain; - if(user_param->verb == SEND || user_param->verb == WRITE_IMM) + if (user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) srq_init_attr.cq = ctx->recv_cq; else srq_init_attr.cq = ctx->send_cq; @@ -904,6 +909,8 @@ static struct ibv_qp *ctx_xrc_qp_create(struct pingpong_context *ctx, opcode = opcode_verbs_array[user_param->verb]; if (opcode == IBV_WR_SEND) qp_init_attr.send_ops_flags |= IBV_QP_EX_WITH_SEND; + else if (opcode == IBV_WR_SEND_WITH_IMM) + qp_init_attr.send_ops_flags |= IBV_QP_EX_WITH_SEND_WITH_IMM; else if (opcode == IBV_WR_RDMA_WRITE) qp_init_attr.send_ops_flags |= IBV_QP_EX_WITH_RDMA_WRITE; else if (opcode == IBV_WR_RDMA_WRITE_WITH_IMM) @@ -1145,7 +1152,8 @@ int alloc_ctx(struct pingpong_context *ctx,struct perftest_parameters *user_para memset(ctx->ccnt, 0, user_param->num_of_qps * sizeof (uint64_t)); } else if ((user_param->tst == BW || user_param->tst == LAT_BY_BW) - && (user_param->verb == SEND || user_param->verb == WRITE_IMM) && user_param->machine == SERVER) { + && (user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) + && user_param->machine == SERVER) { ALLOC(ctx->my_addr, uint64_t, user_param->num_of_qps); ALLOC(user_param->tcompleted, cycles_t, 1); @@ -1159,7 +1167,7 @@ int alloc_ctx(struct pingpong_context *ctx,struct perftest_parameters *user_para ALLOC(ctx->sge_list, struct ibv_sge,user_param->num_of_qps * user_param->post_list); ALLOC(ctx->wr, struct ibv_send_wr, user_param->num_of_qps * user_param->post_list); ALLOC(ctx->rem_qpn, uint32_t, user_param->num_of_qps); - if ((user_param->verb == SEND && user_param->connection_type == UD) || + if (((user_param->verb == SEND || user_param->verb == SEND_IMM) && user_param->connection_type == UD) || user_param->connection_type == DC || user_param->connection_type == SRD) { ALLOC(ctx->ah, struct ibv_ah*, user_param->num_of_qps); } @@ -1167,7 +1175,8 @@ int alloc_ctx(struct pingpong_context *ctx,struct perftest_parameters *user_para ALLOC(ctx->ah, struct ibv_ah*, user_param->num_of_qps); } - if ((user_param->verb == SEND || user_param->verb == WRITE_IMM) && (user_param->tst == LAT || user_param->machine == SERVER || user_param->duplex)) { + if ((user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) + && (user_param->tst == LAT || user_param->machine == SERVER || user_param->duplex)) { ALLOC(ctx->recv_sge_list, struct ibv_sge, user_param->num_of_qps * user_param->recv_post_list); ALLOC(ctx->rwr, struct ibv_recv_wr, @@ -1278,7 +1287,8 @@ void dealloc_ctx(struct pingpong_context *ctx,struct perftest_parameters *user_p free(ctx->ah); } - if ((user_param->verb == SEND || user_param->verb == WRITE_IMM) && (user_param->tst == LAT || user_param->machine == SERVER || user_param->duplex)) { + if ((user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) + && (user_param->tst == LAT || user_param->machine == SERVER || user_param->duplex)) { if (ctx->recv_sge_list != NULL) free(ctx->recv_sge_list); if (ctx->rwr != NULL) @@ -1380,7 +1390,8 @@ int destroy_ctx(struct pingpong_context *ctx, test_result = 1; } - if ((user_param->verb == SEND || user_param->verb == WRITE_IMM) || (user_param->connection_type == DC && !dct_only)){ + if ((user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) + || (user_param->connection_type == DC && !dct_only)){ if (ibv_destroy_cq(ctx->recv_cq)) { fprintf(stderr, "Failed to destroy CQ - %s\n", strerror(errno)); test_result = 1; @@ -1496,7 +1507,9 @@ int destroy_ctx(struct pingpong_context *ctx, free(ctx->scnt); free(ctx->ccnt); } - else if ((user_param->tst == BW || user_param->tst == LAT_BY_BW ) && user_param->verb == SEND && user_param->machine == SERVER) { + else if ((user_param->tst == BW || user_param->tst == LAT_BY_BW ) + && (user_param->verb == SEND || user_param->verb == SEND_IMM) + && user_param->machine == SERVER) { free(user_param->tposted); free(user_param->tcompleted); @@ -1508,7 +1521,8 @@ int destroy_ctx(struct pingpong_context *ctx, free(ctx->wr); } - if ((user_param->verb == SEND || user_param->verb == WRITE_IMM) && (user_param->tst == LAT || user_param->machine == SERVER || user_param->duplex)) { + if ((user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) + && (user_param->tst == LAT || user_param->machine == SERVER || user_param->duplex)) { free(ctx->rx_buffer_addr); free(ctx->recv_sge_list); @@ -1543,17 +1557,17 @@ static int check_odp_transport_caps(struct perftest_parameters *user_param, uint MachineType machine = user_param->machine; int duplex = user_param->duplex; - if (verb == SEND && duplex == OFF && machine == CLIENT) { + if ((verb == SEND || verb == SEND_IMM) && duplex == OFF && machine == CLIENT) { if (!(caps & IBV_ODP_SUPPORT_SEND)) { fprintf(stderr, " ODP Send is not supported for %s transport.\n", conn_str[conn]); return 0; } - } else if (verb == SEND && duplex == OFF && machine == SERVER) { + } else if ((verb == SEND || verb == SEND_IMM) && duplex == OFF && machine == SERVER) { if (!(caps & (IBV_ODP_SUPPORT_RECV | IBV_ODP_SUPPORT_SRQ_RECV))) { fprintf(stderr, " ODP Recv is not supported for %s transport.\n", conn_str[conn]); return 0; } - } else if (verb == SEND && duplex == ON) { + } else if ((verb == SEND || verb == SEND_IMM) && duplex == ON) { if (!(caps & IBV_ODP_SUPPORT_SEND && caps & (IBV_ODP_SUPPORT_RECV | IBV_ODP_SUPPORT_SRQ_RECV))) { fprintf(stderr, " ODP bidirectional Send is not supported for %s transport.\n", conn_str[conn]); @@ -1737,7 +1751,8 @@ int create_cqs(struct pingpong_context *ctx, struct perftest_parameters *user_pa if (dct_only) tx_buffer_depth = user_param->rx_depth; - if ((user_param->connection_type == DC && !dct_only) || (user_param->verb == SEND || user_param->verb == WRITE_IMM)) + if ((user_param->connection_type == DC && !dct_only) + || (user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM)) need_recv_cq = 1; ret = create_reg_cqs(ctx, user_param, tx_buffer_depth, need_recv_cq); @@ -1803,9 +1818,9 @@ static void initialize_buffer_content(struct pingpong_context *ctx, } #ifdef HAVE_REG_MR_EX -static struct ibv_mr *register_mr_ex(struct pingpong_context *ctx, +static struct ibv_mr *register_mr_ex(struct pingpong_context *ctx, struct perftest_parameters *user_param, - int qp_index, int flags, int dmabuf_fd, + int qp_index, int flags, int dmabuf_fd, uint64_t dmabuf_offset) { struct ibv_mr_init_attr in = {}; @@ -1883,9 +1898,9 @@ static int register_memory_region(struct pingpong_context *ctx, struct ibv_mr *mr = NULL; /* Select the appropriate registration function */ - struct ibv_mr *(*register_func)(struct pingpong_context *ctx, + struct ibv_mr *(*register_func)(struct pingpong_context *ctx, struct perftest_parameters *user_param, - int qp_index, int flags, int dmabuf_fd, + int qp_index, int flags, int dmabuf_fd, uint64_t dmabuf_offset); #ifdef HAVE_REG_MR_EX @@ -2491,7 +2506,8 @@ xrcd: __attribute__((unused)) cqs: ibv_destroy_cq(ctx->send_cq); - if ((user_param->verb == SEND || user_param->verb == WRITE_IMM) || (user_param->connection_type == DC && !dct_only)){ + if ((user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) + || (user_param->connection_type == DC && !dct_only)){ ibv_destroy_cq(ctx->recv_cq); } @@ -2633,7 +2649,7 @@ struct ibv_qp* ctx_qp_create(struct pingpong_context *ctx, #endif attr.send_cq = ctx->send_cq; - attr.recv_cq = (user_param->verb == SEND || user_param->verb == WRITE_IMM) ? ctx->recv_cq : ctx->send_cq; + attr.recv_cq = (user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) ? ctx->recv_cq : ctx->send_cq; is_dc_server_side = ((!(user_param->duplex || user_param->tst == LAT) && (user_param->machine == SERVER)) || @@ -2696,6 +2712,8 @@ struct ibv_qp* ctx_qp_create(struct pingpong_context *ctx, if(0); else if (opcode == IBV_WR_SEND) attr_ex.send_ops_flags |= IBV_QP_EX_WITH_SEND; + else if (opcode == IBV_WR_SEND_WITH_IMM) + attr_ex.send_ops_flags |= IBV_QP_EX_WITH_SEND_WITH_IMM; else if (opcode == IBV_WR_RDMA_WRITE) attr_ex.send_ops_flags |= IBV_QP_EX_WITH_RDMA_WRITE; else if (opcode == IBV_WR_RDMA_WRITE_WITH_IMM) @@ -2923,7 +2941,9 @@ int ctx_modify_qp_to_init(struct ibv_qp *qp,struct perftest_parameters *user_par case WRITE_IMM: case WRITE : attr.qp_access_flags = IBV_ACCESS_REMOTE_WRITE; break; - case SEND : attr.qp_access_flags = IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE; + case SEND_IMM: + case SEND : attr.qp_access_flags = IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE; break; + default: break; } flags |= IBV_QP_ACCESS_FLAGS; } @@ -3213,6 +3233,7 @@ static void ctx_post_send_work_request_func_pointer(struct pingpong_context *ctx switch (user_param->connection_type) { case DC: switch (user_param->verb) { + case SEND_IMM: case SEND: if (use_inl) { ctx->new_post_send_work_request_func_pointer = &new_post_send_inl_dc; @@ -3247,6 +3268,7 @@ static void ctx_post_send_work_request_func_pointer(struct pingpong_context *ctx break; case RC: switch (user_param->verb) { + case SEND_IMM: case SEND: if (use_enc) { ctx->new_post_send_work_request_func_pointer = &new_post_send_sge_enc_rc; @@ -3292,6 +3314,7 @@ static void ctx_post_send_work_request_func_pointer(struct pingpong_context *ctx break; case UD: switch (user_param->verb) { + case SEND_IMM: case SEND: if (use_inl) { ctx->new_post_send_work_request_func_pointer = &new_post_send_inl_ud; @@ -3306,6 +3329,7 @@ static void ctx_post_send_work_request_func_pointer(struct pingpong_context *ctx break; case UC: switch (user_param->verb) { + case SEND_IMM: case SEND: if (use_inl) { ctx->new_post_send_work_request_func_pointer = &new_post_send_inl_uc; @@ -3329,6 +3353,7 @@ static void ctx_post_send_work_request_func_pointer(struct pingpong_context *ctx break; case XRC: switch (user_param->verb) { + case SEND_IMM: case SEND: if (use_inl) { ctx->new_post_send_work_request_func_pointer = &new_post_send_inl_xrc; @@ -3437,7 +3462,7 @@ void ctx_set_send_reg_wqes(struct pingpong_context *ctx, ctx->scnt[i] = 0; ctx->ccnt[i] = 0; ctx->my_addr[i] = (uintptr_t)ctx->buf[i]; - if (user_param->verb != SEND) + if (user_param->verb != SEND || user_param->verb != SEND_IMM) ctx->rem_addr[i] = rem_dest[xrc_offset + i].vaddr; } @@ -3514,7 +3539,7 @@ void ctx_set_send_reg_wqes(struct pingpong_context *ctx, ctx->wr[i*user_param->post_list + j].wr.atomic.swap = ATOMIC_SWAP_VALUE; - } else if (user_param->verb == SEND) { + } else if (user_param->verb == SEND || user_param->verb == SEND_IMM) { if (user_param->connection_type == UD || user_param->connection_type == SRD) { @@ -3531,7 +3556,8 @@ void ctx_set_send_reg_wqes(struct pingpong_context *ctx, } } - if ((user_param->verb == SEND || user_param->verb == WRITE || user_param->verb == WRITE_IMM) && user_param->size <= user_param->inline_size) + if ((user_param->verb == SEND || user_param->verb == SEND_IMM || user_param->verb == WRITE || user_param->verb == WRITE_IMM) + && user_param->size <= user_param->inline_size) ctx->wr[i*user_param->post_list + j].send_flags |= IBV_SEND_INLINE; #ifdef HAVE_XRCD @@ -3973,7 +3999,7 @@ int run_iter_bw(struct pingpong_context *ctx,struct perftest_parameters *user_pa ctx->my_addr[index] + address_offset , 0, ctx->cache_line_size, ctx->cycle_buffer); - if (user_param->verb != SEND) { + if (user_param->verb != SEND && user_param->verb != SEND_IMM) { increase_rem_addr(&ctx->wr[index], user_param->size, ctx->scnt[index], ctx->rem_addr[index], user_param->verb, ctx->cache_line_size, ctx->cycle_buffer); @@ -4109,6 +4135,7 @@ int run_iter_bw_server(struct pingpong_context *ctx, struct perftest_parameters uintptr_t primary_recv_addr = ctx->recv_sge_list[0].addr; int recv_flows_burst = 0; int address_flows_offset =0; + bool with_imm_data = false; struct dyn_poll_ctx *dyn_ctx = init_dyn_poll_ctx(user_param); if (!dyn_ctx) { @@ -4121,6 +4148,10 @@ int run_iter_bw_server(struct pingpong_context *ctx, struct perftest_parameters ctx_post_send_work_request_func_pointer(ctx, user_param); #endif + if (user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) { + with_imm_data = true; + } + ALLOCATE(wc ,struct ibv_wc ,dyn_ctx->config.max); ALLOCATE(swc ,struct ibv_wc ,user_param->tx_depth); @@ -4181,11 +4212,17 @@ int run_iter_bw_server(struct pingpong_context *ctx, struct perftest_parameters for (i = 0; i < ne; i++) { qp_index = (int)get_wr_id_qp_index(wc[i].wr_id); if (wc[i].status != IBV_WC_SUCCESS) { - NOTIFY_COMP_ERROR_RECV(wc[i],rcnt_for_qp[qp_index]); return_value = FAILURE; goto cleaning; } + + if (with_imm_data && !(wc[i].wc_flags & IBV_WC_WITH_IMM)) { + NOTIFY_COMP_FLAGS_MISMATCH_RECV(wc[i], IBV_WC_WITH_IMM, rcnt) + return_value = FAILURE; + goto cleaning; + } + rcnt_for_qp[qp_index]++; rcnt++; unused_recv_for_qp[qp_index]++; @@ -4362,7 +4399,7 @@ int run_iter_bw_infinitely(struct pingpong_context *ctx,struct perftest_paramete return FAILURE; } - if (!user_param->duplex && user_param->verb != WRITE_IMM && user_param->verb != SEND){ + if (!user_param->duplex && user_param->verb != WRITE_IMM && user_param->verb != SEND && user_param->verb != SEND_IMM) { signal(SIGINT, handle_sigint); } @@ -4465,12 +4502,17 @@ int run_iter_bw_infinitely_server(struct pingpong_context *ctx, struct perftest_ int *scredit_for_qp = NULL; int return_value = 0; int qp_index; + bool with_imm_data = false; #ifdef HAVE_IBV_WR_API if (user_param->connection_type != RawEth) ctx_post_send_work_request_func_pointer(ctx, user_param); #endif + if (user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) { + with_imm_data = true; + } + struct dyn_poll_ctx *dyn_ctx = init_dyn_poll_ctx(user_param); if (!dyn_ctx) { fprintf(stderr, "Failed to allocate dynamic polling context\n"); @@ -4526,6 +4568,13 @@ int run_iter_bw_infinitely_server(struct pingpong_context *ctx, struct perftest_ return_value = FAILURE; goto cleaning; } + + if (with_imm_data && !(wc[i].wc_flags & IBV_WC_WITH_IMM)) { + fprintf(stderr, "A completion with flags mismatch in run_infinitely_bw_server function"); + return_value = FAILURE; + goto cleaning; + } + user_param->iters++; unused_recv_for_qp[qp_index]++; if (unused_recv_for_qp[qp_index] >= user_param->recv_post_list && !user_param->use_unsolicited_write) { @@ -4635,12 +4684,17 @@ int run_iter_bi(struct pingpong_context *ctx, int before_first_rx = ON; int return_value = 0; int qp_index; + bool with_imm_data = false; #ifdef HAVE_IBV_WR_API if (user_param->connection_type != RawEth) ctx_post_send_work_request_func_pointer(ctx, user_param); #endif + if (user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) { + with_imm_data = true; + } + ALLOCATE(wc_tx,struct ibv_wc,user_param->cqe_poll); ALLOCATE(rcnt_for_qp,uint64_t,user_param->num_of_qps); ALLOCATE(scredit_for_qp,int,user_param->num_of_qps); @@ -4773,6 +4827,12 @@ int run_iter_bi(struct pingpong_context *ctx, goto cleaning; } + if (with_imm_data && !(wc[i].wc_flags & IBV_WC_WITH_IMM)) { + NOTIFY_COMP_FLAGS_MISMATCH_RECV(wc[i], IBV_WC_WITH_IMM, totrcnt) + return_value = FAILURE; + goto cleaning; + } + rcnt_for_qp[qp_index]++; unused_recv_for_qp[qp_index]++; totrcnt++; @@ -5123,7 +5183,13 @@ int run_iter_lat_write_imm(struct pingpong_context *ctx,struct perftest_paramete if (wc.status != IBV_WC_SUCCESS) { //coverity[uninit_use_in_call] NOTIFY_COMP_ERROR_SEND(wc,scnt,ccnt); - return 1; + return FAILURE; + } + + if (!(wc.wc_flags & IBV_WC_WITH_IMM)) { + //coverity[uninit_use_in_call] + NOTIFY_COMP_FLAGS_MISMATCH_SEND(wc, IBV_WC_WITH_IMM, scnt, rcnt); + return FAILURE; } /*if we're in duration mode or there @@ -5306,12 +5372,17 @@ int run_iter_lat_send(struct pingpong_context *ctx,struct perftest_parameters *u cycles_t end_cycle, start_gap; uintptr_t primary_send_addr = ctx->sge_list[0].addr; uintptr_t primary_recv_addr = ctx->recv_sge_list[0].addr; + bool with_imm_data = false; #ifdef HAVE_IBV_WR_API if (user_param->connection_type != RawEth) ctx_post_send_work_request_func_pointer(ctx, user_param); #endif + if (user_param->verb == SEND_IMM) { + with_imm_data = true; + } + if (user_param->connection_type != RawEth) { ctx->wr[0].sg_list->length = user_param->size; ctx->wr[0].send_flags = 0; @@ -5348,7 +5419,13 @@ int run_iter_lat_send(struct pingpong_context *ctx,struct perftest_parameters *u if (wc.status != IBV_WC_SUCCESS) { //coverity[uninit_use_in_call] NOTIFY_COMP_ERROR_RECV(wc,rcnt); - return 1; + return FAILURE; + } + + if (with_imm_data && !(wc.wc_flags & IBV_WC_WITH_IMM)) { + //coverity[uninit_use_in_call] + NOTIFY_COMP_FLAGS_MISMATCH_RECV(wc, IBV_WC_WITH_IMM, rcnt); + return FAILURE; } rcnt++; @@ -5478,12 +5555,17 @@ int run_iter_lat_burst_server(struct pingpong_context *ctx, struct perftest_para struct ibv_send_wr *bad_wr; struct ibv_recv_wr *bad_wr_recv = NULL; int qp_index; + bool with_imm_data = false; #ifdef HAVE_IBV_WR_API if (user_param->connection_type != RawEth) ctx_post_send_work_request_func_pointer(ctx, user_param); #endif + if (user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) { + with_imm_data = true; + } + ALLOCATE(wc, struct ibv_wc, user_param->burst_size); /* main loop for polling */ @@ -5498,6 +5580,13 @@ int run_iter_lat_burst_server(struct pingpong_context *ctx, struct perftest_para free(wc); return FAILURE; } + + if (with_imm_data && !(wc[i].wc_flags & IBV_WC_WITH_IMM)) { + NOTIFY_COMP_FLAGS_MISMATCH_RECV(wc[i], IBV_WC_WITH_IMM, rcnt) + free(wc); + return FAILURE; + } + rcnt++; if (rcnt%user_param->reply_every == 0 && scnt - ccnt < user_param->tx_depth) { err = ibv_post_send(ctx->qp[0], &ctx->wr[0], &bad_wr); @@ -5567,12 +5656,17 @@ int run_iter_lat_burst(struct pingpong_context *ctx, struct perftest_parameters int burst_iter = 0; int is_sending_burst = 0; struct ibv_recv_wr *bad_wr_recv = NULL; + bool with_imm_data = false; #ifdef HAVE_IBV_WR_API if (user_param->connection_type != RawEth) ctx_post_send_work_request_func_pointer(ctx, user_param); #endif + if (user_param->verb == SEND_IMM || user_param->verb == WRITE_IMM) { + with_imm_data = true; + } + ALLOCATE(wc, struct ibv_wc, user_param->burst_size); tot_iters = (uint64_t)user_param->iters; @@ -5656,6 +5750,13 @@ int run_iter_lat_burst(struct pingpong_context *ctx, struct perftest_parameters return_value = FAILURE; goto cleaning; } + + if (with_imm_data && !(wc[i].wc_flags & IBV_WC_WITH_IMM)) { + NOTIFY_COMP_FLAGS_MISMATCH_SEND(wc[i], IBV_WC_WITH_IMM, totscnt, totccnt); + return_value = FAILURE; + goto cleaning; + } + if (ibv_post_recv(ctx->qp[qp_index], &ctx->rwr[qp_index], &bad_wr_recv)) { fprintf(stderr, "Couldn't post recv Qp=%d rcnt=%lu\n", (int)wc[i].qp_num, totrcnt); return_value = FAILURE; diff --git a/src/perftest_resources.h b/src/perftest_resources.h index be17c117..f6fb5715 100755 --- a/src/perftest_resources.h +++ b/src/perftest_resources.h @@ -113,6 +113,16 @@ fprintf(stderr," Failed status %d: qp_num %d wr_id %d syndrom 0x%x\n",wc.status,(int) wc.qp_num,(int) wc.wr_id,wc.vendor_err); \ fprintf(stderr," rcnt=%lu\n",rcnt); } +#define NOTIFY_COMP_FLAGS_MISMATCH_SEND(wc,flag,scnt,ccnt) \ + { fprintf(stderr," Completion with wc_flags mismatch at client\n"); \ + fprintf(stderr," Failed wr_id %d flag: 0x%x (should contain 0x%x)\n", (int)wc.wr_id, wc.wc_flags, flag); \ + fprintf(stderr, "scnt=%lu, ccnt=%lu\n",scnt, ccnt); } + +#define NOTIFY_COMP_FLAGS_MISMATCH_RECV(wc,flag,rcnt) \ + { fprintf(stderr," Completion with wc_flags mismatch at server\n"); \ + fprintf(stderr," Failed wr_id %d flag: 0x%x (should contain 0x%x)\n", (int)wc.wr_id, wc.wc_flags, flag); \ + fprintf(stderr," rcnt=%lu\n",rcnt); } + /* Macro to determine packet size in case of UD. The UD addition is for the GRH . */ #define SIZE(type,size,valid) ((type == UD && valid) ? (size + UD_ADDITION) : (size))