#include <stdlib.h>
#include <string.h>
#include "plarena.h"
#include "prmem.h"
#include "prbit.h"
#include "prlog.h"
#include "prinit.h"
#ifdef PL_ARENAMETER
static PLArenaStats *arena_stats_list;
#define COUNT(pool,what) (pool)->stats.what++
#else
#define COUNT(pool,what)
#endif
#define PL_ARENA_DEFAULT_ALIGN sizeof(double)
PR_IMPLEMENT(void) PL_InitArenaPool(
PLArenaPool *pool, const char *name, PRSize size, PRSize align)
{
#if !defined (__GNUC__)
#pragma unused (name)
#endif
if (align == 0)
align = PL_ARENA_DEFAULT_ALIGN;
pool->mask = PR_BITMASK(PR_CeilingLog2(align));
pool->first.next = NULL;
pool->first.base = pool->first.avail = pool->first.limit =
(PRUword)PL_ARENA_ALIGN(pool, &pool->first + 1);
pool->current = &pool->first;
pool->arenasize = size;
#ifdef PL_ARENAMETER
memset(&pool->stats, 0, sizeof pool->stats);
pool->stats.name = strdup(name);
pool->stats.next = arena_stats_list;
arena_stats_list = &pool->stats;
#endif
}
PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRSize nb)
{
PLArena *a;
char *rp;
PR_ASSERT((nb & pool->mask) == 0);
nb = (PRUword)PL_ARENA_ALIGN(pool, nb);
{
a = pool->current;
do {
if ( a->avail +nb <= a->limit ) {
pool->current = a;
rp = (char *)a->avail;
a->avail += nb;
return rp;
}
} while( NULL != (a = a->next) );
}
{
PRSize sz = PR_MAX(pool->arenasize, nb);
sz += sizeof *a + pool->mask;
a = (PLArena*)PR_MALLOC(sz);
if ( NULL != a ) {
a->limit = (PRUword)a + sz;
a->base = a->avail = (PRUword)PL_ARENA_ALIGN(pool, a + 1);
rp = (char *)a->avail;
a->avail += nb;
a->next = pool->current->next;
pool->current->next = a;
pool->current = a;
if ( NULL == pool->first.next )
pool->first.next = a;
PL_COUNT_ARENA(pool,++);
COUNT(pool, nmallocs);
return(rp);
}
}
return(NULL);
}
PR_IMPLEMENT(void *) PL_ArenaGrow(
PLArenaPool *pool, void *p, PRSize origSize, PRSize incr)
{
void *newp;
PLArena *thisArena;
PLArena *lastArena;
PRSize origAlignSize; PRSize newSize;
origAlignSize = PL_ARENA_ALIGN(pool, origSize);
newSize = PR_MAX(origAlignSize+incr, 2*origAlignSize);
newSize = PL_ARENA_ALIGN(pool, newSize);
PL_ARENA_ALLOCATE(newp, pool, newSize);
if (newp == NULL) {
return NULL;
}
PRSize newAlignSize = PL_ARENA_ALIGN(pool, origSize+incr);
PR_ASSERT(pool->current->avail == ((PRSize)newp + newSize));
pool->current->avail = (PRSize)newp + newAlignSize;
PR_ASSERT(pool->current->avail <= pool->current->limit);
memcpy(newp, p, origSize);
lastArena = &pool->first;
thisArena = lastArena->next;
PRUword origPtr = (PRUword)p;
while(thisArena != NULL) {
if(origPtr == thisArena->base) {
if((origPtr + origAlignSize) == thisArena->avail) {
lastArena->next = thisArena->next;
PL_CLEAR_ARENA(thisArena);
PL_COUNT_ARENA(pool,--);
PR_DELETE(thisArena);
break;
}
}
lastArena = thisArena;
thisArena = thisArena->next;
}
return newp;
}
static void FreeArenaList(PLArenaPool *pool, PLArena *head, PRBool reallyFree)
{
PLArena **ap, *a;
ap = &head->next;
a = *ap;
if (!a)
return;
do {
*ap = a->next;
PL_CLEAR_ARENA(a);
PL_COUNT_ARENA(pool,--);
PR_DELETE(a);
} while ((a = *ap) != 0);
pool->current = head;
}
PR_IMPLEMENT(void) PL_ArenaRelease(PLArenaPool *pool, char *mark)
{
#if ARENA_MARK_ENABLE
PLArena *a;
for (a = pool->first.next; a; a = a->next) {
if (PR_UPTRDIFF(mark, a->base) < PR_UPTRDIFF(a->avail, a->base)) {
a->avail = (PRUword)PL_ARENA_ALIGN(pool, mark);
FreeArenaList(pool, a, PR_FALSE);
return;
}
}
#endif
}
PR_IMPLEMENT(void) PL_FreeArenaPool(PLArenaPool *pool)
{
FreeArenaList(pool, &pool->first, PR_FALSE);
COUNT(pool, ndeallocs);
}
PR_IMPLEMENT(void) PL_FinishArenaPool(PLArenaPool *pool)
{
FreeArenaList(pool, &pool->first, PR_TRUE);
#ifdef PL_ARENAMETER
{
PLArenaStats *stats, **statsp;
if (pool->stats.name)
PR_DELETE(pool->stats.name);
for (statsp = &arena_stats_list; (stats = *statsp) != 0;
statsp = &stats->next) {
if (stats == &pool->stats) {
*statsp = stats->next;
return;
}
}
}
#endif
}
PR_IMPLEMENT(void) PL_CompactArenaPool(PLArenaPool *ap)
{
}
PR_IMPLEMENT(void) PL_ArenaFinish(void)
{
}
#ifdef PL_ARENAMETER
PR_IMPLEMENT(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRSize nb)
{
pool->stats.nallocs++;
pool->stats.nbytes += nb;
if (nb > pool->stats.maxalloc)
pool->stats.maxalloc = nb;
pool->stats.variance += nb * nb;
}
PR_IMPLEMENT(void) PL_ArenaCountInplaceGrowth(
PLArenaPool *pool, PRSize size, PRSize incr)
{
pool->stats.ninplace++;
}
PR_IMPLEMENT(void) PL_ArenaCountGrowth(
PLArenaPool *pool, PRSize size, PRSize incr)
{
pool->stats.ngrows++;
pool->stats.nbytes += incr;
pool->stats.variance -= size * size;
size += incr;
if (size > pool->stats.maxalloc)
pool->stats.maxalloc = size;
pool->stats.variance += size * size;
}
PR_IMPLEMENT(void) PL_ArenaCountRelease(PLArenaPool *pool, char *mark)
{
pool->stats.nreleases++;
}
PR_IMPLEMENT(void) PL_ArenaCountRetract(PLArenaPool *pool, char *mark)
{
pool->stats.nfastrels++;
}
#include <math.h>
#include <stdio.h>
PR_IMPLEMENT(void) PL_DumpArenaStats(FILE *fp)
{
PLArenaStats *stats;
double mean, variance;
for (stats = arena_stats_list; stats; stats = stats->next) {
if (stats->nallocs != 0) {
mean = (double)stats->nbytes / stats->nallocs;
variance = fabs(stats->variance / stats->nallocs - mean * mean);
} else {
mean = variance = 0;
}
fprintf(fp, "\n%s allocation statistics:\n", stats->name);
fprintf(fp, " number of arenas: %u\n", stats->narenas);
fprintf(fp, " number of allocations: %u\n", stats->nallocs);
fprintf(fp, " number of free arena reclaims: %u\n", stats->nreclaims);
fprintf(fp, " number of malloc calls: %u\n", stats->nmallocs);
fprintf(fp, " number of deallocations: %u\n", stats->ndeallocs);
fprintf(fp, " number of allocation growths: %u\n", stats->ngrows);
fprintf(fp, " number of in-place growths: %u\n", stats->ninplace);
fprintf(fp, "number of released allocations: %u\n", stats->nreleases);
fprintf(fp, " number of fast releases: %u\n", stats->nfastrels);
fprintf(fp, " total bytes allocated: %u\n", stats->nbytes);
fprintf(fp, " mean allocation size: %g\n", mean);
fprintf(fp, " standard deviation: %g\n", sqrt(variance));
fprintf(fp, " maximum allocation size: %u\n", stats->maxalloc);
}
}
#endif