1
2 #if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)
3 # define _CRT_SECURE_NO_WARNINGS
4 #endif
5
6 #include <rpmalloc.h>
7 #include <thread.h>
8 #include <test.h>
9
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <math.h>
15 #include <time.h>
16
17 #define pointer_offset(ptr, ofs) (void*)((char*)(ptr) + (ptrdiff_t)(ofs))
18 #define pointer_diff(first, second) (ptrdiff_t)((const char*)(first) - (const char*)(second))
19
20 static size_t _hardware_threads;
21
22 static void
23 test_initialize(void);
24
25 static int
test_fail(const char * reason)26 test_fail(const char* reason) {
27 fprintf(stderr, "FAIL: %s\n", reason);
28 return -1;
29 }
30
31 static int
test_alloc(void)32 test_alloc(void) {
33 unsigned int iloop = 0;
34 unsigned int ipass = 0;
35 unsigned int icheck = 0;
36 unsigned int id = 0;
37 void* addr[8142];
38 char data[20000];
39 unsigned int datasize[7] = { 473, 39, 195, 24, 73, 376, 245 };
40
41 rpmalloc_initialize();
42
43 for (id = 0; id < 20000; ++id)
44 data[id] = (char)(id % 139 + id % 17);
45
46 //Verify that blocks are 16 byte size aligned
47 void* testptr = rpmalloc(16);
48 if (rpmalloc_usable_size(testptr) != 16)
49 return test_fail("Bad base alloc usable size");
50 rpfree(testptr);
51 testptr = rpmalloc(32);
52 if (rpmalloc_usable_size(testptr) != 32)
53 return test_fail("Bad base alloc usable size");
54 rpfree(testptr);
55 testptr = rpmalloc(128);
56 if (rpmalloc_usable_size(testptr) != 128)
57 return test_fail("Bad base alloc usable size");
58 rpfree(testptr);
59 for (iloop = 0; iloop <= 1024; ++iloop) {
60 testptr = rpmalloc(iloop);
61 size_t wanted_usable_size = 16 * ((iloop / 16) + ((!iloop || (iloop % 16)) ? 1 : 0));
62 if (rpmalloc_usable_size(testptr) != wanted_usable_size)
63 return test_fail("Bad base alloc usable size");
64 rpfree(testptr);
65 }
66
67 //Verify medium block sizes (until class merging kicks in)
68 for (iloop = 1025; iloop <= 6000; ++iloop) {
69 testptr = rpmalloc(iloop);
70 size_t wanted_usable_size = 512 * ((iloop / 512) + ((iloop % 512) ? 1 : 0));
71 if (rpmalloc_usable_size(testptr) != wanted_usable_size)
72 return test_fail("Bad medium alloc usable size");
73 rpfree(testptr);
74 }
75
76 //Large reallocation test
77 testptr = rpmalloc(253000);
78 testptr = rprealloc(testptr, 151);
79 if (rpmalloc_usable_size(testptr) != 160)
80 return test_fail("Bad usable size");
81 if (rpmalloc_usable_size(pointer_offset(testptr, 16)) != 144)
82 return test_fail("Bad offset usable size");
83 rpfree(testptr);
84
85 //Reallocation tests
86 for (iloop = 1; iloop < 24; ++iloop) {
87 size_t size = 37 * iloop;
88 testptr = rpmalloc(size);
89 *((uintptr_t*)testptr) = 0x12345678;
90 size_t wanted_usable_size = 16 * ((size / 16) + ((size % 16) ? 1 : 0));
91 if (rpmalloc_usable_size(testptr) != wanted_usable_size)
92 return test_fail("Bad usable size (alloc)");
93 testptr = rprealloc(testptr, size + 16);
94 if (rpmalloc_usable_size(testptr) < (wanted_usable_size + 16))
95 return test_fail("Bad usable size (realloc)");
96 if (*((uintptr_t*)testptr) != 0x12345678)
97 return test_fail("Data not preserved on realloc");
98 rpfree(testptr);
99
100 testptr = rpaligned_alloc(128, size);
101 *((uintptr_t*)testptr) = 0x12345678;
102 wanted_usable_size = 16 * ((size / 16) + ((size % 16) ? 1 : 0));
103 if (rpmalloc_usable_size(testptr) < wanted_usable_size)
104 return test_fail("Bad usable size (aligned alloc)");
105 if (rpmalloc_usable_size(testptr) > (wanted_usable_size + 128))
106 return test_fail("Bad usable size (aligned alloc)");
107 testptr = rpaligned_realloc(testptr, 128, size + 32, 0, 0);
108 if (rpmalloc_usable_size(testptr) < (wanted_usable_size + 32))
109 return test_fail("Bad usable size (aligned realloc)");
110 if (*((uintptr_t*)testptr) != 0x12345678)
111 return test_fail("Data not preserved on realloc");
112 void* unaligned = rprealloc(testptr, size);
113 if (unaligned != testptr) {
114 ptrdiff_t diff = pointer_diff(testptr, unaligned);
115 if (diff < 0)
116 return test_fail("Bad realloc behaviour");
117 if (diff >= 128)
118 return test_fail("Bad realloc behaviour");
119 }
120 rpfree(testptr);
121 }
122
123 static size_t alignment[3] = { 0, 64, 256 };
124 for (iloop = 0; iloop < 64; ++iloop) {
125 for (ipass = 0; ipass < 8142; ++ipass) {
126 size_t size = iloop + ipass + datasize[(iloop + ipass) % 7];
127 char* baseptr = rpaligned_alloc(alignment[ipass % 3], size);
128 for (size_t ibyte = 0; ibyte < size; ++ibyte)
129 baseptr[ibyte] = (char)(ibyte & 0xFF);
130
131 size_t resize = (iloop * ipass + datasize[(iloop + ipass) % 7]) & 0x2FF;
132 size_t capsize = (size > resize ? resize : size);
133 baseptr = rprealloc(baseptr, resize);
134 for (size_t ibyte = 0; ibyte < capsize; ++ibyte) {
135 if (baseptr[ibyte] != (char)(ibyte & 0xFF))
136 return test_fail("Data not preserved on realloc");
137 }
138
139 size_t alignsize = (iloop * ipass + datasize[(iloop + ipass * 3) % 7]) & 0x2FF;
140 capsize = (capsize > alignsize ? alignsize : capsize);
141 baseptr = rpaligned_realloc(baseptr, 128, alignsize, resize, 0);
142 for (size_t ibyte = 0; ibyte < capsize; ++ibyte) {
143 if (baseptr[ibyte] != (char)(ibyte & 0xFF))
144 return test_fail("Data not preserved on realloc");
145 }
146
147 rpfree(baseptr);
148 }
149 }
150
151 for (iloop = 0; iloop < 64; ++iloop) {
152 for (ipass = 0; ipass < 8142; ++ipass) {
153 addr[ipass] = rpmalloc(500);
154 if (addr[ipass] == 0)
155 return test_fail("Allocation failed");
156
157 memcpy(addr[ipass], data + ipass, 500);
158
159 for (icheck = 0; icheck < ipass; ++icheck) {
160 if (addr[icheck] == addr[ipass])
161 return test_fail("Bad allocation result");
162 if (addr[icheck] < addr[ipass]) {
163 if (pointer_offset(addr[icheck], 500) > addr[ipass])
164 return test_fail("Bad allocation result");
165 }
166 else if (addr[icheck] > addr[ipass]) {
167 if (pointer_offset(addr[ipass], 500) > addr[icheck])
168 return test_fail("Bad allocation result");
169 }
170 }
171 }
172
173 for (ipass = 0; ipass < 8142; ++ipass) {
174 if (memcmp(addr[ipass], data + ipass, 500))
175 return test_fail("Data corruption");
176 }
177
178 for (ipass = 0; ipass < 8142; ++ipass)
179 rpfree(addr[ipass]);
180 }
181
182 for (iloop = 0; iloop < 64; ++iloop) {
183 for (ipass = 0; ipass < 1024; ++ipass) {
184 unsigned int cursize = datasize[ipass%7] + ipass;
185
186 addr[ipass] = rpmalloc(cursize);
187 if (addr[ipass] == 0)
188 return test_fail("Allocation failed");
189
190 memcpy(addr[ipass], data + ipass, cursize);
191
192 for (icheck = 0; icheck < ipass; ++icheck) {
193 if (addr[icheck] == addr[ipass])
194 return test_fail("Identical pointer returned from allocation");
195 if (addr[icheck] < addr[ipass]) {
196 if (pointer_offset(addr[icheck], rpmalloc_usable_size(addr[icheck])) > addr[ipass])
197 return test_fail("Invalid pointer inside another block returned from allocation");
198 }
199 else if (addr[icheck] > addr[ipass]) {
200 if (pointer_offset(addr[ipass], rpmalloc_usable_size(addr[ipass])) > addr[icheck])
201 return test_fail("Invalid pointer inside another block returned from allocation");
202 }
203 }
204 }
205
206 for (ipass = 0; ipass < 1024; ++ipass) {
207 unsigned int cursize = datasize[ipass%7] + ipass;
208 if (memcmp(addr[ipass], data + ipass, cursize))
209 return test_fail("Data corruption");
210 }
211
212 for (ipass = 0; ipass < 1024; ++ipass)
213 rpfree(addr[ipass]);
214 }
215
216 for (iloop = 0; iloop < 128; ++iloop) {
217 for (ipass = 0; ipass < 1024; ++ipass) {
218 addr[ipass] = rpmalloc(500);
219 if (addr[ipass] == 0)
220 return test_fail("Allocation failed");
221
222 memcpy(addr[ipass], data + ipass, 500);
223
224 for (icheck = 0; icheck < ipass; ++icheck) {
225 if (addr[icheck] == addr[ipass])
226 return test_fail("Identical pointer returned from allocation");
227 if (addr[icheck] < addr[ipass]) {
228 if (pointer_offset(addr[icheck], 500) > addr[ipass])
229 return test_fail("Invalid pointer inside another block returned from allocation");
230 }
231 else if (addr[icheck] > addr[ipass]) {
232 if (pointer_offset(addr[ipass], 500) > addr[icheck])
233 return test_fail("Invalid pointer inside another block returned from allocation");
234 }
235 }
236 }
237
238 for (ipass = 0; ipass < 1024; ++ipass) {
239 if (memcmp(addr[ipass], data + ipass, 500))
240 return test_fail("Data corruption");
241 }
242
243 for (ipass = 0; ipass < 1024; ++ipass)
244 rpfree(addr[ipass]);
245 }
246
247 rpmalloc_finalize();
248
249 for (iloop = 0; iloop < 2048; iloop += 16) {
250 rpmalloc_initialize();
251 addr[0] = rpmalloc(iloop);
252 if (!addr[0])
253 return test_fail("Allocation failed");
254 rpfree(addr[0]);
255 rpmalloc_finalize();
256 }
257
258 for (iloop = 2048; iloop < (64 * 1024); iloop += 512) {
259 rpmalloc_initialize();
260 addr[0] = rpmalloc(iloop);
261 if (!addr[0])
262 return test_fail("Allocation failed");
263 rpfree(addr[0]);
264 rpmalloc_finalize();
265 }
266
267 for (iloop = (64 * 1024); iloop < (2 * 1024 * 1024); iloop += 4096) {
268 rpmalloc_initialize();
269 addr[0] = rpmalloc(iloop);
270 if (!addr[0])
271 return test_fail("Allocation failed");
272 rpfree(addr[0]);
273 rpmalloc_finalize();
274 }
275
276 rpmalloc_initialize();
277 for (iloop = 0; iloop < (2 * 1024 * 1024); iloop += 16) {
278 addr[0] = rpmalloc(iloop);
279 if (!addr[0])
280 return test_fail("Allocation failed");
281 rpfree(addr[0]);
282 }
283 rpmalloc_finalize();
284
285 printf("Memory allocation tests passed\n");
286
287 return 0;
288 }
289
290 static int
test_realloc(void)291 test_realloc(void) {
292 srand((unsigned int)time(0));
293
294 rpmalloc_initialize();
295
296 size_t pointer_count = 4096;
297 void** pointers = rpmalloc(sizeof(void*) * pointer_count);
298 memset(pointers, 0, sizeof(void*) * pointer_count);
299
300 size_t alignments[5] = {0, 16, 32, 64, 128};
301
302 for (size_t iloop = 0; iloop < 8000; ++iloop) {
303 for (size_t iptr = 0; iptr < pointer_count; ++iptr) {
304 if (iloop)
305 rpfree(rprealloc(pointers[iptr], rand() % 4096));
306 pointers[iptr] = rpaligned_alloc(alignments[(iptr + iloop) % 5], iloop + iptr);
307 }
308 }
309
310 for (size_t iptr = 0; iptr < pointer_count; ++iptr)
311 rpfree(pointers[iptr]);
312 rpfree(pointers);
313
314 size_t bigsize = 1024 * 1024;
315 void* bigptr = rpmalloc(bigsize);
316 while (bigsize < 3 * 1024 * 1024) {
317 ++bigsize;
318 bigptr = rprealloc(bigptr, bigsize);
319 }
320 rpfree(bigptr);
321
322 rpmalloc_finalize();
323
324 printf("Memory reallocation tests passed\n");
325
326 return 0;
327 }
328
329 static int
test_superalign(void)330 test_superalign(void) {
331
332 rpmalloc_initialize();
333
334 size_t alignment[] = { 2048, 4096, 8192, 16384, 32768 };
335 size_t sizes[] = { 187, 1057, 2436, 5234, 9235, 17984, 35783, 72436 };
336
337 for (size_t ipass = 0; ipass < 8; ++ipass) {
338 for (size_t iloop = 0; iloop < 4096; ++iloop) {
339 for (size_t ialign = 0, asize = sizeof(alignment) / sizeof(alignment[0]); ialign < asize; ++ialign) {
340 for (size_t isize = 0, ssize = sizeof(sizes) / sizeof(sizes[0]); isize < ssize; ++isize) {
341 size_t alloc_size = sizes[isize] + iloop + ipass;
342 uint8_t* ptr = rpaligned_alloc(alignment[ialign], alloc_size);
343 if (!ptr || ((uintptr_t)ptr & (alignment[ialign] - 1)))
344 return test_fail("Super alignment allocation failed");
345 ptr[0] = 1;
346 ptr[alloc_size - 1] = 1;
347 rpfree(ptr);
348 }
349 }
350 }
351 }
352
353 rpmalloc_finalize();
354
355 printf("Memory super aligned tests passed\n");
356
357 return 0;
358 }
359
360 typedef struct _allocator_thread_arg {
361 unsigned int loops;
362 unsigned int passes; //max 4096
363 unsigned int datasize[32];
364 unsigned int num_datasize; //max 32
365 void** pointers;
366 void** crossthread_pointers;
367 } allocator_thread_arg_t;
368
369 static void
allocator_thread(void * argp)370 allocator_thread(void* argp) {
371 allocator_thread_arg_t arg = *(allocator_thread_arg_t*)argp;
372 unsigned int iloop = 0;
373 unsigned int ipass = 0;
374 unsigned int icheck = 0;
375 unsigned int id = 0;
376 void** addr;
377 uint32_t* data;
378 unsigned int cursize;
379 unsigned int iwait = 0;
380 int ret = 0;
381
382 rpmalloc_thread_initialize();
383
384 addr = rpmalloc(sizeof(void*) * arg.passes);
385 data = rpmalloc(512 * 1024);
386 for (id = 0; id < 512 * 1024 / 4; ++id)
387 data[id] = id;
388
389 thread_sleep(1);
390
391 for (iloop = 0; iloop < arg.loops; ++iloop) {
392 for (ipass = 0; ipass < arg.passes; ++ipass) {
393 cursize = 4 + arg.datasize[(iloop + ipass + iwait) % arg.num_datasize] + ((iloop + ipass) % 1024);
394
395 addr[ipass] = rpmalloc(4 + cursize);
396 if (addr[ipass] == 0) {
397 ret = test_fail("Allocation failed");
398 goto end;
399 }
400
401 *(uint32_t*)addr[ipass] = (uint32_t)cursize;
402 memcpy(pointer_offset(addr[ipass], 4), data, cursize);
403
404 for (icheck = 0; icheck < ipass; ++icheck) {
405 if (addr[icheck] == addr[ipass]) {
406 ret = test_fail("Identical pointer returned from allocation");
407 goto end;
408 }
409 if (addr[icheck] < addr[ipass]) {
410 if (pointer_offset(addr[icheck], *(uint32_t*)addr[icheck] + 4) > addr[ipass]) {
411 ret = test_fail("Invalid pointer inside another block returned from allocation");
412 goto end;
413 }
414 }
415 else if (addr[icheck] > addr[ipass]) {
416 if (pointer_offset(addr[ipass], *(uint32_t*)addr[ipass] + 4) > addr[icheck]) {
417 ret = test_fail("Invalid pointer inside another block returned from allocation");
418 goto end;
419 }
420 }
421 }
422 }
423
424 for (ipass = 0; ipass < arg.passes; ++ipass) {
425 cursize = *(uint32_t*)addr[ipass];
426
427 if (memcmp(pointer_offset(addr[ipass], 4), data, cursize)) {
428 ret = test_fail("Data corrupted");
429 goto end;
430 }
431
432 rpfree(addr[ipass]);
433 }
434 }
435
436 rpfree(data);
437 rpfree(addr);
438
439 rpmalloc_thread_finalize();
440
441 end:
442 thread_exit((uintptr_t)ret);
443 }
444
445 static void
crossallocator_thread(void * argp)446 crossallocator_thread(void* argp) {
447 allocator_thread_arg_t arg = *(allocator_thread_arg_t*)argp;
448 unsigned int iloop = 0;
449 unsigned int ipass = 0;
450 unsigned int cursize;
451 unsigned int iextra = 0;
452 int ret = 0;
453
454 rpmalloc_thread_initialize();
455
456 thread_sleep(10);
457
458 size_t next_crossthread = 0;
459 size_t end_crossthread = arg.loops * arg.passes;
460
461 void** extra_pointers = rpmalloc(sizeof(void*) * arg.loops * arg.passes);
462
463 for (iloop = 0; iloop < arg.loops; ++iloop) {
464 for (ipass = 0; ipass < arg.passes; ++ipass) {
465 size_t iarg = (iloop + ipass + iextra++) % arg.num_datasize;
466 cursize = arg.datasize[iarg] + ((iloop + ipass) % 21);
467 void* first_addr = rpmalloc(cursize);
468 if (first_addr == 0) {
469 ret = test_fail("Allocation failed");
470 goto end;
471 }
472
473 iarg = (iloop + ipass + iextra++) % arg.num_datasize;
474 cursize = arg.datasize[iarg] + ((iloop + ipass) % 71);
475 void* second_addr = rpmalloc(cursize);
476 if (second_addr == 0) {
477 ret = test_fail("Allocation failed");
478 goto end;
479 }
480
481 iarg = (iloop + ipass + iextra++) % arg.num_datasize;
482 cursize = arg.datasize[iarg] + ((iloop + ipass) % 17);
483 void* third_addr = rpmalloc(cursize);
484 if (third_addr == 0) {
485 ret = test_fail("Allocation failed");
486 goto end;
487 }
488
489 rpfree(first_addr);
490 arg.pointers[iloop * arg.passes + ipass] = second_addr;
491 extra_pointers[iloop * arg.passes + ipass] = third_addr;
492
493 while ((next_crossthread < end_crossthread) &&
494 arg.crossthread_pointers[next_crossthread]) {
495 rpfree(arg.crossthread_pointers[next_crossthread]);
496 arg.crossthread_pointers[next_crossthread] = 0;
497 ++next_crossthread;
498 }
499 }
500 }
501
502 for (iloop = 0; iloop < arg.loops; ++iloop) {
503 for (ipass = 0; ipass < arg.passes; ++ipass) {
504 rpfree(extra_pointers[(iloop * arg.passes) + ipass]);
505 }
506 }
507
508 rpfree(extra_pointers);
509
510 while (next_crossthread < end_crossthread) {
511 if (arg.crossthread_pointers[next_crossthread]) {
512 rpfree(arg.crossthread_pointers[next_crossthread]);
513 arg.crossthread_pointers[next_crossthread] = 0;
514 ++next_crossthread;
515 } else {
516 thread_yield();
517 }
518 }
519
520 end:
521 rpmalloc_thread_finalize();
522
523 thread_exit((uintptr_t)ret);
524 }
525
526 static void
initfini_thread(void * argp)527 initfini_thread(void* argp) {
528 allocator_thread_arg_t arg = *(allocator_thread_arg_t*)argp;
529 unsigned int iloop = 0;
530 unsigned int ipass = 0;
531 unsigned int icheck = 0;
532 unsigned int id = 0;
533 void* addr[4096];
534 char data[8192];
535 unsigned int cursize;
536 unsigned int iwait = 0;
537 int ret = 0;
538
539 for (id = 0; id < 8192; ++id)
540 data[id] = (char)id;
541
542 thread_yield();
543
544 for (iloop = 0; iloop < arg.loops; ++iloop) {
545 rpmalloc_thread_initialize();
546
547 unsigned int max_datasize = 0;
548 for (ipass = 0; ipass < arg.passes; ++ipass) {
549 cursize = arg.datasize[(iloop + ipass + iwait) % arg.num_datasize] + ((iloop + ipass) % 1024);
550 if (cursize > max_datasize)
551 max_datasize = cursize;
552
553 addr[ipass] = rpmalloc(4 + cursize);
554 if (addr[ipass] == 0) {
555 ret = test_fail("Allocation failed");
556 goto end;
557 }
558
559 *(uint32_t*)addr[ipass] = (uint32_t)cursize;
560 memcpy(pointer_offset(addr[ipass], 4), data, cursize);
561
562 for (icheck = 0; icheck < ipass; ++icheck) {
563 size_t this_size = *(uint32_t*)addr[ipass];
564 size_t check_size = *(uint32_t*)addr[icheck];
565 if (this_size != cursize) {
566 ret = test_fail("Data corrupted in this block (size)");
567 goto end;
568 }
569 if (check_size > max_datasize) {
570 ret = test_fail("Data corrupted in previous block (size)");
571 goto end;
572 }
573 if (addr[icheck] == addr[ipass]) {
574 ret = test_fail("Identical pointer returned from allocation");
575 goto end;
576 }
577 if (addr[icheck] < addr[ipass]) {
578 if (pointer_offset(addr[icheck], check_size + 4) > addr[ipass]) {
579 ret = test_fail("Invalid pointer inside another block returned from allocation");
580 goto end;
581 }
582 }
583 else if (addr[icheck] > addr[ipass]) {
584 if (pointer_offset(addr[ipass], cursize + 4) > addr[icheck]) {
585 ret = test_fail("Invalid pointer inside another block returned from allocation");
586 goto end;
587 }
588 }
589 }
590 }
591
592 for (ipass = 0; ipass < arg.passes; ++ipass) {
593 cursize = *(uint32_t*)addr[ipass];
594 if (cursize > max_datasize) {
595 ret = test_fail("Data corrupted (size)");
596 goto end;
597 }
598
599 if (memcmp(pointer_offset(addr[ipass], 4), data, cursize)) {
600 ret = test_fail("Data corrupted");
601 goto end;
602 }
603
604 rpfree(addr[ipass]);
605 }
606
607 rpmalloc_thread_finalize();
608 thread_yield();
609 }
610
611 end:
612 rpmalloc_thread_finalize();
613 thread_exit((uintptr_t)ret);
614 }
615
616 static int
test_threaded(void)617 test_threaded(void) {
618 uintptr_t thread[32];
619 uintptr_t threadres[32];
620 unsigned int i;
621 size_t num_alloc_threads;
622 allocator_thread_arg_t arg;
623
624 rpmalloc_initialize();
625
626 num_alloc_threads = _hardware_threads;
627 if (num_alloc_threads < 2)
628 num_alloc_threads = 2;
629 if (num_alloc_threads > 32)
630 num_alloc_threads = 32;
631
632 arg.datasize[0] = 19;
633 arg.datasize[1] = 249;
634 arg.datasize[2] = 797;
635 arg.datasize[3] = 3058;
636 arg.datasize[4] = 47892;
637 arg.datasize[5] = 173902;
638 arg.datasize[6] = 389;
639 arg.datasize[7] = 19;
640 arg.datasize[8] = 2493;
641 arg.datasize[9] = 7979;
642 arg.datasize[10] = 3;
643 arg.datasize[11] = 79374;
644 arg.datasize[12] = 3432;
645 arg.datasize[13] = 548;
646 arg.datasize[14] = 38934;
647 arg.datasize[15] = 234;
648 arg.num_datasize = 16;
649 arg.loops = 100;
650 arg.passes = 4000;
651
652 thread_arg targ;
653 targ.fn = allocator_thread;
654 targ.arg = &arg;
655 for (i = 0; i < num_alloc_threads; ++i)
656 thread[i] = thread_run(&targ);
657
658 thread_sleep(1000);
659
660 for (i = 0; i < num_alloc_threads; ++i)
661 threadres[i] = thread_join(thread[i]);
662
663 rpmalloc_finalize();
664
665 for (i = 0; i < num_alloc_threads; ++i) {
666 if (threadres[i])
667 return -1;
668 }
669
670 printf("Memory threaded tests passed\n");
671
672 return 0;
673 }
674
675 static int
test_crossthread(void)676 test_crossthread(void) {
677 uintptr_t thread[8];
678 allocator_thread_arg_t arg[8];
679 thread_arg targ[8];
680
681 rpmalloc_initialize();
682
683 size_t num_alloc_threads = _hardware_threads;
684 if (num_alloc_threads < 2)
685 num_alloc_threads = 2;
686 if (num_alloc_threads > 4)
687 num_alloc_threads = 4;
688
689 for (unsigned int ithread = 0; ithread < num_alloc_threads; ++ithread) {
690 unsigned int iadd = (ithread * (16 + ithread) + ithread) % 128;
691 arg[ithread].loops = 50;
692 arg[ithread].passes = 1024;
693 arg[ithread].pointers = rpmalloc(sizeof(void*) * arg[ithread].loops * arg[ithread].passes);
694 memset(arg[ithread].pointers, 0, sizeof(void*) * arg[ithread].loops * arg[ithread].passes);
695 arg[ithread].datasize[0] = 19 + iadd;
696 arg[ithread].datasize[1] = 249 + iadd;
697 arg[ithread].datasize[2] = 797 + iadd;
698 arg[ithread].datasize[3] = 3 + iadd;
699 arg[ithread].datasize[4] = 7923 + iadd;
700 arg[ithread].datasize[5] = 344 + iadd;
701 arg[ithread].datasize[6] = 3892 + iadd;
702 arg[ithread].datasize[7] = 19 + iadd;
703 arg[ithread].datasize[8] = 154 + iadd;
704 arg[ithread].datasize[9] = 39723 + iadd;
705 arg[ithread].datasize[10] = 15 + iadd;
706 arg[ithread].datasize[11] = 493 + iadd;
707 arg[ithread].datasize[12] = 34 + iadd;
708 arg[ithread].datasize[13] = 894 + iadd;
709 arg[ithread].datasize[14] = 193 + iadd;
710 arg[ithread].datasize[15] = 2893 + iadd;
711 arg[ithread].num_datasize = 16;
712
713 targ[ithread].fn = crossallocator_thread;
714 targ[ithread].arg = &arg[ithread];
715 }
716
717 for (unsigned int ithread = 0; ithread < num_alloc_threads; ++ithread) {
718 arg[ithread].crossthread_pointers = arg[(ithread + 1) % num_alloc_threads].pointers;
719 }
720
721 for (int iloop = 0; iloop < 32; ++iloop) {
722 for (unsigned int ithread = 0; ithread < num_alloc_threads; ++ithread)
723 thread[ithread] = thread_run(&targ[ithread]);
724
725 thread_sleep(100);
726
727 for (unsigned int ithread = 0; ithread < num_alloc_threads; ++ithread) {
728 if (thread_join(thread[ithread]) != 0)
729 return -1;
730 }
731 }
732
733 for (unsigned int ithread = 0; ithread < num_alloc_threads; ++ithread)
734 rpfree(arg[ithread].pointers);
735
736 rpmalloc_finalize();
737
738 printf("Memory cross thread free tests passed\n");
739
740 return 0;
741 }
742
743 static int
test_threadspam(void)744 test_threadspam(void) {
745 uintptr_t thread[64];
746 uintptr_t threadres[64];
747 unsigned int i, j;
748 size_t num_passes, num_alloc_threads;
749 allocator_thread_arg_t arg;
750
751 rpmalloc_initialize();
752
753 num_passes = 100;
754 num_alloc_threads = _hardware_threads;
755 if (num_alloc_threads < 2)
756 num_alloc_threads = 2;
757 if (num_alloc_threads > 64)
758 num_alloc_threads = 64;
759
760 arg.loops = 500;
761 arg.passes = 10;
762 arg.datasize[0] = 19;
763 arg.datasize[1] = 249;
764 arg.datasize[2] = 797;
765 arg.datasize[3] = 3;
766 arg.datasize[4] = 79;
767 arg.datasize[5] = 34;
768 arg.datasize[6] = 389;
769 arg.num_datasize = 7;
770
771 thread_arg targ;
772 targ.fn = initfini_thread;
773 targ.arg = &arg;
774 for (i = 0; i < num_alloc_threads; ++i)
775 thread[i] = thread_run(&targ);
776
777 for (j = 0; j < num_passes; ++j) {
778 thread_sleep(10);
779 thread_fence();
780
781 for (i = 0; i < num_alloc_threads; ++i) {
782 threadres[i] = thread_join(thread[i]);
783 if (threadres[i])
784 return -1;
785 thread[i] = thread_run(&targ);
786 }
787 }
788
789 thread_sleep(1000);
790
791 for (i = 0; i < num_alloc_threads; ++i)
792 threadres[i] = thread_join(thread[i]);
793
794 rpmalloc_finalize();
795
796 for (i = 0; i < num_alloc_threads; ++i) {
797 if (threadres[i])
798 return -1;
799 }
800
801 printf("Memory thread spam tests passed\n");
802
803 return 0;
804 }
805
806 int
test_run(int argc,char ** argv)807 test_run(int argc, char** argv) {
808 (void)sizeof(argc);
809 (void)sizeof(argv);
810 test_initialize();
811 if (test_alloc())
812 return -1;
813 if (test_realloc())
814 return -1;
815 if (test_superalign())
816 return -1;
817 if (test_crossthread())
818 return -1;
819 if (test_threadspam())
820 return -1;
821 if (test_threaded())
822 return -1;
823 printf("All tests passed\n");
824 return 0;
825 }
826
827 #if (defined(__APPLE__) && __APPLE__)
828 # include <TargetConditionals.h>
829 # if defined(__IPHONE__) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR)
830 # define NO_MAIN 1
831 # endif
832 #elif (defined(__linux__) || defined(__linux))
833 # include <sched.h>
834 #endif
835
836 #if !defined(NO_MAIN)
837
838 int
main(int argc,char ** argv)839 main(int argc, char** argv) {
840 return test_run(argc, argv);
841 }
842
843 #endif
844
845 #ifdef _WIN32
846 #include <Windows.h>
847
848 static void
test_initialize(void)849 test_initialize(void) {
850 SYSTEM_INFO system_info;
851 GetSystemInfo(&system_info);
852 _hardware_threads = (size_t)system_info.dwNumberOfProcessors;
853 }
854
855 #elif (defined(__linux__) || defined(__linux))
856
857 static void
test_initialize(void)858 test_initialize(void) {
859 cpu_set_t prevmask, testmask;
860 CPU_ZERO(&prevmask);
861 CPU_ZERO(&testmask);
862 sched_getaffinity(0, sizeof(prevmask), &prevmask); //Get current mask
863 sched_setaffinity(0, sizeof(testmask), &testmask); //Set zero mask
864 sched_getaffinity(0, sizeof(testmask), &testmask); //Get mask for all CPUs
865 sched_setaffinity(0, sizeof(prevmask), &prevmask); //Reset current mask
866 int num = CPU_COUNT(&testmask);
867 _hardware_threads = (size_t)(num > 1 ? num : 1);
868 }
869
870 #else
871
872 static void
test_initialize(void)873 test_initialize(void) {
874 _hardware_threads = 1;
875 }
876
877 #endif
878