blob: f9389e9e9deb106c4551c596ee46b1a24c38cdc3 [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**
danielk1977f3d3c272008-11-19 16:52:44 +000026** $Id: mem5.c,v 1.19 2008/11/19 16:52:44 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
drhd1370b62008-10-28 18:58:20 +000032** SQLITE_ENABLE_MEMSYS5 is defined.
drh0d180202008-02-14 23:26:56 +000033*/
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** A minimum allocation is an instance of the following structure.
38** Larger allocations are an array of these structures where the
39** size of the array is a power of 2.
40*/
danielk19775099be52008-06-27 13:27:03 +000041typedef struct Mem5Link Mem5Link;
42struct Mem5Link {
43 int next; /* Index of next free chunk */
44 int prev; /* Index of previous free chunk */
drh0d180202008-02-14 23:26:56 +000045};
46
47/*
danielk19775099be52008-06-27 13:27:03 +000048** Maximum size of any allocation is ((1<<LOGMAX)*mem5.nAtom). Since
49** mem5.nAtom is always at least 8, this is not really a practical
50** limitation.
drh2d7636e2008-02-16 16:21:45 +000051*/
danielk19775099be52008-06-27 13:27:03 +000052#define LOGMAX 30
drh2d7636e2008-02-16 16:21:45 +000053
54/*
danielk1977c66c0e12008-06-25 14:26:07 +000055** Masks used for mem5.aCtrl[] elements.
drh2d7636e2008-02-16 16:21:45 +000056*/
57#define CTRL_LOGSIZE 0x1f /* Log2 Size of this block relative to POW2_MIN */
58#define CTRL_FREE 0x20 /* True if not checked out */
59
60/*
drh0d180202008-02-14 23:26:56 +000061** All of the static variables used by this module are collected
danielk1977c66c0e12008-06-25 14:26:07 +000062** into a single structure named "mem5". This is to keep the
drh0d180202008-02-14 23:26:56 +000063** static variables organized and to reduce namespace pollution
64** when this module is combined with other in the amalgamation.
65*/
danielk19775c8f8582008-09-02 10:22:00 +000066static SQLITE_WSD struct Mem5Global {
drh0d180202008-02-14 23:26:56 +000067 /*
danielk197723bf0f42008-09-02 17:52:51 +000068 ** Memory available for allocation
drh0d180202008-02-14 23:26:56 +000069 */
danielk197723bf0f42008-09-02 17:52:51 +000070 int nAtom; /* Smallest possible allocation in bytes */
71 int nBlock; /* Number of nAtom sized blocks in zPool */
72 u8 *zPool;
drh0d180202008-02-14 23:26:56 +000073
74 /*
75 ** Mutex to control access to the memory allocation subsystem.
76 */
77 sqlite3_mutex *mutex;
drh2d7636e2008-02-16 16:21:45 +000078
79 /*
80 ** Performance statistics
81 */
82 u64 nAlloc; /* Total number of calls to malloc */
83 u64 totalAlloc; /* Total of all malloc calls - includes internal frag */
84 u64 totalExcess; /* Total internal fragmentation */
85 u32 currentOut; /* Current checkout, including internal fragmentation */
86 u32 currentCount; /* Current number of distinct checkouts */
87 u32 maxOut; /* Maximum instantaneous currentOut */
88 u32 maxCount; /* Maximum instantaneous currentCount */
89 u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
drh0d180202008-02-14 23:26:56 +000090
91 /*
drh2d7636e2008-02-16 16:21:45 +000092 ** Lists of free blocks of various sizes.
drh0d180202008-02-14 23:26:56 +000093 */
danielk19775099be52008-06-27 13:27:03 +000094 int aiFreelist[LOGMAX+1];
drh0d180202008-02-14 23:26:56 +000095
96 /*
drh2d7636e2008-02-16 16:21:45 +000097 ** Space for tracking which blocks are checked out and the size
98 ** of each block. One byte per block.
drh0d180202008-02-14 23:26:56 +000099 */
danielk1977c66c0e12008-06-25 14:26:07 +0000100 u8 *aCtrl;
drh0d180202008-02-14 23:26:56 +0000101
danielk197723bf0f42008-09-02 17:52:51 +0000102} mem5 = { 19804167 };
danielk19775c8f8582008-09-02 10:22:00 +0000103
104#define mem5 GLOBAL(struct Mem5Global, mem5)
drh0d180202008-02-14 23:26:56 +0000105
danielk19775099be52008-06-27 13:27:03 +0000106#define MEM5LINK(idx) ((Mem5Link *)(&mem5.zPool[(idx)*mem5.nAtom]))
107
drh0d180202008-02-14 23:26:56 +0000108/*
danielk1977c66c0e12008-06-25 14:26:07 +0000109** Unlink the chunk at mem5.aPool[i] from list it is currently
110** on. It should be found on mem5.aiFreelist[iLogsize].
drh0d180202008-02-14 23:26:56 +0000111*/
drh2d7636e2008-02-16 16:21:45 +0000112static void memsys5Unlink(int i, int iLogsize){
113 int next, prev;
danielk1977c66c0e12008-06-25 14:26:07 +0000114 assert( i>=0 && i<mem5.nBlock );
danielk19775099be52008-06-27 13:27:03 +0000115 assert( iLogsize>=0 && iLogsize<=LOGMAX );
danielk1977c66c0e12008-06-25 14:26:07 +0000116 assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
drh2d7636e2008-02-16 16:21:45 +0000117
danielk19775099be52008-06-27 13:27:03 +0000118 next = MEM5LINK(i)->next;
119 prev = MEM5LINK(i)->prev;
drh2d7636e2008-02-16 16:21:45 +0000120 if( prev<0 ){
danielk1977c66c0e12008-06-25 14:26:07 +0000121 mem5.aiFreelist[iLogsize] = next;
drh0d180202008-02-14 23:26:56 +0000122 }else{
danielk19775099be52008-06-27 13:27:03 +0000123 MEM5LINK(prev)->next = next;
drh0d180202008-02-14 23:26:56 +0000124 }
drh2d7636e2008-02-16 16:21:45 +0000125 if( next>=0 ){
danielk19775099be52008-06-27 13:27:03 +0000126 MEM5LINK(next)->prev = prev;
drh0d180202008-02-14 23:26:56 +0000127 }
drh0d180202008-02-14 23:26:56 +0000128}
129
130/*
danielk1977c66c0e12008-06-25 14:26:07 +0000131** Link the chunk at mem5.aPool[i] so that is on the iLogsize
drh2d7636e2008-02-16 16:21:45 +0000132** free list.
drh0d180202008-02-14 23:26:56 +0000133*/
drh2d7636e2008-02-16 16:21:45 +0000134static void memsys5Link(int i, int iLogsize){
135 int x;
danielk1977c66c0e12008-06-25 14:26:07 +0000136 assert( sqlite3_mutex_held(mem5.mutex) );
137 assert( i>=0 && i<mem5.nBlock );
danielk19775099be52008-06-27 13:27:03 +0000138 assert( iLogsize>=0 && iLogsize<=LOGMAX );
danielk1977c66c0e12008-06-25 14:26:07 +0000139 assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize );
drh0d180202008-02-14 23:26:56 +0000140
danielk19775099be52008-06-27 13:27:03 +0000141 x = MEM5LINK(i)->next = mem5.aiFreelist[iLogsize];
142 MEM5LINK(i)->prev = -1;
drh2d7636e2008-02-16 16:21:45 +0000143 if( x>=0 ){
danielk1977c66c0e12008-06-25 14:26:07 +0000144 assert( x<mem5.nBlock );
danielk19775099be52008-06-27 13:27:03 +0000145 MEM5LINK(x)->prev = i;
drh0d180202008-02-14 23:26:56 +0000146 }
danielk1977c66c0e12008-06-25 14:26:07 +0000147 mem5.aiFreelist[iLogsize] = i;
drh0d180202008-02-14 23:26:56 +0000148}
149
150/*
danielk19776b39c2e2008-06-25 14:57:53 +0000151** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
152** will already be held (obtained by code in malloc.c) if
danielk1977075c23a2008-09-01 18:34:20 +0000153** sqlite3GlobalConfig.bMemStat is true.
drh0d180202008-02-14 23:26:56 +0000154*/
drh2d7636e2008-02-16 16:21:45 +0000155static void memsys5Enter(void){
danielk1977075c23a2008-09-01 18:34:20 +0000156 if( sqlite3GlobalConfig.bMemstat==0 && mem5.mutex==0 ){
danielk19776b39c2e2008-06-25 14:57:53 +0000157 mem5.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
158 }
159 sqlite3_mutex_enter(mem5.mutex);
drh0d180202008-02-14 23:26:56 +0000160}
danielk1977c66c0e12008-06-25 14:26:07 +0000161static void memsys5Leave(void){
danielk19776b39c2e2008-06-25 14:57:53 +0000162 sqlite3_mutex_leave(mem5.mutex);
drh0d180202008-02-14 23:26:56 +0000163}
164
165/*
drh0d180202008-02-14 23:26:56 +0000166** Return the size of an outstanding allocation, in bytes. The
167** size returned omits the 8-byte header overhead. This only
168** works for chunks that are currently checked out.
169*/
danielk1977c66c0e12008-06-25 14:26:07 +0000170static int memsys5Size(void *p){
drh0d180202008-02-14 23:26:56 +0000171 int iSize = 0;
172 if( p ){
danielk19775099be52008-06-27 13:27:03 +0000173 int i = ((u8 *)p-mem5.zPool)/mem5.nAtom;
danielk1977c66c0e12008-06-25 14:26:07 +0000174 assert( i>=0 && i<mem5.nBlock );
danielk19775099be52008-06-27 13:27:03 +0000175 iSize = mem5.nAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
drh0d180202008-02-14 23:26:56 +0000176 }
177 return iSize;
178}
179
180/*
drh2d7636e2008-02-16 16:21:45 +0000181** Find the first entry on the freelist iLogsize. Unlink that
182** entry and return its index.
drh0d180202008-02-14 23:26:56 +0000183*/
drh2d7636e2008-02-16 16:21:45 +0000184static int memsys5UnlinkFirst(int iLogsize){
185 int i;
186 int iFirst;
drh0d180202008-02-14 23:26:56 +0000187
danielk19775099be52008-06-27 13:27:03 +0000188 assert( iLogsize>=0 && iLogsize<=LOGMAX );
danielk1977c66c0e12008-06-25 14:26:07 +0000189 i = iFirst = mem5.aiFreelist[iLogsize];
drh2d7636e2008-02-16 16:21:45 +0000190 assert( iFirst>=0 );
191 while( i>0 ){
192 if( i<iFirst ) iFirst = i;
danielk19775099be52008-06-27 13:27:03 +0000193 i = MEM5LINK(i)->next;
drh0d180202008-02-14 23:26:56 +0000194 }
drh2d7636e2008-02-16 16:21:45 +0000195 memsys5Unlink(iFirst, iLogsize);
196 return iFirst;
drh0d180202008-02-14 23:26:56 +0000197}
198
199/*
200** Return a block of memory of at least nBytes in size.
201** Return NULL if unable.
202*/
danielk1977c66c0e12008-06-25 14:26:07 +0000203static void *memsys5MallocUnsafe(int nByte){
204 int i; /* Index of a mem5.aPool[] slot */
205 int iBin; /* Index into mem5.aiFreelist[] */
drh2d7636e2008-02-16 16:21:45 +0000206 int iFullSz; /* Size of allocation rounded up to power of 2 */
207 int iLogsize; /* Log2 of iFullSz/POW2_MIN */
drh0d180202008-02-14 23:26:56 +0000208
drheee4c8c2008-02-18 22:24:57 +0000209 /* Keep track of the maximum allocation request. Even unfulfilled
210 ** requests are counted */
danielk197700e13612008-11-17 19:18:54 +0000211 if( (u32)nByte>mem5.maxRequest ){
danielk1977c66c0e12008-06-25 14:26:07 +0000212 mem5.maxRequest = nByte;
drheee4c8c2008-02-18 22:24:57 +0000213 }
214
drheee4c8c2008-02-18 22:24:57 +0000215 /* Round nByte up to the next valid power of two */
danielk19775099be52008-06-27 13:27:03 +0000216 for(iFullSz=mem5.nAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
drh0d180202008-02-14 23:26:56 +0000217
danielk1977c66c0e12008-06-25 14:26:07 +0000218 /* Make sure mem5.aiFreelist[iLogsize] contains at least one free
drheee4c8c2008-02-18 22:24:57 +0000219 ** block. If not, then split a block of the next larger power of
220 ** two in order to create a new free block of size iLogsize.
221 */
danielk19775099be52008-06-27 13:27:03 +0000222 for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){}
223 if( iBin>LOGMAX ) return 0;
drh2d7636e2008-02-16 16:21:45 +0000224 i = memsys5UnlinkFirst(iBin);
225 while( iBin>iLogsize ){
226 int newSize;
227
228 iBin--;
229 newSize = 1 << iBin;
danielk1977c66c0e12008-06-25 14:26:07 +0000230 mem5.aCtrl[i+newSize] = CTRL_FREE | iBin;
drh2d7636e2008-02-16 16:21:45 +0000231 memsys5Link(i+newSize, iBin);
drh0d180202008-02-14 23:26:56 +0000232 }
danielk1977c66c0e12008-06-25 14:26:07 +0000233 mem5.aCtrl[i] = iLogsize;
drh0d180202008-02-14 23:26:56 +0000234
drheee4c8c2008-02-18 22:24:57 +0000235 /* Update allocator performance statistics. */
danielk1977c66c0e12008-06-25 14:26:07 +0000236 mem5.nAlloc++;
237 mem5.totalAlloc += iFullSz;
238 mem5.totalExcess += iFullSz - nByte;
239 mem5.currentCount++;
240 mem5.currentOut += iFullSz;
241 if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
242 if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
drh0d180202008-02-14 23:26:56 +0000243
drheee4c8c2008-02-18 22:24:57 +0000244 /* Return a pointer to the allocated memory. */
danielk19775099be52008-06-27 13:27:03 +0000245 return (void*)&mem5.zPool[i*mem5.nAtom];
drh0d180202008-02-14 23:26:56 +0000246}
247
248/*
249** Free an outstanding memory allocation.
250*/
danielk1977c66c0e12008-06-25 14:26:07 +0000251static void memsys5FreeUnsafe(void *pOld){
drh2d7636e2008-02-16 16:21:45 +0000252 u32 size, iLogsize;
danielk19775099be52008-06-27 13:27:03 +0000253 int iBlock;
drh0d180202008-02-14 23:26:56 +0000254
danielk19775099be52008-06-27 13:27:03 +0000255 /* Set iBlock to the index of the block pointed to by pOld in
256 ** the array of mem5.nAtom byte blocks pointed to by mem5.zPool.
257 */
258 iBlock = ((u8 *)pOld-mem5.zPool)/mem5.nAtom;
259
260 /* Check that the pointer pOld points to a valid, non-free block. */
261 assert( iBlock>=0 && iBlock<mem5.nBlock );
262 assert( ((u8 *)pOld-mem5.zPool)%mem5.nAtom==0 );
263 assert( (mem5.aCtrl[iBlock] & CTRL_FREE)==0 );
264
265 iLogsize = mem5.aCtrl[iBlock] & CTRL_LOGSIZE;
drh2d7636e2008-02-16 16:21:45 +0000266 size = 1<<iLogsize;
danielk197700e13612008-11-17 19:18:54 +0000267 assert( iBlock+size-1<(u32)mem5.nBlock );
danielk19775099be52008-06-27 13:27:03 +0000268
269 mem5.aCtrl[iBlock] |= CTRL_FREE;
270 mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
danielk1977c66c0e12008-06-25 14:26:07 +0000271 assert( mem5.currentCount>0 );
danielk197700e13612008-11-17 19:18:54 +0000272 assert( mem5.currentOut>=(size*mem5.nAtom) );
danielk1977c66c0e12008-06-25 14:26:07 +0000273 mem5.currentCount--;
danielk19775099be52008-06-27 13:27:03 +0000274 mem5.currentOut -= size*mem5.nAtom;
danielk1977c66c0e12008-06-25 14:26:07 +0000275 assert( mem5.currentOut>0 || mem5.currentCount==0 );
276 assert( mem5.currentCount>0 || mem5.currentOut==0 );
drh2d7636e2008-02-16 16:21:45 +0000277
danielk19775099be52008-06-27 13:27:03 +0000278 mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
279 while( iLogsize<LOGMAX ){
drh2d7636e2008-02-16 16:21:45 +0000280 int iBuddy;
danielk19775099be52008-06-27 13:27:03 +0000281 if( (iBlock>>iLogsize) & 1 ){
282 iBuddy = iBlock - size;
drh2d7636e2008-02-16 16:21:45 +0000283 }else{
danielk19775099be52008-06-27 13:27:03 +0000284 iBuddy = iBlock + size;
drh0d180202008-02-14 23:26:56 +0000285 }
danielk19775099be52008-06-27 13:27:03 +0000286 assert( iBuddy>=0 );
287 if( (iBuddy+(1<<iLogsize))>mem5.nBlock ) break;
danielk1977c66c0e12008-06-25 14:26:07 +0000288 if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;
drh2d7636e2008-02-16 16:21:45 +0000289 memsys5Unlink(iBuddy, iLogsize);
290 iLogsize++;
danielk19775099be52008-06-27 13:27:03 +0000291 if( iBuddy<iBlock ){
danielk1977c66c0e12008-06-25 14:26:07 +0000292 mem5.aCtrl[iBuddy] = CTRL_FREE | iLogsize;
danielk19775099be52008-06-27 13:27:03 +0000293 mem5.aCtrl[iBlock] = 0;
294 iBlock = iBuddy;
drh2d7636e2008-02-16 16:21:45 +0000295 }else{
danielk19775099be52008-06-27 13:27:03 +0000296 mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
danielk1977c66c0e12008-06-25 14:26:07 +0000297 mem5.aCtrl[iBuddy] = 0;
drh0d180202008-02-14 23:26:56 +0000298 }
drh2d7636e2008-02-16 16:21:45 +0000299 size *= 2;
drh0d180202008-02-14 23:26:56 +0000300 }
danielk19775099be52008-06-27 13:27:03 +0000301 memsys5Link(iBlock, iLogsize);
drh0d180202008-02-14 23:26:56 +0000302}
303
304/*
305** Allocate nBytes of memory
306*/
danielk1977c66c0e12008-06-25 14:26:07 +0000307static void *memsys5Malloc(int nBytes){
drh0d180202008-02-14 23:26:56 +0000308 sqlite3_int64 *p = 0;
309 if( nBytes>0 ){
drh2d7636e2008-02-16 16:21:45 +0000310 memsys5Enter();
danielk1977c66c0e12008-06-25 14:26:07 +0000311 p = memsys5MallocUnsafe(nBytes);
312 memsys5Leave();
drh0d180202008-02-14 23:26:56 +0000313 }
314 return (void*)p;
315}
316
317/*
318** Free memory.
319*/
danielk1977c66c0e12008-06-25 14:26:07 +0000320static void memsys5Free(void *pPrior){
drh0d180202008-02-14 23:26:56 +0000321 if( pPrior==0 ){
danielk19775099be52008-06-27 13:27:03 +0000322assert(0);
drh0d180202008-02-14 23:26:56 +0000323 return;
324 }
danielk1977c66c0e12008-06-25 14:26:07 +0000325 memsys5Enter();
326 memsys5FreeUnsafe(pPrior);
327 memsys5Leave();
drh0d180202008-02-14 23:26:56 +0000328}
329
330/*
331** Change the size of an existing memory allocation
332*/
danielk1977c66c0e12008-06-25 14:26:07 +0000333static void *memsys5Realloc(void *pPrior, int nBytes){
drh0d180202008-02-14 23:26:56 +0000334 int nOld;
335 void *p;
336 if( pPrior==0 ){
danielk1977c66c0e12008-06-25 14:26:07 +0000337 return memsys5Malloc(nBytes);
drh0d180202008-02-14 23:26:56 +0000338 }
339 if( nBytes<=0 ){
danielk1977c66c0e12008-06-25 14:26:07 +0000340 memsys5Free(pPrior);
drh0d180202008-02-14 23:26:56 +0000341 return 0;
342 }
danielk1977c66c0e12008-06-25 14:26:07 +0000343 nOld = memsys5Size(pPrior);
drh2d7636e2008-02-16 16:21:45 +0000344 if( nBytes<=nOld ){
drh0d180202008-02-14 23:26:56 +0000345 return pPrior;
346 }
danielk1977c66c0e12008-06-25 14:26:07 +0000347 memsys5Enter();
348 p = memsys5MallocUnsafe(nBytes);
drh0d180202008-02-14 23:26:56 +0000349 if( p ){
drh2d7636e2008-02-16 16:21:45 +0000350 memcpy(p, pPrior, nOld);
danielk1977c66c0e12008-06-25 14:26:07 +0000351 memsys5FreeUnsafe(pPrior);
drh0d180202008-02-14 23:26:56 +0000352 }
danielk1977c66c0e12008-06-25 14:26:07 +0000353 memsys5Leave();
drh0d180202008-02-14 23:26:56 +0000354 return p;
355}
356
357/*
danielk1977c66c0e12008-06-25 14:26:07 +0000358** Round up a request size to the next valid allocation size.
359*/
360static int memsys5Roundup(int n){
361 int iFullSz;
danielk19775099be52008-06-27 13:27:03 +0000362 for(iFullSz=mem5.nAtom; iFullSz<n; iFullSz *= 2);
danielk1977c66c0e12008-06-25 14:26:07 +0000363 return iFullSz;
364}
365
danielk19775099be52008-06-27 13:27:03 +0000366static int memsys5Log(int iValue){
367 int iLog;
368 for(iLog=0; (1<<iLog)<iValue; iLog++);
369 return iLog;
370}
371
danielk1977c66c0e12008-06-25 14:26:07 +0000372/*
373** Initialize this module.
374*/
375static int memsys5Init(void *NotUsed){
danielk19775099be52008-06-27 13:27:03 +0000376 int ii;
danielk1977075c23a2008-09-01 18:34:20 +0000377 int nByte = sqlite3GlobalConfig.nHeap;
378 u8 *zByte = (u8 *)sqlite3GlobalConfig.pHeap;
danielk19775099be52008-06-27 13:27:03 +0000379 int nMinLog; /* Log of minimum allocation size in bytes*/
380 int iOffset;
381
danielk1977a03396a2008-11-19 14:35:46 +0000382 UNUSED_PARAMETER(NotUsed);
383
danielk19770d84e5b2008-06-27 14:05:24 +0000384 if( !zByte ){
385 return SQLITE_ERROR;
386 }
387
danielk1977075c23a2008-09-01 18:34:20 +0000388 nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq);
danielk19775099be52008-06-27 13:27:03 +0000389 mem5.nAtom = (1<<nMinLog);
danielk197700e13612008-11-17 19:18:54 +0000390 while( (int)sizeof(Mem5Link)>mem5.nAtom ){
danielk19775099be52008-06-27 13:27:03 +0000391 mem5.nAtom = mem5.nAtom << 1;
392 }
393
394 mem5.nBlock = (nByte / (mem5.nAtom+sizeof(u8)));
395 mem5.zPool = zByte;
396 mem5.aCtrl = (u8 *)&mem5.zPool[mem5.nBlock*mem5.nAtom];
397
398 for(ii=0; ii<=LOGMAX; ii++){
399 mem5.aiFreelist[ii] = -1;
400 }
401
402 iOffset = 0;
403 for(ii=LOGMAX; ii>=0; ii--){
404 int nAlloc = (1<<ii);
405 if( (iOffset+nAlloc)<=mem5.nBlock ){
406 mem5.aCtrl[iOffset] = ii | CTRL_FREE;
407 memsys5Link(iOffset, ii);
408 iOffset += nAlloc;
409 }
410 assert((iOffset+nAlloc)>mem5.nBlock);
411 }
412
danielk1977c66c0e12008-06-25 14:26:07 +0000413 return SQLITE_OK;
414}
415
416/*
417** Deinitialize this module.
418*/
419static void memsys5Shutdown(void *NotUsed){
danielk1977a03396a2008-11-19 14:35:46 +0000420 UNUSED_PARAMETER(NotUsed);
danielk1977c66c0e12008-06-25 14:26:07 +0000421 return;
422}
423
424/*
drh0d180202008-02-14 23:26:56 +0000425** Open the file indicated and write a log of all unfreed memory
426** allocations into that log.
427*/
danielk1977c66c0e12008-06-25 14:26:07 +0000428void sqlite3Memsys5Dump(const char *zFilename){
drh0d180202008-02-14 23:26:56 +0000429#ifdef SQLITE_DEBUG
430 FILE *out;
drh2d7636e2008-02-16 16:21:45 +0000431 int i, j, n;
danielk19775099be52008-06-27 13:27:03 +0000432 int nMinLog;
drh2d7636e2008-02-16 16:21:45 +0000433
drh0d180202008-02-14 23:26:56 +0000434 if( zFilename==0 || zFilename[0]==0 ){
435 out = stdout;
436 }else{
437 out = fopen(zFilename, "w");
438 if( out==0 ){
439 fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
440 zFilename);
441 return;
442 }
443 }
drh2d7636e2008-02-16 16:21:45 +0000444 memsys5Enter();
danielk19775099be52008-06-27 13:27:03 +0000445 nMinLog = memsys5Log(mem5.nAtom);
446 for(i=0; i<=LOGMAX && i+nMinLog<32; i++){
447 for(n=0, j=mem5.aiFreelist[i]; j>=0; j = MEM5LINK(j)->next, n++){}
448 fprintf(out, "freelist items of size %d: %d\n", mem5.nAtom << i, n);
drh0d180202008-02-14 23:26:56 +0000449 }
danielk1977c66c0e12008-06-25 14:26:07 +0000450 fprintf(out, "mem5.nAlloc = %llu\n", mem5.nAlloc);
451 fprintf(out, "mem5.totalAlloc = %llu\n", mem5.totalAlloc);
452 fprintf(out, "mem5.totalExcess = %llu\n", mem5.totalExcess);
453 fprintf(out, "mem5.currentOut = %u\n", mem5.currentOut);
454 fprintf(out, "mem5.currentCount = %u\n", mem5.currentCount);
455 fprintf(out, "mem5.maxOut = %u\n", mem5.maxOut);
456 fprintf(out, "mem5.maxCount = %u\n", mem5.maxCount);
457 fprintf(out, "mem5.maxRequest = %u\n", mem5.maxRequest);
458 memsys5Leave();
drh0d180202008-02-14 23:26:56 +0000459 if( out==stdout ){
460 fflush(stdout);
461 }else{
462 fclose(out);
463 }
danielk1977f3d3c272008-11-19 16:52:44 +0000464#else
465 UNUSED_PARAMETER(zFilename);
drh0d180202008-02-14 23:26:56 +0000466#endif
467}
468
danielk1977c66c0e12008-06-25 14:26:07 +0000469/*
470** This routine is the only routine in this file with external
danielk19775099be52008-06-27 13:27:03 +0000471** linkage. It returns a pointer to a static sqlite3_mem_methods
472** struct populated with the memsys5 methods.
danielk1977c66c0e12008-06-25 14:26:07 +0000473*/
danielk19775099be52008-06-27 13:27:03 +0000474const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){
danielk1977c66c0e12008-06-25 14:26:07 +0000475 static const sqlite3_mem_methods memsys5Methods = {
476 memsys5Malloc,
477 memsys5Free,
478 memsys5Realloc,
479 memsys5Size,
480 memsys5Roundup,
481 memsys5Init,
482 memsys5Shutdown,
483 0
484 };
danielk19775099be52008-06-27 13:27:03 +0000485 return &memsys5Methods;
danielk1977c66c0e12008-06-25 14:26:07 +0000486}
487
488#endif /* SQLITE_ENABLE_MEMSYS5 */