xref: /dpdk/app/test-compress-perf/comp_perf_test_common.c (revision 54ad947eda42042d2bdae69b57d0c7c8e291d9ec)
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