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