tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */