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