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