e82e4f8b59f33918a6cf938006291912db2fff0f
[platform/upstream/nspr.git] / nspr / lib / tests / arena.c
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 */