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