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

Last change on this file since 446 was 229, checked in by katerina, 16 years ago

Add missing file for dnmalloc test, update for testing on AIX 5.3

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