LCOV - app.info - nsprpub/lib/ds/plarena.c

LCOV - code coverage report
| Current view: | directory - nsprpub/lib/ds - plarena.c (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 127 | 107 | 84.3 %
| Date: | 2012-07-07 | Functions: | 14 | 12 | 85.7 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is the Netscape Portable Runtime (NSPR).
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is Netscape
          18                 :  * Communications Corporation.  Portions created by Netscape are
          19                 :  * Copyright (C) 1998-2000 Netscape Communications Corporation.  All
          20                 :  * Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *
          24                 :  * Alternatively, the contents of this file may be used under the terms of
          25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          28                 :  * of those above. If you wish to allow use of your version of this file only
          29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          30                 :  * use your version of this file under the terms of the MPL, indicate your
          31                 :  * decision by deleting the provisions above and replace them with the notice
          32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          33                 :  * the provisions above, a recipient may use your version of this file under
          34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          35                 :  *
          36                 :  * ***** END LICENSE BLOCK *****
          37                 :  */
          38                 :
          39                 : /*
          40                 :  * Lifetime-based fast allocation, inspired by much prior art, including
          41                 :  * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
          42                 :  * David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
          43                 :  */
          44                 : #include <stdlib.h>
          45                 : #include <string.h>
          46                 : #include "plarena.h"
          47                 : #include "prmem.h"
          48                 : #include "prbit.h"
          49                 : #include "prlog.h"
          50                 : #include "prlock.h"
          51                 : #include "prinit.h"
          52                 :
          53                 : static PLArena *arena_freelist;
          54                 :
          55                 : #ifdef PL_ARENAMETER
          56                 : static PLArenaStats *arena_stats_list;
          57                 :
          58                 : #define COUNT(pool,what)  (pool)->stats.what++
          59                 : #else
          60                 : #define COUNT(pool,what)  /* nothing */
          61                 : #endif
          62                 :
          63                 : #define PL_ARENA_DEFAULT_ALIGN  sizeof(double)
          64                 :
          65                 : static PRLock    *arenaLock;
          66                 : static PRCallOnceType once;
          67                 : static const PRCallOnceType pristineCallOnce;
          68                 :
          69                 : /*
          70                 : ** InitializeArenas() -- Initialize arena operations.
          71                 : **
          72                 : ** InitializeArenas() is called exactly once and only once from
          73                 : ** LockArena(). This function creates the arena protection
          74                 : ** lock: arenaLock.
          75                 : **
          76                 : ** Note: If the arenaLock cannot be created, InitializeArenas()
          77                 : ** fails quietly, returning only PR_FAILURE. This percolates up
          78                 : ** to the application using the Arena API. He gets no arena
          79                 : ** from PL_ArenaAllocate(). It's up to him to fail gracefully
          80                 : ** or recover.
          81                 : **
          82                 : */
          83            1559 : static PRStatus InitializeArenas( void )
          84                 : {
          85            1559 :     PR_ASSERT( arenaLock == NULL );
          86            1559 :     arenaLock = PR_NewLock();
          87            1559 :     if ( arenaLock == NULL )
          88               0 :         return PR_FAILURE;
          89                 :     else
          90            1559 :         return PR_SUCCESS;
          91                 : } /* end ArenaInitialize() */
          92                 :
          93          418872 : static PRStatus LockArena( void )
          94                 : {
          95          418872 :     PRStatus rc = PR_CallOnce( &once, InitializeArenas );
          96                 :
          97          418872 :     if ( PR_FAILURE != rc )
          98          418872 :         PR_Lock( arenaLock );
          99          418872 :     return(rc);
         100                 : } /* end LockArena() */
         101                 :
         102          418872 : static void UnlockArena( void )
         103                 : {
         104          418872 :     PR_Unlock( arenaLock );
         105                 :     return;
         106                 : } /* end UnlockArena() */
         107                 :
         108          236744 : PR_IMPLEMENT(void) PL_InitArenaPool(
         109                 :     PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align)
         110                 : {
         111                 :     /*
         112                 :      * Look-up table of PR_BITMASK(PR_CeilingLog2(align)) values for
         113                 :      * align = 1 to 32.
         114                 :      */
         115                 :     static const PRUint8 pmasks[33] = {
         116                 :          0,                                               /*  not used */
         117                 :          0, 1, 3, 3, 7, 7, 7, 7,15,15,15,15,15,15,15,15,  /*  1 ... 16 */
         118                 :         31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31}; /* 17 ... 32 */
         119                 :
         120          236744 :     if (align == 0)
         121            7417 :         align = PL_ARENA_DEFAULT_ALIGN;
         122                 :
         123          236744 :     if (align < sizeof(pmasks)/sizeof(pmasks[0]))
         124          236744 :         pool->mask = pmasks[align];
         125                 :     else
         126               0 :         pool->mask = PR_BITMASK(PR_CeilingLog2(align));
         127                 :
         128          236744 :     pool->first.next = NULL;
         129          236744 :     pool->first.base = pool->first.avail = pool->first.limit =
         130          236744 :         (PRUword)PL_ARENA_ALIGN(pool, &pool->first + 1);
         131          236744 :     pool->current = &pool->first;
         132                 :     /*
         133                 :      * Compute the net size so that each arena's gross size is |size|.
         134                 :      * sizeof(PLArena) + pool->mask is the header and alignment slop
         135                 :      * that PL_ArenaAllocate adds to the net size.
         136                 :      */
         137          236744 :     if (size > sizeof(PLArena) + pool->mask)
         138          236744 :         pool->arenasize = size - (sizeof(PLArena) + pool->mask);
         139                 :     else
         140               0 :         pool->arenasize = size;
         141                 : #ifdef PL_ARENAMETER
         142                 :     memset(&pool->stats, 0, sizeof pool->stats);
         143                 :     pool->stats.name = strdup(name);
         144                 :     pool->stats.next = arena_stats_list;
         145                 :     arena_stats_list = &pool->stats;
         146                 : #endif
         147          236744 : }
         148                 :
         149                 :
         150                 : /*
         151                 : ** PL_ArenaAllocate() -- allocate space from an arena pool
         152                 : **
         153                 : ** Description: PL_ArenaAllocate() allocates space from an arena
         154                 : ** pool.
         155                 : **
         156                 : ** First, try to satisfy the request from arenas starting at
         157                 : ** pool->current.
         158                 : **
         159                 : ** If there is not enough space in the arena pool->current, try
         160                 : ** to claim an arena, on a first fit basis, from the global
         161                 : ** freelist (arena_freelist).
         162                 : **
         163                 : ** If no arena in arena_freelist is suitable, then try to
         164                 : ** allocate a new arena from the heap.
         165                 : **
         166                 : ** Returns: pointer to allocated space or NULL
         167                 : **
         168                 : ** Notes: The original implementation had some difficult to
         169                 : ** solve bugs; the code was difficult to read. Sometimes it's
         170                 : ** just easier to rewrite it. I did that. larryh.
         171                 : **
         172                 : ** See also: bugzilla: 45343.
         173                 : **
         174                 : */
         175                 :
         176          235458 : PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb)
         177                 : {
         178                 :     PLArena *a;
         179                 :     char *rp;     /* returned pointer */
         180                 :
         181          235458 :     PR_ASSERT((nb & pool->mask) == 0);
         182                 :
         183          235458 :     nb = (PRUword)PL_ARENA_ALIGN(pool, nb); /* force alignment */
         184                 :
         185                 :     /* attempt to allocate from arenas at pool->current */
         186                 :     {
         187          235458 :         a = pool->current;
         188                 :         do {
         189          235458 :             if ( a->avail +nb <= a->limit )  {
         190               0 :                 pool->current = a;
         191               0 :                 rp = (char *)a->avail;
         192               0 :                 a->avail += nb;
         193               0 :                 return rp;
         194                 :             }
         195          235458 :         } while( NULL != (a = a->next) );
         196                 :     }
         197                 :
         198                 :     /* attempt to allocate from arena_freelist */
         199                 :     {
         200                 :         PLArena *p; /* previous pointer, for unlinking from freelist */
         201                 :
         202                 :         /* lock the arena_freelist. Make access to the freelist MT-Safe */
         203          235458 :         if ( PR_FAILURE == LockArena())
         204               0 :             return(0);
         205                 :
         206          235786 :         for ( a = arena_freelist, p = NULL; a != NULL ; p = a, a = a->next ) {
         207          177470 :             if ( a->base +nb <= a->limit )  {
         208          177142 :                 if ( p == NULL )
         209          177142 :                     arena_freelist = a->next;
         210                 :                 else
         211               0 :                     p->next = a->next;
         212          177142 :                 UnlockArena();
         213          177142 :                 a->avail = a->base;
         214          177142 :                 rp = (char *)a->avail;
         215          177142 :                 a->avail += nb;
         216                 :                 /* the newly allocated arena is linked after pool->current
         217                 :                 *  and becomes pool->current */
         218          177142 :                 a->next = pool->current->next;
         219          177142 :                 pool->current->next = a;
         220          177142 :                 pool->current = a;
         221          177142 :                 if ( NULL == pool->first.next )
         222               0 :                     pool->first.next = a;
         223          177142 :                 return(rp);
         224                 :             }
         225                 :         }
         226           58316 :         UnlockArena();
         227                 :     }
         228                 :
         229                 :     /* attempt to allocate from the heap */
         230                 :     {
         231           58316 :         PRUint32 sz = PR_MAX(pool->arenasize, nb);
         232           58316 :         sz += sizeof *a + pool->mask;  /* header and alignment slop */
         233           58316 :         a = (PLArena*)PR_MALLOC(sz);
         234           58316 :         if ( NULL != a )  {
         235           58316 :             a->limit = (PRUword)a + sz;
         236           58316 :             a->base = a->avail = (PRUword)PL_ARENA_ALIGN(pool, a + 1);
         237           58316 :             rp = (char *)a->avail;
         238           58316 :             a->avail += nb;
         239                 :             /* the newly allocated arena is linked after pool->current
         240                 :             *  and becomes pool->current */
         241           58316 :             a->next = pool->current->next;
         242           58316 :             pool->current->next = a;
         243           58316 :             pool->current = a;
         244           58316 :             if ( NULL == pool->first.next )
         245               0 :                 pool->first.next = a;
         246                 :             PL_COUNT_ARENA(pool,++);
         247                 :             COUNT(pool, nmallocs);
         248           58316 :             return(rp);
         249                 :         }
         250                 :     }
         251                 :
         252                 :     /* we got to here, and there's no memory to allocate */
         253               0 :     return(NULL);
         254                 : } /* --- end PL_ArenaAllocate() --- */
         255                 :
         256           16544 : PR_IMPLEMENT(void *) PL_ArenaGrow(
         257                 :     PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr)
         258                 : {
         259                 :     void *newp;
         260                 :
         261           16544 :     PL_ARENA_ALLOCATE(newp, pool, size + incr);
         262           16544 :     if (newp)
         263           16544 :         memcpy(newp, p, size);
         264           16544 :     return newp;
         265                 : }
         266                 :
         267          271640 : static void ClearArenaList(PLArena *a, PRInt32 pattern)
         268                 : {
         269                 :
         270          569610 :     for (; a; a = a->next) {
         271          297970 :         PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
         272          297970 :         a->avail = a->base;
         273          297970 :         PL_CLEAR_UNUSED_PATTERN(a, pattern);
         274                 :     }
         275          271640 : }
         276                 :
         277           62283 : PR_IMPLEMENT(void) PL_ClearArenaPool(PLArenaPool *pool, PRInt32 pattern)
         278                 : {
         279           62283 :     ClearArenaList(pool->first.next, pattern);
         280           62283 : }
         281                 :
         282                 : /*
         283                 :  * Free tail arenas linked after head, which may not be the true list head.
         284                 :  * Reset pool->current to point to head in case it pointed at a tail arena.
         285                 :  */
         286          238579 : static void FreeArenaList(PLArenaPool *pool, PLArena *head, PRBool reallyFree)
         287                 : {
         288                 :     PLArena **ap, *a;
         289                 :
         290          238579 :     ap = &head->next;
         291          238579 :     a = *ap;
         292          238579 :     if (!a)
         293           29222 :         return;
         294                 :
         295                 : #ifdef DEBUG
         296          209357 :     ClearArenaList(a, PL_FREE_PATTERN);
         297                 : #endif
         298                 :
         299          209357 :     if (reallyFree) {
         300                 :         do {
         301           50113 :             *ap = a->next;
         302           50113 :             PL_CLEAR_ARENA(a);
         303                 :             PL_COUNT_ARENA(pool,--);
         304           50113 :             PR_DELETE(a);
         305           50113 :         } while ((a = *ap) != 0);
         306                 :     } else {
         307                 :         /* Insert the whole arena chain at the front of the freelist. */
         308                 :         do {
         309          185274 :             ap = &(*ap)->next;
         310          185274 :         } while (*ap);
         311          183414 :         LockArena();
         312          183414 :         *ap = arena_freelist;
         313          183414 :         arena_freelist = a;
         314          183414 :         head->next = 0;
         315          183414 :         UnlockArena();
         316                 :     }
         317                 :
         318          209357 :     pool->current = head;
         319                 : }
         320                 :
         321               0 : PR_IMPLEMENT(void) PL_ArenaRelease(PLArenaPool *pool, char *mark)
         322                 : {
         323                 :     PLArena *a;
         324                 :
         325               0 :     for (a = &pool->first; a; a = a->next) {
         326               0 :         if (PR_UPTRDIFF(mark, a->base) <= PR_UPTRDIFF(a->avail, a->base)) {
         327               0 :             a->avail = (PRUword)PL_ARENA_ALIGN(pool, mark);
         328               0 :             FreeArenaList(pool, a, PR_FALSE);
         329               0 :             return;
         330                 :         }
         331                 :     }
         332                 : }
         333                 :
         334          211211 : PR_IMPLEMENT(void) PL_FreeArenaPool(PLArenaPool *pool)
         335                 : {
         336          211211 :     FreeArenaList(pool, &pool->first, PR_FALSE);
         337                 :     COUNT(pool, ndeallocs);
         338          211211 : }
         339                 :
         340           27368 : PR_IMPLEMENT(void) PL_FinishArenaPool(PLArenaPool *pool)
         341                 : {
         342           27368 :     FreeArenaList(pool, &pool->first, PR_TRUE);
         343                 : #ifdef PL_ARENAMETER
         344                 :     {
         345                 :         PLArenaStats *stats, **statsp;
         346                 :
         347                 :         if (pool->stats.name)
         348                 :             PR_DELETE(pool->stats.name);
         349                 :         for (statsp = &arena_stats_list; (stats = *statsp) != 0;
         350                 :              statsp = &stats->next) {
         351                 :             if (stats == &pool->stats) {
         352                 :                 *statsp = stats->next;
         353                 :                 return;
         354                 :             }
         355                 :         }
         356                 :     }
         357                 : #endif
         358           27368 : }
         359                 :
         360               0 : PR_IMPLEMENT(void) PL_CompactArenaPool(PLArenaPool *ap)
         361                 : {
         362               0 : }
         363                 :
         364             140 : PR_IMPLEMENT(void) PL_ArenaFinish(void)
         365                 : {
         366                 :     PLArena *a, *next;
         367                 :
         368            1420 :     for (a = arena_freelist; a; a = next) {
         369            1280 :         next = a->next;
         370            1280 :         PR_DELETE(a);
         371                 :     }
         372             140 :     arena_freelist = NULL;
         373                 :
         374             140 :     if (arenaLock) {
         375             140 :         PR_DestroyLock(arenaLock);
         376             140 :         arenaLock = NULL;
         377                 :     }
         378             140 :     once = pristineCallOnce;
         379             140 : }
         380                 :
         381                 : #ifdef PL_ARENAMETER
         382                 : PR_IMPLEMENT(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRUint32 nb)
         383                 : {
         384                 :     pool->stats.nallocs++;
         385                 :     pool->stats.nbytes += nb;
         386                 :     if (nb > pool->stats.maxalloc)
         387                 :         pool->stats.maxalloc = nb;
         388                 :     pool->stats.variance += nb * nb;
         389                 : }
         390                 :
         391                 : PR_IMPLEMENT(void) PL_ArenaCountInplaceGrowth(
         392                 :     PLArenaPool *pool, PRUint32 size, PRUint32 incr)
         393                 : {
         394                 :     pool->stats.ninplace++;
         395                 : }
         396                 :
         397                 : PR_IMPLEMENT(void) PL_ArenaCountGrowth(
         398                 :     PLArenaPool *pool, PRUint32 size, PRUint32 incr)
         399                 : {
         400                 :     pool->stats.ngrows++;
         401                 :     pool->stats.nbytes += incr;
         402                 :     pool->stats.variance -= size * size;
         403                 :     size += incr;
         404                 :     if (size > pool->stats.maxalloc)
         405                 :         pool->stats.maxalloc = size;
         406                 :     pool->stats.variance += size * size;
         407                 : }
         408                 :
         409                 : PR_IMPLEMENT(void) PL_ArenaCountRelease(PLArenaPool *pool, char *mark)
         410                 : {
         411                 :     pool->stats.nreleases++;
         412                 : }
         413                 :
         414                 : PR_IMPLEMENT(void) PL_ArenaCountRetract(PLArenaPool *pool, char *mark)
         415                 : {
         416                 :     pool->stats.nfastrels++;
         417                 : }
         418                 :
         419                 : #include <math.h>
         420                 : #include <stdio.h>
         421                 :
         422                 : PR_IMPLEMENT(void) PL_DumpArenaStats(FILE *fp)
         423                 : {
         424                 :     PLArenaStats *stats;
         425                 :     double mean, variance;
         426                 :
         427                 :     for (stats = arena_stats_list; stats; stats = stats->next) {
         428                 :         if (stats->nallocs != 0) {
         429                 :             mean = (double)stats->nbytes / stats->nallocs;
         430                 :             variance = fabs(stats->variance / stats->nallocs - mean * mean);
         431                 :         } else {
         432                 :             mean = variance = 0;
         433                 :         }
         434                 :
         435                 :         fprintf(fp, "\n%s allocation statistics:\n", stats->name);
         436                 :         fprintf(fp, "              number of arenas: %u\n", stats->narenas);
         437                 :         fprintf(fp, "         number of allocations: %u\n", stats->nallocs);
         438                 :         fprintf(fp, " number of free arena reclaims: %u\n", stats->nreclaims);
         439                 :         fprintf(fp, "        number of malloc calls: %u\n", stats->nmallocs);
         440                 :         fprintf(fp, "       number of deallocations: %u\n", stats->ndeallocs);
         441                 :         fprintf(fp, "  number of allocation growths: %u\n", stats->ngrows);
         442                 :         fprintf(fp, "    number of in-place growths: %u\n", stats->ninplace);
         443                 :         fprintf(fp, "number of released allocations: %u\n", stats->nreleases);
         444                 :         fprintf(fp, "       number of fast releases: %u\n", stats->nfastrels);
         445                 :         fprintf(fp, "         total bytes allocated: %u\n", stats->nbytes);
         446                 :         fprintf(fp, "          mean allocation size: %g\n", mean);
         447                 :         fprintf(fp, "            standard deviation: %g\n", sqrt(variance));
         448                 :         fprintf(fp, "       maximum allocation size: %u\n", stats->maxalloc);
         449                 :     }
         450                 : }
         451                 : #endif /* PL_ARENAMETER */

Generated by: LCOV version 1.7