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 if (mem->decomp_bufs != NULL) 85 for (i = 0; i < mem->total_bufs; i++) 86 rte_pktmbuf_free(mem->decomp_bufs[i]); 87 88 if (mem->comp_bufs != NULL) 89 for (i = 0; i < mem->total_bufs; i++) 90 rte_pktmbuf_free(mem->comp_bufs[i]); 91 92 rte_free(mem->decomp_bufs); 93 rte_free(mem->comp_bufs); 94 rte_free(mem->decompressed_data); 95 rte_free(mem->compressed_data); 96 rte_mempool_free(mem->op_pool); 97 rte_mempool_free(mem->decomp_buf_pool); 98 rte_mempool_free(mem->comp_buf_pool); 99 } 100 101 int 102 comp_perf_allocate_memory(struct comp_test_data *test_data, 103 struct cperf_mem_resources *mem) 104 { 105 test_data->out_seg_sz = find_buf_size(test_data->seg_sz); 106 /* Number of segments for input and output 107 * (compression and decompression) 108 */ 109 uint32_t total_segs = DIV_CEIL(test_data->input_data_sz, 110 test_data->seg_sz); 111 char pool_name[32] = ""; 112 113 snprintf(pool_name, sizeof(pool_name), "comp_buf_pool_%u_qp_%u", 114 mem->dev_id, mem->qp_id); 115 mem->comp_buf_pool = rte_pktmbuf_pool_create(pool_name, 116 total_segs, 117 0, 0, 118 test_data->out_seg_sz + RTE_PKTMBUF_HEADROOM, 119 rte_socket_id()); 120 if (mem->comp_buf_pool == NULL) { 121 RTE_LOG(ERR, USER1, "Mbuf mempool could not be created\n"); 122 return -1; 123 } 124 125 snprintf(pool_name, sizeof(pool_name), "decomp_buf_pool_%u_qp_%u", 126 mem->dev_id, mem->qp_id); 127 mem->decomp_buf_pool = rte_pktmbuf_pool_create(pool_name, 128 total_segs, 129 0, 0, test_data->seg_sz + RTE_PKTMBUF_HEADROOM, 130 rte_socket_id()); 131 if (mem->decomp_buf_pool == NULL) { 132 RTE_LOG(ERR, USER1, "Mbuf mempool could not be created\n"); 133 return -1; 134 } 135 136 mem->total_bufs = DIV_CEIL(total_segs, test_data->max_sgl_segs); 137 138 snprintf(pool_name, sizeof(pool_name), "op_pool_%u_qp_%u", 139 mem->dev_id, mem->qp_id); 140 mem->op_pool = rte_comp_op_pool_create(pool_name, 141 mem->total_bufs, 142 0, 0, rte_socket_id()); 143 if (mem->op_pool == NULL) { 144 RTE_LOG(ERR, USER1, "Comp op mempool could not be created\n"); 145 return -1; 146 } 147 148 /* 149 * Compressed data might be a bit larger than input data, 150 * if data cannot be compressed 151 */ 152 mem->compressed_data = rte_zmalloc_socket(NULL, 153 RTE_MAX( 154 (size_t) test_data->out_seg_sz * total_segs, 155 (size_t) MIN_COMPRESSED_BUF_SIZE), 156 0, 157 rte_socket_id()); 158 if (mem->compressed_data == NULL) { 159 RTE_LOG(ERR, USER1, "Memory to hold the data from the input " 160 "file could not be allocated\n"); 161 return -1; 162 } 163 164 mem->decompressed_data = rte_zmalloc_socket(NULL, 165 test_data->input_data_sz, 0, 166 rte_socket_id()); 167 if (mem->decompressed_data == NULL) { 168 RTE_LOG(ERR, USER1, "Memory to hold the data from the input " 169 "file could not be allocated\n"); 170 return -1; 171 } 172 173 mem->comp_bufs = rte_zmalloc_socket(NULL, 174 mem->total_bufs * sizeof(struct rte_mbuf *), 175 0, rte_socket_id()); 176 if (mem->comp_bufs == NULL) { 177 RTE_LOG(ERR, USER1, "Memory to hold the compression mbufs" 178 " could not be allocated\n"); 179 return -1; 180 } 181 182 mem->decomp_bufs = rte_zmalloc_socket(NULL, 183 mem->total_bufs * sizeof(struct rte_mbuf *), 184 0, rte_socket_id()); 185 if (mem->decomp_bufs == NULL) { 186 RTE_LOG(ERR, USER1, "Memory to hold the decompression mbufs" 187 " could not be allocated\n"); 188 return -1; 189 } 190 191 buffer_info.total_segments = total_segs; 192 buffer_info.segment_sz = test_data->seg_sz; 193 buffer_info.total_buffs = mem->total_bufs; 194 buffer_info.segments_per_buff = test_data->max_sgl_segs; 195 buffer_info.input_data_sz = test_data->input_data_sz; 196 197 return 0; 198 } 199 200 int 201 prepare_bufs(struct comp_test_data *test_data, struct cperf_mem_resources *mem) 202 { 203 uint32_t remaining_data = test_data->input_data_sz; 204 uint8_t *input_data_ptr = test_data->input_data; 205 size_t data_sz = 0; 206 uint8_t *data_addr; 207 uint32_t i, j; 208 uint16_t segs_per_mbuf = 0; 209 210 for (i = 0; i < mem->total_bufs; i++) { 211 /* Allocate data in input mbuf and copy data from input file */ 212 mem->decomp_bufs[i] = 213 rte_pktmbuf_alloc(mem->decomp_buf_pool); 214 if (mem->decomp_bufs[i] == NULL) { 215 RTE_LOG(ERR, USER1, "Could not allocate mbuf\n"); 216 return -1; 217 } 218 219 data_sz = RTE_MIN(remaining_data, test_data->seg_sz); 220 data_addr = (uint8_t *) rte_pktmbuf_append( 221 mem->decomp_bufs[i], data_sz); 222 if (data_addr == NULL) { 223 RTE_LOG(ERR, USER1, "Could not append data\n"); 224 return -1; 225 } 226 rte_memcpy(data_addr, input_data_ptr, data_sz); 227 228 input_data_ptr += data_sz; 229 remaining_data -= data_sz; 230 231 /* Already one segment in the mbuf */ 232 segs_per_mbuf = 1; 233 234 /* Chain mbufs if needed for input mbufs */ 235 while (segs_per_mbuf < test_data->max_sgl_segs 236 && remaining_data > 0) { 237 struct rte_mbuf *next_seg = 238 rte_pktmbuf_alloc(mem->decomp_buf_pool); 239 240 if (next_seg == NULL) { 241 RTE_LOG(ERR, USER1, 242 "Could not allocate mbuf\n"); 243 return -1; 244 } 245 246 data_sz = RTE_MIN(remaining_data, test_data->seg_sz); 247 data_addr = (uint8_t *)rte_pktmbuf_append(next_seg, 248 data_sz); 249 250 if (data_addr == NULL) { 251 RTE_LOG(ERR, USER1, "Could not append data\n"); 252 return -1; 253 } 254 255 rte_memcpy(data_addr, input_data_ptr, data_sz); 256 input_data_ptr += data_sz; 257 remaining_data -= data_sz; 258 259 if (rte_pktmbuf_chain(mem->decomp_bufs[i], 260 next_seg) < 0) { 261 RTE_LOG(ERR, USER1, "Could not chain mbufs\n"); 262 return -1; 263 } 264 segs_per_mbuf++; 265 } 266 267 /* Allocate data in output mbuf */ 268 mem->comp_bufs[i] = 269 rte_pktmbuf_alloc(mem->comp_buf_pool); 270 if (mem->comp_bufs[i] == NULL) { 271 RTE_LOG(ERR, USER1, "Could not allocate mbuf\n"); 272 return -1; 273 } 274 data_addr = (uint8_t *) rte_pktmbuf_append( 275 mem->comp_bufs[i], 276 test_data->out_seg_sz); 277 if (data_addr == NULL) { 278 RTE_LOG(ERR, USER1, "Could not append data\n"); 279 return -1; 280 } 281 282 /* Chain mbufs if needed for output mbufs */ 283 for (j = 1; j < segs_per_mbuf; j++) { 284 struct rte_mbuf *next_seg = 285 rte_pktmbuf_alloc(mem->comp_buf_pool); 286 287 if (next_seg == NULL) { 288 RTE_LOG(ERR, USER1, 289 "Could not allocate mbuf\n"); 290 return -1; 291 } 292 293 data_addr = (uint8_t *)rte_pktmbuf_append(next_seg, 294 test_data->out_seg_sz); 295 if (data_addr == NULL) { 296 RTE_LOG(ERR, USER1, "Could not append data\n"); 297 return -1; 298 } 299 300 if (rte_pktmbuf_chain(mem->comp_bufs[i], 301 next_seg) < 0) { 302 RTE_LOG(ERR, USER1, "Could not chain mbufs\n"); 303 return -1; 304 } 305 } 306 } 307 308 buffer_info.segments_per_last_buff = segs_per_mbuf; 309 buffer_info.last_segment_sz = data_sz; 310 311 return 0; 312 } 313 314 void 315 print_test_dynamics(void) 316 { 317 uint32_t opt_total_segs = DIV_CEIL(buffer_info.input_data_sz, 318 MAX_SEG_SIZE); 319 320 if (buffer_info.total_buffs > 1) { 321 printf("\nWarning: for the current input parameters, number" 322 " of ops is higher than one, which may result" 323 " in sub-optimal performance.\n"); 324 printf("To improve the performance (for the current" 325 " input data) following parameters are" 326 " suggested:\n"); 327 printf(" * Segment size: %d\n", MAX_SEG_SIZE); 328 printf(" * Number of segments: %u\n", opt_total_segs); 329 } else if (buffer_info.total_buffs == 1) { 330 printf("\nInfo: there is only one op with %u segments -" 331 " the compression ratio is the best.\n", 332 buffer_info.segments_per_last_buff); 333 if (buffer_info.segment_sz < MAX_SEG_SIZE) 334 printf("To reduce compression time, please use" 335 " bigger segment size: %d.\n", 336 MAX_SEG_SIZE); 337 else if (buffer_info.segment_sz == MAX_SEG_SIZE) 338 printf("Segment size is optimal for the best" 339 " performance.\n"); 340 } else 341 printf("Warning: something wrong happened!!\n"); 342 343 printf("\nFor the current input parameters (segment size = %u," 344 " maximum segments per SGL = %u):\n", 345 buffer_info.segment_sz, 346 buffer_info.segments_per_buff); 347 printf(" * Total number of buffers: %d\n", 348 buffer_info.total_segments); 349 printf(" * %u buffer(s) %u bytes long, last buffer %u" 350 " byte(s) long\n", 351 buffer_info.total_segments - 1, 352 buffer_info.segment_sz, 353 buffer_info.last_segment_sz); 354 printf(" * Number of ops: %u\n", buffer_info.total_buffs); 355 printf(" * Total memory allocation: %u\n", 356 (buffer_info.total_segments - 1) * buffer_info.segment_sz 357 + buffer_info.last_segment_sz); 358 if (buffer_info.total_buffs > 1) 359 printf(" * %u ops: %u segment(s) in each," 360 " segment size %u\n", 361 buffer_info.total_buffs - 1, 362 buffer_info.segments_per_buff, 363 buffer_info.segment_sz); 364 if (buffer_info.segments_per_last_buff > 1) { 365 printf(" * 1 op %u segments:\n", 366 buffer_info.segments_per_last_buff); 367 printf(" o %u segment size %u\n", 368 buffer_info.segments_per_last_buff - 1, 369 buffer_info.segment_sz); 370 printf(" o last segment size %u\n", 371 buffer_info.last_segment_sz); 372 } else if (buffer_info.segments_per_last_buff == 1) { 373 printf(" * 1 op (the last one): %u segment %u" 374 " byte(s) long\n\n", 375 buffer_info.segments_per_last_buff, 376 buffer_info.last_segment_sz); 377 } 378 printf("\n"); 379 } 380