1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2019 Intel Corporation 3 */ 4 5 #include <rte_malloc.h> 6 #include <rte_eal.h> 7 #include <rte_log.h> 8 #include <rte_compressdev.h> 9 10 #include "comp_perf.h" 11 #include "comp_perf_options.h" 12 #include "comp_perf_test_benchmark.h" 13 #include "comp_perf_test_common.h" 14 #include "comp_perf_test_verify.h" 15 16 17 #define DIV_CEIL(a, b) ((a) / (b) + ((a) % (b) != 0)) 18 19 struct cperf_buffer_info { 20 uint16_t total_segments; 21 uint16_t segment_sz; 22 uint16_t last_segment_sz; 23 uint32_t total_buffs; /*number of buffers = number of ops*/ 24 uint16_t segments_per_buff; 25 uint16_t segments_per_last_buff; 26 size_t input_data_sz; 27 }; 28 29 static struct cperf_buffer_info buffer_info; 30 31 int 32 param_range_check(uint16_t size, const struct rte_param_log2_range *range) 33 { 34 unsigned int next_size; 35 36 /* Check lower/upper bounds */ 37 if (size < range->min) 38 return -1; 39 40 if (size > range->max) 41 return -1; 42 43 /* If range is actually only one value, size is correct */ 44 if (range->increment == 0) 45 return 0; 46 47 /* Check if value is one of the supported sizes */ 48 for (next_size = range->min; next_size <= range->max; 49 next_size += range->increment) 50 if (size == next_size) 51 return 0; 52 53 return -1; 54 } 55 56 static uint32_t 57 find_buf_size(uint32_t input_size) 58 { 59 uint32_t i; 60 61 /* From performance point of view the buffer size should be a 62 * power of 2 but also should be enough to store incompressible data 63 */ 64 65 /* We're looking for nearest power of 2 buffer size, which is greater 66 * than input_size 67 */ 68 uint32_t size = 69 !input_size ? MIN_COMPRESSED_BUF_SIZE : (input_size << 1); 70 71 for (i = UINT16_MAX + 1; !(i & size); i >>= 1) 72 ; 73 74 return i > ((UINT16_MAX + 1) >> 1) 75 ? (uint32_t)((float)input_size * EXPANSE_RATIO) 76 : i; 77 } 78 79 void 80 comp_perf_free_memory(struct cperf_mem_resources *mem) 81 { 82 uint32_t i; 83 84 for (i = 0; i < mem->total_bufs; i++) { 85 rte_pktmbuf_free(mem->comp_bufs[i]); 86 rte_pktmbuf_free(mem->decomp_bufs[i]); 87 } 88 89 rte_free(mem->decomp_bufs); 90 rte_free(mem->comp_bufs); 91 rte_free(mem->decompressed_data); 92 rte_free(mem->compressed_data); 93 rte_mempool_free(mem->op_pool); 94 rte_mempool_free(mem->decomp_buf_pool); 95 rte_mempool_free(mem->comp_buf_pool); 96 } 97 98 int 99 comp_perf_allocate_memory(struct comp_test_data *test_data, 100 struct cperf_mem_resources *mem) 101 { 102 test_data->out_seg_sz = find_buf_size(test_data->seg_sz); 103 /* Number of segments for input and output 104 * (compression and decompression) 105 */ 106 uint32_t total_segs = DIV_CEIL(test_data->input_data_sz, 107 test_data->seg_sz); 108 char pool_name[32] = ""; 109 110 snprintf(pool_name, sizeof(pool_name), "comp_buf_pool_%u_qp_%u", 111 mem->dev_id, mem->qp_id); 112 mem->comp_buf_pool = rte_pktmbuf_pool_create(pool_name, 113 total_segs, 114 0, 0, 115 test_data->out_seg_sz + RTE_PKTMBUF_HEADROOM, 116 rte_socket_id()); 117 if (mem->comp_buf_pool == NULL) { 118 RTE_LOG(ERR, USER1, "Mbuf mempool could not be created\n"); 119 return -1; 120 } 121 122 snprintf(pool_name, sizeof(pool_name), "decomp_buf_pool_%u_qp_%u", 123 mem->dev_id, mem->qp_id); 124 mem->decomp_buf_pool = rte_pktmbuf_pool_create(pool_name, 125 total_segs, 126 0, 0, test_data->seg_sz + RTE_PKTMBUF_HEADROOM, 127 rte_socket_id()); 128 if (mem->decomp_buf_pool == NULL) { 129 RTE_LOG(ERR, USER1, "Mbuf mempool could not be created\n"); 130 return -1; 131 } 132 133 mem->total_bufs = DIV_CEIL(total_segs, test_data->max_sgl_segs); 134 135 snprintf(pool_name, sizeof(pool_name), "op_pool_%u_qp_%u", 136 mem->dev_id, mem->qp_id); 137 mem->op_pool = rte_comp_op_pool_create(pool_name, 138 mem->total_bufs, 139 0, 0, rte_socket_id()); 140 if (mem->op_pool == NULL) { 141 RTE_LOG(ERR, USER1, "Comp op mempool could not be created\n"); 142 return -1; 143 } 144 145 /* 146 * Compressed data might be a bit larger than input data, 147 * if data cannot be compressed 148 */ 149 mem->compressed_data = rte_zmalloc_socket(NULL, 150 RTE_MAX( 151 (size_t) test_data->out_seg_sz * total_segs, 152 (size_t) MIN_COMPRESSED_BUF_SIZE), 153 0, 154 rte_socket_id()); 155 if (mem->compressed_data == NULL) { 156 RTE_LOG(ERR, USER1, "Memory to hold the data from the input " 157 "file could not be allocated\n"); 158 return -1; 159 } 160 161 mem->decompressed_data = rte_zmalloc_socket(NULL, 162 test_data->input_data_sz, 0, 163 rte_socket_id()); 164 if (mem->decompressed_data == NULL) { 165 RTE_LOG(ERR, USER1, "Memory to hold the data from the input " 166 "file could not be allocated\n"); 167 return -1; 168 } 169 170 mem->comp_bufs = rte_zmalloc_socket(NULL, 171 mem->total_bufs * sizeof(struct rte_mbuf *), 172 0, rte_socket_id()); 173 if (mem->comp_bufs == NULL) { 174 RTE_LOG(ERR, USER1, "Memory to hold the compression mbufs" 175 " could not be allocated\n"); 176 return -1; 177 } 178 179 mem->decomp_bufs = rte_zmalloc_socket(NULL, 180 mem->total_bufs * sizeof(struct rte_mbuf *), 181 0, rte_socket_id()); 182 if (mem->decomp_bufs == NULL) { 183 RTE_LOG(ERR, USER1, "Memory to hold the decompression mbufs" 184 " could not be allocated\n"); 185 return -1; 186 } 187 188 buffer_info.total_segments = total_segs; 189 buffer_info.segment_sz = test_data->seg_sz; 190 buffer_info.total_buffs = mem->total_bufs; 191 buffer_info.segments_per_buff = test_data->max_sgl_segs; 192 buffer_info.input_data_sz = test_data->input_data_sz; 193 194 return 0; 195 } 196 197 int 198 prepare_bufs(struct comp_test_data *test_data, struct cperf_mem_resources *mem) 199 { 200 uint32_t remaining_data = test_data->input_data_sz; 201 uint8_t *input_data_ptr = test_data->input_data; 202 size_t data_sz = 0; 203 uint8_t *data_addr; 204 uint32_t i, j; 205 uint16_t segs_per_mbuf = 0; 206 207 for (i = 0; i < mem->total_bufs; i++) { 208 /* Allocate data in input mbuf and copy data from input file */ 209 mem->decomp_bufs[i] = 210 rte_pktmbuf_alloc(mem->decomp_buf_pool); 211 if (mem->decomp_bufs[i] == NULL) { 212 RTE_LOG(ERR, USER1, "Could not allocate mbuf\n"); 213 return -1; 214 } 215 216 data_sz = RTE_MIN(remaining_data, test_data->seg_sz); 217 data_addr = (uint8_t *) rte_pktmbuf_append( 218 mem->decomp_bufs[i], data_sz); 219 if (data_addr == NULL) { 220 RTE_LOG(ERR, USER1, "Could not append data\n"); 221 return -1; 222 } 223 rte_memcpy(data_addr, input_data_ptr, data_sz); 224 225 input_data_ptr += data_sz; 226 remaining_data -= data_sz; 227 228 /* Already one segment in the mbuf */ 229 segs_per_mbuf = 1; 230 231 /* Chain mbufs if needed for input mbufs */ 232 while (segs_per_mbuf < test_data->max_sgl_segs 233 && remaining_data > 0) { 234 struct rte_mbuf *next_seg = 235 rte_pktmbuf_alloc(mem->decomp_buf_pool); 236 237 if (next_seg == NULL) { 238 RTE_LOG(ERR, USER1, 239 "Could not allocate mbuf\n"); 240 return -1; 241 } 242 243 data_sz = RTE_MIN(remaining_data, test_data->seg_sz); 244 data_addr = (uint8_t *)rte_pktmbuf_append(next_seg, 245 data_sz); 246 247 if (data_addr == NULL) { 248 RTE_LOG(ERR, USER1, "Could not append data\n"); 249 return -1; 250 } 251 252 rte_memcpy(data_addr, input_data_ptr, data_sz); 253 input_data_ptr += data_sz; 254 remaining_data -= data_sz; 255 256 if (rte_pktmbuf_chain(mem->decomp_bufs[i], 257 next_seg) < 0) { 258 RTE_LOG(ERR, USER1, "Could not chain mbufs\n"); 259 return -1; 260 } 261 segs_per_mbuf++; 262 } 263 264 /* Allocate data in output mbuf */ 265 mem->comp_bufs[i] = 266 rte_pktmbuf_alloc(mem->comp_buf_pool); 267 if (mem->comp_bufs[i] == NULL) { 268 RTE_LOG(ERR, USER1, "Could not allocate mbuf\n"); 269 return -1; 270 } 271 data_addr = (uint8_t *) rte_pktmbuf_append( 272 mem->comp_bufs[i], 273 test_data->out_seg_sz); 274 if (data_addr == NULL) { 275 RTE_LOG(ERR, USER1, "Could not append data\n"); 276 return -1; 277 } 278 279 /* Chain mbufs if needed for output mbufs */ 280 for (j = 1; j < segs_per_mbuf; j++) { 281 struct rte_mbuf *next_seg = 282 rte_pktmbuf_alloc(mem->comp_buf_pool); 283 284 if (next_seg == NULL) { 285 RTE_LOG(ERR, USER1, 286 "Could not allocate mbuf\n"); 287 return -1; 288 } 289 290 data_addr = (uint8_t *)rte_pktmbuf_append(next_seg, 291 test_data->out_seg_sz); 292 if (data_addr == NULL) { 293 RTE_LOG(ERR, USER1, "Could not append data\n"); 294 return -1; 295 } 296 297 if (rte_pktmbuf_chain(mem->comp_bufs[i], 298 next_seg) < 0) { 299 RTE_LOG(ERR, USER1, "Could not chain mbufs\n"); 300 return -1; 301 } 302 } 303 } 304 305 buffer_info.segments_per_last_buff = segs_per_mbuf; 306 buffer_info.last_segment_sz = data_sz; 307 308 return 0; 309 } 310 311 void 312 print_test_dynamics(void) 313 { 314 uint32_t opt_total_segs = DIV_CEIL(buffer_info.input_data_sz, 315 MAX_SEG_SIZE); 316 317 if (buffer_info.total_buffs > 1) { 318 printf("\nWarning: for the current input parameters, number" 319 " of ops is higher than one, which may result" 320 " in sub-optimal performance.\n"); 321 printf("To improve the performance (for the current" 322 " input data) following parameters are" 323 " suggested:\n"); 324 printf(" * Segment size: %d\n", MAX_SEG_SIZE); 325 printf(" * Number of segments: %u\n", opt_total_segs); 326 } else if (buffer_info.total_buffs == 1) { 327 printf("\nInfo: there is only one op with %u segments -" 328 " the compression ratio is the best.\n", 329 buffer_info.segments_per_last_buff); 330 if (buffer_info.segment_sz < MAX_SEG_SIZE) 331 printf("To reduce compression time, please use" 332 " bigger segment size: %d.\n", 333 MAX_SEG_SIZE); 334 else if (buffer_info.segment_sz == MAX_SEG_SIZE) 335 printf("Segment size is optimal for the best" 336 " performance.\n"); 337 } else 338 printf("Warning: something wrong happened!!\n"); 339 340 printf("\nFor the current input parameters (segment size = %u," 341 " maximum segments per SGL = %u):\n", 342 buffer_info.segment_sz, 343 buffer_info.segments_per_buff); 344 printf(" * Total number of buffers: %d\n", 345 buffer_info.total_segments); 346 printf(" * %u buffer(s) %u bytes long, last buffer %u" 347 " byte(s) long\n", 348 buffer_info.total_segments - 1, 349 buffer_info.segment_sz, 350 buffer_info.last_segment_sz); 351 printf(" * Number of ops: %u\n", buffer_info.total_buffs); 352 printf(" * Total memory allocation: %u\n", 353 (buffer_info.total_segments - 1) * buffer_info.segment_sz 354 + buffer_info.last_segment_sz); 355 if (buffer_info.total_buffs > 1) 356 printf(" * %u ops: %u segment(s) in each," 357 " segment size %u\n", 358 buffer_info.total_buffs - 1, 359 buffer_info.segments_per_buff, 360 buffer_info.segment_sz); 361 if (buffer_info.segments_per_last_buff > 1) { 362 printf(" * 1 op %u segments:\n", 363 buffer_info.segments_per_last_buff); 364 printf(" o %u segment size %u\n", 365 buffer_info.segments_per_last_buff - 1, 366 buffer_info.segment_sz); 367 printf(" o last segment size %u\n", 368 buffer_info.last_segment_sz); 369 } else if (buffer_info.segments_per_last_buff == 1) { 370 printf(" * 1 op (the last one): %u segment %u" 371 " byte(s) long\n\n", 372 buffer_info.segments_per_last_buff, 373 buffer_info.last_segment_sz); 374 } 375 printf("\n"); 376 } 377