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>