LCOV - code coverage report
Current view: top level - nsprpub/lib/ds - plarena.c (source / functions) Hit Total Coverage
Test: output.info Lines: 57 92 62.0 %
Date: 2017-07-14 16:53:18 Functions: 6 11 54.5 %
Legend: Lines: hit not hit

          Line data    Source code
       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             :  * Lifetime-based fast allocation, inspired by much prior art, including
       8             :  * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
       9             :  * David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
      10             :  */
      11             : #include <stdlib.h>
      12             : #include <string.h>
      13             : #include "plarena.h"
      14             : #include "prmem.h"
      15             : #include "prbit.h"
      16             : #include "prlog.h"
      17             : #include "prlock.h"
      18             : #include "prinit.h"
      19             : 
      20             : #ifdef PL_ARENAMETER
      21             : static PLArenaStats *arena_stats_list;
      22             : 
      23             : #define COUNT(pool,what)  (pool)->stats.what++
      24             : #else
      25             : #define COUNT(pool,what)  /* nothing */
      26             : #endif
      27             : 
      28             : #define PL_ARENA_DEFAULT_ALIGN  sizeof(double)
      29             : 
      30        2516 : PR_IMPLEMENT(void) PL_InitArenaPool(
      31             :     PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align)
      32             : {
      33             :     /*
      34             :      * Look-up table of PR_BITMASK(PR_CeilingLog2(align)) values for
      35             :      * align = 1 to 32.
      36             :      */
      37             :     static const PRUint8 pmasks[33] = {
      38             :          0,                                               /*  not used */
      39             :          0, 1, 3, 3, 7, 7, 7, 7,15,15,15,15,15,15,15,15,  /*  1 ... 16 */
      40             :         31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31}; /* 17 ... 32 */
      41             : 
      42        2516 :     if (align == 0)
      43           0 :         align = PL_ARENA_DEFAULT_ALIGN;
      44             : 
      45        2516 :     if (align < sizeof(pmasks)/sizeof(pmasks[0]))
      46        2516 :         pool->mask = pmasks[align];
      47             :     else
      48           0 :         pool->mask = PR_BITMASK(PR_CeilingLog2(align));
      49             : 
      50        2516 :     pool->first.next = NULL;
      51             :     /* Set all three addresses in pool->first to the same dummy value.
      52             :      * These addresses are only compared with each other, but never
      53             :      * dereferenced. */
      54        2516 :     pool->first.base = pool->first.avail = pool->first.limit =
      55        2516 :         (PRUword)PL_ARENA_ALIGN(pool, &pool->first + 1);
      56        2516 :     pool->current = &pool->first;
      57             :     /*
      58             :      * Compute the net size so that each arena's gross size is |size|.
      59             :      * sizeof(PLArena) + pool->mask is the header and alignment slop
      60             :      * that PL_ArenaAllocate adds to the net size.
      61             :      */
      62        2516 :     if (size > sizeof(PLArena) + pool->mask)
      63        2516 :         pool->arenasize = size - (sizeof(PLArena) + pool->mask);
      64             :     else
      65           0 :         pool->arenasize = size;
      66             : #ifdef PL_ARENAMETER
      67             :     memset(&pool->stats, 0, sizeof pool->stats);
      68             :     pool->stats.name = strdup(name);
      69             :     pool->stats.next = arena_stats_list;
      70             :     arena_stats_list = &pool->stats;
      71             : #endif
      72        2516 : }
      73             : 
      74             : 
      75             : /*
      76             : ** PL_ArenaAllocate() -- allocate space from an arena pool
      77             : ** 
      78             : ** Description: PL_ArenaAllocate() allocates space from an arena
      79             : ** pool. 
      80             : **
      81             : ** First, try to satisfy the request from arenas starting at
      82             : ** pool->current. Then try to allocate a new arena from the heap.
      83             : **
      84             : ** Returns: pointer to allocated space or NULL
      85             : ** 
      86             : ** Notes: The original implementation had some difficult to
      87             : ** solve bugs; the code was difficult to read. Sometimes it's
      88             : ** just easier to rewrite it. I did that. larryh.
      89             : **
      90             : ** See also: bugzilla: 45343.
      91             : **
      92             : */
      93             : 
      94        1393 : PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb)
      95             : {
      96             :     PLArena *a;   
      97             :     char *rp;     /* returned pointer */
      98             :     PRUint32 nbOld;
      99             : 
     100        1393 :     PR_ASSERT((nb & pool->mask) == 0);
     101             :     
     102        1393 :     nbOld = nb;
     103        1393 :     nb = (PRUword)PL_ARENA_ALIGN(pool, nb); /* force alignment */
     104        1393 :     if (nb < nbOld)
     105           0 :         return NULL;
     106             : 
     107             :     /* attempt to allocate from arenas at pool->current */
     108             :     {
     109        1393 :         a = pool->current;
     110             :         do {
     111        1393 :             if ( nb <= a->limit - a->avail )  {
     112           0 :                 pool->current = a;
     113           0 :                 rp = (char *)a->avail;
     114           0 :                 a->avail += nb;
     115           0 :                 return rp;
     116             :             }
     117        1393 :         } while( NULL != (a = a->next) );
     118             :     }
     119             : 
     120             :     /* attempt to allocate from the heap */ 
     121             :     {  
     122        1393 :         PRUint32 sz = PR_MAX(pool->arenasize, nb);
     123        1393 :         if (PR_UINT32_MAX - sz < sizeof *a + pool->mask) {
     124           0 :             a = NULL;
     125             :         } else {
     126        1393 :             sz += sizeof *a + pool->mask;  /* header and alignment slop */
     127        1393 :             a = (PLArena*)PR_MALLOC(sz);
     128             :         }
     129        1393 :         if ( NULL != a )  {
     130        1393 :             a->limit = (PRUword)a + sz;
     131        1393 :             a->base = a->avail = (PRUword)PL_ARENA_ALIGN(pool, a + 1);
     132             :             PL_MAKE_MEM_NOACCESS((void*)a->avail, a->limit - a->avail);
     133        1393 :             rp = (char *)a->avail;
     134        1393 :             a->avail += nb;
     135        1393 :             PR_ASSERT(a->avail <= a->limit);
     136             :             /* the newly allocated arena is linked after pool->current 
     137             :             *  and becomes pool->current */
     138        1393 :             a->next = pool->current->next;
     139        1393 :             pool->current->next = a;
     140        1393 :             pool->current = a;
     141        1393 :             if ( NULL == pool->first.next )
     142           0 :                 pool->first.next = a;
     143             :             PL_COUNT_ARENA(pool,++);
     144             :             COUNT(pool, nmallocs);
     145        1393 :             return(rp);
     146             :         }
     147             :     }
     148             : 
     149             :     /* we got to here, and there's no memory to allocate */
     150           0 :     return(NULL);
     151             : } /* --- end PL_ArenaAllocate() --- */
     152             : 
     153           0 : PR_IMPLEMENT(void *) PL_ArenaGrow(
     154             :     PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr)
     155             : {
     156             :     void *newp;
     157             : 
     158           0 :     if (PR_UINT32_MAX - size < incr)
     159           0 :         return NULL;
     160           0 :     PL_ARENA_ALLOCATE(newp, pool, size + incr);
     161           0 :     if (newp)
     162           0 :         memcpy(newp, p, size);
     163           0 :     return newp;
     164             : }
     165             : 
     166           2 : PR_IMPLEMENT(void) PL_ClearArenaPool(PLArenaPool *pool, PRInt32 pattern)
     167             : {
     168             :     PLArena *a;
     169             : 
     170           4 :     for (a = pool->first.next; a; a = a->next) {
     171           2 :         PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
     172           2 :         a->avail = a->base;
     173           2 :         PL_CLEAR_UNUSED_PATTERN(a, pattern);
     174             :         PL_MAKE_MEM_NOACCESS((void*)a->avail, a->limit - a->avail);
     175             :     }
     176           2 : }
     177             : 
     178             : /*
     179             :  * Free tail arenas linked after head, which may not be the true list head.
     180             :  * Reset pool->current to point to head in case it pointed at a tail arena.
     181             :  */
     182        2466 : static void FreeArenaList(PLArenaPool *pool, PLArena *head)
     183             : {
     184        2466 :     PLArena *a = head->next;
     185        2466 :     if (!a)
     186        1303 :         return;
     187             : 
     188        1163 :     head->next = NULL;
     189             : 
     190             :     do {
     191        1328 :         PLArena *tmp = a;
     192        1328 :         a = a->next;
     193        1328 :         PL_CLEAR_ARENA(tmp);
     194             :         PL_COUNT_ARENA(pool,--);
     195        1328 :         PR_DELETE(tmp);
     196        1328 :     } while (a);
     197             : 
     198        1163 :     pool->current = head;
     199             : }
     200             : 
     201           0 : PR_IMPLEMENT(void) PL_ArenaRelease(PLArenaPool *pool, char *mark)
     202             : {
     203             :     PLArena *a;
     204             : 
     205           0 :     for (a = &pool->first; a; a = a->next) {
     206           0 :         if (PR_UPTRDIFF(mark, a->base) <= PR_UPTRDIFF(a->avail, a->base)) {
     207           0 :             a->avail = (PRUword)PL_ARENA_ALIGN(pool, mark);
     208           0 :             FreeArenaList(pool, a);
     209           0 :             return;
     210             :         }
     211             :     }
     212             : }
     213             : 
     214        1795 : PR_IMPLEMENT(void) PL_FreeArenaPool(PLArenaPool *pool)
     215             : {
     216        1795 :     FreeArenaList(pool, &pool->first);
     217             :     COUNT(pool, ndeallocs);
     218        1795 : }
     219             : 
     220         671 : PR_IMPLEMENT(void) PL_FinishArenaPool(PLArenaPool *pool)
     221             : {
     222         671 :     FreeArenaList(pool, &pool->first);
     223             : #ifdef PL_ARENAMETER
     224             :     {
     225             :         PLArenaStats *stats, **statsp;
     226             : 
     227             :         if (pool->stats.name)
     228             :             PR_DELETE(pool->stats.name);
     229             :         for (statsp = &arena_stats_list; (stats = *statsp) != 0;
     230             :              statsp = &stats->next) {
     231             :             if (stats == &pool->stats) {
     232             :                 *statsp = stats->next;
     233             :                 return;
     234             :             }
     235             :         }
     236             :     }
     237             : #endif
     238         671 : }
     239             : 
     240           0 : PR_IMPLEMENT(void) PL_CompactArenaPool(PLArenaPool *ap)
     241             : {
     242           0 : }
     243             : 
     244           0 : PR_IMPLEMENT(void) PL_ArenaFinish(void)
     245             : {
     246           0 : }
     247             : 
     248           0 : PR_IMPLEMENT(size_t) PL_SizeOfArenaPoolExcludingPool(
     249             :     const PLArenaPool *pool, PLMallocSizeFn mallocSizeOf)
     250             : {
     251             :     /*
     252             :      * The first PLArena is within |pool|, so don't measure it.  Subsequent
     253             :      * PLArenas are separate and must be measured.
     254             :      */
     255           0 :     size_t size = 0;
     256           0 :     const PLArena *arena = pool->first.next;
     257           0 :     while (arena) {
     258           0 :         size += mallocSizeOf(arena);
     259           0 :         arena = arena->next;
     260             :     }
     261           0 :     return size;
     262             : }
     263             : 
     264             : #ifdef PL_ARENAMETER
     265             : PR_IMPLEMENT(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRUint32 nb)
     266             : {
     267             :     pool->stats.nallocs++;
     268             :     pool->stats.nbytes += nb;
     269             :     if (nb > pool->stats.maxalloc)
     270             :         pool->stats.maxalloc = nb;
     271             :     pool->stats.variance += nb * nb;
     272             : }
     273             : 
     274             : PR_IMPLEMENT(void) PL_ArenaCountInplaceGrowth(
     275             :     PLArenaPool *pool, PRUint32 size, PRUint32 incr)
     276             : {
     277             :     pool->stats.ninplace++;
     278             : }
     279             : 
     280             : PR_IMPLEMENT(void) PL_ArenaCountGrowth(
     281             :     PLArenaPool *pool, PRUint32 size, PRUint32 incr)
     282             : {
     283             :     pool->stats.ngrows++;
     284             :     pool->stats.nbytes += incr;
     285             :     pool->stats.variance -= size * size;
     286             :     size += incr;
     287             :     if (size > pool->stats.maxalloc)
     288             :         pool->stats.maxalloc = size;
     289             :     pool->stats.variance += size * size;
     290             : }
     291             : 
     292             : PR_IMPLEMENT(void) PL_ArenaCountRelease(PLArenaPool *pool, char *mark)
     293             : {
     294             :     pool->stats.nreleases++;
     295             : }
     296             : 
     297             : PR_IMPLEMENT(void) PL_ArenaCountRetract(PLArenaPool *pool, char *mark)
     298             : {
     299             :     pool->stats.nfastrels++;
     300             : }
     301             : 
     302             : #include <math.h>
     303             : #include <stdio.h>
     304             : 
     305             : PR_IMPLEMENT(void) PL_DumpArenaStats(FILE *fp)
     306             : {
     307             :     PLArenaStats *stats;
     308             :     double mean, variance;
     309             : 
     310             :     for (stats = arena_stats_list; stats; stats = stats->next) {
     311             :         if (stats->nallocs != 0) {
     312             :             mean = (double)stats->nbytes / stats->nallocs;
     313             :             variance = fabs(stats->variance / stats->nallocs - mean * mean);
     314             :         } else {
     315             :             mean = variance = 0;
     316             :         }
     317             : 
     318             :         fprintf(fp, "\n%s allocation statistics:\n", stats->name);
     319             :         fprintf(fp, "              number of arenas: %u\n", stats->narenas);
     320             :         fprintf(fp, "         number of allocations: %u\n", stats->nallocs);
     321             :         fprintf(fp, " number of free arena reclaims: %u\n", stats->nreclaims);
     322             :         fprintf(fp, "        number of malloc calls: %u\n", stats->nmallocs);
     323             :         fprintf(fp, "       number of deallocations: %u\n", stats->ndeallocs);
     324             :         fprintf(fp, "  number of allocation growths: %u\n", stats->ngrows);
     325             :         fprintf(fp, "    number of in-place growths: %u\n", stats->ninplace);
     326             :         fprintf(fp, "number of released allocations: %u\n", stats->nreleases);
     327             :         fprintf(fp, "       number of fast releases: %u\n", stats->nfastrels);
     328             :         fprintf(fp, "         total bytes allocated: %u\n", stats->nbytes);
     329             :         fprintf(fp, "          mean allocation size: %g\n", mean);
     330             :         fprintf(fp, "            standard deviation: %g\n", sqrt(variance));
     331             :         fprintf(fp, "       maximum allocation size: %u\n", stats->maxalloc);
     332             :     }
     333             : }
     334             : #endif /* PL_ARENAMETER */

Generated by: LCOV version 1.13