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

Last change on this file since 454 was 454, checked in by katerina, 7 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.