Annotation of embedaddon/sqlite3/src/mem5.c, revision 1.1

1.1     ! misho       1: /*
        !             2: ** 2007 October 14
        !             3: **
        !             4: ** The author disclaims copyright to this source code.  In place of
        !             5: ** a legal notice, here is a blessing:
        !             6: **
        !             7: **    May you do good and not evil.
        !             8: **    May you find forgiveness for yourself and forgive others.
        !             9: **    May you share freely, never taking more than you give.
        !            10: **
        !            11: *************************************************************************
        !            12: ** This file contains the C functions that implement a memory
        !            13: ** allocation subsystem for use by SQLite. 
        !            14: **
        !            15: ** This version of the memory allocation subsystem omits all
        !            16: ** use of malloc(). The application gives SQLite a block of memory
        !            17: ** before calling sqlite3_initialize() from which allocations
        !            18: ** are made and returned by the xMalloc() and xRealloc() 
        !            19: ** implementations. Once sqlite3_initialize() has been called,
        !            20: ** the amount of memory available to SQLite is fixed and cannot
        !            21: ** be changed.
        !            22: **
        !            23: ** This version of the memory allocation subsystem is included
        !            24: ** in the build only if SQLITE_ENABLE_MEMSYS5 is defined.
        !            25: **
        !            26: ** This memory allocator uses the following algorithm:
        !            27: **
        !            28: **   1.  All memory allocations sizes are rounded up to a power of 2.
        !            29: **
        !            30: **   2.  If two adjacent free blocks are the halves of a larger block,
        !            31: **       then the two blocks are coalesed into the single larger block.
        !            32: **
        !            33: **   3.  New memory is allocated from the first available free block.
        !            34: **
        !            35: ** This algorithm is described in: J. M. Robson. "Bounds for Some Functions
        !            36: ** Concerning Dynamic Storage Allocation". Journal of the Association for
        !            37: ** Computing Machinery, Volume 21, Number 8, July 1974, pages 491-499.
        !            38: ** 
        !            39: ** Let n be the size of the largest allocation divided by the minimum
        !            40: ** allocation size (after rounding all sizes up to a power of 2.)  Let M
        !            41: ** be the maximum amount of memory ever outstanding at one time.  Let
        !            42: ** N be the total amount of memory available for allocation.  Robson
        !            43: ** proved that this memory allocator will never breakdown due to 
        !            44: ** fragmentation as long as the following constraint holds:
        !            45: **
        !            46: **      N >=  M*(1 + log2(n)/2) - n + 1
        !            47: **
        !            48: ** The sqlite3_status() logic tracks the maximum values of n and M so
        !            49: ** that an application can, at any time, verify this constraint.
        !            50: */
        !            51: #include "sqliteInt.h"
        !            52: 
        !            53: /*
        !            54: ** This version of the memory allocator is used only when 
        !            55: ** SQLITE_ENABLE_MEMSYS5 is defined.
        !            56: */
        !            57: #ifdef SQLITE_ENABLE_MEMSYS5
        !            58: 
        !            59: /*
        !            60: ** A minimum allocation is an instance of the following structure.
        !            61: ** Larger allocations are an array of these structures where the
        !            62: ** size of the array is a power of 2.
        !            63: **
        !            64: ** The size of this object must be a power of two.  That fact is
        !            65: ** verified in memsys5Init().
        !            66: */
        !            67: typedef struct Mem5Link Mem5Link;
        !            68: struct Mem5Link {
        !            69:   int next;       /* Index of next free chunk */
        !            70:   int prev;       /* Index of previous free chunk */
        !            71: };
        !            72: 
        !            73: /*
        !            74: ** Maximum size of any allocation is ((1<<LOGMAX)*mem5.szAtom). Since
        !            75: ** mem5.szAtom is always at least 8 and 32-bit integers are used,
        !            76: ** it is not actually possible to reach this limit.
        !            77: */
        !            78: #define LOGMAX 30
        !            79: 
        !            80: /*
        !            81: ** Masks used for mem5.aCtrl[] elements.
        !            82: */
        !            83: #define CTRL_LOGSIZE  0x1f    /* Log2 Size of this block */
        !            84: #define CTRL_FREE     0x20    /* True if not checked out */
        !            85: 
        !            86: /*
        !            87: ** All of the static variables used by this module are collected
        !            88: ** into a single structure named "mem5".  This is to keep the
        !            89: ** static variables organized and to reduce namespace pollution
        !            90: ** when this module is combined with other in the amalgamation.
        !            91: */
        !            92: static SQLITE_WSD struct Mem5Global {
        !            93:   /*
        !            94:   ** Memory available for allocation
        !            95:   */
        !            96:   int szAtom;      /* Smallest possible allocation in bytes */
        !            97:   int nBlock;      /* Number of szAtom sized blocks in zPool */
        !            98:   u8 *zPool;       /* Memory available to be allocated */
        !            99:   
        !           100:   /*
        !           101:   ** Mutex to control access to the memory allocation subsystem.
        !           102:   */
        !           103:   sqlite3_mutex *mutex;
        !           104: 
        !           105:   /*
        !           106:   ** Performance statistics
        !           107:   */
        !           108:   u64 nAlloc;         /* Total number of calls to malloc */
        !           109:   u64 totalAlloc;     /* Total of all malloc calls - includes internal frag */
        !           110:   u64 totalExcess;    /* Total internal fragmentation */
        !           111:   u32 currentOut;     /* Current checkout, including internal fragmentation */
        !           112:   u32 currentCount;   /* Current number of distinct checkouts */
        !           113:   u32 maxOut;         /* Maximum instantaneous currentOut */
        !           114:   u32 maxCount;       /* Maximum instantaneous currentCount */
        !           115:   u32 maxRequest;     /* Largest allocation (exclusive of internal frag) */
        !           116:   
        !           117:   /*
        !           118:   ** Lists of free blocks.  aiFreelist[0] is a list of free blocks of
        !           119:   ** size mem5.szAtom.  aiFreelist[1] holds blocks of size szAtom*2.
        !           120:   ** and so forth.
        !           121:   */
        !           122:   int aiFreelist[LOGMAX+1];
        !           123: 
        !           124:   /*
        !           125:   ** Space for tracking which blocks are checked out and the size
        !           126:   ** of each block.  One byte per block.
        !           127:   */
        !           128:   u8 *aCtrl;
        !           129: 
        !           130: } mem5;
        !           131: 
        !           132: /*
        !           133: ** Access the static variable through a macro for SQLITE_OMIT_WSD
        !           134: */
        !           135: #define mem5 GLOBAL(struct Mem5Global, mem5)
        !           136: 
        !           137: /*
        !           138: ** Assuming mem5.zPool is divided up into an array of Mem5Link
        !           139: ** structures, return a pointer to the idx-th such lik.
        !           140: */
        !           141: #define MEM5LINK(idx) ((Mem5Link *)(&mem5.zPool[(idx)*mem5.szAtom]))
        !           142: 
        !           143: /*
        !           144: ** Unlink the chunk at mem5.aPool[i] from list it is currently
        !           145: ** on.  It should be found on mem5.aiFreelist[iLogsize].
        !           146: */
        !           147: static void memsys5Unlink(int i, int iLogsize){
        !           148:   int next, prev;
        !           149:   assert( i>=0 && i<mem5.nBlock );
        !           150:   assert( iLogsize>=0 && iLogsize<=LOGMAX );
        !           151:   assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
        !           152: 
        !           153:   next = MEM5LINK(i)->next;
        !           154:   prev = MEM5LINK(i)->prev;
        !           155:   if( prev<0 ){
        !           156:     mem5.aiFreelist[iLogsize] = next;
        !           157:   }else{
        !           158:     MEM5LINK(prev)->next = next;
        !           159:   }
        !           160:   if( next>=0 ){
        !           161:     MEM5LINK(next)->prev = prev;
        !           162:   }
        !           163: }
        !           164: 
        !           165: /*
        !           166: ** Link the chunk at mem5.aPool[i] so that is on the iLogsize
        !           167: ** free list.
        !           168: */
        !           169: static void memsys5Link(int i, int iLogsize){
        !           170:   int x;
        !           171:   assert( sqlite3_mutex_held(mem5.mutex) );
        !           172:   assert( i>=0 && i<mem5.nBlock );
        !           173:   assert( iLogsize>=0 && iLogsize<=LOGMAX );
        !           174:   assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
        !           175: 
        !           176:   x = MEM5LINK(i)->next = mem5.aiFreelist[iLogsize];
        !           177:   MEM5LINK(i)->prev = -1;
        !           178:   if( x>=0 ){
        !           179:     assert( x<mem5.nBlock );
        !           180:     MEM5LINK(x)->prev = i;
        !           181:   }
        !           182:   mem5.aiFreelist[iLogsize] = i;
        !           183: }
        !           184: 
        !           185: /*
        !           186: ** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
        !           187: ** will already be held (obtained by code in malloc.c) if
        !           188: ** sqlite3GlobalConfig.bMemStat is true.
        !           189: */
        !           190: static void memsys5Enter(void){
        !           191:   sqlite3_mutex_enter(mem5.mutex);
        !           192: }
        !           193: static void memsys5Leave(void){
        !           194:   sqlite3_mutex_leave(mem5.mutex);
        !           195: }
        !           196: 
        !           197: /*
        !           198: ** Return the size of an outstanding allocation, in bytes.  The
        !           199: ** size returned omits the 8-byte header overhead.  This only
        !           200: ** works for chunks that are currently checked out.
        !           201: */
        !           202: static int memsys5Size(void *p){
        !           203:   int iSize = 0;
        !           204:   if( p ){
        !           205:     int i = ((u8 *)p-mem5.zPool)/mem5.szAtom;
        !           206:     assert( i>=0 && i<mem5.nBlock );
        !           207:     iSize = mem5.szAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
        !           208:   }
        !           209:   return iSize;
        !           210: }
        !           211: 
        !           212: /*
        !           213: ** Find the first entry on the freelist iLogsize.  Unlink that
        !           214: ** entry and return its index. 
        !           215: */
        !           216: static int memsys5UnlinkFirst(int iLogsize){
        !           217:   int i;
        !           218:   int iFirst;
        !           219: 
        !           220:   assert( iLogsize>=0 && iLogsize<=LOGMAX );
        !           221:   i = iFirst = mem5.aiFreelist[iLogsize];
        !           222:   assert( iFirst>=0 );
        !           223:   while( i>0 ){
        !           224:     if( i<iFirst ) iFirst = i;
        !           225:     i = MEM5LINK(i)->next;
        !           226:   }
        !           227:   memsys5Unlink(iFirst, iLogsize);
        !           228:   return iFirst;
        !           229: }
        !           230: 
        !           231: /*
        !           232: ** Return a block of memory of at least nBytes in size.
        !           233: ** Return NULL if unable.  Return NULL if nBytes==0.
        !           234: **
        !           235: ** The caller guarantees that nByte positive.
        !           236: **
        !           237: ** The caller has obtained a mutex prior to invoking this
        !           238: ** routine so there is never any chance that two or more
        !           239: ** threads can be in this routine at the same time.
        !           240: */
        !           241: static void *memsys5MallocUnsafe(int nByte){
        !           242:   int i;           /* Index of a mem5.aPool[] slot */
        !           243:   int iBin;        /* Index into mem5.aiFreelist[] */
        !           244:   int iFullSz;     /* Size of allocation rounded up to power of 2 */
        !           245:   int iLogsize;    /* Log2 of iFullSz/POW2_MIN */
        !           246: 
        !           247:   /* nByte must be a positive */
        !           248:   assert( nByte>0 );
        !           249: 
        !           250:   /* Keep track of the maximum allocation request.  Even unfulfilled
        !           251:   ** requests are counted */
        !           252:   if( (u32)nByte>mem5.maxRequest ){
        !           253:     mem5.maxRequest = nByte;
        !           254:   }
        !           255: 
        !           256:   /* Abort if the requested allocation size is larger than the largest
        !           257:   ** power of two that we can represent using 32-bit signed integers.
        !           258:   */
        !           259:   if( nByte > 0x40000000 ){
        !           260:     return 0;
        !           261:   }
        !           262: 
        !           263:   /* Round nByte up to the next valid power of two */
        !           264:   for(iFullSz=mem5.szAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
        !           265: 
        !           266:   /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
        !           267:   ** block.  If not, then split a block of the next larger power of
        !           268:   ** two in order to create a new free block of size iLogsize.
        !           269:   */
        !           270:   for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){}
        !           271:   if( iBin>LOGMAX ){
        !           272:     testcase( sqlite3GlobalConfig.xLog!=0 );
        !           273:     sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
        !           274:     return 0;
        !           275:   }
        !           276:   i = memsys5UnlinkFirst(iBin);
        !           277:   while( iBin>iLogsize ){
        !           278:     int newSize;
        !           279: 
        !           280:     iBin--;
        !           281:     newSize = 1 << iBin;
        !           282:     mem5.aCtrl[i+newSize] = CTRL_FREE | iBin;
        !           283:     memsys5Link(i+newSize, iBin);
        !           284:   }
        !           285:   mem5.aCtrl[i] = iLogsize;
        !           286: 
        !           287:   /* Update allocator performance statistics. */
        !           288:   mem5.nAlloc++;
        !           289:   mem5.totalAlloc += iFullSz;
        !           290:   mem5.totalExcess += iFullSz - nByte;
        !           291:   mem5.currentCount++;
        !           292:   mem5.currentOut += iFullSz;
        !           293:   if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
        !           294:   if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
        !           295: 
        !           296:   /* Return a pointer to the allocated memory. */
        !           297:   return (void*)&mem5.zPool[i*mem5.szAtom];
        !           298: }
        !           299: 
        !           300: /*
        !           301: ** Free an outstanding memory allocation.
        !           302: */
        !           303: static void memsys5FreeUnsafe(void *pOld){
        !           304:   u32 size, iLogsize;
        !           305:   int iBlock;
        !           306: 
        !           307:   /* Set iBlock to the index of the block pointed to by pOld in 
        !           308:   ** the array of mem5.szAtom byte blocks pointed to by mem5.zPool.
        !           309:   */
        !           310:   iBlock = ((u8 *)pOld-mem5.zPool)/mem5.szAtom;
        !           311: 
        !           312:   /* Check that the pointer pOld points to a valid, non-free block. */
        !           313:   assert( iBlock>=0 && iBlock<mem5.nBlock );
        !           314:   assert( ((u8 *)pOld-mem5.zPool)%mem5.szAtom==0 );
        !           315:   assert( (mem5.aCtrl[iBlock] & CTRL_FREE)==0 );
        !           316: 
        !           317:   iLogsize = mem5.aCtrl[iBlock] & CTRL_LOGSIZE;
        !           318:   size = 1<<iLogsize;
        !           319:   assert( iBlock+size-1<(u32)mem5.nBlock );
        !           320: 
        !           321:   mem5.aCtrl[iBlock] |= CTRL_FREE;
        !           322:   mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
        !           323:   assert( mem5.currentCount>0 );
        !           324:   assert( mem5.currentOut>=(size*mem5.szAtom) );
        !           325:   mem5.currentCount--;
        !           326:   mem5.currentOut -= size*mem5.szAtom;
        !           327:   assert( mem5.currentOut>0 || mem5.currentCount==0 );
        !           328:   assert( mem5.currentCount>0 || mem5.currentOut==0 );
        !           329: 
        !           330:   mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
        !           331:   while( ALWAYS(iLogsize<LOGMAX) ){
        !           332:     int iBuddy;
        !           333:     if( (iBlock>>iLogsize) & 1 ){
        !           334:       iBuddy = iBlock - size;
        !           335:     }else{
        !           336:       iBuddy = iBlock + size;
        !           337:     }
        !           338:     assert( iBuddy>=0 );
        !           339:     if( (iBuddy+(1<<iLogsize))>mem5.nBlock ) break;
        !           340:     if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;
        !           341:     memsys5Unlink(iBuddy, iLogsize);
        !           342:     iLogsize++;
        !           343:     if( iBuddy<iBlock ){
        !           344:       mem5.aCtrl[iBuddy] = CTRL_FREE | iLogsize;
        !           345:       mem5.aCtrl[iBlock] = 0;
        !           346:       iBlock = iBuddy;
        !           347:     }else{
        !           348:       mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
        !           349:       mem5.aCtrl[iBuddy] = 0;
        !           350:     }
        !           351:     size *= 2;
        !           352:   }
        !           353:   memsys5Link(iBlock, iLogsize);
        !           354: }
        !           355: 
        !           356: /*
        !           357: ** Allocate nBytes of memory
        !           358: */
        !           359: static void *memsys5Malloc(int nBytes){
        !           360:   sqlite3_int64 *p = 0;
        !           361:   if( nBytes>0 ){
        !           362:     memsys5Enter();
        !           363:     p = memsys5MallocUnsafe(nBytes);
        !           364:     memsys5Leave();
        !           365:   }
        !           366:   return (void*)p; 
        !           367: }
        !           368: 
        !           369: /*
        !           370: ** Free memory.
        !           371: **
        !           372: ** The outer layer memory allocator prevents this routine from
        !           373: ** being called with pPrior==0.
        !           374: */
        !           375: static void memsys5Free(void *pPrior){
        !           376:   assert( pPrior!=0 );
        !           377:   memsys5Enter();
        !           378:   memsys5FreeUnsafe(pPrior);
        !           379:   memsys5Leave();  
        !           380: }
        !           381: 
        !           382: /*
        !           383: ** Change the size of an existing memory allocation.
        !           384: **
        !           385: ** The outer layer memory allocator prevents this routine from
        !           386: ** being called with pPrior==0.  
        !           387: **
        !           388: ** nBytes is always a value obtained from a prior call to
        !           389: ** memsys5Round().  Hence nBytes is always a non-negative power
        !           390: ** of two.  If nBytes==0 that means that an oversize allocation
        !           391: ** (an allocation larger than 0x40000000) was requested and this
        !           392: ** routine should return 0 without freeing pPrior.
        !           393: */
        !           394: static void *memsys5Realloc(void *pPrior, int nBytes){
        !           395:   int nOld;
        !           396:   void *p;
        !           397:   assert( pPrior!=0 );
        !           398:   assert( (nBytes&(nBytes-1))==0 );  /* EV: R-46199-30249 */
        !           399:   assert( nBytes>=0 );
        !           400:   if( nBytes==0 ){
        !           401:     return 0;
        !           402:   }
        !           403:   nOld = memsys5Size(pPrior);
        !           404:   if( nBytes<=nOld ){
        !           405:     return pPrior;
        !           406:   }
        !           407:   memsys5Enter();
        !           408:   p = memsys5MallocUnsafe(nBytes);
        !           409:   if( p ){
        !           410:     memcpy(p, pPrior, nOld);
        !           411:     memsys5FreeUnsafe(pPrior);
        !           412:   }
        !           413:   memsys5Leave();
        !           414:   return p;
        !           415: }
        !           416: 
        !           417: /*
        !           418: ** Round up a request size to the next valid allocation size.  If
        !           419: ** the allocation is too large to be handled by this allocation system,
        !           420: ** return 0.
        !           421: **
        !           422: ** All allocations must be a power of two and must be expressed by a
        !           423: ** 32-bit signed integer.  Hence the largest allocation is 0x40000000
        !           424: ** or 1073741824 bytes.
        !           425: */
        !           426: static int memsys5Roundup(int n){
        !           427:   int iFullSz;
        !           428:   if( n > 0x40000000 ) return 0;
        !           429:   for(iFullSz=mem5.szAtom; iFullSz<n; iFullSz *= 2);
        !           430:   return iFullSz;
        !           431: }
        !           432: 
        !           433: /*
        !           434: ** Return the ceiling of the logarithm base 2 of iValue.
        !           435: **
        !           436: ** Examples:   memsys5Log(1) -> 0
        !           437: **             memsys5Log(2) -> 1
        !           438: **             memsys5Log(4) -> 2
        !           439: **             memsys5Log(5) -> 3
        !           440: **             memsys5Log(8) -> 3
        !           441: **             memsys5Log(9) -> 4
        !           442: */
        !           443: static int memsys5Log(int iValue){
        !           444:   int iLog;
        !           445:   for(iLog=0; (iLog<(int)((sizeof(int)*8)-1)) && (1<<iLog)<iValue; iLog++);
        !           446:   return iLog;
        !           447: }
        !           448: 
        !           449: /*
        !           450: ** Initialize the memory allocator.
        !           451: **
        !           452: ** This routine is not threadsafe.  The caller must be holding a mutex
        !           453: ** to prevent multiple threads from entering at the same time.
        !           454: */
        !           455: static int memsys5Init(void *NotUsed){
        !           456:   int ii;            /* Loop counter */
        !           457:   int nByte;         /* Number of bytes of memory available to this allocator */
        !           458:   u8 *zByte;         /* Memory usable by this allocator */
        !           459:   int nMinLog;       /* Log base 2 of minimum allocation size in bytes */
        !           460:   int iOffset;       /* An offset into mem5.aCtrl[] */
        !           461: 
        !           462:   UNUSED_PARAMETER(NotUsed);
        !           463: 
        !           464:   /* For the purposes of this routine, disable the mutex */
        !           465:   mem5.mutex = 0;
        !           466: 
        !           467:   /* The size of a Mem5Link object must be a power of two.  Verify that
        !           468:   ** this is case.
        !           469:   */
        !           470:   assert( (sizeof(Mem5Link)&(sizeof(Mem5Link)-1))==0 );
        !           471: 
        !           472:   nByte = sqlite3GlobalConfig.nHeap;
        !           473:   zByte = (u8*)sqlite3GlobalConfig.pHeap;
        !           474:   assert( zByte!=0 );  /* sqlite3_config() does not allow otherwise */
        !           475: 
        !           476:   /* boundaries on sqlite3GlobalConfig.mnReq are enforced in sqlite3_config() */
        !           477:   nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq);
        !           478:   mem5.szAtom = (1<<nMinLog);
        !           479:   while( (int)sizeof(Mem5Link)>mem5.szAtom ){
        !           480:     mem5.szAtom = mem5.szAtom << 1;
        !           481:   }
        !           482: 
        !           483:   mem5.nBlock = (nByte / (mem5.szAtom+sizeof(u8)));
        !           484:   mem5.zPool = zByte;
        !           485:   mem5.aCtrl = (u8 *)&mem5.zPool[mem5.nBlock*mem5.szAtom];
        !           486: 
        !           487:   for(ii=0; ii<=LOGMAX; ii++){
        !           488:     mem5.aiFreelist[ii] = -1;
        !           489:   }
        !           490: 
        !           491:   iOffset = 0;
        !           492:   for(ii=LOGMAX; ii>=0; ii--){
        !           493:     int nAlloc = (1<<ii);
        !           494:     if( (iOffset+nAlloc)<=mem5.nBlock ){
        !           495:       mem5.aCtrl[iOffset] = ii | CTRL_FREE;
        !           496:       memsys5Link(iOffset, ii);
        !           497:       iOffset += nAlloc;
        !           498:     }
        !           499:     assert((iOffset+nAlloc)>mem5.nBlock);
        !           500:   }
        !           501: 
        !           502:   /* If a mutex is required for normal operation, allocate one */
        !           503:   if( sqlite3GlobalConfig.bMemstat==0 ){
        !           504:     mem5.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
        !           505:   }
        !           506: 
        !           507:   return SQLITE_OK;
        !           508: }
        !           509: 
        !           510: /*
        !           511: ** Deinitialize this module.
        !           512: */
        !           513: static void memsys5Shutdown(void *NotUsed){
        !           514:   UNUSED_PARAMETER(NotUsed);
        !           515:   mem5.mutex = 0;
        !           516:   return;
        !           517: }
        !           518: 
        !           519: #ifdef SQLITE_TEST
        !           520: /*
        !           521: ** Open the file indicated and write a log of all unfreed memory 
        !           522: ** allocations into that log.
        !           523: */
        !           524: void sqlite3Memsys5Dump(const char *zFilename){
        !           525:   FILE *out;
        !           526:   int i, j, n;
        !           527:   int nMinLog;
        !           528: 
        !           529:   if( zFilename==0 || zFilename[0]==0 ){
        !           530:     out = stdout;
        !           531:   }else{
        !           532:     out = fopen(zFilename, "w");
        !           533:     if( out==0 ){
        !           534:       fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
        !           535:                       zFilename);
        !           536:       return;
        !           537:     }
        !           538:   }
        !           539:   memsys5Enter();
        !           540:   nMinLog = memsys5Log(mem5.szAtom);
        !           541:   for(i=0; i<=LOGMAX && i+nMinLog<32; i++){
        !           542:     for(n=0, j=mem5.aiFreelist[i]; j>=0; j = MEM5LINK(j)->next, n++){}
        !           543:     fprintf(out, "freelist items of size %d: %d\n", mem5.szAtom << i, n);
        !           544:   }
        !           545:   fprintf(out, "mem5.nAlloc       = %llu\n", mem5.nAlloc);
        !           546:   fprintf(out, "mem5.totalAlloc   = %llu\n", mem5.totalAlloc);
        !           547:   fprintf(out, "mem5.totalExcess  = %llu\n", mem5.totalExcess);
        !           548:   fprintf(out, "mem5.currentOut   = %u\n", mem5.currentOut);
        !           549:   fprintf(out, "mem5.currentCount = %u\n", mem5.currentCount);
        !           550:   fprintf(out, "mem5.maxOut       = %u\n", mem5.maxOut);
        !           551:   fprintf(out, "mem5.maxCount     = %u\n", mem5.maxCount);
        !           552:   fprintf(out, "mem5.maxRequest   = %u\n", mem5.maxRequest);
        !           553:   memsys5Leave();
        !           554:   if( out==stdout ){
        !           555:     fflush(stdout);
        !           556:   }else{
        !           557:     fclose(out);
        !           558:   }
        !           559: }
        !           560: #endif
        !           561: 
        !           562: /*
        !           563: ** This routine is the only routine in this file with external 
        !           564: ** linkage. It returns a pointer to a static sqlite3_mem_methods
        !           565: ** struct populated with the memsys5 methods.
        !           566: */
        !           567: const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){
        !           568:   static const sqlite3_mem_methods memsys5Methods = {
        !           569:      memsys5Malloc,
        !           570:      memsys5Free,
        !           571:      memsys5Realloc,
        !           572:      memsys5Size,
        !           573:      memsys5Roundup,
        !           574:      memsys5Init,
        !           575:      memsys5Shutdown,
        !           576:      0
        !           577:   };
        !           578:   return &memsys5Methods;
        !           579: }
        !           580: 
        !           581: #endif /* SQLITE_ENABLE_MEMSYS5 */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>