Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2019 Intel Corporation
3 : : */
4 : :
5 : : #include "test.h"
6 : :
7 : : #include <stdio.h>
8 : : #include <stdint.h>
9 : : #include <string.h>
10 : : #include <stdarg.h>
11 : : #include <errno.h>
12 : : #include <stdlib.h>
13 : : #ifndef RTE_EXEC_ENV_WINDOWS
14 : : #include <sys/mman.h>
15 : : #endif
16 : : #include <sys/queue.h>
17 : : #include <unistd.h>
18 : :
19 : : #include <rte_common.h>
20 : : #include <rte_memory.h>
21 : : #include <rte_per_lcore.h>
22 : : #include <rte_launch.h>
23 : : #include <rte_eal.h>
24 : : #include <rte_lcore.h>
25 : : #include <rte_malloc.h>
26 : : #include <rte_cycles.h>
27 : : #include <rte_random.h>
28 : : #include <rte_string_fns.h>
29 : :
30 : : #define N 10000
31 : :
32 : : static int
33 : : is_mem_on_socket(int32_t socket);
34 : :
35 : : static int32_t
36 : : addr_to_socket(void *addr);
37 : :
38 : : /*
39 : : * Malloc
40 : : * ======
41 : : *
42 : : * Allocate some dynamic memory from heap (3 areas). Check that areas
43 : : * don't overlap and that alignment constraints match. This test is
44 : : * done many times on different lcores simultaneously.
45 : : */
46 : :
47 : : /* Test if memory overlaps: return 1 if true, or 0 if false. */
48 : : static int
49 : : is_memory_overlap(void *p1, size_t len1, void *p2, size_t len2)
50 : : {
51 : 10030 : uintptr_t ptr1 = (uintptr_t)p1;
52 : 20060 : uintptr_t ptr2 = (uintptr_t)p2;
53 : :
54 [ - + - - : 30090 : if (ptr2 >= ptr1 && (ptr2 - ptr1) < len1)
- + - - -
+ - - - +
- - - + -
- - + -
- ]
55 : : return 1;
56 [ + - - + : 30090 : else if (ptr2 < ptr1 && (ptr1 - ptr2) < len2)
+ - - + +
- - + + -
- + + - -
+ + - -
+ ]
57 : : return 1;
58 : : return 0;
59 : : }
60 : :
61 : : static int
62 : : is_aligned(void *p, int align)
63 : : {
64 : : uintptr_t addr = (uintptr_t)p;
65 : : unsigned mask = align - 1;
66 : :
67 [ - + - + : 10030 : if (addr & mask)
- + - + -
+ - + ]
68 : : return 0;
69 : : return 1;
70 : : }
71 : :
72 : : static int
73 : 1 : test_align_overlap_per_lcore(__rte_unused void *arg)
74 : : {
75 : : const unsigned align1 = 8,
76 : : align2 = 64,
77 : : align3 = 2048;
78 : : unsigned i,j;
79 : : void *p1 = NULL, *p2 = NULL, *p3 = NULL;
80 : : int ret = 0;
81 : :
82 [ + + ]: 10001 : for (i = 0; i < N; i++) {
83 : 10000 : p1 = rte_zmalloc("dummy", 1000, align1);
84 [ + - ]: 10000 : if (!p1){
85 : : printf("rte_zmalloc returned NULL (i=%u)\n", i);
86 : : ret = -1;
87 : 0 : break;
88 : : }
89 [ + + ]: 10010000 : for(j = 0; j < 1000 ; j++) {
90 [ - + ]: 10000000 : if( *(char *)p1 != 0) {
91 : : printf("rte_zmalloc didn't zero the allocated memory\n");
92 : : ret = -1;
93 : : }
94 : : }
95 : 10000 : p2 = rte_malloc("dummy", 1000, align2);
96 [ - + ]: 10000 : if (!p2){
97 : : printf("rte_malloc returned NULL (i=%u)\n", i);
98 : : ret = -1;
99 : 0 : rte_free(p1);
100 : 0 : break;
101 : : }
102 : 10000 : p3 = rte_malloc("dummy", 1000, align3);
103 [ - + ]: 10000 : if (!p3){
104 : : printf("rte_malloc returned NULL (i=%u)\n", i);
105 : : ret = -1;
106 : 0 : rte_free(p1);
107 : 0 : rte_free(p2);
108 : 0 : break;
109 : : }
110 : : if (is_memory_overlap(p1, 1000, p2, 1000)) {
111 : : printf("p1 and p2 overlaps\n");
112 : : ret = -1;
113 : : }
114 : : if (is_memory_overlap(p2, 1000, p3, 1000)) {
115 : : printf("p2 and p3 overlaps\n");
116 : : ret = -1;
117 : : }
118 : : if (is_memory_overlap(p1, 1000, p3, 1000)) {
119 : : printf("p1 and p3 overlaps\n");
120 : : ret = -1;
121 : : }
122 : : if (!is_aligned(p1, align1)) {
123 : : printf("p1 is not aligned\n");
124 : : ret = -1;
125 : : }
126 : : if (!is_aligned(p2, align2)) {
127 : : printf("p2 is not aligned\n");
128 : : ret = -1;
129 : : }
130 : : if (!is_aligned(p3, align3)) {
131 : : printf("p3 is not aligned\n");
132 : : ret = -1;
133 : : }
134 : 10000 : rte_free(p1);
135 : 10000 : rte_free(p2);
136 : 10000 : rte_free(p3);
137 : : }
138 : 1 : rte_malloc_dump_stats(stdout, "dummy");
139 : :
140 : 1 : return ret;
141 : : }
142 : :
143 : : static int
144 : 1 : test_reordered_free_per_lcore(__rte_unused void *arg)
145 : : {
146 : : const unsigned align1 = 8,
147 : : align2 = 64,
148 : : align3 = 2048;
149 : : unsigned i,j;
150 : : void *p1, *p2, *p3;
151 : : int ret = 0;
152 : :
153 [ + + ]: 31 : for (i = 0; i < 30; i++) {
154 : 30 : p1 = rte_zmalloc("dummy", 1000, align1);
155 [ + - ]: 30 : if (!p1){
156 : : printf("rte_zmalloc returned NULL (i=%u)\n", i);
157 : : ret = -1;
158 : 0 : break;
159 : : }
160 [ + + ]: 30030 : for(j = 0; j < 1000 ; j++) {
161 [ - + ]: 30000 : if( *(char *)p1 != 0) {
162 : : printf("rte_zmalloc didn't zero the allocated memory\n");
163 : : ret = -1;
164 : : }
165 : : }
166 : : /* use calloc to allocate 1000 16-byte items this time */
167 : 30 : p2 = rte_calloc("dummy", 1000, 16, align2);
168 : : /* for third request use regular malloc again */
169 : 30 : p3 = rte_malloc("dummy", 1000, align3);
170 [ - + ]: 30 : if (!p2 || !p3){
171 : : printf("rte_malloc returned NULL (i=%u)\n", i);
172 : : ret = -1;
173 : 0 : break;
174 : : }
175 : : if (is_memory_overlap(p1, 1000, p2, 1000)) {
176 : : printf("p1 and p2 overlaps\n");
177 : : ret = -1;
178 : : }
179 : : if (is_memory_overlap(p2, 1000, p3, 1000)) {
180 : : printf("p2 and p3 overlaps\n");
181 : : ret = -1;
182 : : }
183 : : if (is_memory_overlap(p1, 1000, p3, 1000)) {
184 : : printf("p1 and p3 overlaps\n");
185 : : ret = -1;
186 : : }
187 : : if (!is_aligned(p1, align1)) {
188 : : printf("p1 is not aligned\n");
189 : : ret = -1;
190 : : }
191 : : if (!is_aligned(p2, align2)) {
192 : : printf("p2 is not aligned\n");
193 : : ret = -1;
194 : : }
195 : : if (!is_aligned(p3, align3)) {
196 : : printf("p3 is not aligned\n");
197 : : ret = -1;
198 : : }
199 : : /* try freeing in every possible order */
200 [ + + + + : 30 : switch (i%6){
+ + ]
201 : 5 : case 0:
202 : 5 : rte_free(p1);
203 : 5 : rte_free(p2);
204 : 5 : rte_free(p3);
205 : 5 : break;
206 : 5 : case 1:
207 : 5 : rte_free(p1);
208 : 5 : rte_free(p3);
209 : 5 : rte_free(p2);
210 : 5 : break;
211 : 5 : case 2:
212 : 5 : rte_free(p2);
213 : 5 : rte_free(p1);
214 : 5 : rte_free(p3);
215 : 5 : break;
216 : 5 : case 3:
217 : 5 : rte_free(p2);
218 : 5 : rte_free(p3);
219 : 5 : rte_free(p1);
220 : 5 : break;
221 : 5 : case 4:
222 : 5 : rte_free(p3);
223 : 5 : rte_free(p1);
224 : 5 : rte_free(p2);
225 : 5 : break;
226 : 5 : case 5:
227 : 5 : rte_free(p3);
228 : 5 : rte_free(p2);
229 : 5 : rte_free(p1);
230 : 5 : break;
231 : : }
232 : : }
233 : 1 : rte_malloc_dump_stats(stdout, "dummy");
234 : :
235 : 1 : return ret;
236 : : }
237 : :
238 : : /* test function inside the malloc lib*/
239 : : static int
240 : 1 : test_str_to_size(void)
241 : : {
242 : : struct {
243 : : const char *str;
244 : : uint64_t value;
245 : 1 : } test_values[] =
246 : : {{ "5G", (uint64_t)5 * 1024 * 1024 *1024 },
247 : : {"0x20g", (uint64_t)0x20 * 1024 * 1024 *1024},
248 : : {"10M", 10 * 1024 * 1024},
249 : : {"050m", 050 * 1024 * 1024},
250 : : {"8K", 8 * 1024},
251 : : {"15k", 15 * 1024},
252 : : {"0200", 0200},
253 : : {"0x103", 0x103},
254 : : {"432", 432},
255 : : {"-1", 0}, /* negative values return 0 */
256 : : {" -2", 0},
257 : : {" -3MB", 0},
258 : : {"18446744073709551616", 0} /* ULLONG_MAX + 1 == out of range*/
259 : : };
260 : : unsigned i;
261 [ + + ]: 14 : for (i = 0; i < RTE_DIM(test_values); i++)
262 [ + - ]: 13 : if (rte_str_to_size(test_values[i].str) != test_values[i].value)
263 : : return -1;
264 : : return 0;
265 : : }
266 : :
267 : : static int
268 : 1 : test_multi_alloc_statistics(void)
269 : : {
270 : : int socket = 0;
271 : : struct rte_malloc_socket_stats pre_stats, post_stats ,first_stats, second_stats;
272 : : size_t size = 2048;
273 : : int align = 1024;
274 : : int overhead = 0;
275 : :
276 : : /* Dynamically calculate the overhead by allocating one cacheline and
277 : : * then comparing what was allocated from the heap.
278 : : */
279 : 1 : rte_malloc_get_socket_stats(socket, &pre_stats);
280 : :
281 : 1 : void *dummy = rte_malloc_socket(NULL, RTE_CACHE_LINE_SIZE, 0, socket);
282 [ + - ]: 1 : if (dummy == NULL)
283 : : return -1;
284 : :
285 : 1 : rte_malloc_get_socket_stats(socket, &post_stats);
286 : :
287 : : /* after subtracting cache line, remainder is overhead */
288 : 1 : overhead = post_stats.heap_allocsz_bytes - pre_stats.heap_allocsz_bytes;
289 : : overhead -= RTE_CACHE_LINE_SIZE;
290 : :
291 : 1 : rte_free(dummy);
292 : :
293 : : /* Now start the real tests */
294 : 1 : rte_malloc_get_socket_stats(socket, &pre_stats);
295 : :
296 : 1 : void *p1 = rte_malloc_socket("stats", size , align, socket);
297 [ + - ]: 1 : if (!p1)
298 : : return -1;
299 : 1 : rte_free(p1);
300 : 1 : rte_malloc_dump_stats(stdout, "stats");
301 : :
302 : 1 : rte_malloc_get_socket_stats(socket,&post_stats);
303 : : /* Check statistics reported are correct */
304 : : /* All post stats should be equal to pre stats after alloc freed */
305 [ + - ]: 1 : if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) ||
306 [ + - ]: 1 : (post_stats.heap_freesz_bytes != pre_stats.heap_freesz_bytes) ||
307 [ + - ]: 1 : (post_stats.heap_allocsz_bytes != pre_stats.heap_allocsz_bytes) ||
308 [ - + ]: 1 : (post_stats.alloc_count != pre_stats.alloc_count) ||
309 : : (post_stats.free_count != pre_stats.free_count)) {
310 : : printf("Malloc statistics are incorrect - freed alloc\n");
311 : 0 : return -1;
312 : : }
313 : : /* Check two consecutive allocations */
314 : : size = 1024;
315 : : align = 0;
316 : 1 : rte_malloc_get_socket_stats(socket,&pre_stats);
317 : 1 : void *p2 = rte_malloc_socket("add", size ,align, socket);
318 [ + - ]: 1 : if (!p2)
319 : : return -1;
320 : 1 : rte_malloc_get_socket_stats(socket,&first_stats);
321 : :
322 : 1 : void *p3 = rte_malloc_socket("add2", size,align, socket);
323 [ + - ]: 1 : if (!p3)
324 : : return -1;
325 : :
326 : 1 : rte_malloc_get_socket_stats(socket,&second_stats);
327 : :
328 : 1 : rte_free(p2);
329 : 1 : rte_free(p3);
330 : :
331 : : /* After freeing both allocations check stats return to original */
332 : 1 : rte_malloc_get_socket_stats(socket, &post_stats);
333 : :
334 [ - + ]: 1 : if(second_stats.heap_totalsz_bytes != first_stats.heap_totalsz_bytes) {
335 : : printf("Incorrect heap statistics: Total size \n");
336 : 0 : return -1;
337 : : }
338 : : /* Check allocated size is equal to two additions plus overhead */
339 : 1 : if(second_stats.heap_allocsz_bytes !=
340 [ - + ]: 1 : size + overhead + first_stats.heap_allocsz_bytes) {
341 : : printf("Incorrect heap statistics: Allocated size \n");
342 : 0 : return -1;
343 : : }
344 : : /* Check that allocation count increments correctly i.e. +1 */
345 [ - + ]: 1 : if (second_stats.alloc_count != first_stats.alloc_count + 1) {
346 : : printf("Incorrect heap statistics: Allocated count \n");
347 : 0 : return -1;
348 : : }
349 : :
350 [ - + ]: 1 : if (second_stats.free_count != first_stats.free_count){
351 : : printf("Incorrect heap statistics: Free count \n");
352 : 0 : return -1;
353 : : }
354 : :
355 : : /* Make sure that we didn't touch our greatest chunk: 2 * 11M) */
356 [ - + ]: 1 : if (post_stats.greatest_free_size != pre_stats.greatest_free_size) {
357 : : printf("Incorrect heap statistics: Greatest free size \n");
358 : 0 : return -1;
359 : : }
360 : : /* Free size must equal the original free size minus the new allocation*/
361 [ - + ]: 1 : if (first_stats.heap_freesz_bytes <= second_stats.heap_freesz_bytes) {
362 : : printf("Incorrect heap statistics: Free size \n");
363 : 0 : return -1;
364 : : }
365 : :
366 [ + - ]: 1 : if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) ||
367 [ + - ]: 1 : (post_stats.heap_freesz_bytes != pre_stats.heap_freesz_bytes) ||
368 [ + - ]: 1 : (post_stats.heap_allocsz_bytes != pre_stats.heap_allocsz_bytes) ||
369 [ - + ]: 1 : (post_stats.alloc_count != pre_stats.alloc_count) ||
370 : : (post_stats.free_count != pre_stats.free_count)) {
371 : : printf("Malloc statistics are incorrect - freed alloc\n");
372 : 0 : return -1;
373 : : }
374 : : return 0;
375 : : }
376 : :
377 : : #ifdef RTE_EXEC_ENV_WINDOWS
378 : : static int
379 : : test_realloc(void)
380 : : {
381 : : return TEST_SKIPPED;
382 : : }
383 : : #else
384 : :
385 : : static int
386 : 1 : test_realloc_socket(int socket)
387 : : {
388 : 1 : const char hello_str[] = "Hello, world!";
389 : : const unsigned size1 = 1024;
390 : : const unsigned size2 = size1 + 1024;
391 : : const unsigned size3 = size2;
392 : : const unsigned size4 = size3 + 1024;
393 : :
394 : : /* test data is the same even if element is moved*/
395 : 1 : char *ptr1 = rte_zmalloc_socket(
396 : : NULL, size1, RTE_CACHE_LINE_SIZE, socket);
397 [ - + ]: 1 : if (!ptr1){
398 : : printf("NULL pointer returned from rte_zmalloc\n");
399 : 0 : return -1;
400 : : }
401 : : strlcpy(ptr1, hello_str, size1);
402 : 1 : char *ptr2 = rte_realloc_socket(
403 : : ptr1, size2, RTE_CACHE_LINE_SIZE, socket);
404 [ - + ]: 1 : if (!ptr2){
405 : 0 : rte_free(ptr1);
406 : : printf("NULL pointer returned from rte_realloc\n");
407 : 0 : return -1;
408 : : }
409 [ - + ]: 1 : if (ptr1 == ptr2){
410 : : printf("unexpected - ptr1 == ptr2\n");
411 : : }
412 [ - + ]: 1 : if (strcmp(ptr2, hello_str) != 0){
413 : : printf("Error - lost data from pointed area\n");
414 : 0 : rte_free(ptr2);
415 : 0 : return -1;
416 : : }
417 : : unsigned i;
418 [ + + ]: 1012 : for (i = strnlen(hello_str, sizeof(hello_str)); i < size1; i++)
419 [ - + ]: 1011 : if (ptr2[i] != 0){
420 : : printf("Bad data in realloc\n");
421 : 0 : rte_free(ptr2);
422 : 0 : return -1;
423 : : }
424 : : /* now allocate third element, free the second
425 : : * and resize third. It should not move. (ptr1 is now invalid)
426 : : */
427 : 1 : char *ptr3 = rte_zmalloc_socket(
428 : : NULL, size3, RTE_CACHE_LINE_SIZE, socket);
429 [ - + ]: 1 : if (!ptr3){
430 : : printf("NULL pointer returned from rte_zmalloc\n");
431 : 0 : rte_free(ptr2);
432 : 0 : return -1;
433 : : }
434 [ + + ]: 2049 : for (i = 0; i < size3; i++)
435 [ - + ]: 2048 : if (ptr3[i] != 0){
436 : : printf("Bad data in zmalloc\n");
437 : 0 : rte_free(ptr3);
438 : 0 : rte_free(ptr2);
439 : 0 : return -1;
440 : : }
441 : 1 : rte_free(ptr2);
442 : : /* first resize to half the size of the freed block */
443 : 1 : char *ptr4 = rte_realloc_socket(
444 : : ptr3, size4, RTE_CACHE_LINE_SIZE, socket);
445 [ - + ]: 1 : if (!ptr4){
446 : : printf("NULL pointer returned from rte_realloc\n");
447 : 0 : rte_free(ptr3);
448 : 0 : return -1;
449 : : }
450 [ - + ]: 1 : if (ptr3 != ptr4){
451 : : printf("Unexpected - ptr4 != ptr3\n");
452 : 0 : rte_free(ptr4);
453 : 0 : return -1;
454 : : }
455 : : /* now resize again to the full size of the freed block */
456 : 1 : ptr4 = rte_realloc_socket(ptr3, size3 + size2 + size1,
457 : : RTE_CACHE_LINE_SIZE, socket);
458 [ - + ]: 1 : if (ptr3 != ptr4){
459 : : printf("Unexpected - ptr4 != ptr3 on second resize\n");
460 : 0 : rte_free(ptr4);
461 : 0 : return -1;
462 : : }
463 : 1 : rte_free(ptr4);
464 : :
465 : : /* now try a resize to a smaller size, see if it works */
466 : : const unsigned size5 = 1024;
467 : : const unsigned size6 = size5 / 2;
468 : 1 : char *ptr5 = rte_malloc_socket(
469 : : NULL, size5, RTE_CACHE_LINE_SIZE, socket);
470 [ - + ]: 1 : if (!ptr5){
471 : : printf("NULL pointer returned from rte_malloc\n");
472 : 0 : return -1;
473 : : }
474 : 1 : char *ptr6 = rte_realloc_socket(
475 : : ptr5, size6, RTE_CACHE_LINE_SIZE, socket);
476 [ - + ]: 1 : if (!ptr6){
477 : : printf("NULL pointer returned from rte_realloc\n");
478 : 0 : rte_free(ptr5);
479 : 0 : return -1;
480 : : }
481 [ - + ]: 1 : if (ptr5 != ptr6){
482 : : printf("Error, resizing to a smaller size moved data\n");
483 : 0 : rte_free(ptr6);
484 : 0 : return -1;
485 : : }
486 : 1 : rte_free(ptr6);
487 : :
488 : : /* check for behaviour changing alignment */
489 : : const unsigned size7 = 1024;
490 : : const unsigned orig_align = RTE_CACHE_LINE_SIZE;
491 : : unsigned new_align = RTE_CACHE_LINE_SIZE * 2;
492 : 1 : char *ptr7 = rte_malloc_socket(NULL, size7, orig_align, socket);
493 [ - + ]: 1 : if (!ptr7){
494 : : printf("NULL pointer returned from rte_malloc\n");
495 : 0 : return -1;
496 : : }
497 : : /* calc an alignment we don't already have */
498 [ + + ]: 5 : while(RTE_PTR_ALIGN(ptr7, new_align) == ptr7)
499 : 4 : new_align *= 2;
500 : 1 : char *ptr8 = rte_realloc_socket(ptr7, size7, new_align, socket);
501 [ - + ]: 1 : if (!ptr8){
502 : : printf("NULL pointer returned from rte_realloc\n");
503 : 0 : rte_free(ptr7);
504 : 0 : return -1;
505 : : }
506 [ - + ]: 1 : if (RTE_PTR_ALIGN(ptr8, new_align) != ptr8){
507 : : printf("Failure to re-align data\n");
508 : 0 : rte_free(ptr8);
509 : 0 : return -1;
510 : : }
511 : 1 : rte_free(ptr8);
512 : :
513 : : /* test behaviour when there is a free block after current one,
514 : : * but its not big enough
515 : : */
516 : : unsigned size9 = 1024, size10 = 1024;
517 : : unsigned size11 = size9 + size10 + 256;
518 : 1 : char *ptr9 = rte_malloc_socket(
519 : : NULL, size9, RTE_CACHE_LINE_SIZE, socket);
520 [ - + ]: 1 : if (!ptr9){
521 : : printf("NULL pointer returned from rte_malloc\n");
522 : 0 : return -1;
523 : : }
524 : 1 : char *ptr10 = rte_malloc_socket(
525 : : NULL, size10, RTE_CACHE_LINE_SIZE, socket);
526 [ - + ]: 1 : if (!ptr10){
527 : : printf("NULL pointer returned from rte_malloc\n");
528 : 0 : return -1;
529 : : }
530 : 1 : rte_free(ptr9);
531 : 1 : char *ptr11 = rte_realloc_socket(
532 : : ptr10, size11, RTE_CACHE_LINE_SIZE, socket);
533 [ - + ]: 1 : if (!ptr11){
534 : : printf("NULL pointer returned from rte_realloc\n");
535 : 0 : rte_free(ptr10);
536 : 0 : return -1;
537 : : }
538 [ - + ]: 1 : if (ptr11 == ptr10){
539 : : printf("Error, unexpected that realloc has not created new buffer\n");
540 : 0 : rte_free(ptr11);
541 : 0 : return -1;
542 : : }
543 : 1 : rte_free(ptr11);
544 : :
545 : : /* check we don't crash if we pass null to realloc
546 : : * We should get a malloc of the size requested*/
547 : : const size_t size12 = 1024;
548 : : size_t size12_check;
549 : 1 : char *ptr12 = rte_realloc_socket(
550 : : NULL, size12, RTE_CACHE_LINE_SIZE, socket);
551 [ - + ]: 1 : if (!ptr12){
552 : : printf("NULL pointer returned from rte_realloc\n");
553 : 0 : return -1;
554 : : }
555 [ + - ]: 1 : if (rte_malloc_validate(ptr12, &size12_check) < 0 ||
556 [ - + ]: 1 : size12_check != size12){
557 : 0 : rte_free(ptr12);
558 : 0 : return -1;
559 : : }
560 : 1 : rte_free(ptr12);
561 : :
562 : : /* do the same, but for regular memory */
563 : 1 : ptr12 = rte_realloc(NULL, size12, RTE_CACHE_LINE_SIZE);
564 [ - + ]: 1 : if (!ptr12) {
565 : : printf("NULL pointer returned from rte_realloc\n");
566 : 0 : return -1;
567 : : }
568 [ + - ]: 1 : if (rte_malloc_validate(ptr12, &size12_check) < 0 ||
569 [ - + ]: 1 : size12_check != size12) {
570 : 0 : rte_free(ptr12);
571 : 0 : return -1;
572 : : }
573 : 1 : rte_free(ptr12);
574 : :
575 : 1 : return 0;
576 : : }
577 : :
578 : : static int
579 : 1 : test_realloc_numa(void)
580 : : {
581 : : /* check realloc_socket part */
582 : : int32_t socket_count = 0, socket_allocated, socket;
583 : : void *ptr1, *ptr2;
584 : : int ret = -1;
585 : : size_t size = 1024;
586 : :
587 : : ptr1 = NULL;
588 [ + + ]: 33 : for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
589 [ + + ]: 32 : if (is_mem_on_socket(socket)) {
590 : : int j = 2;
591 : :
592 : 2 : socket_count++;
593 [ + + ]: 6 : while (j--) {
594 : : /* j == 1 -> resizing */
595 : 4 : ptr2 = rte_realloc_socket(ptr1, size,
596 : : RTE_CACHE_LINE_SIZE,
597 : : socket);
598 [ - + ]: 4 : if (ptr2 == NULL) {
599 : : printf("NULL pointer returned from rte_realloc_socket\n");
600 : 0 : goto end;
601 : : }
602 : :
603 : : ptr1 = ptr2;
604 : : socket_allocated = addr_to_socket(ptr2);
605 [ - + ]: 4 : if (socket_allocated != socket) {
606 : : printf("Requested socket (%d) doesn't mach allocated one (%d)\n",
607 : : socket, socket_allocated);
608 : 0 : goto end;
609 : : }
610 : 4 : size += RTE_CACHE_LINE_SIZE;
611 : : }
612 : : }
613 : : }
614 : :
615 : : /* Print warning if only a single socket, but don't fail the test */
616 [ - + ]: 1 : if (socket_count < 2)
617 : : printf("WARNING: realloc_socket test needs memory on multiple sockets!\n");
618 : :
619 : : ret = 0;
620 : 1 : end:
621 : 1 : rte_free(ptr1);
622 : 1 : return ret;
623 : : }
624 : :
625 : : static int
626 : 1 : test_realloc(void)
627 : : {
628 : : const char *heap_name = "realloc_heap";
629 : : int realloc_heap_socket;
630 : : unsigned int mem_sz = 1U << 13; /* 8K */
631 : 1 : unsigned int page_sz = sysconf(_SC_PAGESIZE);
632 : : void *mem;
633 : : int ret;
634 : :
635 : : /* page size may be bigger than total mem size, so adjust */
636 : 1 : mem_sz = RTE_MAX(mem_sz, page_sz);
637 : :
638 : : /*
639 : : * the realloc tests depend on specific layout of underlying memory, so
640 : : * to prevent accidental failures to do fragmented main heap, we will
641 : : * do all of our tests on an artificially created memory.
642 : : */
643 [ - + ]: 1 : if (rte_malloc_heap_create(heap_name) != 0) {
644 : : printf("Failed to create external heap\n");
645 : : ret = -1;
646 : 0 : goto end;
647 : : }
648 : 1 : realloc_heap_socket = rte_malloc_heap_get_socket(heap_name);
649 : :
650 : 1 : mem = mmap(NULL, mem_sz, PROT_READ | PROT_WRITE,
651 : : MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
652 [ - + ]: 1 : if (mem == MAP_FAILED) {
653 : : printf("Failed to allocate memory for external heap\n");
654 : : ret = -1;
655 : 0 : goto heap_destroy;
656 : : }
657 : :
658 [ - + ]: 1 : if (rte_malloc_heap_memory_add(
659 : : heap_name, mem, mem_sz, NULL, 0, page_sz) != 0) {
660 : : printf("Failed to add memory to external heap\n");
661 : : ret = -1;
662 : 0 : goto mem_free;
663 : : }
664 : :
665 : : /* run the socket-bound tests */
666 : 1 : ret = test_realloc_socket(realloc_heap_socket);
667 [ - + ]: 1 : if (ret != 0)
668 : 0 : goto mem_remove;
669 : :
670 : : /* now, run the NUMA node tests */
671 : 1 : ret = test_realloc_numa();
672 : :
673 : 1 : mem_remove:
674 : 1 : rte_malloc_heap_memory_remove(heap_name, mem, mem_sz);
675 : 1 : mem_free:
676 : 1 : munmap(mem, mem_sz);
677 : 1 : heap_destroy:
678 : 1 : rte_malloc_heap_destroy(heap_name);
679 : 1 : end:
680 : 1 : return ret;
681 : : }
682 : :
683 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
684 : :
685 : : static int
686 : 1 : test_random_alloc_free(void *_ __rte_unused)
687 : : {
688 : : struct mem_list {
689 : : struct mem_list *next;
690 : : char data[0];
691 : : } *list_head = NULL;
692 : : unsigned i;
693 : : unsigned count = 0;
694 : :
695 : 1 : rte_srand((unsigned)rte_rdtsc());
696 : :
697 [ + + ]: 10001 : for (i = 0; i < N; i++){
698 : : unsigned free_mem = 0;
699 : : size_t allocated_size;
700 [ + + ]: 60741 : while (!free_mem){
701 : 50741 : const unsigned mem_size = sizeof(struct mem_list) + \
702 : 50741 : rte_rand() % (64 * 1024);
703 : 50741 : const unsigned align = 1 << (rte_rand() % 12); /* up to 4k alignment */
704 : 50741 : struct mem_list *entry = rte_malloc(NULL,
705 : : mem_size, align);
706 [ + - ]: 50741 : if (entry == NULL)
707 : 0 : return -1;
708 [ + - ]: 50741 : if (RTE_PTR_ALIGN(entry, align)!= entry)
709 : : return -1;
710 [ + - ]: 50741 : if (rte_malloc_validate(entry, &allocated_size) == -1
711 [ + - ]: 50741 : || allocated_size < mem_size)
712 : : return -1;
713 : 50741 : memset(entry->data, rte_lcore_id(),
714 : : mem_size - sizeof(*entry));
715 : 50741 : entry->next = list_head;
716 [ + - ]: 50741 : if (rte_malloc_validate(entry, NULL) == -1)
717 : : return -1;
718 : : list_head = entry;
719 : :
720 : 50741 : count++;
721 : : /* switch to freeing the memory with a 20% probability */
722 : 50741 : free_mem = ((rte_rand() % 10) >= 8);
723 : : }
724 [ + + ]: 60741 : while (list_head){
725 : : struct mem_list *entry = list_head;
726 : 50741 : list_head = list_head->next;
727 : 50741 : rte_free(entry);
728 : : }
729 : : }
730 : : printf("Lcore %u allocated/freed %u blocks\n", rte_lcore_id(), count);
731 : 1 : return 0;
732 : : }
733 : :
734 : : #define err_return() do { \
735 : : printf("%s: %d - Error\n", __func__, __LINE__); \
736 : : goto err_return; \
737 : : } while (0)
738 : :
739 : : static int
740 : 1 : test_rte_malloc_validate(void)
741 : : {
742 : : const size_t request_size = 1024;
743 : : size_t allocated_size;
744 : 1 : char *data_ptr = rte_malloc(NULL, request_size, RTE_CACHE_LINE_SIZE);
745 : : #ifdef RTE_MALLOC_DEBUG
746 : : int retval;
747 : : char *over_write_vals = NULL;
748 : : #endif
749 : :
750 [ - + ]: 1 : if (data_ptr == NULL) {
751 : : printf("%s: %d - Allocation error\n", __func__, __LINE__);
752 : 0 : return -1;
753 : : }
754 : :
755 : : /* check that a null input returns -1 */
756 [ - + ]: 1 : if (rte_malloc_validate(NULL, NULL) != -1)
757 : 0 : err_return();
758 : :
759 : : /* check that we get ok on a valid pointer */
760 [ - + ]: 1 : if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
761 : 0 : err_return();
762 : :
763 : : /* check that the returned size is ok */
764 [ - + ]: 1 : if (allocated_size < request_size)
765 : 0 : err_return();
766 : :
767 : : #ifdef RTE_MALLOC_DEBUG
768 : :
769 : : /****** change the header to be bad */
770 : : char save_buf[64];
771 : : over_write_vals = (char *)((uintptr_t)data_ptr - sizeof(save_buf));
772 : : /* first save the data as a backup before overwriting it */
773 : : memcpy(save_buf, over_write_vals, sizeof(save_buf));
774 : : memset(over_write_vals, 1, sizeof(save_buf));
775 : : /* then run validate */
776 : : retval = rte_malloc_validate(data_ptr, NULL);
777 : : /* finally restore the data again */
778 : : memcpy(over_write_vals, save_buf, sizeof(save_buf));
779 : : /* check we previously had an error */
780 : : if (retval != -1)
781 : : err_return();
782 : :
783 : : /* check all ok again */
784 : : if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
785 : : err_return();
786 : :
787 : : /**** change the trailer to be bad */
788 : : over_write_vals = (char *)((uintptr_t)data_ptr + allocated_size);
789 : : /* first save the data as a backup before overwriting it */
790 : : memcpy(save_buf, over_write_vals, sizeof(save_buf));
791 : : memset(over_write_vals, 1, sizeof(save_buf));
792 : : /* then run validate */
793 : : retval = rte_malloc_validate(data_ptr, NULL);
794 : : /* finally restore the data again */
795 : : memcpy(over_write_vals, save_buf, sizeof(save_buf));
796 : : if (retval != -1)
797 : : err_return();
798 : :
799 : : /* check all ok again */
800 : : if (rte_malloc_validate(data_ptr, &allocated_size) < 0)
801 : : err_return();
802 : : #endif
803 : :
804 : 1 : rte_free(data_ptr);
805 : 1 : return 0;
806 : :
807 : 0 : err_return:
808 : : /*clean up */
809 : 0 : rte_free(data_ptr);
810 : 0 : return -1;
811 : : }
812 : :
813 : : static int
814 : 1 : test_zero_aligned_alloc(void)
815 : : {
816 : 1 : char *p1 = rte_malloc(NULL,1024, 0);
817 [ - + ]: 1 : if (!p1)
818 : 0 : goto err_return;
819 [ - + ]: 1 : if (!rte_is_aligned(p1, RTE_CACHE_LINE_SIZE))
820 : 0 : goto err_return;
821 : 1 : rte_free(p1);
822 : 1 : return 0;
823 : :
824 : 0 : err_return:
825 : : /*clean up */
826 : 0 : rte_free(p1);
827 : 0 : return -1;
828 : : }
829 : :
830 : : static int
831 : 1 : test_malloc_bad_params(void)
832 : : {
833 : : const char *type = NULL;
834 : : size_t size = 0;
835 : : unsigned align = RTE_CACHE_LINE_SIZE;
836 : :
837 : : /* rte_malloc expected to return null with inappropriate size */
838 : 1 : char *bad_ptr = rte_malloc(type, size, align);
839 [ - + ]: 1 : if (bad_ptr != NULL)
840 : 0 : goto err_return;
841 : :
842 : : /* rte_realloc expected to return null with inappropriate size */
843 : 1 : bad_ptr = rte_realloc(NULL, size, align);
844 [ - + ]: 1 : if (bad_ptr != NULL)
845 : 0 : goto err_return;
846 : :
847 : : /* rte_malloc expected to return null with inappropriate alignment */
848 : : align = 17;
849 : : size = 1024;
850 : :
851 : 1 : bad_ptr = rte_malloc(type, size, align);
852 [ - + ]: 1 : if (bad_ptr != NULL)
853 : 0 : goto err_return;
854 : :
855 : : /* rte_realloc expected to return null with inappropriate alignment */
856 : 1 : bad_ptr = rte_realloc(NULL, size, align);
857 [ - + ]: 1 : if (bad_ptr != NULL)
858 : 0 : goto err_return;
859 : :
860 : : #if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
861 : : /* this test can not be built, will get trapped at compile time! */
862 : : #else
863 : : /* rte_malloc expected to return null with size will cause overflow */
864 : : align = RTE_CACHE_LINE_SIZE;
865 : : size = (size_t)-8;
866 : :
867 : : bad_ptr = rte_malloc(type, size, align);
868 : : if (bad_ptr != NULL)
869 : : goto err_return;
870 : :
871 : : bad_ptr = rte_realloc(NULL, size, align);
872 : : if (bad_ptr != NULL)
873 : : goto err_return;
874 : : #endif
875 : : return 0;
876 : :
877 : 0 : err_return:
878 : : /* clean up pointer */
879 : 0 : rte_free(bad_ptr);
880 : 0 : return -1;
881 : : }
882 : :
883 : : static int
884 : 522 : check_socket_mem(const struct rte_memseg_list *msl, void *arg)
885 : : {
886 : : int32_t *socket = arg;
887 : :
888 [ + + ]: 522 : if (msl->external)
889 : : return 0;
890 : :
891 : 492 : return *socket == msl->socket_id;
892 : : }
893 : :
894 : : /* Check if memory is available on a specific socket */
895 : : static int
896 : : is_mem_on_socket(int32_t socket)
897 : : {
898 : 32 : return rte_memseg_list_walk(check_socket_mem, &socket);
899 : : }
900 : :
901 : :
902 : : /*
903 : : * Find what socket a memory address is on. Only works for addresses within
904 : : * memsegs, not heap or stack...
905 : : */
906 : : static int32_t
907 : : addr_to_socket(void * addr)
908 : : {
909 : 13 : const struct rte_memseg *ms = rte_mem_virt2memseg(addr, NULL);
910 [ + - + - : 13 : return ms == NULL ? -1 : ms->socket_id;
+ - + - ]
911 : :
912 : : }
913 : :
914 : : /* Test using rte_[c|m|zm]alloc_socket() on a specific socket */
915 : : static int
916 : 33 : test_alloc_single_socket(int32_t socket)
917 : : {
918 : : const char *type = NULL;
919 : : const size_t size = 10;
920 : : const unsigned align = 0;
921 : : char *mem = NULL;
922 : : int32_t desired_socket = (socket == SOCKET_ID_ANY) ?
923 [ + + ]: 33 : (int32_t)rte_socket_id() : socket;
924 : :
925 : : /* Test rte_calloc_socket() */
926 : 33 : mem = rte_calloc_socket(type, size, sizeof(char), align, socket);
927 [ + + ]: 33 : if (mem == NULL)
928 : : return -1;
929 [ - + ]: 3 : if (addr_to_socket(mem) != desired_socket) {
930 : 0 : rte_free(mem);
931 : 0 : return -1;
932 : : }
933 : 3 : rte_free(mem);
934 : :
935 : : /* Test rte_malloc_socket() */
936 : 3 : mem = rte_malloc_socket(type, size, align, socket);
937 [ + - ]: 3 : if (mem == NULL)
938 : : return -1;
939 [ - + ]: 3 : if (addr_to_socket(mem) != desired_socket) {
940 : 0 : rte_free(mem);
941 : 0 : return -1;
942 : : }
943 : 3 : rte_free(mem);
944 : :
945 : : /* Test rte_zmalloc_socket() */
946 : 3 : mem = rte_zmalloc_socket(type, size, align, socket);
947 [ + - ]: 3 : if (mem == NULL)
948 : : return -1;
949 [ - + ]: 3 : if (addr_to_socket(mem) != desired_socket) {
950 : 0 : rte_free(mem);
951 : 0 : return -1;
952 : : }
953 : 3 : rte_free(mem);
954 : :
955 : 3 : return 0;
956 : : }
957 : :
958 : : static int
959 : 1 : test_alloc_socket(void)
960 : : {
961 : : unsigned socket_count = 0;
962 : : unsigned i;
963 : :
964 [ + - ]: 1 : if (test_alloc_single_socket(SOCKET_ID_ANY) < 0)
965 : : return -1;
966 : :
967 [ + + ]: 33 : for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
968 [ + + ]: 32 : if (is_mem_on_socket(i)) {
969 : 2 : socket_count++;
970 [ - + ]: 2 : if (test_alloc_single_socket(i) < 0) {
971 : : printf("Fail: rte_malloc_socket(..., %u) did not succeed\n",
972 : : i);
973 : 0 : return -1;
974 : : }
975 : : }
976 : : else {
977 [ - + ]: 30 : if (test_alloc_single_socket(i) == 0) {
978 : : printf("Fail: rte_malloc_socket(..., %u) succeeded\n",
979 : : i);
980 : 0 : return -1;
981 : : }
982 : : }
983 : : }
984 : :
985 : : /* Print warning if only a single socket, but don't fail the test */
986 [ - + ]: 1 : if (socket_count < 2) {
987 : : printf("WARNING: alloc_socket test needs memory on multiple sockets!\n");
988 : : }
989 : :
990 : : return 0;
991 : : }
992 : :
993 : : static int
994 : 1 : test_malloc(void)
995 : : {
996 : : unsigned lcore_id;
997 : : int ret = 0;
998 : :
999 [ - + ]: 1 : if (test_str_to_size() < 0){
1000 : : printf("test_str_to_size() failed\n");
1001 : 0 : return -1;
1002 : : }
1003 : : else printf("test_str_to_size() passed\n");
1004 : :
1005 [ - + ]: 1 : if (test_zero_aligned_alloc() < 0){
1006 : : printf("test_zero_aligned_alloc() failed\n");
1007 : 0 : return -1;
1008 : : }
1009 : : else printf("test_zero_aligned_alloc() passed\n");
1010 : :
1011 [ - + ]: 1 : if (test_malloc_bad_params() < 0){
1012 : : printf("test_malloc_bad_params() failed\n");
1013 : 0 : return -1;
1014 : : }
1015 : : else printf("test_malloc_bad_params() passed\n");
1016 : :
1017 [ - + ]: 1 : if (test_realloc() < 0){
1018 : : printf("test_realloc() failed\n");
1019 : 0 : return -1;
1020 : : }
1021 : : else printf("test_realloc() passed\n");
1022 : :
1023 : : /*----------------------------*/
1024 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
1025 : 1 : rte_eal_remote_launch(test_align_overlap_per_lcore, NULL, lcore_id);
1026 : : }
1027 : :
1028 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
1029 [ - + ]: 1 : if (rte_eal_wait_lcore(lcore_id) < 0)
1030 : : ret = -1;
1031 : : }
1032 [ - + ]: 1 : if (ret < 0){
1033 : : printf("test_align_overlap_per_lcore() failed\n");
1034 : 0 : return ret;
1035 : : }
1036 : : else printf("test_align_overlap_per_lcore() passed\n");
1037 : :
1038 : : /*----------------------------*/
1039 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
1040 : 1 : rte_eal_remote_launch(test_reordered_free_per_lcore, NULL, lcore_id);
1041 : : }
1042 : :
1043 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
1044 [ - + ]: 1 : if (rte_eal_wait_lcore(lcore_id) < 0)
1045 : : ret = -1;
1046 : : }
1047 [ - + ]: 1 : if (ret < 0){
1048 : : printf("test_reordered_free_per_lcore() failed\n");
1049 : 0 : return ret;
1050 : : }
1051 : : else printf("test_reordered_free_per_lcore() passed\n");
1052 : :
1053 : : /*----------------------------*/
1054 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
1055 : 1 : rte_eal_remote_launch(test_random_alloc_free, NULL, lcore_id);
1056 : : }
1057 : :
1058 [ + + ]: 2 : RTE_LCORE_FOREACH_WORKER(lcore_id) {
1059 [ - + ]: 1 : if (rte_eal_wait_lcore(lcore_id) < 0)
1060 : : ret = -1;
1061 : : }
1062 [ - + ]: 1 : if (ret < 0){
1063 : : printf("test_random_alloc_free() failed\n");
1064 : 0 : return ret;
1065 : : }
1066 : : else printf("test_random_alloc_free() passed\n");
1067 : :
1068 : : /*----------------------------*/
1069 : 1 : ret = test_rte_malloc_validate();
1070 [ - + ]: 1 : if (ret < 0){
1071 : : printf("test_rte_malloc_validate() failed\n");
1072 : 0 : return ret;
1073 : : }
1074 : : else printf("test_rte_malloc_validate() passed\n");
1075 : :
1076 : 1 : ret = test_alloc_socket();
1077 [ - + ]: 1 : if (ret < 0){
1078 : : printf("test_alloc_socket() failed\n");
1079 : 0 : return ret;
1080 : : }
1081 : : else printf("test_alloc_socket() passed\n");
1082 : :
1083 : 1 : ret = test_multi_alloc_statistics();
1084 [ - + ]: 1 : if (ret < 0) {
1085 : : printf("test_multi_alloc_statistics() failed\n");
1086 : 0 : return ret;
1087 : : }
1088 : : else
1089 : : printf("test_multi_alloc_statistics() passed\n");
1090 : :
1091 : 1 : return 0;
1092 : : }
1093 : :
1094 : 235 : REGISTER_FAST_TEST(malloc_autotest, false, true, test_malloc);
|