|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* |
|
7 ** File: arena.c |
|
8 ** Description: Testing arenas |
|
9 ** |
|
10 */ |
|
11 |
|
12 #include <string.h> |
|
13 #include <time.h> |
|
14 #include <stdlib.h> |
|
15 #include "nspr.h" |
|
16 #include "plarena.h" |
|
17 #include "plgetopt.h" |
|
18 |
|
19 PRLogModuleInfo *tLM; |
|
20 PRIntn threadCount = 0; |
|
21 PRMonitor *tMon; |
|
22 PRBool failed_already = PR_FALSE; |
|
23 |
|
24 /* Arguments from the command line with default values */ |
|
25 PRIntn debug_mode = 0; |
|
26 PRIntn poolMin = 4096; |
|
27 PRIntn poolMax = (100 * 4096); |
|
28 PRIntn arenaMin = 40; |
|
29 PRIntn arenaMax = (100 * 40); |
|
30 PRIntn stressIterations = 15; |
|
31 PRIntn maxAlloc = (1024 * 1024); |
|
32 PRIntn stressThreads = 4; |
|
33 |
|
34 void DumpAll( void ) |
|
35 { |
|
36 return; |
|
37 } |
|
38 |
|
39 /* |
|
40 ** Test Arena allocation. |
|
41 */ |
|
42 static void ArenaAllocate( void ) |
|
43 { |
|
44 PLArenaPool ap; |
|
45 void *ptr; |
|
46 PRInt32 i; |
|
47 |
|
48 PL_InitArenaPool( &ap, "AllocArena", 2048, sizeof(double)); |
|
49 PR_LOG( tLM, PR_LOG_DEBUG, ("AA, InitPool -- Pool: %p. first: %p, current: %p, size: %d", |
|
50 &ap, ap.first, ap.current, ap.arenasize )); |
|
51 |
|
52 for( i = 0; i < 150; i++ ) |
|
53 { |
|
54 PL_ARENA_ALLOCATE( ptr, &ap, 512 ); |
|
55 PR_LOG( tLM, PR_LOG_DEBUG,("AA, after alloc -- Pool: %p. first: %p, current: %p, size: %d", |
|
56 &ap, ap.first, ap.current, ap.arenasize )); |
|
57 PR_LOG( tLM, PR_LOG_DEBUG,( |
|
58 "AA -- Pool: %p. alloc: %p ", &ap, ptr )); |
|
59 } |
|
60 |
|
61 PL_FreeArenaPool( &ap ); |
|
62 |
|
63 for( i = 0; i < 221; i++ ) |
|
64 { |
|
65 PL_ARENA_ALLOCATE( ptr, &ap, 512 ); |
|
66 PR_LOG( tLM, PR_LOG_DEBUG,("AA, after alloc -- Pool: %p. first: %p, current: %p, size: %d", |
|
67 &ap, ap.first, ap.current, ap.arenasize )); |
|
68 PR_LOG( tLM, PR_LOG_DEBUG,( |
|
69 "AA -- Pool: %p. alloc: %p ", &ap, ptr )); |
|
70 } |
|
71 |
|
72 PL_FreeArenaPool( &ap ); |
|
73 |
|
74 return; |
|
75 } /* end ArenaGrow() */ |
|
76 /* |
|
77 ** Test Arena grow. |
|
78 */ |
|
79 static void ArenaGrow( void ) |
|
80 { |
|
81 PLArenaPool ap; |
|
82 void *ptr; |
|
83 PRInt32 i; |
|
84 |
|
85 PL_InitArenaPool( &ap, "TheArena", 4096, sizeof(double)); |
|
86 PL_ARENA_ALLOCATE( ptr, &ap, 512 ); |
|
87 |
|
88 PR_LOG( tLM, PR_LOG_DEBUG, ("Before growth -- Pool: %p. alloc: %p ", &ap, ptr )); |
|
89 |
|
90 for( i = 0; i < 10; i++ ) |
|
91 { |
|
92 PL_ARENA_GROW( ptr, &ap, 512, 7000 ); |
|
93 PR_LOG( tLM, PR_LOG_DEBUG, ("After growth -- Pool: %p. alloc: %p ", &ap, ptr )); |
|
94 } |
|
95 |
|
96 |
|
97 return; |
|
98 } /* end ArenaGrow() */ |
|
99 |
|
100 |
|
101 /* |
|
102 ** Test arena Mark and Release. |
|
103 */ |
|
104 static void MarkAndRelease( void ) |
|
105 { |
|
106 PLArenaPool ap; |
|
107 void *ptr = NULL; |
|
108 void *mark0, *mark1; |
|
109 PRIntn i; |
|
110 |
|
111 PL_InitArenaPool( &ap, "TheArena", 4096, sizeof(double)); |
|
112 mark0 = PL_ARENA_MARK( &ap ); |
|
113 PR_LOG( tLM, PR_LOG_DEBUG, |
|
114 ("mark0. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p, m0: %p", |
|
115 &ap, ap.first.next, ap.current, ap.arenasize, ptr, mark0 )); |
|
116 |
|
117 for( i = 0; i < 201; i++ ) |
|
118 { |
|
119 PL_ARENA_ALLOCATE( ptr, &ap, 512 ); |
|
120 PR_LOG( tLM, PR_LOG_DEBUG, |
|
121 ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", |
|
122 &ap, ap.first.next, ap.current, ap.arenasize, ptr )); |
|
123 } |
|
124 |
|
125 mark1 = PL_ARENA_MARK( &ap ); |
|
126 PR_LOG( tLM, PR_LOG_DEBUG, |
|
127 ("mark1. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p, m1: %p", |
|
128 &ap, ap.first.next, ap.current, ap.arenasize, ptr, mark1 )); |
|
129 |
|
130 |
|
131 for( i = 0; i < 225; i++ ) |
|
132 { |
|
133 PL_ARENA_ALLOCATE( ptr, &ap, 512 ); |
|
134 PR_LOG( tLM, PR_LOG_DEBUG, |
|
135 ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", |
|
136 &ap, ap.first.next, ap.current, ap.arenasize, ptr )); |
|
137 } |
|
138 |
|
139 PL_ARENA_RELEASE( &ap, mark1 ); |
|
140 PR_LOG( tLM, PR_LOG_DEBUG, |
|
141 ("Release-1: %p -- Pool: %p. first: %p, current: %p, size: %d", |
|
142 mark1, &ap, ap.first, ap.current, ap.arenasize )); |
|
143 |
|
144 for( i = 0; i < 20; i++ ) |
|
145 { |
|
146 PL_ARENA_ALLOCATE( ptr, &ap, 512 ); |
|
147 PR_LOG( tLM, PR_LOG_DEBUG, |
|
148 ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", |
|
149 &ap, ap.first.next, ap.current, ap.arenasize, ptr )); |
|
150 } |
|
151 |
|
152 PL_ARENA_RELEASE( &ap, mark1 ); |
|
153 PR_LOG( tLM, PR_LOG_DEBUG, |
|
154 ("Release-1. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", |
|
155 &ap, ap.first.next, ap.current, ap.arenasize, ptr )); |
|
156 |
|
157 PL_ARENA_RELEASE( &ap, mark0 ); |
|
158 PR_LOG( tLM, PR_LOG_DEBUG, |
|
159 ("Release-0. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", |
|
160 &ap, ap.first.next, ap.current, ap.arenasize, ptr )); |
|
161 |
|
162 PL_FreeArenaPool( &ap ); |
|
163 PR_LOG( tLM, PR_LOG_DEBUG, |
|
164 ("Free. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", |
|
165 &ap, ap.first.next, ap.current, ap.arenasize, ptr )); |
|
166 |
|
167 PL_FinishArenaPool( &ap ); |
|
168 PR_LOG( tLM, PR_LOG_DEBUG, |
|
169 ("Finish. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", |
|
170 &ap, ap.first.next, ap.current, ap.arenasize, ptr )); |
|
171 |
|
172 return; |
|
173 } /* end MarkAndRelease() */ |
|
174 |
|
175 /* |
|
176 ** RandSize() returns a random number in the range |
|
177 ** min..max, rounded to the next doubleword |
|
178 ** |
|
179 */ |
|
180 static PRIntn RandSize( PRIntn min, PRIntn max ) |
|
181 { |
|
182 PRIntn sz = (rand() % (max -min)) + min + sizeof(double); |
|
183 |
|
184 sz &= ~sizeof(double)-1; |
|
185 |
|
186 return(sz); |
|
187 } |
|
188 |
|
189 |
|
190 /* |
|
191 ** StressThread() |
|
192 ** A bunch of these beat on individual arenas |
|
193 ** This tests the free_list protection. |
|
194 ** |
|
195 */ |
|
196 static void PR_CALLBACK StressThread( void *arg ) |
|
197 { |
|
198 PLArenaPool ap; |
|
199 PRIntn i; |
|
200 PRIntn sz; |
|
201 void *ptr; |
|
202 PRThread *tp = PR_GetCurrentThread(); |
|
203 |
|
204 PR_LOG( tLM, PR_LOG_DEBUG, ("Stress Thread %p started\n", PR_GetCurrentThread())); |
|
205 PL_InitArenaPool( &ap, "TheArena", RandSize( poolMin, poolMax), sizeof(double)); |
|
206 |
|
207 for ( i = 0; i < stressIterations; i++ ) |
|
208 { |
|
209 PRIntn allocated = 0; |
|
210 |
|
211 while ( allocated < maxAlloc ) |
|
212 { |
|
213 sz = RandSize( arenaMin, arenaMax ); |
|
214 PL_ARENA_ALLOCATE( ptr, &ap, sz ); |
|
215 if ( ptr == NULL ) |
|
216 { |
|
217 PR_LOG( tLM, PR_LOG_ERROR, ("ARENA_ALLOCATE() returned NULL\n\tAllocated: %d\n", allocated)); |
|
218 break; |
|
219 } |
|
220 allocated += sz; |
|
221 } |
|
222 PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p finished one iteration\n", tp)); |
|
223 PL_FreeArenaPool( &ap ); |
|
224 } |
|
225 PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p finished all iteration\n", tp)); |
|
226 PL_FinishArenaPool( &ap ); |
|
227 PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p after FinishArenaPool()\n", tp)); |
|
228 |
|
229 /* That's all folks! let's quit */ |
|
230 PR_EnterMonitor(tMon); |
|
231 threadCount--; |
|
232 PR_Notify(tMon); |
|
233 PR_ExitMonitor(tMon); |
|
234 return; |
|
235 } |
|
236 |
|
237 /* |
|
238 ** Stress() |
|
239 ** Flog the hell out of arenas multi-threaded. |
|
240 ** Do NOT pass an individual arena to another thread. |
|
241 ** |
|
242 */ |
|
243 static void Stress( void ) |
|
244 { |
|
245 PRThread *tt; |
|
246 PRIntn i; |
|
247 |
|
248 tMon = PR_NewMonitor(); |
|
249 |
|
250 for ( i = 0 ; i < stressThreads ; i++ ) |
|
251 { |
|
252 PR_EnterMonitor(tMon); |
|
253 tt = PR_CreateThread(PR_USER_THREAD, |
|
254 StressThread, |
|
255 NULL, |
|
256 PR_PRIORITY_NORMAL, |
|
257 PR_GLOBAL_THREAD, |
|
258 PR_UNJOINABLE_THREAD, |
|
259 0); |
|
260 threadCount++; |
|
261 PR_ExitMonitor(tMon); |
|
262 } |
|
263 |
|
264 /* Wait for all threads to exit */ |
|
265 PR_EnterMonitor(tMon); |
|
266 while ( threadCount != 0 ) |
|
267 { |
|
268 PR_Wait(tMon, PR_INTERVAL_NO_TIMEOUT); |
|
269 } |
|
270 PR_ExitMonitor(tMon); |
|
271 PR_DestroyMonitor(tMon); |
|
272 |
|
273 return; |
|
274 } /* end Stress() */ |
|
275 |
|
276 /* |
|
277 ** EvaluateResults() |
|
278 ** uses failed_already to display results and set program |
|
279 ** exit code. |
|
280 */ |
|
281 static PRIntn EvaluateResults(void) |
|
282 { |
|
283 PRIntn rc = 0; |
|
284 |
|
285 if ( failed_already == PR_TRUE ) |
|
286 { |
|
287 PR_LOG( tLM, PR_LOG_DEBUG, ("FAIL\n")); |
|
288 rc =1; |
|
289 } |
|
290 else |
|
291 { |
|
292 PR_LOG( tLM, PR_LOG_DEBUG, ("PASS\n")); |
|
293 } |
|
294 return(rc); |
|
295 } /* EvaluateResults() */ |
|
296 |
|
297 void Help( void ) |
|
298 { |
|
299 printf("arena [options]\n"); |
|
300 printf("where options are:\n"); |
|
301 printf("-p <n> minimum size of an arena pool. Default(%d)\n", poolMin); |
|
302 printf("-P <n> maximum size of an arena pool. Default(%d)\n", poolMax); |
|
303 printf("-a <n> minimum size of an arena allocation. Default(%d)\n", arenaMin); |
|
304 printf("-A <n> maximum size of an arena allocation. Default(%d)\n", arenaMax); |
|
305 printf("-i <n> number of iterations in a stress thread. Default(%d)\n", stressIterations); |
|
306 printf("-s <n> maximum allocation for a single stress thread. Default(%d)\n", maxAlloc); |
|
307 printf("-t <n> number of stress threads. Default(%d)\n", stressThreads ); |
|
308 printf("-d enable debug mode\n"); |
|
309 printf("\n"); |
|
310 exit(1); |
|
311 } |
|
312 |
|
313 PRIntn main(PRIntn argc, char *argv[]) |
|
314 { |
|
315 PLOptStatus os; |
|
316 PLOptState *opt = PL_CreateOptState(argc, argv, "dhp:P:a:A:i:s:t:"); |
|
317 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) |
|
318 { |
|
319 if (PL_OPT_BAD == os) continue; |
|
320 switch (opt->option) |
|
321 { |
|
322 case 'a': /* arena Min size */ |
|
323 arenaMin = atol( opt->value ); |
|
324 break; |
|
325 case 'A': /* arena Max size */ |
|
326 arenaMax = atol( opt->value ); |
|
327 break; |
|
328 case 'p': /* pool Min size */ |
|
329 poolMin = atol( opt->value ); |
|
330 break; |
|
331 case 'P': /* pool Max size */ |
|
332 poolMax = atol( opt->value ); |
|
333 break; |
|
334 case 'i': /* Iterations in stress tests */ |
|
335 stressIterations = atol( opt->value ); |
|
336 break; |
|
337 case 's': /* storage to get per iteration */ |
|
338 maxAlloc = atol( opt->value ); |
|
339 break; |
|
340 case 't': /* Number of stress threads to create */ |
|
341 stressThreads = atol( opt->value ); |
|
342 break; |
|
343 case 'd': /* debug mode */ |
|
344 debug_mode = 1; |
|
345 break; |
|
346 case 'h': /* help */ |
|
347 default: |
|
348 Help(); |
|
349 } /* end switch() */ |
|
350 } /* end while() */ |
|
351 PL_DestroyOptState(opt); |
|
352 |
|
353 srand( (unsigned)time( NULL ) ); /* seed random number generator */ |
|
354 tLM = PR_NewLogModule("testcase"); |
|
355 |
|
356 |
|
357 #if 0 |
|
358 ArenaAllocate(); |
|
359 ArenaGrow(); |
|
360 #endif |
|
361 |
|
362 MarkAndRelease(); |
|
363 |
|
364 Stress(); |
|
365 |
|
366 return(EvaluateResults()); |
|
367 } /* end main() */ |
|
368 |
|
369 /* arena.c */ |