1 /*
2 * $Id: t-test2.c,v 1.3 2004/11/04 15:01:05 wg Exp $
3 * by Wolfram Gloger 1996-1999, 2001, 2004
4 * A multi-thread test for malloc performance, maintaining a single
5 * global pool of allocated bins.
6 */
7
8 #if (defined __STDC__ && __STDC__) || defined __cplusplus
9 # include <stdlib.h>
10 #endif
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <sys/time.h>
15 #include <sys/resource.h>
16 #include <sys/wait.h>
17
18 #if !USE_MALLOC
19 #include <malloc.h>
20 #else
21 #include "malloc.h"
22 #endif
23
24 #include "lran2.h"
25 #include "t-test.h"
26
27 struct user_data {
28 int max;
29 unsigned long size;
30 long seed;
31 };
32 #include "thread-st.h"
33 #include "malloc-machine.h" /* for mutex */
34
35 #define N_TOTAL 10
36 #ifndef N_THREADS
37 #define N_THREADS 2
38 #endif
39 #ifndef N_TOTAL_PRINT
40 #define N_TOTAL_PRINT 50
41 #endif
42 #define STACKSIZE 32768
43 #ifndef MEMORY
44 #define MEMORY 8000000l
45 #endif
46 #define SIZE 10000
47 #define I_MAX 10000
48 #define BINS_PER_BLOCK 20
49
50 #define RANDOM(d,s) (lran2(d) % (s))
51
52 struct block {
53 struct bin b[BINS_PER_BLOCK];
54 mutex_t mutex;
55 } *blocks;
56
57 int n_blocks;
58
59 #if TEST > 0
60
61 void
bin_test(void)62 bin_test(void)
63 {
64 int b, i;
65
66 for(b=0; b<n_blocks; b++) {
67 mutex_lock(&blocks[b].mutex);
68 for(i=0; i<BINS_PER_BLOCK; i++) {
69 if(mem_check(blocks[b].b[i].ptr, blocks[b].b[i].size)) {
70 printf("memory corrupt!\n");
71 exit(1);
72 }
73 }
74 mutex_unlock(&blocks[b].mutex);
75 }
76 }
77
78 #endif
79
80 void
malloc_test(struct thread_st * st)81 malloc_test(struct thread_st *st)
82 {
83 struct block *bl;
84 int i, b, r;
85 struct lran2_st ld; /* data for random number generator */
86 unsigned long rsize[BINS_PER_BLOCK];
87 int rnum[BINS_PER_BLOCK];
88
89 lran2_init(&ld, st->u.seed);
90 for(i=0; i<=st->u.max;) {
91 #if TEST > 1
92 bin_test();
93 #endif
94 bl = &blocks[RANDOM(&ld, n_blocks)];
95 r = RANDOM(&ld, 1024);
96 if(r < 200) { /* free only */
97 mutex_lock(&bl->mutex);
98 for(b=0; b<BINS_PER_BLOCK; b++)
99 bin_free(&bl->b[b]);
100 mutex_unlock(&bl->mutex);
101 i += BINS_PER_BLOCK;
102 } else { /* alloc/realloc */
103 /* Generate random numbers in advance. */
104 for(b=0; b<BINS_PER_BLOCK; b++) {
105 rsize[b] = RANDOM(&ld, st->u.size) + 1;
106 rnum[b] = lran2(&ld);
107 }
108 mutex_lock(&bl->mutex);
109 for(b=0; b<BINS_PER_BLOCK; b++)
110 bin_alloc(&bl->b[b], rsize[b], rnum[b]);
111 mutex_unlock(&bl->mutex);
112 i += BINS_PER_BLOCK;
113 }
114 #if TEST > 2
115 bin_test();
116 #endif
117 }
118 }
119
120 int n_total=0, n_total_max=N_TOTAL, n_running;
121
122 int
my_end_thread(struct thread_st * st)123 my_end_thread(struct thread_st *st)
124 {
125 /* Thread st has finished. Start a new one. */
126 #if 0
127 printf("Thread %lx terminated.\n", (long)st->id);
128 #endif
129 if(n_total >= n_total_max) {
130 n_running--;
131 } else if(st->u.seed++, thread_create(st)) {
132 printf("Creating thread #%d failed.\n", n_total);
133 } else {
134 n_total++;
135 if(n_total%N_TOTAL_PRINT == 0)
136 printf("n_total = %d\n", n_total);
137 }
138 return 0;
139 }
140
141 int
main(int argc,char * argv[])142 main(int argc, char *argv[])
143 {
144 int i, j, bins;
145 int n_thr=N_THREADS;
146 int i_max=I_MAX;
147 unsigned long size=SIZE;
148 struct thread_st *st;
149
150 #if USE_MALLOC && USE_STARTER==2
151 ptmalloc_init();
152 printf("ptmalloc_init\n");
153 #endif
154
155 if(argc > 1) n_total_max = atoi(argv[1]);
156 if(n_total_max < 1) n_thr = 1;
157 if(argc > 2) n_thr = atoi(argv[2]);
158 if(n_thr < 1) n_thr = 1;
159 if(n_thr > 100) n_thr = 100;
160 if(argc > 3) i_max = atoi(argv[3]);
161
162 if(argc > 4) size = atol(argv[4]);
163 if(size < 2) size = 2;
164
165 bins = MEMORY/size;
166 if(argc > 5) bins = atoi(argv[5]);
167 if(bins < BINS_PER_BLOCK) bins = BINS_PER_BLOCK;
168
169 n_blocks = bins/BINS_PER_BLOCK;
170 blocks = (struct block *)malloc(n_blocks*sizeof(*blocks));
171 if(!blocks)
172 exit(1);
173
174 thread_init();
175 printf("total=%d threads=%d i_max=%d size=%ld bins=%d\n",
176 n_total_max, n_thr, i_max, size, n_blocks*BINS_PER_BLOCK);
177
178 for(i=0; i<n_blocks; i++) {
179 mutex_init(&blocks[i].mutex);
180 for(j=0; j<BINS_PER_BLOCK; j++) blocks[i].b[j].size = 0;
181 }
182
183 st = (struct thread_st *)malloc(n_thr*sizeof(*st));
184 if(!st) exit(-1);
185
186 #if !defined NO_THREADS && (defined __sun__ || defined sun)
187 /* I know of no other way to achieve proper concurrency with Solaris. */
188 thr_setconcurrency(n_thr);
189 #endif
190
191 /* Start all n_thr threads. */
192 for(i=0; i<n_thr; i++) {
193 st[i].u.max = i_max;
194 st[i].u.size = size;
195 st[i].u.seed = ((long)i_max*size + i) ^ n_blocks;
196 st[i].sp = 0;
197 st[i].func = malloc_test;
198 if(thread_create(&st[i])) {
199 printf("Creating thread #%d failed.\n", i);
200 n_thr = i;
201 break;
202 }
203 printf("Created thread %lx.\n", (long)st[i].id);
204 }
205
206 for(n_running=n_total=n_thr; n_running>0;) {
207 wait_for_thread(st, n_thr, my_end_thread);
208 }
209
210 for(i=0; i<n_blocks; i++) {
211 for(j=0; j<BINS_PER_BLOCK; j++)
212 bin_free(&blocks[i].b[j]);
213 }
214
215 for(i=0; i<n_thr; i++) {
216 free(st[i].sp);
217 }
218 free(st);
219 free(blocks);
220 #if USE_MALLOC
221 malloc_stats();
222 #endif
223 printf("Done.\n");
224 return 0;
225 }
226
227 /*
228 * Local variables:
229 * tab-width: 4
230 * End:
231 */
232