Source code
Revision control
Copy as Markdown
Other Tools
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
/*
** File: arena.c
** Description: Testing arenas
**
*/
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include "nspr.h"
#include "plarena.h"
#include "plgetopt.h"
PRLogModuleInfo* tLM;
PRIntn threadCount = 0;
PRMonitor* tMon;
PRBool failed_already = PR_FALSE;
/* Arguments from the command line with default values */
PRIntn debug_mode = 0;
PRIntn poolMin = 4096;
PRIntn poolMax = (100 * 4096);
PRIntn arenaMin = 40;
PRIntn arenaMax = (100 * 40);
PRIntn stressIterations = 15;
PRIntn maxAlloc = (1024 * 1024);
PRIntn stressThreads = 4;
void DumpAll(void) { return; }
/*
** Test Arena allocation.
*/
static void ArenaAllocate(void) {
PLArenaPool ap;
void* ptr;
PRInt32 i;
PL_InitArenaPool(&ap, "AllocArena", 2048, sizeof(double));
PR_LOG(tLM, PR_LOG_DEBUG,
("AA, InitPool -- Pool: %p. first: %p, current: %p, size: %d", &ap,
ap.first, ap.current, ap.arenasize));
for (i = 0; i < 150; i++) {
PL_ARENA_ALLOCATE(ptr, &ap, 512);
PR_LOG(tLM, PR_LOG_DEBUG,
("AA, after alloc -- Pool: %p. first: %p, current: %p, size: %d",
&ap, ap.first, ap.current, ap.arenasize));
PR_LOG(tLM, PR_LOG_DEBUG, ("AA -- Pool: %p. alloc: %p ", &ap, ptr));
}
PL_FreeArenaPool(&ap);
for (i = 0; i < 221; i++) {
PL_ARENA_ALLOCATE(ptr, &ap, 512);
PR_LOG(tLM, PR_LOG_DEBUG,
("AA, after alloc -- Pool: %p. first: %p, current: %p, size: %d",
&ap, ap.first, ap.current, ap.arenasize));
PR_LOG(tLM, PR_LOG_DEBUG, ("AA -- Pool: %p. alloc: %p ", &ap, ptr));
}
PL_FreeArenaPool(&ap);
return;
} /* end ArenaGrow() */
/*
** Test Arena grow.
*/
static void ArenaGrow(void) {
PLArenaPool ap;
void* ptr;
PRInt32 i;
PL_InitArenaPool(&ap, "TheArena", 4096, sizeof(double));
PL_ARENA_ALLOCATE(ptr, &ap, 512);
PR_LOG(tLM, PR_LOG_DEBUG,
("Before growth -- Pool: %p. alloc: %p ", &ap, ptr));
for (i = 0; i < 10; i++) {
PL_ARENA_GROW(ptr, &ap, 512, 7000);
PR_LOG(tLM, PR_LOG_DEBUG,
("After growth -- Pool: %p. alloc: %p ", &ap, ptr));
}
return;
} /* end ArenaGrow() */
/*
** Test arena Mark and Release.
*/
static void MarkAndRelease(void) {
PLArenaPool ap;
void* ptr = NULL;
void *mark0, *mark1;
PRIntn i;
PL_InitArenaPool(&ap, "TheArena", 4096, sizeof(double));
mark0 = PL_ARENA_MARK(&ap);
PR_LOG(tLM, PR_LOG_DEBUG,
("mark0. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p, m0: %p",
&ap, ap.first.next, ap.current, ap.arenasize, ptr, mark0));
for (i = 0; i < 201; i++) {
PL_ARENA_ALLOCATE(ptr, &ap, 512);
PR_LOG(tLM, PR_LOG_DEBUG,
("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", &ap,
ap.first.next, ap.current, ap.arenasize, ptr));
}
mark1 = PL_ARENA_MARK(&ap);
PR_LOG(tLM, PR_LOG_DEBUG,
("mark1. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p, m1: %p",
&ap, ap.first.next, ap.current, ap.arenasize, ptr, mark1));
for (i = 0; i < 225; i++) {
PL_ARENA_ALLOCATE(ptr, &ap, 512);
PR_LOG(tLM, PR_LOG_DEBUG,
("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", &ap,
ap.first.next, ap.current, ap.arenasize, ptr));
}
PL_ARENA_RELEASE(&ap, mark1);
PR_LOG(tLM, PR_LOG_DEBUG,
("Release-1: %p -- Pool: %p. first: %p, current: %p, size: %d", mark1,
&ap, ap.first, ap.current, ap.arenasize));
for (i = 0; i < 20; i++) {
PL_ARENA_ALLOCATE(ptr, &ap, 512);
PR_LOG(tLM, PR_LOG_DEBUG,
("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", &ap,
ap.first.next, ap.current, ap.arenasize, ptr));
}
PL_ARENA_RELEASE(&ap, mark1);
PR_LOG(tLM, PR_LOG_DEBUG,
("Release-1. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", &ap,
ap.first.next, ap.current, ap.arenasize, ptr));
PL_ARENA_RELEASE(&ap, mark0);
PR_LOG(tLM, PR_LOG_DEBUG,
("Release-0. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", &ap,
ap.first.next, ap.current, ap.arenasize, ptr));
PL_FreeArenaPool(&ap);
PR_LOG(tLM, PR_LOG_DEBUG,
("Free. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", &ap,
ap.first.next, ap.current, ap.arenasize, ptr));
PL_FinishArenaPool(&ap);
PR_LOG(tLM, PR_LOG_DEBUG,
("Finish. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", &ap,
ap.first.next, ap.current, ap.arenasize, ptr));
return;
} /* end MarkAndRelease() */
/*
** RandSize() returns a random number in the range
** min..max, rounded to the next doubleword
**
*/
static PRIntn RandSize(PRIntn min, PRIntn max) {
PRIntn sz = (rand() % (max - min)) + min + sizeof(double);
sz &= ~sizeof(double) - 1;
return (sz);
}
/*
** StressThread()
** A bunch of these beat on individual arenas
** This tests the free_list protection.
**
*/
static void PR_CALLBACK StressThread(void* arg) {
PLArenaPool ap;
PRIntn i;
PRIntn sz;
void* ptr;
PRThread* tp = PR_GetCurrentThread();
PR_LOG(tLM, PR_LOG_DEBUG,
("Stress Thread %p started\n", PR_GetCurrentThread()));
PL_InitArenaPool(&ap, "TheArena", RandSize(poolMin, poolMax), sizeof(double));
for (i = 0; i < stressIterations; i++) {
PRIntn allocated = 0;
while (allocated < maxAlloc) {
sz = RandSize(arenaMin, arenaMax);
PL_ARENA_ALLOCATE(ptr, &ap, sz);
if (ptr == NULL) {
PR_LOG(
tLM, PR_LOG_ERROR,
("ARENA_ALLOCATE() returned NULL\n\tAllocated: %d\n", allocated));
break;
}
allocated += sz;
}
PR_LOG(tLM, PR_LOG_DEBUG,
("Stress thread %p finished one iteration\n", tp));
PL_FreeArenaPool(&ap);
}
PR_LOG(tLM, PR_LOG_DEBUG, ("Stress thread %p finished all iteration\n", tp));
PL_FinishArenaPool(&ap);
PR_LOG(tLM, PR_LOG_DEBUG, ("Stress thread %p after FinishArenaPool()\n", tp));
/* That's all folks! let's quit */
PR_EnterMonitor(tMon);
threadCount--;
PR_Notify(tMon);
PR_ExitMonitor(tMon);
return;
}
/*
** Stress()
** Flog the hell out of arenas multi-threaded.
** Do NOT pass an individual arena to another thread.
**
*/
static void Stress(void) {
PRThread* tt;
PRIntn i;
tMon = PR_NewMonitor();
for (i = 0; i < stressThreads; i++) {
PR_EnterMonitor(tMon);
tt = PR_CreateThread(PR_USER_THREAD, StressThread, NULL, PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
threadCount++;
PR_ExitMonitor(tMon);
}
/* Wait for all threads to exit */
PR_EnterMonitor(tMon);
while (threadCount != 0) {
PR_Wait(tMon, PR_INTERVAL_NO_TIMEOUT);
}
PR_ExitMonitor(tMon);
PR_DestroyMonitor(tMon);
return;
} /* end Stress() */
/*
** EvaluateResults()
** uses failed_already to display results and set program
** exit code.
*/
static PRIntn EvaluateResults(void) {
PRIntn rc = 0;
if (failed_already == PR_TRUE) {
PR_LOG(tLM, PR_LOG_DEBUG, ("FAIL\n"));
rc = 1;
} else {
PR_LOG(tLM, PR_LOG_DEBUG, ("PASS\n"));
}
return (rc);
} /* EvaluateResults() */
void Help(void) {
printf("arena [options]\n");
printf("where options are:\n");
printf("-p <n> minimum size of an arena pool. Default(%d)\n", poolMin);
printf("-P <n> maximum size of an arena pool. Default(%d)\n", poolMax);
printf("-a <n> minimum size of an arena allocation. Default(%d)\n",
arenaMin);
printf("-A <n> maximum size of an arena allocation. Default(%d)\n",
arenaMax);
printf("-i <n> number of iterations in a stress thread. Default(%d)\n",
stressIterations);
printf(
"-s <n> maximum allocation for a single stress thread. Default(%d)\n",
maxAlloc);
printf("-t <n> number of stress threads. Default(%d)\n", stressThreads);
printf("-d enable debug mode\n");
printf("\n");
exit(1);
}
PRIntn main(PRIntn argc, char* argv[]) {
PLOptStatus os;
PLOptState* opt = PL_CreateOptState(argc, argv, "dhp:P:a:A:i:s:t:");
while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
if (PL_OPT_BAD == os) {
continue;
}
switch (opt->option) {
case 'a': /* arena Min size */
arenaMin = atol(opt->value);
break;
case 'A': /* arena Max size */
arenaMax = atol(opt->value);
break;
case 'p': /* pool Min size */
poolMin = atol(opt->value);
break;
case 'P': /* pool Max size */
poolMax = atol(opt->value);
break;
case 'i': /* Iterations in stress tests */
stressIterations = atol(opt->value);
break;
case 's': /* storage to get per iteration */
maxAlloc = atol(opt->value);
break;
case 't': /* Number of stress threads to create */
stressThreads = atol(opt->value);
break;
case 'd': /* debug mode */
debug_mode = 1;
break;
case 'h': /* help */
default:
Help();
} /* end switch() */
} /* end while() */
PL_DestroyOptState(opt);
srand((unsigned)time(NULL)); /* seed random number generator */
tLM = PR_NewLogModule("testcase");
#if 0
ArenaAllocate();
ArenaGrow();
#endif
MarkAndRelease();
Stress();
return (EvaluateResults());
} /* end main() */
/* arena.c */