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

Last change on this file since 481 was 481, checked in by katerina, 6 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

File size: 14.4 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                ++n_memalign;
233        } else if(r < 20) { /* calloc */
234                if(m->size > 0) free(m->ptr);
235                m->ptr = (unsigned char *)calloc(size, 1);
236#if TEST > 0
237                if(zero_check((unsigned*)m->ptr, size)) {
238                        unsigned long i;
239                        for(i=0; i<size; i++)
240                                if(m->ptr[i] != 0)
241                                        break;
242                        fprintf(stderr, "calloc'ed memory non-zero (ptr=%p, i=%ld)!\n", m->ptr, i);
243                        exit(1);
244                }
245#endif
246                ++n_calloc;
247        } else if(r < 100 && m->size < REALLOC_MAX) { /* realloc */
248                if(m->size == 0) m->ptr = NULL;
249                m->ptr = realloc(m->ptr, size);
250                ++n_realloc;
251        } else { /* plain malloc */
252                if(m->size > 0) free(m->ptr);
253                m->ptr = (unsigned char *)malloc(size);
254                ++n_malloc;
255        }
256        if(!m->ptr) {
257          fprintf(stderr, "out of memory (r=%d, size=%ld)!\n", r, (long)size);
258          exit(1);
259        }
260        m->size = size;
261#if TEST > 0
262        mem_init(m->ptr, m->size);
263#endif
264}
265
266/* Free a bin. */
267
268static void
269bin_free(struct bin *m)
270{
271        if(m->size == 0) return;
272#if TEST > 0
273        if(mem_check(m->ptr, m->size)) {
274          fprintf(stderr, "memory corrupt!\n");
275          exit(1);
276        }
277#endif
278        free(m->ptr);
279        m->size = 0;
280}
281
282/*
283 * Local variables:
284 * tab-width: 4
285 * End:
286 */
287
288
289struct user_data {
290        int bins, max;
291        unsigned long size;
292        long seed;
293};
294
295/*
296 * $Id: thread-st.h$
297 * pthread version
298 * by Wolfram Gloger 2004
299 */
300
301#include <pthread.h>
302#include <stdio.h>
303
304pthread_cond_t finish_cond = PTHREAD_COND_INITIALIZER;
305pthread_mutex_t finish_mutex = PTHREAD_MUTEX_INITIALIZER;
306
307#ifndef USE_PTHREADS_STACKS
308#define USE_PTHREADS_STACKS 0
309#endif
310
311#ifndef STACKSIZE
312#define STACKSIZE       32768
313#endif
314
315struct thread_st {
316        char *sp;                                                       /* stack pointer, can be 0 */
317        void (*func)(struct thread_st* st);     /* must be set by user */
318        pthread_t id;
319        int flags;
320        struct user_data u;
321};
322
323static void
324mthread_init(void)
325{
326#if !defined(USE_SYSTEM_MALLOC) && defined(USE_MALLOC_LOCK)
327  extern int dnmalloc_pthread_init(void);
328  dnmalloc_pthread_init();
329#endif
330
331  if (verbose)
332        printf("Using posix threads.\n");
333  pthread_cond_init(&finish_cond, NULL);
334  pthread_mutex_init(&finish_mutex, NULL);
335}
336
337static void *
338mthread_wrapper(void *ptr)
339{
340        struct thread_st *st = (struct thread_st*)ptr;
341
342        /*printf("begin %p\n", st->sp);*/
343        st->func(st);
344        pthread_mutex_lock(&finish_mutex);
345        st->flags = 1;
346        pthread_mutex_unlock(&finish_mutex);
347        pthread_cond_signal(&finish_cond);
348        /*printf("end %p\n", st->sp);*/
349        return NULL;
350}
351
352/* Create a thread. */
353static int
354mthread_create(struct thread_st *st)
355{
356        st->flags = 0;
357        {
358                pthread_attr_t* attr_p = 0;
359#if USE_PTHREADS_STACKS
360                pthread_attr_t attr;
361
362                pthread_attr_init (&attr);
363                if(!st->sp)
364                        st->sp = malloc(STACKSIZE+16);
365                if(!st->sp)
366                        return -1;
367                if(pthread_attr_setstacksize(&attr, STACKSIZE))
368                        fprintf(stderr, "error setting stacksize");
369                else
370                        pthread_attr_setstackaddr(&attr, st->sp + STACKSIZE);
371                /*printf("create %p\n", st->sp);*/
372                attr_p = &attr;
373#endif
374                return pthread_create(&st->id, attr_p, mthread_wrapper, st);
375        }
376        return 0;
377}
378
379/* Wait for one of several subthreads to finish. */
380static void
381wait_for_thread(struct thread_st st[], int n_thr,
382                                int (*end_thr)(struct thread_st*))
383{
384        int i;
385
386        pthread_mutex_lock(&finish_mutex);
387        for(;;) {
388                int term = 0;
389                for(i=0; i<n_thr; i++)
390                        if(st[i].flags) {
391                                /*printf("joining %p\n", st[i].sp);*/
392                                if(pthread_join(st[i].id, NULL) == 0) {
393                                        st[i].flags = 0;
394                                        if(end_thr)
395                                                end_thr(&st[i]);
396                                } else
397                                        fprintf(stderr, "can't join\n");
398                                ++term;
399                        }
400                if(term > 0)
401                        break;
402                pthread_cond_wait(&finish_cond, &finish_mutex);
403        }
404        pthread_mutex_unlock(&finish_mutex);
405}
406
407/*
408 * Local variables:
409 * tab-width: 4
410 * End:
411 */
412
413
414#define N_TOTAL         10
415#ifndef N_THREADS
416#define N_THREADS       2
417#endif
418#ifndef N_TOTAL_PRINT
419#define N_TOTAL_PRINT 50
420#endif
421#ifndef MEMORY
422#define MEMORY          8000000l
423#endif
424#define SIZE            10000
425#define I_MAX           10000
426#define ACTIONS_MAX     30
427#ifndef TEST_FORK
428#define TEST_FORK 0
429#endif
430
431#define RANDOM(d,s)     (lran2(d) % (s))
432
433struct bin_info {
434        struct bin *m;
435        unsigned long size, bins;
436};
437
438#if TEST > 0
439
440void
441bin_test(struct bin_info *p)
442{
443        unsigned int b;
444
445        for(b=0; b<p->bins; b++) {
446                if(mem_check(p->m[b].ptr, p->m[b].size)) {
447                  fprintf(stderr, "memory corrupt!\n");
448                  abort();
449                }
450        }
451}
452
453#endif
454
455void
456malloc_test(struct thread_st *st)
457{
458    unsigned int b;
459        int i, j, actions, pid = 1;
460        struct bin_info p;
461        struct lran2_st ld; /* data for random number generator */
462
463        lran2_init(&ld, st->u.seed);
464#if TEST_FORK>0
465        if(RANDOM(&ld, TEST_FORK) == 0) {
466                int status;
467
468#if !USE_THR
469                pid = fork();
470#else
471                pid = fork1();
472#endif
473                if(pid > 0) {
474                    /*printf("forked, waiting for %d...\n", pid);*/
475                        waitpid(pid, &status, 0);
476                        printf("done with %d...\n", pid);
477                        if(!WIFEXITED(status)) {
478                                printf("child term with signal %d\n", WTERMSIG(status));
479                                exit(1);
480                        }
481                        return;
482                }
483                exit(0);
484        }
485#endif
486        p.m = (struct bin *)malloc(st->u.bins*sizeof(*p.m));
487        p.bins = st->u.bins;
488        p.size = st->u.size;
489        for(b=0; b<p.bins; b++) {
490                p.m[b].size = 0;
491                p.m[b].ptr = NULL;
492                if(RANDOM(&ld, 2) == 0)
493                        bin_alloc(&p.m[b], RANDOM(&ld, p.size) + 1, lran2(&ld));
494        }
495        for(i=0; i<=st->u.max;) {
496#if TEST > 1
497                bin_test(&p);
498#endif
499                actions = RANDOM(&ld, ACTIONS_MAX);
500#if USE_MALLOC && MALLOC_DEBUG
501                if(actions < 2) { mallinfo(); }
502#endif
503                for(j=0; j<actions; j++) {
504                        b = RANDOM(&ld, p.bins);
505                        bin_free(&p.m[b]);
506                }
507                i += actions;
508                actions = RANDOM(&ld, ACTIONS_MAX);
509                for(j=0; j<actions; j++) {
510                        b = RANDOM(&ld, p.bins);
511                        bin_alloc(&p.m[b], RANDOM(&ld, p.size) + 1, lran2(&ld));
512#if TEST > 2
513                        bin_test(&p);
514#endif
515                }
516#if 0 /* Test illegal free()s while setting MALLOC_CHECK_ */
517                for(j=0; j<8; j++) {
518                        b = RANDOM(&ld, p.bins);
519                        if(p.m[b].ptr) {
520                          int offset = (RANDOM(&ld, 11) - 5)*8;
521                          char *rogue = (char*)(p.m[b].ptr) + offset;
522                          /*printf("p=%p rogue=%p\n", p.m[b].ptr, rogue);*/
523                          free(rogue);
524                        }
525                }
526#endif
527                i += actions;
528        }
529        for(b=0; b<p.bins; b++)
530                bin_free(&p.m[b]);
531        free(p.m);
532        if(pid == 0)
533                exit(0);
534}
535
536int n_total=0, n_total_max=N_TOTAL, n_running;
537
538int
539my_end_thread(struct thread_st *st)
540{
541        /* Thread st has finished.  Start a new one. */
542#if 0
543        printf("Thread %lx terminated.\n", (long)st->id);
544#endif
545        if(n_total >= n_total_max) {
546                n_running--;
547        } else if(st->u.seed++, mthread_create(st)) {
548                printf("Creating thread #%d failed.\n", n_total);
549                exit(1);
550        } else {
551                n_total++;
552                if (verbose)
553                  if(n_total%N_TOTAL_PRINT == 0)
554                        printf("n_total = %8d - malloc %12d / memalign %12d / realloc %12d / calloc %12d\n", 
555                                   n_total, 
556                                   n_malloc, n_memalign, n_realloc, n_calloc);
557               
558        }
559        return 0;
560}
561
562#if 0
563/* Protect address space for allocation of n threads by LinuxThreads.  */
564static void
565protect_stack(int n)
566{
567        char buf[2048*1024];
568        char* guard;
569        size_t guard_size = 2*2048*1024UL*(n+2);
570
571        buf[0] = '\0';
572        guard = (char*)(((unsigned long)buf - 4096)& ~4095UL) - guard_size;
573        printf("Setting up stack guard at %p\n", guard);
574        if(mmap(guard, guard_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
575                        -1, 0)
576           != guard)
577                printf("failed!\n");
578}
579#endif
580
581int
582main(int argc, char *argv[])
583{
584        int i, bins;
585        int n_thr=N_THREADS;
586        int i_max=I_MAX;
587        unsigned long size=SIZE;
588        struct thread_st *st;
589
590#if USE_MALLOC && USE_STARTER==2
591        ptmalloc_init();
592        printf("ptmalloc_init\n");
593#endif
594
595        if((argc > 1) && (0 == strcmp(argv[1], "-h") || 0 == strcmp(argv[1], "--help")))
596          {
597                printf("%s <n-total> <n-parallel> <n-allocs> <size-max> <bins>\n\n", argv[0]);
598                printf(" n-total = total number of threads executed (default 10)\n");
599                printf(" n-parallel = number of threads running in parallel (2)\n");
600                printf(" n-allocs = number of malloc()'s / free()'s per thread (10000)\n");
601                printf(" size-max = max. size requested with malloc() in bytes (10000)\n");
602                printf(" bins = number of bins to maintain\n");
603                return 0;
604          }
605
606        if(argc > 1) n_total_max = atoi(argv[1]);
607        if(n_total_max < 1) n_thr = 1;
608        if(argc > 2) n_thr = atoi(argv[2]);
609        if(n_thr < 1) n_thr = 1;
610        if(n_thr > 100) n_thr = 100;
611        if(argc > 3) i_max = atoi(argv[3]);
612
613        if(argc > 4) size = atol(argv[4]);
614        if(size < 2) size = 2;
615
616        bins = MEMORY/(size*n_thr);
617        if(argc > 5) bins = atoi(argv[5]);
618        if(bins < 4) bins = 4;
619
620        /*protect_stack(n_thr);*/
621
622        mthread_init();
623        printf("total=%d threads=%d i_max=%d size=%ld bins=%d\n",
624                   n_total_max, n_thr, i_max, size, bins);
625
626        st = (struct thread_st *)malloc(n_thr*sizeof(*st));
627        if(!st) exit(-1);
628
629#if !defined NO_THREADS && (defined __sun__ || defined sun)
630        /* I know of no other way to achieve proper concurrency with Solaris. */
631        thr_setconcurrency(n_thr);
632#endif
633
634        /* Start all n_thr threads. */
635        for(i=0; i<n_thr; i++) {
636                st[i].u.bins = bins;
637                st[i].u.max = i_max;
638                st[i].u.size = size;
639                st[i].u.seed = ((long)i_max*size + i) ^ bins;
640                st[i].sp = 0;
641                st[i].func = malloc_test;
642                if(mthread_create(&st[i])) {
643                  fprintf(stderr, "Creating thread #%d failed.\n", i);
644                  n_thr = i;
645                  exit(1);
646                }
647                if (verbose)
648                  printf("Created thread %lx.\n", (long)st[i].id);
649        }
650
651        /* Start an extra thread so we don't run out of stacks. */
652        if(0) {
653                struct thread_st lst;
654                lst.u.bins = 10; lst.u.max = 20; lst.u.size = 8000; lst.u.seed = 8999;
655                lst.sp = 0;
656                lst.func = malloc_test;
657                if(mthread_create(&lst)) {
658                  fprintf(stderr, "Creating thread #%d failed.\n", i);
659                  exit(1);
660                } else {
661                        wait_for_thread(&lst, 1, NULL);
662                }
663        }
664
665        for(n_running=n_total=n_thr; n_running>0;) {
666                wait_for_thread(st, n_thr, my_end_thread);
667        }
668        for(i=0; i<n_thr; i++) {
669                free(st[i].sp);
670        }
671        free(st);
672#if USE_MALLOC
673        malloc_stats();
674#endif
675        if (verbose)
676          printf("Done.\n");
677        return 0;
678}
679
680/*
681 * Local variables:
682 * tab-width: 4
683 * End:
684 */
Note: See TracBrowser for help on using the repository browser.