blob: acbe92d15d65cb21b79eaa3a66fde555db2ef66c [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**
danielk19775099be52008-06-27 13:27:03 +000026** $Id: mem5.c,v 1.9 2008/06/27 13:27:04 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
drh0d180202008-02-14 23:26:56 +000044
45/*
drh2d7636e2008-02-16 16:21:45 +000046** Log2 of the maximum size of an allocation.
drh0d180202008-02-14 23:26:56 +000047*/
drh2d7636e2008-02-16 16:21:45 +000048#ifndef SQLITE_POW2_LOGMAX
49# define SQLITE_POW2_LOGMAX 18
50#endif
51#define POW2_MAX (((unsigned int)1)<<SQLITE_POW2_LOGMAX)
drh0d180202008-02-14 23:26:56 +000052
53/*
drh2d7636e2008-02-16 16:21:45 +000054** Number of distinct allocation sizes.
drh0d180202008-02-14 23:26:56 +000055*/
drh2d7636e2008-02-16 16:21:45 +000056#define NSIZE (SQLITE_POW2_LOGMAX - SQLITE_POW2_LOGMIN + 1)
57
58/*
59** A minimum allocation is an instance of the following structure.
60** Larger allocations are an array of these structures where the
61** size of the array is a power of 2.
62*/
danielk19775099be52008-06-27 13:27:03 +000063typedef struct Mem5Link Mem5Link;
64struct Mem5Link {
65 int next; /* Index of next free chunk */
66 int prev; /* Index of previous free chunk */
drh0d180202008-02-14 23:26:56 +000067};
68
69/*
danielk19775099be52008-06-27 13:27:03 +000070** Maximum size of any allocation is ((1<<LOGMAX)*mem5.nAtom). Since
71** mem5.nAtom is always at least 8, this is not really a practical
72** limitation.
drh2d7636e2008-02-16 16:21:45 +000073*/
danielk19775099be52008-06-27 13:27:03 +000074#define LOGMAX 30
drh2d7636e2008-02-16 16:21:45 +000075
76/*
danielk1977c66c0e12008-06-25 14:26:07 +000077** Masks used for mem5.aCtrl[] elements.
drh2d7636e2008-02-16 16:21:45 +000078*/
79#define CTRL_LOGSIZE 0x1f /* Log2 Size of this block relative to POW2_MIN */
80#define CTRL_FREE 0x20 /* True if not checked out */
81
82/*
drh0d180202008-02-14 23:26:56 +000083** All of the static variables used by this module are collected
danielk1977c66c0e12008-06-25 14:26:07 +000084** into a single structure named "mem5". This is to keep the
drh0d180202008-02-14 23:26:56 +000085** static variables organized and to reduce namespace pollution
86** when this module is combined with other in the amalgamation.
87*/
88static struct {
89 /*
danielk1977c66c0e12008-06-25 14:26:07 +000090 ** The alarm callback and its arguments. The mem5.mutex lock will
drheee4c8c2008-02-18 22:24:57 +000091 ** be held while the callback is running. Recursive calls into
92 ** the memory subsystem are allowed, but no new callbacks will be
93 ** issued. The alarmBusy variable is set to prevent recursive
94 ** callbacks.
drh0d180202008-02-14 23:26:56 +000095 */
drheee4c8c2008-02-18 22:24:57 +000096 sqlite3_int64 alarmThreshold;
97 void (*alarmCallback)(void*, sqlite3_int64,int);
98 void *alarmArg;
drh0d180202008-02-14 23:26:56 +000099 int alarmBusy;
100
101 /*
102 ** Mutex to control access to the memory allocation subsystem.
103 */
104 sqlite3_mutex *mutex;
drh2d7636e2008-02-16 16:21:45 +0000105
106 /*
107 ** Performance statistics
108 */
109 u64 nAlloc; /* Total number of calls to malloc */
110 u64 totalAlloc; /* Total of all malloc calls - includes internal frag */
111 u64 totalExcess; /* Total internal fragmentation */
112 u32 currentOut; /* Current checkout, including internal fragmentation */
113 u32 currentCount; /* Current number of distinct checkouts */
114 u32 maxOut; /* Maximum instantaneous currentOut */
115 u32 maxCount; /* Maximum instantaneous currentCount */
116 u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
drh0d180202008-02-14 23:26:56 +0000117
118 /*
drh2d7636e2008-02-16 16:21:45 +0000119 ** Lists of free blocks of various sizes.
drh0d180202008-02-14 23:26:56 +0000120 */
danielk19775099be52008-06-27 13:27:03 +0000121 int aiFreelist[LOGMAX+1];
drh0d180202008-02-14 23:26:56 +0000122
123 /*
drh2d7636e2008-02-16 16:21:45 +0000124 ** Space for tracking which blocks are checked out and the size
125 ** of each block. One byte per block.
drh0d180202008-02-14 23:26:56 +0000126 */
danielk1977c66c0e12008-06-25 14:26:07 +0000127 u8 *aCtrl;
drh0d180202008-02-14 23:26:56 +0000128
129 /*
130 ** Memory available for allocation
131 */
danielk19775099be52008-06-27 13:27:03 +0000132 int nAtom; /* Smallest possible allocation in bytes */
133 int nBlock; /* Number of nAtom sized blocks in zPool */
134 u8 *zPool;
danielk1977c66c0e12008-06-25 14:26:07 +0000135} mem5;
drh0d180202008-02-14 23:26:56 +0000136
danielk19775099be52008-06-27 13:27:03 +0000137#define MEM5LINK(idx) ((Mem5Link *)(&mem5.zPool[(idx)*mem5.nAtom]))
138
drh0d180202008-02-14 23:26:56 +0000139/*
danielk1977c66c0e12008-06-25 14:26:07 +0000140** Unlink the chunk at mem5.aPool[i] from list it is currently
141** on. It should be found on mem5.aiFreelist[iLogsize].
drh0d180202008-02-14 23:26:56 +0000142*/
drh2d7636e2008-02-16 16:21:45 +0000143static void memsys5Unlink(int i, int iLogsize){
144 int next, prev;
danielk1977c66c0e12008-06-25 14:26:07 +0000145 assert( i>=0 && i<mem5.nBlock );
danielk19775099be52008-06-27 13:27:03 +0000146 assert( iLogsize>=0 && iLogsize<=LOGMAX );
danielk1977c66c0e12008-06-25 14:26:07 +0000147 assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
drh2d7636e2008-02-16 16:21:45 +0000148
danielk19775099be52008-06-27 13:27:03 +0000149 next = MEM5LINK(i)->next;
150 prev = MEM5LINK(i)->prev;
drh2d7636e2008-02-16 16:21:45 +0000151 if( prev<0 ){
danielk1977c66c0e12008-06-25 14:26:07 +0000152 mem5.aiFreelist[iLogsize] = next;
drh0d180202008-02-14 23:26:56 +0000153 }else{
danielk19775099be52008-06-27 13:27:03 +0000154 MEM5LINK(prev)->next = next;
drh0d180202008-02-14 23:26:56 +0000155 }
drh2d7636e2008-02-16 16:21:45 +0000156 if( next>=0 ){
danielk19775099be52008-06-27 13:27:03 +0000157 MEM5LINK(next)->prev = prev;
drh0d180202008-02-14 23:26:56 +0000158 }
drh0d180202008-02-14 23:26:56 +0000159}
160
161/*
danielk1977c66c0e12008-06-25 14:26:07 +0000162** Link the chunk at mem5.aPool[i] so that is on the iLogsize
drh2d7636e2008-02-16 16:21:45 +0000163** free list.
drh0d180202008-02-14 23:26:56 +0000164*/
drh2d7636e2008-02-16 16:21:45 +0000165static void memsys5Link(int i, int iLogsize){
166 int x;
danielk1977c66c0e12008-06-25 14:26:07 +0000167 assert( sqlite3_mutex_held(mem5.mutex) );
168 assert( i>=0 && i<mem5.nBlock );
danielk19775099be52008-06-27 13:27:03 +0000169 assert( iLogsize>=0 && iLogsize<=LOGMAX );
danielk1977c66c0e12008-06-25 14:26:07 +0000170 assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
drh0d180202008-02-14 23:26:56 +0000171
danielk19775099be52008-06-27 13:27:03 +0000172 x = MEM5LINK(i)->next = mem5.aiFreelist[iLogsize];
173 MEM5LINK(i)->prev = -1;
drh2d7636e2008-02-16 16:21:45 +0000174 if( x>=0 ){
danielk1977c66c0e12008-06-25 14:26:07 +0000175 assert( x<mem5.nBlock );
danielk19775099be52008-06-27 13:27:03 +0000176 MEM5LINK(x)->prev = i;
drh0d180202008-02-14 23:26:56 +0000177 }
danielk1977c66c0e12008-06-25 14:26:07 +0000178 mem5.aiFreelist[iLogsize] = i;
drh0d180202008-02-14 23:26:56 +0000179}
180
181/*
danielk19776b39c2e2008-06-25 14:57:53 +0000182** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
183** will already be held (obtained by code in malloc.c) if
184** sqlite3Config.bMemStat is true.
drh0d180202008-02-14 23:26:56 +0000185*/
drh2d7636e2008-02-16 16:21:45 +0000186static void memsys5Enter(void){
danielk19776b39c2e2008-06-25 14:57:53 +0000187 if( sqlite3Config.bMemstat==0 && mem5.mutex==0 ){
188 mem5.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
189 }
190 sqlite3_mutex_enter(mem5.mutex);
drh0d180202008-02-14 23:26:56 +0000191}
danielk1977c66c0e12008-06-25 14:26:07 +0000192static void memsys5Leave(void){
danielk19776b39c2e2008-06-25 14:57:53 +0000193 sqlite3_mutex_leave(mem5.mutex);
drh0d180202008-02-14 23:26:56 +0000194}
195
196/*
drh0d180202008-02-14 23:26:56 +0000197** Return the size of an outstanding allocation, in bytes. The
198** size returned omits the 8-byte header overhead. This only
199** works for chunks that are currently checked out.
200*/
danielk1977c66c0e12008-06-25 14:26:07 +0000201static int memsys5Size(void *p){
drh0d180202008-02-14 23:26:56 +0000202 int iSize = 0;
203 if( p ){
danielk19775099be52008-06-27 13:27:03 +0000204 int i = ((u8 *)p-mem5.zPool)/mem5.nAtom;
danielk1977c66c0e12008-06-25 14:26:07 +0000205 assert( i>=0 && i<mem5.nBlock );
danielk19775099be52008-06-27 13:27:03 +0000206 iSize = mem5.nAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
drh0d180202008-02-14 23:26:56 +0000207 }
208 return iSize;
209}
210
211/*
drh2d7636e2008-02-16 16:21:45 +0000212** Find the first entry on the freelist iLogsize. Unlink that
213** entry and return its index.
drh0d180202008-02-14 23:26:56 +0000214*/
drh2d7636e2008-02-16 16:21:45 +0000215static int memsys5UnlinkFirst(int iLogsize){
216 int i;
217 int iFirst;
drh0d180202008-02-14 23:26:56 +0000218
danielk19775099be52008-06-27 13:27:03 +0000219 assert( iLogsize>=0 && iLogsize<=LOGMAX );
danielk1977c66c0e12008-06-25 14:26:07 +0000220 i = iFirst = mem5.aiFreelist[iLogsize];
drh2d7636e2008-02-16 16:21:45 +0000221 assert( iFirst>=0 );
222 while( i>0 ){
223 if( i<iFirst ) iFirst = i;
danielk19775099be52008-06-27 13:27:03 +0000224 i = MEM5LINK(i)->next;
drh0d180202008-02-14 23:26:56 +0000225 }
drh2d7636e2008-02-16 16:21:45 +0000226 memsys5Unlink(iFirst, iLogsize);
227 return iFirst;
drh0d180202008-02-14 23:26:56 +0000228}
229
230/*
231** Return a block of memory of at least nBytes in size.
232** Return NULL if unable.
233*/
danielk1977c66c0e12008-06-25 14:26:07 +0000234static void *memsys5MallocUnsafe(int nByte){
235 int i; /* Index of a mem5.aPool[] slot */
236 int iBin; /* Index into mem5.aiFreelist[] */
drh2d7636e2008-02-16 16:21:45 +0000237 int iFullSz; /* Size of allocation rounded up to power of 2 */
238 int iLogsize; /* Log2 of iFullSz/POW2_MIN */
drh0d180202008-02-14 23:26:56 +0000239
drheee4c8c2008-02-18 22:24:57 +0000240 /* Keep track of the maximum allocation request. Even unfulfilled
241 ** requests are counted */
danielk1977c66c0e12008-06-25 14:26:07 +0000242 if( nByte>mem5.maxRequest ){
243 mem5.maxRequest = nByte;
drheee4c8c2008-02-18 22:24:57 +0000244 }
245
drheee4c8c2008-02-18 22:24:57 +0000246 /* Round nByte up to the next valid power of two */
drh2d7636e2008-02-16 16:21:45 +0000247 if( nByte>POW2_MAX ) return 0;
danielk19775099be52008-06-27 13:27:03 +0000248 for(iFullSz=mem5.nAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
drh0d180202008-02-14 23:26:56 +0000249
danielk1977c66c0e12008-06-25 14:26:07 +0000250 /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
drheee4c8c2008-02-18 22:24:57 +0000251 ** block. If not, then split a block of the next larger power of
252 ** two in order to create a new free block of size iLogsize.
253 */
danielk19775099be52008-06-27 13:27:03 +0000254 for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){}
255 if( iBin>LOGMAX ) return 0;
drh2d7636e2008-02-16 16:21:45 +0000256 i = memsys5UnlinkFirst(iBin);
257 while( iBin>iLogsize ){
258 int newSize;
259
260 iBin--;
261 newSize = 1 << iBin;
danielk1977c66c0e12008-06-25 14:26:07 +0000262 mem5.aCtrl[i+newSize] = CTRL_FREE | iBin;
drh2d7636e2008-02-16 16:21:45 +0000263 memsys5Link(i+newSize, iBin);
drh0d180202008-02-14 23:26:56 +0000264 }
danielk1977c66c0e12008-06-25 14:26:07 +0000265 mem5.aCtrl[i] = iLogsize;
drh0d180202008-02-14 23:26:56 +0000266
drheee4c8c2008-02-18 22:24:57 +0000267 /* Update allocator performance statistics. */
danielk1977c66c0e12008-06-25 14:26:07 +0000268 mem5.nAlloc++;
269 mem5.totalAlloc += iFullSz;
270 mem5.totalExcess += iFullSz - nByte;
271 mem5.currentCount++;
272 mem5.currentOut += iFullSz;
273 if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
274 if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
drh0d180202008-02-14 23:26:56 +0000275
drheee4c8c2008-02-18 22:24:57 +0000276 /* Return a pointer to the allocated memory. */
danielk19775099be52008-06-27 13:27:03 +0000277 return (void*)&mem5.zPool[i*mem5.nAtom];
drh0d180202008-02-14 23:26:56 +0000278}
279
280/*
281** Free an outstanding memory allocation.
282*/
danielk1977c66c0e12008-06-25 14:26:07 +0000283static void memsys5FreeUnsafe(void *pOld){
drh2d7636e2008-02-16 16:21:45 +0000284 u32 size, iLogsize;
danielk19775099be52008-06-27 13:27:03 +0000285 int iBlock;
drh0d180202008-02-14 23:26:56 +0000286
danielk19775099be52008-06-27 13:27:03 +0000287 /* Set iBlock to the index of the block pointed to by pOld in
288 ** the array of mem5.nAtom byte blocks pointed to by mem5.zPool.
289 */
290 iBlock = ((u8 *)pOld-mem5.zPool)/mem5.nAtom;
291
292 /* Check that the pointer pOld points to a valid, non-free block. */
293 assert( iBlock>=0 && iBlock<mem5.nBlock );
294 assert( ((u8 *)pOld-mem5.zPool)%mem5.nAtom==0 );
295 assert( (mem5.aCtrl[iBlock] & CTRL_FREE)==0 );
296
297 iLogsize = mem5.aCtrl[iBlock] & CTRL_LOGSIZE;
drh2d7636e2008-02-16 16:21:45 +0000298 size = 1<<iLogsize;
danielk19775099be52008-06-27 13:27:03 +0000299 assert( iBlock+size-1<mem5.nBlock );
300
301 mem5.aCtrl[iBlock] |= CTRL_FREE;
302 mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
danielk1977c66c0e12008-06-25 14:26:07 +0000303 assert( mem5.currentCount>0 );
304 assert( mem5.currentOut>=0 );
305 mem5.currentCount--;
danielk19775099be52008-06-27 13:27:03 +0000306 mem5.currentOut -= size*mem5.nAtom;
danielk1977c66c0e12008-06-25 14:26:07 +0000307 assert( mem5.currentOut>0 || mem5.currentCount==0 );
308 assert( mem5.currentCount>0 || mem5.currentOut==0 );
drh2d7636e2008-02-16 16:21:45 +0000309
danielk19775099be52008-06-27 13:27:03 +0000310 mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
311 while( iLogsize<LOGMAX ){
drh2d7636e2008-02-16 16:21:45 +0000312 int iBuddy;
danielk19775099be52008-06-27 13:27:03 +0000313 if( (iBlock>>iLogsize) & 1 ){
314 iBuddy = iBlock - size;
drh2d7636e2008-02-16 16:21:45 +0000315 }else{
danielk19775099be52008-06-27 13:27:03 +0000316 iBuddy = iBlock + size;
drh0d180202008-02-14 23:26:56 +0000317 }
danielk19775099be52008-06-27 13:27:03 +0000318 assert( iBuddy>=0 );
319 if( (iBuddy+(1<<iLogsize))>mem5.nBlock ) break;
danielk1977c66c0e12008-06-25 14:26:07 +0000320 if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;
drh2d7636e2008-02-16 16:21:45 +0000321 memsys5Unlink(iBuddy, iLogsize);
322 iLogsize++;
danielk19775099be52008-06-27 13:27:03 +0000323 if( iBuddy<iBlock ){
danielk1977c66c0e12008-06-25 14:26:07 +0000324 mem5.aCtrl[iBuddy] = CTRL_FREE | iLogsize;
danielk19775099be52008-06-27 13:27:03 +0000325 mem5.aCtrl[iBlock] = 0;
326 iBlock = iBuddy;
drh2d7636e2008-02-16 16:21:45 +0000327 }else{
danielk19775099be52008-06-27 13:27:03 +0000328 mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
danielk1977c66c0e12008-06-25 14:26:07 +0000329 mem5.aCtrl[iBuddy] = 0;
drh0d180202008-02-14 23:26:56 +0000330 }
drh2d7636e2008-02-16 16:21:45 +0000331 size *= 2;
drh0d180202008-02-14 23:26:56 +0000332 }
danielk19775099be52008-06-27 13:27:03 +0000333 memsys5Link(iBlock, iLogsize);
drh0d180202008-02-14 23:26:56 +0000334}
335
336/*
337** Allocate nBytes of memory
338*/
danielk1977c66c0e12008-06-25 14:26:07 +0000339static void *memsys5Malloc(int nBytes){
drh0d180202008-02-14 23:26:56 +0000340 sqlite3_int64 *p = 0;
341 if( nBytes>0 ){
drh2d7636e2008-02-16 16:21:45 +0000342 memsys5Enter();
danielk1977c66c0e12008-06-25 14:26:07 +0000343 p = memsys5MallocUnsafe(nBytes);
344 memsys5Leave();
drh0d180202008-02-14 23:26:56 +0000345 }
346 return (void*)p;
347}
348
349/*
350** Free memory.
351*/
danielk1977c66c0e12008-06-25 14:26:07 +0000352static void memsys5Free(void *pPrior){
drh0d180202008-02-14 23:26:56 +0000353 if( pPrior==0 ){
danielk19775099be52008-06-27 13:27:03 +0000354assert(0);
drh0d180202008-02-14 23:26:56 +0000355 return;
356 }
danielk1977c66c0e12008-06-25 14:26:07 +0000357 memsys5Enter();
358 memsys5FreeUnsafe(pPrior);
359 memsys5Leave();
drh0d180202008-02-14 23:26:56 +0000360}
361
362/*
363** Change the size of an existing memory allocation
364*/
danielk1977c66c0e12008-06-25 14:26:07 +0000365static void *memsys5Realloc(void *pPrior, int nBytes){
drh0d180202008-02-14 23:26:56 +0000366 int nOld;
367 void *p;
368 if( pPrior==0 ){
danielk1977c66c0e12008-06-25 14:26:07 +0000369 return memsys5Malloc(nBytes);
drh0d180202008-02-14 23:26:56 +0000370 }
371 if( nBytes<=0 ){
danielk1977c66c0e12008-06-25 14:26:07 +0000372 memsys5Free(pPrior);
drh0d180202008-02-14 23:26:56 +0000373 return 0;
374 }
danielk1977c66c0e12008-06-25 14:26:07 +0000375 nOld = memsys5Size(pPrior);
drh2d7636e2008-02-16 16:21:45 +0000376 if( nBytes<=nOld ){
drh0d180202008-02-14 23:26:56 +0000377 return pPrior;
378 }
danielk1977c66c0e12008-06-25 14:26:07 +0000379 memsys5Enter();
380 p = memsys5MallocUnsafe(nBytes);
drh0d180202008-02-14 23:26:56 +0000381 if( p ){
drh2d7636e2008-02-16 16:21:45 +0000382 memcpy(p, pPrior, nOld);
danielk1977c66c0e12008-06-25 14:26:07 +0000383 memsys5FreeUnsafe(pPrior);
drh0d180202008-02-14 23:26:56 +0000384 }
danielk1977c66c0e12008-06-25 14:26:07 +0000385 memsys5Leave();
drh0d180202008-02-14 23:26:56 +0000386 return p;
387}
388
389/*
danielk1977c66c0e12008-06-25 14:26:07 +0000390** Round up a request size to the next valid allocation size.
391*/
392static int memsys5Roundup(int n){
393 int iFullSz;
danielk19775099be52008-06-27 13:27:03 +0000394 for(iFullSz=mem5.nAtom; iFullSz<n; iFullSz *= 2);
danielk1977c66c0e12008-06-25 14:26:07 +0000395 return iFullSz;
396}
397
danielk19775099be52008-06-27 13:27:03 +0000398static int memsys5Log(int iValue){
399 int iLog;
400 for(iLog=0; (1<<iLog)<iValue; iLog++);
401 return iLog;
402}
403
danielk1977c66c0e12008-06-25 14:26:07 +0000404/*
405** Initialize this module.
406*/
407static int memsys5Init(void *NotUsed){
danielk19775099be52008-06-27 13:27:03 +0000408 int ii;
409 int nByte = sqlite3Config.nHeap;
410 u8 *zByte = (u8 *)sqlite3Config.pHeap;
411 int nMinLog; /* Log of minimum allocation size in bytes*/
412 int iOffset;
413
414 nMinLog = memsys5Log(sqlite3Config.mnReq);
415 mem5.nAtom = (1<<nMinLog);
416 while( sizeof(Mem5Link)>mem5.nAtom ){
417 mem5.nAtom = mem5.nAtom << 1;
418 }
419
420 mem5.nBlock = (nByte / (mem5.nAtom+sizeof(u8)));
421 mem5.zPool = zByte;
422 mem5.aCtrl = (u8 *)&mem5.zPool[mem5.nBlock*mem5.nAtom];
423
424 for(ii=0; ii<=LOGMAX; ii++){
425 mem5.aiFreelist[ii] = -1;
426 }
427
428 iOffset = 0;
429 for(ii=LOGMAX; ii>=0; ii--){
430 int nAlloc = (1<<ii);
431 if( (iOffset+nAlloc)<=mem5.nBlock ){
432 mem5.aCtrl[iOffset] = ii | CTRL_FREE;
433 memsys5Link(iOffset, ii);
434 iOffset += nAlloc;
435 }
436 assert((iOffset+nAlloc)>mem5.nBlock);
437 }
438
danielk1977c66c0e12008-06-25 14:26:07 +0000439 return SQLITE_OK;
440}
441
442/*
443** Deinitialize this module.
444*/
445static void memsys5Shutdown(void *NotUsed){
446 return;
447}
448
449/*
drh0d180202008-02-14 23:26:56 +0000450** Open the file indicated and write a log of all unfreed memory
451** allocations into that log.
452*/
danielk1977c66c0e12008-06-25 14:26:07 +0000453void sqlite3Memsys5Dump(const char *zFilename){
drh0d180202008-02-14 23:26:56 +0000454#ifdef SQLITE_DEBUG
455 FILE *out;
drh2d7636e2008-02-16 16:21:45 +0000456 int i, j, n;
danielk19775099be52008-06-27 13:27:03 +0000457 int nMinLog;
drh2d7636e2008-02-16 16:21:45 +0000458
drh0d180202008-02-14 23:26:56 +0000459 if( zFilename==0 || zFilename[0]==0 ){
460 out = stdout;
461 }else{
462 out = fopen(zFilename, "w");
463 if( out==0 ){
464 fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
465 zFilename);
466 return;
467 }
468 }
drh2d7636e2008-02-16 16:21:45 +0000469 memsys5Enter();
danielk19775099be52008-06-27 13:27:03 +0000470 nMinLog = memsys5Log(mem5.nAtom);
471 for(i=0; i<=LOGMAX && i+nMinLog<32; i++){
472 for(n=0, j=mem5.aiFreelist[i]; j>=0; j = MEM5LINK(j)->next, n++){}
473 fprintf(out, "freelist items of size %d: %d\n", mem5.nAtom << i, n);
drh0d180202008-02-14 23:26:56 +0000474 }
danielk1977c66c0e12008-06-25 14:26:07 +0000475 fprintf(out, "mem5.nAlloc = %llu\n", mem5.nAlloc);
476 fprintf(out, "mem5.totalAlloc = %llu\n", mem5.totalAlloc);
477 fprintf(out, "mem5.totalExcess = %llu\n", mem5.totalExcess);
478 fprintf(out, "mem5.currentOut = %u\n", mem5.currentOut);
479 fprintf(out, "mem5.currentCount = %u\n", mem5.currentCount);
480 fprintf(out, "mem5.maxOut = %u\n", mem5.maxOut);
481 fprintf(out, "mem5.maxCount = %u\n", mem5.maxCount);
482 fprintf(out, "mem5.maxRequest = %u\n", mem5.maxRequest);
483 memsys5Leave();
drh0d180202008-02-14 23:26:56 +0000484 if( out==stdout ){
485 fflush(stdout);
486 }else{
487 fclose(out);
488 }
489#endif
490}
491
danielk1977c66c0e12008-06-25 14:26:07 +0000492/*
493** This routine is the only routine in this file with external
danielk19775099be52008-06-27 13:27:03 +0000494** linkage. It returns a pointer to a static sqlite3_mem_methods
495** struct populated with the memsys5 methods.
danielk1977c66c0e12008-06-25 14:26:07 +0000496*/
danielk19775099be52008-06-27 13:27:03 +0000497const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){
danielk1977c66c0e12008-06-25 14:26:07 +0000498 static const sqlite3_mem_methods memsys5Methods = {
499 memsys5Malloc,
500 memsys5Free,
501 memsys5Realloc,
502 memsys5Size,
503 memsys5Roundup,
504 memsys5Init,
505 memsys5Shutdown,
506 0
507 };
danielk19775099be52008-06-27 13:27:03 +0000508 return &memsys5Methods;
danielk1977c66c0e12008-06-25 14:26:07 +0000509}
510
511#endif /* SQLITE_ENABLE_MEMSYS5 */