source: trunk/src/t-test1.c@ 465

Last change on this file since 465 was 454, checked in by katerina, 10 years ago

Fix for ticket #355 (use calloc instead of malloc).

File size: 14.6 KB
Line 
1/*
2* Copyright (c) 1996-1999, 2001-2004 Wolfram Gloger
3
4Permission to use, copy, modify, distribute, and sell this software
5and its documentation for any purpose is hereby granted without fee,
6provided that (i) the above copyright notices and this permission
7notice appear in all copies of the software and related documentation,
8and (ii) the name of Wolfram Gloger may not be used in any advertising
9or publicity relating to the software.
10
11THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
12EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
13WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
14
15IN NO EVENT SHALL WOLFRAM GLOGER BE LIABLE FOR ANY SPECIAL,
16INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
17DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY
19OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20PERFORMANCE OF THIS SOFTWARE.
21*/
22
23/*
24 * $Id: t-test1.c,v 1.2 2004/11/04 14:58:45 wg Exp $
25 * by Wolfram Gloger 1996-1999, 2001, 2004
26 * A multi-thread test for malloc performance, maintaining one pool of
27 * allocated bins per thread.
28 */
29/*
30 t-test[12] <n-total> <n-parallel> <n-allocs> <size-max> <bins>
31
32 n-total = total number of threads executed (default 10)
33 n-parallel = number of threads running in parallel (2)
34 n-allocs = number of malloc()'s / free()'s per thread (10000)
35 size-max = max. size requested with malloc() in bytes (10000)
36 bins = number of bins to maintain
37*/
38
39#if defined(HAVE_CONFIG_H)
40#include "config.h"
41#endif
42
43#if (defined __STDC__ && __STDC__) || defined __cplusplus
44# include <stdlib.h>
45#endif
46#include <stdio.h>
47#include <string.h>
48#include <unistd.h>
49#include <sys/types.h>
50#include <sys/time.h>
51#include <sys/resource.h>
52#include <sys/wait.h>
53#include <sys/mman.h>
54
55/*
56#if !USE_MALLOC
57#include <malloc.h>
58#else
59#include "malloc.h"
60#endif
61*/
62
63#ifdef USE_SYSTEM_MALLOC
64extern void *memalign(size_t boundary, size_t size);
65/* #define memalign(a,b) malloc(b) */
66#else
67extern void *memalign(size_t boundary, size_t size);
68#endif
69
70static int verbose = 1;
71
72/* dummy for the samhain safe_fatal logger
73 */
74void safe_fatal(const char * details,
75 const char * file, int line)
76{
77 (void) file;
78 (void) line;
79 fputs("assert failed: ", stderr);
80 puts(details);
81 _exit(EXIT_FAILURE);
82}
83
84/* lran2.h
85 * by Wolfram Gloger 1996.
86 *
87 * A small, portable pseudo-random number generator.
88 */
89
90#ifndef _LRAN2_H
91#define _LRAN2_H
92
93#define LRAN2_MAX 714025l /* constants for portable */
94#define IA 1366l /* random number generator */
95#define IC 150889l /* (see e.g. `Numerical Recipes') */
96
97struct lran2_st {
98 long x, y, v[97];
99};
100
101static void
102lran2_init(struct lran2_st* d, long seed)
103{
104 long x;
105 int j;
106
107 x = (IC - seed) % LRAN2_MAX;
108 if(x < 0) x = -x;
109 for(j=0; j<97; j++) {
110 x = (IA*x + IC) % LRAN2_MAX;
111 d->v[j] = x;
112 }
113 d->x = (IA*x + IC) % LRAN2_MAX;
114 d->y = d->x;
115}
116
117#ifdef __GNUC__
118__inline__
119#endif
120static long
121lran2(struct lran2_st* d)
122{
123 int j = (d->y % 97);
124
125 d->y = d->v[j];
126 d->x = (IA*d->x + IC) % LRAN2_MAX;
127 d->v[j] = d->x;
128 return d->y;
129}
130
131#undef IA
132#undef IC
133
134#endif
135
136/*
137 * $Id: t-test.h,v 1.1 2004/11/04 14:32:21 wg Exp $
138 * by Wolfram Gloger 1996.
139 * Common data structures and functions for testing malloc performance.
140 */
141
142/* Testing level */
143#ifndef TEST
144#define TEST 99
145#endif
146
147/* For large allocation sizes, the time required by copying in
148 realloc() can dwarf all other execution times. Avoid this with a
149 size threshold. */
150#ifndef REALLOC_MAX
151#define REALLOC_MAX 2000
152#endif
153
154struct bin {
155 unsigned char *ptr;
156 unsigned long size;
157};
158
159#if TEST > 0
160
161static void
162mem_init(unsigned char *ptr, unsigned long size)
163{
164 unsigned long i, j;
165
166 if(size == 0) return;
167#if TEST > 3
168 memset(ptr, '\0', size);
169#endif
170 for(i=0; i<size; i+=2047) {
171 j = (unsigned long)ptr ^ i;
172 ptr[i] = ((j ^ (j>>8)) & 0xFF);
173 }
174 j = (unsigned long)ptr ^ (size-1);
175 ptr[size-1] = ((j ^ (j>>8)) & 0xFF);
176}
177
178static int
179mem_check(unsigned char *ptr, unsigned long size)
180{
181 unsigned long i, j;
182
183 if(size == 0) return 0;
184 for(i=0; i<size; i+=2047) {
185 j = (unsigned long)ptr ^ i;
186 if(ptr[i] != ((j ^ (j>>8)) & 0xFF)) return 1;
187 }
188 j = (unsigned long)ptr ^ (size-1);
189 if(ptr[size-1] != ((j ^ (j>>8)) & 0xFF)) return 2;
190 return 0;
191}
192
193static int
194zero_check(unsigned* ptr, unsigned long size)
195{
196 unsigned char* ptr2;
197
198 while(size >= sizeof(*ptr)) {
199 if(*ptr++ != 0)
200 return -1;
201 size -= sizeof(*ptr);
202 }
203 ptr2 = (unsigned char*)ptr;
204 while(size > 0) {
205 if(*ptr2++ != 0)
206 return -1;
207 --size;
208 }
209 return 0;
210}
211
212#endif /* TEST > 0 */
213
214/* Allocate a bin with malloc(), realloc() or memalign(). r must be a
215 random number >= 1024. */
216int n_malloc=0, n_memalign=0, n_realloc=0, n_calloc=0;
217
218static void
219bin_alloc(struct bin *m, unsigned long size, int r)
220{
221#if TEST > 0
222 if(mem_check(m->ptr, m->size)) {
223 fprintf(stderr, "memory corrupt!\n");
224 exit(1);
225 }
226#endif
227 r %= 1024;
228 /*printf("%d ", r);*/
229 if(r < 4) { /* memalign */
230 if(m->size > 0) free(m->ptr);
231 m->ptr = (unsigned char *)memalign(sizeof(int) << r, size);
232 /* fprintf(stderr, "FIXME memalign %p\n", m->ptr); */
233 ++n_memalign;
234 } else if(r < 20) { /* calloc */
235 if(m->size > 0) free(m->ptr);
236 m->ptr = (unsigned char *)calloc(size, 1);
237#if TEST > 0
238 if(zero_check((unsigned*)m->ptr, size)) {
239 unsigned long i;
240 for(i=0; i<size; i++)
241 if(m->ptr[i] != 0)
242 break;
243 fprintf(stderr, "calloc'ed memory non-zero (ptr=%p, i=%ld)!\n", m->ptr, i);
244 exit(1);
245 }
246#endif
247 ++n_calloc;
248 /* fprintf(stderr, "FIXME calloc %p\n", m->ptr); */
249 } else if(r < 100 && m->size < REALLOC_MAX) { /* realloc */
250 if(m->size == 0) m->ptr = NULL;
251 m->ptr = realloc(m->ptr, size);
252 /* fprintf(stderr, "FIXME realloc %p\n", m->ptr); */
253 ++n_realloc;
254 } else { /* plain malloc */
255 if(m->size > 0) free(m->ptr);
256 m->ptr = (unsigned char *)malloc(size);
257 /* fprintf(stderr, "FIXME malloc %p\n", m->ptr); */
258 ++n_malloc;
259 }
260 if(!m->ptr) {
261 fprintf(stderr, "out of memory (r=%d, size=%ld)!\n", r, (long)size);
262 exit(1);
263 }
264 m->size = size;
265#if TEST > 0
266 mem_init(m->ptr, m->size);
267#endif
268}
269
270/* Free a bin. */
271
272static void
273bin_free(struct bin *m)
274{
275 if(m->size == 0) return;
276#if TEST > 0
277 if(mem_check(m->ptr, m->size)) {
278 fprintf(stderr, "memory corrupt!\n");
279 exit(1);
280 }
281#endif
282 free(m->ptr);
283 m->size = 0;
284}
285
286/*
287 * Local variables:
288 * tab-width: 4
289 * End:
290 */
291
292
293struct user_data {
294 int bins, max;
295 unsigned long size;
296 long seed;
297};
298
299/*
300 * $Id: thread-st.h$
301 * pthread version
302 * by Wolfram Gloger 2004
303 */
304
305#include <pthread.h>
306#include <stdio.h>
307
308pthread_cond_t finish_cond = PTHREAD_COND_INITIALIZER;
309pthread_mutex_t finish_mutex = PTHREAD_MUTEX_INITIALIZER;
310
311#ifndef USE_PTHREADS_STACKS
312#define USE_PTHREADS_STACKS 0
313#endif
314
315#ifndef STACKSIZE
316#define STACKSIZE 32768
317#endif
318
319struct thread_st {
320 char *sp; /* stack pointer, can be 0 */
321 void (*func)(struct thread_st* st); /* must be set by user */
322 pthread_t id;
323 int flags;
324 struct user_data u;
325};
326
327static void
328mthread_init(void)
329{
330#if !defined(USE_SYSTEM_MALLOC) && defined(USE_MALLOC_LOCK)
331 extern int dnmalloc_pthread_init(void);
332 dnmalloc_pthread_init();
333#endif
334
335 if (verbose)
336 printf("Using posix threads.\n");
337 pthread_cond_init(&finish_cond, NULL);
338 pthread_mutex_init(&finish_mutex, NULL);
339}
340
341static void *
342mthread_wrapper(void *ptr)
343{
344 struct thread_st *st = (struct thread_st*)ptr;
345
346 /*printf("begin %p\n", st->sp);*/
347 st->func(st);
348 pthread_mutex_lock(&finish_mutex);
349 st->flags = 1;
350 pthread_mutex_unlock(&finish_mutex);
351 pthread_cond_signal(&finish_cond);
352 /*printf("end %p\n", st->sp);*/
353 return NULL;
354}
355
356/* Create a thread. */
357static int
358mthread_create(struct thread_st *st)
359{
360 st->flags = 0;
361 {
362 pthread_attr_t* attr_p = 0;
363#if USE_PTHREADS_STACKS
364 pthread_attr_t attr;
365
366 pthread_attr_init (&attr);
367 if(!st->sp)
368 st->sp = malloc(STACKSIZE+16);
369 if(!st->sp)
370 return -1;
371 if(pthread_attr_setstacksize(&attr, STACKSIZE))
372 fprintf(stderr, "error setting stacksize");
373 else
374 pthread_attr_setstackaddr(&attr, st->sp + STACKSIZE);
375 /*printf("create %p\n", st->sp);*/
376 attr_p = &attr;
377#endif
378 return pthread_create(&st->id, attr_p, mthread_wrapper, st);
379 }
380 return 0;
381}
382
383/* Wait for one of several subthreads to finish. */
384static void
385wait_for_thread(struct thread_st st[], int n_thr,
386 int (*end_thr)(struct thread_st*))
387{
388 int i;
389
390 pthread_mutex_lock(&finish_mutex);
391 for(;;) {
392 int term = 0;
393 for(i=0; i<n_thr; i++)
394 if(st[i].flags) {
395 /*printf("joining %p\n", st[i].sp);*/
396 if(pthread_join(st[i].id, NULL) == 0) {
397 st[i].flags = 0;
398 if(end_thr)
399 end_thr(&st[i]);
400 } else
401 fprintf(stderr, "can't join\n");
402 ++term;
403 }
404 if(term > 0)
405 break;
406 pthread_cond_wait(&finish_cond, &finish_mutex);
407 }
408 pthread_mutex_unlock(&finish_mutex);
409}
410
411/*
412 * Local variables:
413 * tab-width: 4
414 * End:
415 */
416
417
418#define N_TOTAL 10
419#ifndef N_THREADS
420#define N_THREADS 2
421#endif
422#ifndef N_TOTAL_PRINT
423#define N_TOTAL_PRINT 50
424#endif
425#ifndef MEMORY
426#define MEMORY 8000000l
427#endif
428#define SIZE 10000
429#define I_MAX 10000
430#define ACTIONS_MAX 30
431#ifndef TEST_FORK
432#define TEST_FORK 0
433#endif
434
435#define RANDOM(d,s) (lran2(d) % (s))
436
437struct bin_info {
438 struct bin *m;
439 unsigned long size, bins;
440};
441
442#if TEST > 0
443
444void
445bin_test(struct bin_info *p)
446{
447 unsigned int b;
448
449 for(b=0; b<p->bins; b++) {
450 if(mem_check(p->m[b].ptr, p->m[b].size)) {
451 fprintf(stderr, "memory corrupt!\n");
452 abort();
453 }
454 }
455}
456
457#endif
458
459void
460malloc_test(struct thread_st *st)
461{
462 unsigned int b;
463 int i, j, actions, pid = 1;
464 struct bin_info p;
465 struct lran2_st ld; /* data for random number generator */
466
467 lran2_init(&ld, st->u.seed);
468#if TEST_FORK>0
469 if(RANDOM(&ld, TEST_FORK) == 0) {
470 int status;
471
472#if !USE_THR
473 pid = fork();
474#else
475 pid = fork1();
476#endif
477 if(pid > 0) {
478 /*printf("forked, waiting for %d...\n", pid);*/
479 waitpid(pid, &status, 0);
480 printf("done with %d...\n", pid);
481 if(!WIFEXITED(status)) {
482 printf("child term with signal %d\n", WTERMSIG(status));
483 exit(1);
484 }
485 return;
486 }
487 exit(0);
488 }
489#endif
490 p.m = (struct bin *)malloc(st->u.bins*sizeof(*p.m));
491 p.bins = st->u.bins;
492 p.size = st->u.size;
493 for(b=0; b<p.bins; b++) {
494 p.m[b].size = 0;
495 p.m[b].ptr = NULL;
496 if(RANDOM(&ld, 2) == 0)
497 bin_alloc(&p.m[b], RANDOM(&ld, p.size) + 1, lran2(&ld));
498 }
499 for(i=0; i<=st->u.max;) {
500#if TEST > 1
501 bin_test(&p);
502#endif
503 actions = RANDOM(&ld, ACTIONS_MAX);
504#if USE_MALLOC && MALLOC_DEBUG
505 if(actions < 2) { mallinfo(); }
506#endif
507 for(j=0; j<actions; j++) {
508 b = RANDOM(&ld, p.bins);
509 bin_free(&p.m[b]);
510 }
511 i += actions;
512 actions = RANDOM(&ld, ACTIONS_MAX);
513 for(j=0; j<actions; j++) {
514 b = RANDOM(&ld, p.bins);
515 bin_alloc(&p.m[b], RANDOM(&ld, p.size) + 1, lran2(&ld));
516#if TEST > 2
517 bin_test(&p);
518#endif
519 }
520#if 0 /* Test illegal free()s while setting MALLOC_CHECK_ */
521 for(j=0; j<8; j++) {
522 b = RANDOM(&ld, p.bins);
523 if(p.m[b].ptr) {
524 int offset = (RANDOM(&ld, 11) - 5)*8;
525 char *rogue = (char*)(p.m[b].ptr) + offset;
526 /*printf("p=%p rogue=%p\n", p.m[b].ptr, rogue);*/
527 free(rogue);
528 }
529 }
530#endif
531 i += actions;
532 }
533 for(b=0; b<p.bins; b++)
534 bin_free(&p.m[b]);
535 free(p.m);
536 if(pid == 0)
537 exit(0);
538}
539
540int n_total=0, n_total_max=N_TOTAL, n_running;
541
542int
543my_end_thread(struct thread_st *st)
544{
545 /* Thread st has finished. Start a new one. */
546#if 0
547 printf("Thread %lx terminated.\n", (long)st->id);
548#endif
549 if(n_total >= n_total_max) {
550 n_running--;
551 } else if(st->u.seed++, mthread_create(st)) {
552 printf("Creating thread #%d failed.\n", n_total);
553 exit(1);
554 } else {
555 n_total++;
556 if (verbose)
557 if(n_total%N_TOTAL_PRINT == 0)
558 printf("n_total = %8d - malloc %12d / memalign %12d / realloc %12d / calloc %12d\n",
559 n_total,
560 n_malloc, n_memalign, n_realloc, n_calloc);
561
562 }
563 return 0;
564}
565
566#if 0
567/* Protect address space for allocation of n threads by LinuxThreads. */
568static void
569protect_stack(int n)
570{
571 char buf[2048*1024];
572 char* guard;
573 size_t guard_size = 2*2048*1024UL*(n+2);
574
575 buf[0] = '\0';
576 guard = (char*)(((unsigned long)buf - 4096)& ~4095UL) - guard_size;
577 printf("Setting up stack guard at %p\n", guard);
578 if(mmap(guard, guard_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
579 -1, 0)
580 != guard)
581 printf("failed!\n");
582}
583#endif
584
585int
586main(int argc, char *argv[])
587{
588 int i, bins;
589 int n_thr=N_THREADS;
590 int i_max=I_MAX;
591 unsigned long size=SIZE;
592 struct thread_st *st;
593
594#if USE_MALLOC && USE_STARTER==2
595 ptmalloc_init();
596 printf("ptmalloc_init\n");
597#endif
598
599 if((argc > 1) && (0 == strcmp(argv[1], "-h") || 0 == strcmp(argv[1], "--help")))
600 {
601 printf("%s <n-total> <n-parallel> <n-allocs> <size-max> <bins>\n\n", argv[0]);
602 printf(" n-total = total number of threads executed (default 10)\n");
603 printf(" n-parallel = number of threads running in parallel (2)\n");
604 printf(" n-allocs = number of malloc()'s / free()'s per thread (10000)\n");
605 printf(" size-max = max. size requested with malloc() in bytes (10000)\n");
606 printf(" bins = number of bins to maintain\n");
607 return 0;
608 }
609
610 if(argc > 1) n_total_max = atoi(argv[1]);
611 if(n_total_max < 1) n_thr = 1;
612 if(argc > 2) n_thr = atoi(argv[2]);
613 if(n_thr < 1) n_thr = 1;
614 if(n_thr > 100) n_thr = 100;
615 if(argc > 3) i_max = atoi(argv[3]);
616
617 if(argc > 4) size = atol(argv[4]);
618 if(size < 2) size = 2;
619
620 bins = MEMORY/(size*n_thr);
621 if(argc > 5) bins = atoi(argv[5]);
622 if(bins < 4) bins = 4;
623
624 /*protect_stack(n_thr);*/
625
626 mthread_init();
627 printf("total=%d threads=%d i_max=%d size=%ld bins=%d\n",
628 n_total_max, n_thr, i_max, size, bins);
629
630 st = (struct thread_st *)malloc(n_thr*sizeof(*st));
631 if(!st) exit(-1);
632
633#if !defined NO_THREADS && (defined __sun__ || defined sun)
634 /* I know of no other way to achieve proper concurrency with Solaris. */
635 thr_setconcurrency(n_thr);
636#endif
637
638 /* Start all n_thr threads. */
639 for(i=0; i<n_thr; i++) {
640 st[i].u.bins = bins;
641 st[i].u.max = i_max;
642 st[i].u.size = size;
643 st[i].u.seed = ((long)i_max*size + i) ^ bins;
644 st[i].sp = 0;
645 st[i].func = malloc_test;
646 if(mthread_create(&st[i])) {
647 fprintf(stderr, "Creating thread #%d failed.\n", i);
648 n_thr = i;
649 exit(1);
650 }
651 if (verbose)
652 printf("Created thread %lx.\n", (long)st[i].id);
653 }
654
655 /* Start an extra thread so we don't run out of stacks. */
656 if(0) {
657 struct thread_st lst;
658 lst.u.bins = 10; lst.u.max = 20; lst.u.size = 8000; lst.u.seed = 8999;
659 lst.sp = 0;
660 lst.func = malloc_test;
661 if(mthread_create(&lst)) {
662 fprintf(stderr, "Creating thread #%d failed.\n", i);
663 exit(1);
664 } else {
665 wait_for_thread(&lst, 1, NULL);
666 }
667 }
668
669 for(n_running=n_total=n_thr; n_running>0;) {
670 wait_for_thread(st, n_thr, my_end_thread);
671 }
672 for(i=0; i<n_thr; i++) {
673 free(st[i].sp);
674 }
675 free(st);
676#if USE_MALLOC
677 malloc_stats();
678#endif
679 if (verbose)
680 printf("Done.\n");
681 return 0;
682}
683
684/*
685 * Local variables:
686 * tab-width: 4
687 * End:
688 */
Note: See TracBrowser for help on using the repository browser.