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