blob: 179528dd0593d8ec7ea67d002c671ec4de9b818d [file] [log] [blame]
drh0d180202008-02-14 23:26:56 +00001/*
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
danielk1977c66c0e12008-06-25 14:26:07 +000016** use of malloc(). The SQLite user supplies 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.
drh0d180202008-02-14 23:26:56 +000022**
danielk1977c66c0e12008-06-25 14:26:07 +000023** This version of the memory allocation subsystem is included
24** in the build only if SQLITE_ENABLE_MEMSYS5 is defined.
drh0d180202008-02-14 23:26:56 +000025**
danielk19776b39c2e2008-06-25 14:57:53 +000026** $Id: mem5.c,v 1.8 2008/06/25 14:57:54 danielk1977 Exp $
drh0d180202008-02-14 23:26:56 +000027*/
28#include "sqliteInt.h"
29
30/*
31** This version of the memory allocator is used only when
32** SQLITE_POW2_MEMORY_SIZE is defined.
33*/
danielk1977c66c0e12008-06-25 14:26:07 +000034#ifdef SQLITE_ENABLE_MEMSYS5
drh0d180202008-02-14 23:26:56 +000035
36/*
drh2d7636e2008-02-16 16:21:45 +000037** Log2 of the minimum size of an allocation. For example, if
38** 4 then all allocations will be rounded up to at least 16 bytes.
39** If 5 then all allocations will be rounded up to at least 32 bytes.
drh0d180202008-02-14 23:26:56 +000040*/
drh2d7636e2008-02-16 16:21:45 +000041#ifndef SQLITE_POW2_LOGMIN
42# define SQLITE_POW2_LOGMIN 6
43#endif
44#define POW2_MIN (1<<SQLITE_POW2_LOGMIN)
drh0d180202008-02-14 23:26:56 +000045
46/*
drh2d7636e2008-02-16 16:21:45 +000047** Log2 of the maximum size of an allocation.
drh0d180202008-02-14 23:26:56 +000048*/
drh2d7636e2008-02-16 16:21:45 +000049#ifndef SQLITE_POW2_LOGMAX
50# define SQLITE_POW2_LOGMAX 18
51#endif
52#define POW2_MAX (((unsigned int)1)<<SQLITE_POW2_LOGMAX)
drh0d180202008-02-14 23:26:56 +000053
54/*
drh2d7636e2008-02-16 16:21:45 +000055** Number of distinct allocation sizes.
drh0d180202008-02-14 23:26:56 +000056*/
drh2d7636e2008-02-16 16:21:45 +000057#define NSIZE (SQLITE_POW2_LOGMAX - SQLITE_POW2_LOGMIN + 1)
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*/
64typedef struct Mem5Block Mem5Block;
65struct Mem5Block {
drh0d180202008-02-14 23:26:56 +000066 union {
drh2d7636e2008-02-16 16:21:45 +000067 char aData[POW2_MIN];
drh0d180202008-02-14 23:26:56 +000068 struct {
danielk1977c66c0e12008-06-25 14:26:07 +000069 int next; /* Index in mem5.aPool[] of next free chunk */
70 int prev; /* Index in mem5.aPool[] of previous free chunk */
drh0d180202008-02-14 23:26:56 +000071 } list;
72 } u;
73};
74
75/*
drh2d7636e2008-02-16 16:21:45 +000076** The size in blocks of an POW2_MAX allocation
77*/
78#define SZ_MAX (1<<(NSIZE-1))
79
80/*
danielk1977c66c0e12008-06-25 14:26:07 +000081** Masks used for mem5.aCtrl[] elements.
drh2d7636e2008-02-16 16:21:45 +000082*/
83#define CTRL_LOGSIZE 0x1f /* Log2 Size of this block relative to POW2_MIN */
84#define CTRL_FREE 0x20 /* True if not checked out */
85
86/*
drh0d180202008-02-14 23:26:56 +000087** All of the static variables used by this module are collected
danielk1977c66c0e12008-06-25 14:26:07 +000088** into a single structure named "mem5". This is to keep the
drh0d180202008-02-14 23:26:56 +000089** static variables organized and to reduce namespace pollution
90** when this module is combined with other in the amalgamation.
91*/
92static struct {
93 /*
danielk1977c66c0e12008-06-25 14:26:07 +000094 ** The alarm callback and its arguments. The mem5.mutex lock will
drheee4c8c2008-02-18 22:24:57 +000095 ** be held while the callback is running. Recursive calls into
96 ** the memory subsystem are allowed, but no new callbacks will be
97 ** issued. The alarmBusy variable is set to prevent recursive
98 ** callbacks.
drh0d180202008-02-14 23:26:56 +000099 */
drheee4c8c2008-02-18 22:24:57 +0000100 sqlite3_int64 alarmThreshold;
101 void (*alarmCallback)(void*, sqlite3_int64,int);
102 void *alarmArg;
drh0d180202008-02-14 23:26:56 +0000103 int alarmBusy;
104
105 /*
106 ** Mutex to control access to the memory allocation subsystem.
107 */
108 sqlite3_mutex *mutex;
drh2d7636e2008-02-16 16:21:45 +0000109
110 /*
111 ** Performance statistics
112 */
113 u64 nAlloc; /* Total number of calls to malloc */
114 u64 totalAlloc; /* Total of all malloc calls - includes internal frag */
115 u64 totalExcess; /* Total internal fragmentation */
116 u32 currentOut; /* Current checkout, including internal fragmentation */
117 u32 currentCount; /* Current number of distinct checkouts */
118 u32 maxOut; /* Maximum instantaneous currentOut */
119 u32 maxCount; /* Maximum instantaneous currentCount */
120 u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
drh0d180202008-02-14 23:26:56 +0000121
122 /*
drh2d7636e2008-02-16 16:21:45 +0000123 ** Lists of free blocks of various sizes.
drh0d180202008-02-14 23:26:56 +0000124 */
drh2d7636e2008-02-16 16:21:45 +0000125 int aiFreelist[NSIZE];
drh0d180202008-02-14 23:26:56 +0000126
127 /*
drh2d7636e2008-02-16 16:21:45 +0000128 ** Space for tracking which blocks are checked out and the size
129 ** of each block. One byte per block.
drh0d180202008-02-14 23:26:56 +0000130 */
danielk1977c66c0e12008-06-25 14:26:07 +0000131 u8 *aCtrl;
drh0d180202008-02-14 23:26:56 +0000132
133 /*
134 ** Memory available for allocation
135 */
danielk1977c66c0e12008-06-25 14:26:07 +0000136 int nBlock;
137 Mem5Block *aPool;
138} mem5;
drh0d180202008-02-14 23:26:56 +0000139
140/*
danielk1977c66c0e12008-06-25 14:26:07 +0000141** Unlink the chunk at mem5.aPool[i] from list it is currently
142** on. It should be found on mem5.aiFreelist[iLogsize].
drh0d180202008-02-14 23:26:56 +0000143*/
drh2d7636e2008-02-16 16:21:45 +0000144static void memsys5Unlink(int i, int iLogsize){
145 int next, prev;
danielk1977c66c0e12008-06-25 14:26:07 +0000146 assert( i>=0 && i<mem5.nBlock );
drh2d7636e2008-02-16 16:21:45 +0000147 assert( iLogsize>=0 && iLogsize<NSIZE );
danielk1977c66c0e12008-06-25 14:26:07 +0000148 assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
drh2d7636e2008-02-16 16:21:45 +0000149
danielk1977c66c0e12008-06-25 14:26:07 +0000150 next = mem5.aPool[i].u.list.next;
151 prev = mem5.aPool[i].u.list.prev;
drh2d7636e2008-02-16 16:21:45 +0000152 if( prev<0 ){
danielk1977c66c0e12008-06-25 14:26:07 +0000153 mem5.aiFreelist[iLogsize] = next;
drh0d180202008-02-14 23:26:56 +0000154 }else{
danielk1977c66c0e12008-06-25 14:26:07 +0000155 mem5.aPool[prev].u.list.next = next;
drh0d180202008-02-14 23:26:56 +0000156 }
drh2d7636e2008-02-16 16:21:45 +0000157 if( next>=0 ){
danielk1977c66c0e12008-06-25 14:26:07 +0000158 mem5.aPool[next].u.list.prev = prev;
drh0d180202008-02-14 23:26:56 +0000159 }
drh0d180202008-02-14 23:26:56 +0000160}
161
162/*
danielk1977c66c0e12008-06-25 14:26:07 +0000163** Link the chunk at mem5.aPool[i] so that is on the iLogsize
drh2d7636e2008-02-16 16:21:45 +0000164** free list.
drh0d180202008-02-14 23:26:56 +0000165*/
drh2d7636e2008-02-16 16:21:45 +0000166static void memsys5Link(int i, int iLogsize){
167 int x;
danielk1977c66c0e12008-06-25 14:26:07 +0000168 assert( sqlite3_mutex_held(mem5.mutex) );
169 assert( i>=0 && i<mem5.nBlock );
drh2d7636e2008-02-16 16:21:45 +0000170 assert( iLogsize>=0 && iLogsize<NSIZE );
danielk1977c66c0e12008-06-25 14:26:07 +0000171 assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
drh0d180202008-02-14 23:26:56 +0000172
danielk1977c66c0e12008-06-25 14:26:07 +0000173 mem5.aPool[i].u.list.next = x = mem5.aiFreelist[iLogsize];
174 mem5.aPool[i].u.list.prev = -1;
drh2d7636e2008-02-16 16:21:45 +0000175 if( x>=0 ){
danielk1977c66c0e12008-06-25 14:26:07 +0000176 assert( x<mem5.nBlock );
177 mem5.aPool[x].u.list.prev = i;
drh0d180202008-02-14 23:26:56 +0000178 }
danielk1977c66c0e12008-06-25 14:26:07 +0000179 mem5.aiFreelist[iLogsize] = i;
drh0d180202008-02-14 23:26:56 +0000180}
181
182/*
danielk19776b39c2e2008-06-25 14:57:53 +0000183** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
184** will already be held (obtained by code in malloc.c) if
185** sqlite3Config.bMemStat is true.
drh0d180202008-02-14 23:26:56 +0000186*/
drh2d7636e2008-02-16 16:21:45 +0000187static void memsys5Enter(void){
danielk19776b39c2e2008-06-25 14:57:53 +0000188 if( sqlite3Config.bMemstat==0 && mem5.mutex==0 ){
189 mem5.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
190 }
191 sqlite3_mutex_enter(mem5.mutex);
drh0d180202008-02-14 23:26:56 +0000192}
danielk1977c66c0e12008-06-25 14:26:07 +0000193static void memsys5Leave(void){
danielk19776b39c2e2008-06-25 14:57:53 +0000194 sqlite3_mutex_leave(mem5.mutex);
drh0d180202008-02-14 23:26:56 +0000195}
196
197/*
drh0d180202008-02-14 23:26:56 +0000198** 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*/
danielk1977c66c0e12008-06-25 14:26:07 +0000202static int memsys5Size(void *p){
drh0d180202008-02-14 23:26:56 +0000203 int iSize = 0;
204 if( p ){
danielk1977c66c0e12008-06-25 14:26:07 +0000205 int i = ((Mem5Block*)p) - mem5.aPool;
206 assert( i>=0 && i<mem5.nBlock );
207 iSize = 1 << ((mem5.aCtrl[i]&CTRL_LOGSIZE) + SQLITE_POW2_LOGMIN);
drh0d180202008-02-14 23:26:56 +0000208 }
209 return iSize;
210}
211
212/*
drh2d7636e2008-02-16 16:21:45 +0000213** Find the first entry on the freelist iLogsize. Unlink that
214** entry and return its index.
drh0d180202008-02-14 23:26:56 +0000215*/
drh2d7636e2008-02-16 16:21:45 +0000216static int memsys5UnlinkFirst(int iLogsize){
217 int i;
218 int iFirst;
drh0d180202008-02-14 23:26:56 +0000219
drh2d7636e2008-02-16 16:21:45 +0000220 assert( iLogsize>=0 && iLogsize<NSIZE );
danielk1977c66c0e12008-06-25 14:26:07 +0000221 i = iFirst = mem5.aiFreelist[iLogsize];
drh2d7636e2008-02-16 16:21:45 +0000222 assert( iFirst>=0 );
223 while( i>0 ){
224 if( i<iFirst ) iFirst = i;
danielk1977c66c0e12008-06-25 14:26:07 +0000225 i = mem5.aPool[i].u.list.next;
drh0d180202008-02-14 23:26:56 +0000226 }
drh2d7636e2008-02-16 16:21:45 +0000227 memsys5Unlink(iFirst, iLogsize);
228 return iFirst;
drh0d180202008-02-14 23:26:56 +0000229}
230
231/*
232** Return a block of memory of at least nBytes in size.
233** Return NULL if unable.
234*/
danielk1977c66c0e12008-06-25 14:26:07 +0000235static void *memsys5MallocUnsafe(int nByte){
236 int i; /* Index of a mem5.aPool[] slot */
237 int iBin; /* Index into mem5.aiFreelist[] */
drh2d7636e2008-02-16 16:21:45 +0000238 int iFullSz; /* Size of allocation rounded up to power of 2 */
239 int iLogsize; /* Log2 of iFullSz/POW2_MIN */
drh0d180202008-02-14 23:26:56 +0000240
drheee4c8c2008-02-18 22:24:57 +0000241 /* Keep track of the maximum allocation request. Even unfulfilled
242 ** requests are counted */
danielk1977c66c0e12008-06-25 14:26:07 +0000243 if( nByte>mem5.maxRequest ){
244 mem5.maxRequest = nByte;
drheee4c8c2008-02-18 22:24:57 +0000245 }
246
drheee4c8c2008-02-18 22:24:57 +0000247 /* Round nByte up to the next valid power of two */
drh2d7636e2008-02-16 16:21:45 +0000248 if( nByte>POW2_MAX ) return 0;
249 for(iFullSz=POW2_MIN, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
drh0d180202008-02-14 23:26:56 +0000250
danielk1977c66c0e12008-06-25 14:26:07 +0000251 /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
drheee4c8c2008-02-18 22:24:57 +0000252 ** block. If not, then split a block of the next larger power of
253 ** two in order to create a new free block of size iLogsize.
254 */
danielk1977c66c0e12008-06-25 14:26:07 +0000255 for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<NSIZE; iBin++){}
drh2d7636e2008-02-16 16:21:45 +0000256 if( iBin>=NSIZE ) return 0;
257 i = memsys5UnlinkFirst(iBin);
258 while( iBin>iLogsize ){
259 int newSize;
260
261 iBin--;
262 newSize = 1 << iBin;
danielk1977c66c0e12008-06-25 14:26:07 +0000263 mem5.aCtrl[i+newSize] = CTRL_FREE | iBin;
drh2d7636e2008-02-16 16:21:45 +0000264 memsys5Link(i+newSize, iBin);
drh0d180202008-02-14 23:26:56 +0000265 }
danielk1977c66c0e12008-06-25 14:26:07 +0000266 mem5.aCtrl[i] = iLogsize;
drh0d180202008-02-14 23:26:56 +0000267
drheee4c8c2008-02-18 22:24:57 +0000268 /* Update allocator performance statistics. */
danielk1977c66c0e12008-06-25 14:26:07 +0000269 mem5.nAlloc++;
270 mem5.totalAlloc += iFullSz;
271 mem5.totalExcess += iFullSz - nByte;
272 mem5.currentCount++;
273 mem5.currentOut += iFullSz;
274 if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
275 if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
drh0d180202008-02-14 23:26:56 +0000276
drheee4c8c2008-02-18 22:24:57 +0000277 /* Return a pointer to the allocated memory. */
danielk1977c66c0e12008-06-25 14:26:07 +0000278 return (void*)&mem5.aPool[i];
drh0d180202008-02-14 23:26:56 +0000279}
280
281/*
282** Free an outstanding memory allocation.
283*/
danielk1977c66c0e12008-06-25 14:26:07 +0000284static void memsys5FreeUnsafe(void *pOld){
drh2d7636e2008-02-16 16:21:45 +0000285 u32 size, iLogsize;
drh0d180202008-02-14 23:26:56 +0000286 int i;
drh0d180202008-02-14 23:26:56 +0000287
danielk1977c66c0e12008-06-25 14:26:07 +0000288 i = ((Mem5Block*)pOld) - mem5.aPool;
289 assert( i>=0 && i<mem5.nBlock );
290 assert( (mem5.aCtrl[i] & CTRL_FREE)==0 );
291 iLogsize = mem5.aCtrl[i] & CTRL_LOGSIZE;
drh2d7636e2008-02-16 16:21:45 +0000292 size = 1<<iLogsize;
danielk1977c66c0e12008-06-25 14:26:07 +0000293 assert( i+size-1<mem5.nBlock );
294 mem5.aCtrl[i] |= CTRL_FREE;
295 mem5.aCtrl[i+size-1] |= CTRL_FREE;
296 assert( mem5.currentCount>0 );
297 assert( mem5.currentOut>=0 );
298 mem5.currentCount--;
299 mem5.currentOut -= size*POW2_MIN;
300 assert( mem5.currentOut>0 || mem5.currentCount==0 );
301 assert( mem5.currentCount>0 || mem5.currentOut==0 );
drh2d7636e2008-02-16 16:21:45 +0000302
danielk1977c66c0e12008-06-25 14:26:07 +0000303 mem5.aCtrl[i] = CTRL_FREE | iLogsize;
drh2d7636e2008-02-16 16:21:45 +0000304 while( iLogsize<NSIZE-1 ){
305 int iBuddy;
306
307 if( (i>>iLogsize) & 1 ){
308 iBuddy = i - size;
309 }else{
310 iBuddy = i + size;
drh0d180202008-02-14 23:26:56 +0000311 }
danielk1977c66c0e12008-06-25 14:26:07 +0000312 assert( iBuddy>=0 && iBuddy<mem5.nBlock );
313 if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;
drh2d7636e2008-02-16 16:21:45 +0000314 memsys5Unlink(iBuddy, iLogsize);
315 iLogsize++;
316 if( iBuddy<i ){
danielk1977c66c0e12008-06-25 14:26:07 +0000317 mem5.aCtrl[iBuddy] = CTRL_FREE | iLogsize;
318 mem5.aCtrl[i] = 0;
drh2d7636e2008-02-16 16:21:45 +0000319 i = iBuddy;
320 }else{
danielk1977c66c0e12008-06-25 14:26:07 +0000321 mem5.aCtrl[i] = CTRL_FREE | iLogsize;
322 mem5.aCtrl[iBuddy] = 0;
drh0d180202008-02-14 23:26:56 +0000323 }
drh2d7636e2008-02-16 16:21:45 +0000324 size *= 2;
drh0d180202008-02-14 23:26:56 +0000325 }
drh2d7636e2008-02-16 16:21:45 +0000326 memsys5Link(i, iLogsize);
drh0d180202008-02-14 23:26:56 +0000327}
328
329/*
330** Allocate nBytes of memory
331*/
danielk1977c66c0e12008-06-25 14:26:07 +0000332static void *memsys5Malloc(int nBytes){
drh0d180202008-02-14 23:26:56 +0000333 sqlite3_int64 *p = 0;
334 if( nBytes>0 ){
drh2d7636e2008-02-16 16:21:45 +0000335 memsys5Enter();
danielk1977c66c0e12008-06-25 14:26:07 +0000336 p = memsys5MallocUnsafe(nBytes);
337 memsys5Leave();
drh0d180202008-02-14 23:26:56 +0000338 }
339 return (void*)p;
340}
341
342/*
343** Free memory.
344*/
danielk1977c66c0e12008-06-25 14:26:07 +0000345static void memsys5Free(void *pPrior){
drh0d180202008-02-14 23:26:56 +0000346 if( pPrior==0 ){
347 return;
348 }
danielk1977c66c0e12008-06-25 14:26:07 +0000349 memsys5Enter();
350 memsys5FreeUnsafe(pPrior);
351 memsys5Leave();
drh0d180202008-02-14 23:26:56 +0000352}
353
354/*
355** Change the size of an existing memory allocation
356*/
danielk1977c66c0e12008-06-25 14:26:07 +0000357static void *memsys5Realloc(void *pPrior, int nBytes){
drh0d180202008-02-14 23:26:56 +0000358 int nOld;
359 void *p;
360 if( pPrior==0 ){
danielk1977c66c0e12008-06-25 14:26:07 +0000361 return memsys5Malloc(nBytes);
drh0d180202008-02-14 23:26:56 +0000362 }
363 if( nBytes<=0 ){
danielk1977c66c0e12008-06-25 14:26:07 +0000364 memsys5Free(pPrior);
drh0d180202008-02-14 23:26:56 +0000365 return 0;
366 }
danielk1977c66c0e12008-06-25 14:26:07 +0000367 nOld = memsys5Size(pPrior);
drh2d7636e2008-02-16 16:21:45 +0000368 if( nBytes<=nOld ){
drh0d180202008-02-14 23:26:56 +0000369 return pPrior;
370 }
danielk1977c66c0e12008-06-25 14:26:07 +0000371 memsys5Enter();
372 p = memsys5MallocUnsafe(nBytes);
drh0d180202008-02-14 23:26:56 +0000373 if( p ){
drh2d7636e2008-02-16 16:21:45 +0000374 memcpy(p, pPrior, nOld);
danielk1977c66c0e12008-06-25 14:26:07 +0000375 memsys5FreeUnsafe(pPrior);
drh0d180202008-02-14 23:26:56 +0000376 }
danielk1977c66c0e12008-06-25 14:26:07 +0000377 memsys5Leave();
drh0d180202008-02-14 23:26:56 +0000378 return p;
379}
380
381/*
danielk1977c66c0e12008-06-25 14:26:07 +0000382** Round up a request size to the next valid allocation size.
383*/
384static int memsys5Roundup(int n){
385 int iFullSz;
386 for(iFullSz=POW2_MIN; iFullSz<n; iFullSz *= 2);
387 return iFullSz;
388}
389
390/*
391** Initialize this module.
392*/
393static int memsys5Init(void *NotUsed){
394 return SQLITE_OK;
395}
396
397/*
398** Deinitialize this module.
399*/
400static void memsys5Shutdown(void *NotUsed){
401 return;
402}
403
404/*
drh0d180202008-02-14 23:26:56 +0000405** Open the file indicated and write a log of all unfreed memory
406** allocations into that log.
407*/
danielk1977c66c0e12008-06-25 14:26:07 +0000408void sqlite3Memsys5Dump(const char *zFilename){
drh0d180202008-02-14 23:26:56 +0000409#ifdef SQLITE_DEBUG
410 FILE *out;
drh2d7636e2008-02-16 16:21:45 +0000411 int i, j, n;
412
drh0d180202008-02-14 23:26:56 +0000413 if( zFilename==0 || zFilename[0]==0 ){
414 out = stdout;
415 }else{
416 out = fopen(zFilename, "w");
417 if( out==0 ){
418 fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
419 zFilename);
420 return;
421 }
422 }
drh2d7636e2008-02-16 16:21:45 +0000423 memsys5Enter();
424 for(i=0; i<NSIZE; i++){
danielk1977c66c0e12008-06-25 14:26:07 +0000425 for(n=0, j=mem5.aiFreelist[i]; j>=0; j = mem5.aPool[j].u.list.next, n++){}
drh2d7636e2008-02-16 16:21:45 +0000426 fprintf(out, "freelist items of size %d: %d\n", POW2_MIN << i, n);
drh0d180202008-02-14 23:26:56 +0000427 }
danielk1977c66c0e12008-06-25 14:26:07 +0000428 fprintf(out, "mem5.nAlloc = %llu\n", mem5.nAlloc);
429 fprintf(out, "mem5.totalAlloc = %llu\n", mem5.totalAlloc);
430 fprintf(out, "mem5.totalExcess = %llu\n", mem5.totalExcess);
431 fprintf(out, "mem5.currentOut = %u\n", mem5.currentOut);
432 fprintf(out, "mem5.currentCount = %u\n", mem5.currentCount);
433 fprintf(out, "mem5.maxOut = %u\n", mem5.maxOut);
434 fprintf(out, "mem5.maxCount = %u\n", mem5.maxCount);
435 fprintf(out, "mem5.maxRequest = %u\n", mem5.maxRequest);
436 memsys5Leave();
drh0d180202008-02-14 23:26:56 +0000437 if( out==stdout ){
438 fflush(stdout);
439 }else{
440 fclose(out);
441 }
442#endif
443}
444
danielk1977c66c0e12008-06-25 14:26:07 +0000445/*
446** This routine is the only routine in this file with external
447** linkage.
448**
449** Populate the low-level memory allocation function pointers in
450** sqlite3Config.m with pointers to the routines in this file. The
451** arguments specify the block of memory to manage.
452**
453** This routine is only called by sqlite3_config(), and therefore
454** is not required to be threadsafe (it is not).
455*/
456void sqlite3MemSetMemsys5(u8 *zByte, int nByte){
457 static const sqlite3_mem_methods memsys5Methods = {
458 memsys5Malloc,
459 memsys5Free,
460 memsys5Realloc,
461 memsys5Size,
462 memsys5Roundup,
463 memsys5Init,
464 memsys5Shutdown,
465 0
466 };
467 int i;
drh0d180202008-02-14 23:26:56 +0000468
danielk1977c66c0e12008-06-25 14:26:07 +0000469 mem5.nBlock = (nByte / (sizeof(Mem5Block)+sizeof(u8)));
470 mem5.nBlock -= (mem5.nBlock%SZ_MAX);
471 mem5.aPool = (Mem5Block *)zByte;
472 mem5.aCtrl = (u8 *)&mem5.aPool[mem5.nBlock];
473
474 assert( sizeof(Mem5Block)==POW2_MIN );
475 assert( mem5.nBlock>=SZ_MAX );
476 assert( (mem5.nBlock%SZ_MAX)==0 );
477
478 for(i=0; i<NSIZE; i++) mem5.aiFreelist[i] = -1;
479 for(i=0; i<=mem5.nBlock-SZ_MAX; i += SZ_MAX){
480 mem5.aCtrl[i] = (NSIZE-1) | CTRL_FREE;
481 memsys5Link(i, NSIZE-1);
482 }
483
484 /* Configure the functions to call to allocate memory. */
485 sqlite3_config(SQLITE_CONFIG_MALLOC, &memsys5Methods);
486}
487
488#endif /* SQLITE_ENABLE_MEMSYS5 */