From 2d7636e2121e011100d76b21497dcef157869517 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 16 Feb 2008 16:21:45 +0000 Subject: [PATCH] The power-of-two first-fit memory allocator is now working. (CVS 4793) FossilOrigin-Name: d134d29cea971eb01a0e0fd94341ab79e2d5b57a --- manifest | 20 +- manifest.uuid | 2 +- src/mem5.c | 602 +++++++++++++++----------------------------- src/test_config.c | 8 +- src/test_malloc.c | 5 +- test/tester.tcl | 6 +- tool/mksqlite3c.tcl | 1 + 7 files changed, 231 insertions(+), 413 deletions(-) diff --git a/manifest b/manifest index 79d08c7295..34131e8e04 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sbug\sin\sthe\s".show"\scommand\sof\sthe\sCLI.\s\sTicket\s#2942.\s(CVS\s4792) -D 2008-02-15T17:38:06 +C The\spower-of-two\sfirst-fit\smemory\sallocator\sis\snow\sworking.\s(CVS\s4793) +D 2008-02-16T16:21:46 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in bc2b5df3e3d0d4b801b824b7ef6dec43812b049b F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -109,7 +109,7 @@ F src/mem1.c 62a821702d3292809ca78e7c55c3ca04b05a3757 F src/mem2.c 021eecbb210cfe90a8e7be9f04b01329d2c38851 F src/mem3.c 979191678eb1aac0af7e5df9ab3897a07410ff4c F src/mem4.c 45c328ec6dcb7e8d319cb383615b5fe547ca5409 -F src/mem5.c addb464d2328ad5dcd38a127a19a10fb654e1349 +F src/mem5.c e15148be341ba68af22cf62c59d03ad369a448fd F src/mutex.c 3259f62c2429967aee6dc112117a6d2f499ef061 F src/mutex.h 079fa6fe9da18ceb89e79012c010594c6672addb F src/mutex_os2.c 19ab15764736f13b94b4f70e53f77547cbddd47a @@ -154,11 +154,11 @@ F src/test9.c 4615ef08750245a2d96aaa7cbe2fb4aff2b57acc F src/test_async.c 5f21392d66869a4c87dc9153e40d0dc0e085261f F src/test_autoext.c 855157d97aa28cf84233847548bfacda21807436 F src/test_btree.c c1308ba0b88ab577fa56c9e493a09829dfcded9c -F src/test_config.c e7db7a46833d0df98ae6c9a11f70dada1bcca249 +F src/test_config.c 9223ff4a7b8b97c9d12965b0123db1cbd6757efb F src/test_devsym.c fd8884c2269fb7e0db2c52d21ec59d31a33790ba F src/test_hexio.c 1a1cd8324d57585ea86b922f609fa1fbaaf9662d F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8 -F src/test_malloc.c f57e6327a9c32dc71fb2c15941f64d4e91461d3b +F src/test_malloc.c 6a47772a8530dbf3f6578a53e96303ac1dc3244a F src/test_md5.c c107c96637123239c3518b5fbe97a79130f4d32e F src/test_onefile.c 54282b6796d55d7acc489be83b89b8715e7d3756 F src/test_schema.c 12c9de7661d6294eec2d57afbb52e2af1128084f @@ -454,7 +454,7 @@ F test/table.test 13b1c2e2fb4727b35ee1fb7641fc469214fd2455 F test/tableapi.test 4546eb710d979db023bfcc16b0c108b1557fcb43 F test/tclsqlite.test 3fac87cb1059c46b8fa8a60b553f4f1adb0fb6d9 F test/temptable.test 19b851b9e3e64d91e9867619b2a3f5fffee6e125 -F test/tester.tcl 70ed4c0dda3e2277bac9e0bf38e60df9dc360d08 +F test/tester.tcl 7760c4101448e5595b2ee095e540643fa31a1610 F test/thread001.test 8fbd9559da0bbdc273e00318c7fd66c162020af7 F test/thread002.test 2c4ad2c386f60f6fe268cd91c769ee35b3c1fd0b F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35 @@ -549,7 +549,7 @@ F tool/memleak2.awk 9cc20c8e8f3c675efac71ea0721ee6874a1566e8 F tool/memleak3.tcl 7707006ee908cffff210c98158788d85bb3fcdbf F tool/mkkeywordhash.c ef93810fc41fb3d3dbacf9a33a29be88ea99ffa9 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x -F tool/mksqlite3c.tcl c315696c91d0a986e696dce14b0db1ea93e2c2d0 +F tool/mksqlite3c.tcl c1876ef95be512ce466f09d7b2d1157f9766f2b1 F tool/mksqlite3internalh.tcl 47737a925fb02fce43e2c0a14b3cc17574a4d44a F tool/omittest.tcl 7d1fdf469e2f4d175f70c36e469db64a1626fabb F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c @@ -619,7 +619,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 6d33cbd99cb0db680767ceb31ec6345e90a805bc -R 278e440ef39be86aca5c9fcf37732ebc +P dedf5f230bf34a207f2ee0a8349a2ea602a38aba +R cf36f2227f0aebc7182206911a7828ca U drh -Z 27b6c195ad861a325b1d53c0c1393102 +Z 7f0671ff9d8e2cc545c59a85da0cd625 diff --git a/manifest.uuid b/manifest.uuid index b0e264ea07..7577440125 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dedf5f230bf34a207f2ee0a8349a2ea602a38aba \ No newline at end of file +d134d29cea971eb01a0e0fd94341ab79e2d5b57a \ No newline at end of file diff --git a/src/mem5.c b/src/mem5.c index 1ce321a666..abc0837d93 100644 --- a/src/mem5.c +++ b/src/mem5.c @@ -20,7 +20,7 @@ ** This version of the memory allocation subsystem is used if ** and only if SQLITE_POW2_MEMORY_SIZE is defined. ** -** $Id: mem5.c,v 1.1 2008/02/14 23:26:56 drh Exp $ +** $Id: mem5.c,v 1.2 2008/02/16 16:21:46 drh Exp $ */ #include "sqliteInt.h" @@ -31,62 +31,60 @@ #ifdef SQLITE_POW2_MEMORY_SIZE /* -** Maximum size (in Mem3Blocks) of a "small" chunk. +** Log2 of the minimum size of an allocation. For example, if +** 4 then all allocations will be rounded up to at least 16 bytes. +** If 5 then all allocations will be rounded up to at least 32 bytes. */ -#define MX_SMALL 10 - +#ifndef SQLITE_POW2_LOGMIN +# define SQLITE_POW2_LOGMIN 6 +#endif +#define POW2_MIN (1<=0 && i=0 && iLogsize=0 ){ mem.aPool[next].u.list.prev = prev; } - mem.aPool[i].u.list.next = 0; - mem.aPool[i].u.list.prev = 0; } /* -** Unlink the chunk at index i from -** whatever list is currently a member of. +** Link the chunk at mem.aPool[i] so that is on the iLogsize +** free list. */ -static void memsys3Unlink(u32 i){ - u32 size, hash; +static void memsys5Link(int i, int iLogsize){ + int x; assert( sqlite3_mutex_held(mem.mutex) ); - assert( (mem.aPool[i-1].u.hdr.size4x & 1)==0 ); - assert( i>=1 ); - size = mem.aPool[i-1].u.hdr.size4x/4; - assert( size==mem.aPool[i+size-1].u.hdr.prevSize ); - assert( size>=2 ); - if( size <= MX_SMALL ){ - memsys3UnlinkFromList(i, &mem.aiSmall[size-2]); - }else{ - hash = size % N_HASH; - memsys3UnlinkFromList(i, &mem.aiHash[hash]); - } -} + assert( i>=0 && i=0 && iLogsize=1 ); - assert( (mem.aPool[i-1].u.hdr.size4x & 1)==0 ); - size = mem.aPool[i-1].u.hdr.size4x/4; - assert( size==mem.aPool[i+size-1].u.hdr.prevSize ); - assert( size>=2 ); - if( size <= MX_SMALL ){ - memsys3LinkIntoList(i, &mem.aiSmall[size-2]); - }else{ - hash = size % N_HASH; - memsys3LinkIntoList(i, &mem.aiHash[hash]); + mem.aPool[i].u.list.next = x = mem.aiFreelist[iLogsize]; + mem.aPool[i].u.list.prev = -1; + if( x>=0 ){ + assert( x=POW2_MAX ); mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); - mem.aPool[0].u.hdr.size4x = SQLITE_POW2_MEMORY_SIZE/2 + 2; - mem.aPool[SQLITE_POW2_MEMORY_SIZE/8].u.hdr.prevSize = SQLITE_POW2_MEMORY_SIZE/8; - mem.aPool[SQLITE_POW2_MEMORY_SIZE/8].u.hdr.size4x = 1; - mem.iMaster = 1; - mem.szMaster = SQLITE_POW2_MEMORY_SIZE/8; - mem.mnMaster = mem.szMaster; + sqlite3_mutex_enter(mem.mutex); + for(i=0; i=0 && i=1 ); - assert( mem.aPool[i-1].u.hdr.size4x/4==nBlock ); - assert( mem.aPool[i+nBlock-1].u.hdr.prevSize==nBlock ); - x = mem.aPool[i-1].u.hdr.size4x; - mem.aPool[i-1].u.hdr.size4x = nBlock*4 | 1 | (x&2); - mem.aPool[i+nBlock-1].u.hdr.prevSize = nBlock; - mem.aPool[i+nBlock-1].u.hdr.size4x |= 2; - return &mem.aPool[i]; -} +static int memsys5UnlinkFirst(int iLogsize){ + int i; + int iFirst; -/* -** Carve a piece off of the end of the mem.iMaster free chunk. -** Return a pointer to the new allocation. Or, if the master chunk -** is not large enough, return 0. -*/ -static void *memsys3FromMaster(int nBlock){ - assert( sqlite3_mutex_held(mem.mutex) ); - assert( mem.szMaster>=nBlock ); - if( nBlock>=mem.szMaster-1 ){ - /* Use the entire master */ - void *p = memsys3Checkout(mem.iMaster, mem.szMaster); - mem.iMaster = 0; - mem.szMaster = 0; - mem.mnMaster = 0; - return p; - }else{ - /* Split the master block. Return the tail. */ - u32 newi, x; - newi = mem.iMaster + mem.szMaster - nBlock; - assert( newi > mem.iMaster+1 ); - mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.prevSize = nBlock; - mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.size4x |= 2; - mem.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1; - mem.szMaster -= nBlock; - mem.aPool[newi-1].u.hdr.prevSize = mem.szMaster; - x = mem.aPool[mem.iMaster-1].u.hdr.size4x & 2; - mem.aPool[mem.iMaster-1].u.hdr.size4x = mem.szMaster*4 | x; - if( mem.szMaster < mem.mnMaster ){ - mem.mnMaster = mem.szMaster; - } - return (void*)&mem.aPool[newi]; - } -} - -/* -** *pRoot is the head of a list of free chunks of the same size -** or same size hash. In other words, *pRoot is an entry in either -** mem.aiSmall[] or mem.aiHash[]. -** -** This routine examines all entries on the given list and tries -** to coalesce each entries with adjacent free chunks. -** -** If it sees a chunk that is larger than mem.iMaster, it replaces -** the current mem.iMaster with the new larger chunk. In order for -** this mem.iMaster replacement to work, the master chunk must be -** linked into the hash tables. That is not the normal state of -** affairs, of course. The calling routine must link the master -** chunk before invoking this routine, then must unlink the (possibly -** changed) master chunk once this routine has finished. -*/ -static void memsys3Merge(u32 *pRoot){ - u32 iNext, prev, size, i, x; - - assert( sqlite3_mutex_held(mem.mutex) ); - for(i=*pRoot; i>0; i=iNext){ - iNext = mem.aPool[i].u.list.next; - size = mem.aPool[i-1].u.hdr.size4x; - assert( (size&1)==0 ); - if( (size&2)==0 ){ - memsys3UnlinkFromList(i, pRoot); - assert( i > mem.aPool[i-1].u.hdr.prevSize ); - prev = i - mem.aPool[i-1].u.hdr.prevSize; - if( prev==iNext ){ - iNext = mem.aPool[prev].u.list.next; - } - memsys3Unlink(prev); - size = i + size/4 - prev; - x = mem.aPool[prev-1].u.hdr.size4x & 2; - mem.aPool[prev-1].u.hdr.size4x = size*4 | x; - mem.aPool[prev+size-1].u.hdr.prevSize = size; - memsys3Link(prev); - i = prev; - }else{ - size /= 4; - } - if( size>mem.szMaster ){ - mem.iMaster = i; - mem.szMaster = size; - } + assert( iLogsize>=0 && iLogsize=0 ); + while( i>0 ){ + if( i= 2 ); + if( nByte>mem.maxRequest ) mem.maxRequest = nByte; + if( nByte>POW2_MAX ) return 0; + for(iFullSz=POW2_MIN, iLogsize=0; iFullSz0 ){ - memsys3UnlinkFromList(i, &mem.aiSmall[nBlock-2]); - return memsys3Checkout(i, nBlock); - } - }else{ - int hash = nBlock % N_HASH; - for(i=mem.aiHash[hash]; i>0; i=mem.aPool[i].u.list.next){ - if( mem.aPool[i-1].u.hdr.size4x/4==nBlock ){ - memsys3UnlinkFromList(i, &mem.aiHash[hash]); - return memsys3Checkout(i, nBlock); - } - } + for(iBin=iLogsize; mem.aiFreelist[iBin]<0 && iBin=NSIZE ) return 0; + i = memsys5UnlinkFirst(iBin); + while( iBin>iLogsize ){ + int newSize; + + iBin--; + newSize = 1 << iBin; + mem.aCtrl[i+newSize] = CTRL_FREE | iBin; + memsys5Link(i+newSize, iBin); } + mem.aCtrl[i] = iLogsize; - /* STEP 2: - ** Try to satisfy the allocation by carving a piece off of the end - ** of the master chunk. This step usually works if step 1 fails. - */ - if( mem.szMaster>=nBlock ){ - return memsys3FromMaster(nBlock); - } + mem.nAlloc++; + mem.totalAlloc += iFullSz; + mem.totalExcess += iFullSz - nByte; + mem.currentCount++; + mem.currentOut += iFullSz; + if( mem.maxCount=nBlock ){ - return memsys3FromMaster(nBlock); - } - } - } - - /* If none of the above worked, then we fail. */ - return 0; + return (void*)&mem.aPool[i]; } /* ** Free an outstanding memory allocation. */ -void memsys3Free(void *pOld){ - Mem3Block *p = (Mem3Block*)pOld; +void memsys5Free(void *pOld){ + u32 size, iLogsize; int i; - u32 size, x; - assert( sqlite3_mutex_held(mem.mutex) ); - assert( p>mem.aPool && p<&mem.aPool[SQLITE_POW2_MEMORY_SIZE/8] ); - i = p - mem.aPool; - assert( (mem.aPool[i-1].u.hdr.size4x&1)==1 ); - size = mem.aPool[i-1].u.hdr.size4x/4; - assert( i+size<=SQLITE_POW2_MEMORY_SIZE/8+1 ); - mem.aPool[i-1].u.hdr.size4x &= ~1; - mem.aPool[i+size-1].u.hdr.prevSize = size; - mem.aPool[i+size-1].u.hdr.size4x &= ~2; - memsys3Link(i); - /* Try to expand the master using the newly freed chunk */ - if( mem.iMaster ){ - while( (mem.aPool[mem.iMaster-1].u.hdr.size4x&2)==0 ){ - size = mem.aPool[mem.iMaster-1].u.hdr.prevSize; - mem.iMaster -= size; - mem.szMaster += size; - memsys3Unlink(mem.iMaster); - x = mem.aPool[mem.iMaster-1].u.hdr.size4x & 2; - mem.aPool[mem.iMaster-1].u.hdr.size4x = mem.szMaster*4 | x; - mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.prevSize = mem.szMaster; + i = ((Mem5Block*)pOld) - mem.aPool; + assert( sqlite3_mutex_held(mem.mutex) ); + assert( i>=0 && i0 ); + assert( mem.currentOut>=0 ); + mem.currentCount--; + mem.currentOut -= size*POW2_MIN; + assert( mem.currentOut>0 || mem.currentCount==0 ); + assert( mem.currentCount>0 || mem.currentOut==0 ); + + mem.aCtrl[i] = CTRL_FREE | iLogsize; + while( iLogsize>iLogsize) & 1 ){ + iBuddy = i - size; + }else{ + iBuddy = i + size; } - x = mem.aPool[mem.iMaster-1].u.hdr.size4x & 2; - while( (mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.size4x&1)==0 ){ - memsys3Unlink(mem.iMaster+mem.szMaster); - mem.szMaster += mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.size4x/4; - mem.aPool[mem.iMaster-1].u.hdr.size4x = mem.szMaster*4 | x; - mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.prevSize = mem.szMaster; + assert( iBuddy>=0 && iBuddy0 ){ - memsys3Enter(); - p = memsys3Malloc(nBytes); + memsys5Enter(); + p = memsys5Malloc(nBytes); sqlite3_mutex_leave(mem.mutex); } return (void*)p; @@ -547,7 +395,7 @@ void sqlite3_free(void *pPrior){ } assert( mem.mutex!=0 ); sqlite3_mutex_enter(mem.mutex); - memsys3Free(pPrior); + memsys5Free(pPrior); sqlite3_mutex_leave(mem.mutex); } @@ -566,18 +414,14 @@ void *sqlite3_realloc(void *pPrior, int nBytes){ } assert( mem.mutex!=0 ); nOld = sqlite3MallocSize(pPrior); - if( nBytes<=nOld && nBytes>=nOld-128 ){ + if( nBytes<=nOld ){ return pPrior; } sqlite3_mutex_enter(mem.mutex); - p = memsys3Malloc(nBytes); + p = memsys5Malloc(nBytes); if( p ){ - if( nOld>1)!=(size&1) ){ - fprintf(out, "%p tail checkout bit is incorrect\n", &mem.aPool[i]); - assert( 0 ); - break; - } - if( size&1 ){ - fprintf(out, "%p %6d bytes checked out\n", &mem.aPool[i], (size/4)*8-8); - }else{ - fprintf(out, "%p %6d bytes free%s\n", &mem.aPool[i], (size/4)*8-8, - i==mem.iMaster ? " **master**" : ""); - } + memsys5Enter(); + for(i=0; i=0; j = mem.aPool[j].u.list.next, n++){} + fprintf(out, "freelist items of size %d: %d\n", POW2_MIN << i, n); } - for(i=0; i0; j=mem.aPool[j].u.list.next){ - fprintf(out, " %p(%d)", &mem.aPool[j], - (mem.aPool[j-1].u.hdr.size4x/4)*8-8); - } - fprintf(out, "\n"); - } - for(i=0; i0; j=mem.aPool[j].u.list.next){ - fprintf(out, " %p(%d)", &mem.aPool[j], - (mem.aPool[j-1].u.hdr.size4x/4)*8-8); - } - fprintf(out, "\n"); - } - fprintf(out, "master=%d\n", mem.iMaster); - fprintf(out, "nowUsed=%d\n", SQLITE_POW2_MEMORY_SIZE - mem.szMaster*8); - fprintf(out, "mxUsed=%d\n", SQLITE_POW2_MEMORY_SIZE - mem.mnMaster*8); + fprintf(out, "mem.nAlloc = %llu\n", mem.nAlloc); + fprintf(out, "mem.totalAlloc = %llu\n", mem.totalAlloc); + fprintf(out, "mem.totalExcess = %llu\n", mem.totalExcess); + fprintf(out, "mem.currentOut = %u\n", mem.currentOut); + fprintf(out, "mem.currentCount = %u\n", mem.currentCount); + fprintf(out, "mem.maxOut = %u\n", mem.maxOut); + fprintf(out, "mem.maxCount = %u\n", mem.maxCount); + fprintf(out, "mem.maxRequest = %u\n", mem.maxRequest); sqlite3_mutex_leave(mem.mutex); if( out==stdout ){ fflush(stdout); diff --git a/src/test_config.c b/src/test_config.c index b47ca899e4..535df1d99b 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -16,7 +16,7 @@ ** The focus of this file is providing the TCL testing layer ** access to compile-time constants. ** -** $Id: test_config.c,v 1.19 2008/01/23 12:52:41 drh Exp $ +** $Id: test_config.c,v 1.20 2008/02/16 16:21:46 drh Exp $ */ #include "sqliteLimit.h" @@ -88,6 +88,12 @@ static void set_options(Tcl_Interp *interp){ Tcl_SetVar2(interp, "sqlite_options", "mem3", "0", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_POW2_MEMORY_SIZE + Tcl_SetVar2(interp, "sqlite_options", "mem5", "1", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "mem5", "0", TCL_GLOBAL_ONLY); +#endif + #ifdef SQLITE_OMIT_ALTERTABLE Tcl_SetVar2(interp, "sqlite_options", "altertable", "0", TCL_GLOBAL_ONLY); #else diff --git a/src/test_malloc.c b/src/test_malloc.c index df35b207d0..ef7512e64d 100644 --- a/src/test_malloc.c +++ b/src/test_malloc.c @@ -13,7 +13,7 @@ ** This file contains code used to implement test interfaces to the ** memory allocation subsystem. ** -** $Id: test_malloc.c,v 1.12 2008/02/13 18:25:27 danielk1977 Exp $ +** $Id: test_malloc.c,v 1.13 2008/02/16 16:21:46 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -334,7 +334,8 @@ static int test_memdebug_dump( Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); return TCL_ERROR; } -#if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) +#if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \ + || defined(SQLITE_POW2_MEMORY_SIZE) { extern void sqlite3_memdebug_dump(const char*); sqlite3_memdebug_dump(Tcl_GetString(objv[1])); diff --git a/test/tester.tcl b/test/tester.tcl index e0c2a50c9a..d5b5ae5116 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -11,7 +11,7 @@ # This file implements some common TCL routines used for regression # testing the SQLite library # -# $Id: tester.tcl,v 1.104 2008/02/13 18:25:27 danielk1977 Exp $ +# $Id: tester.tcl,v 1.105 2008/02/16 16:21:46 drh Exp $ set tcl_precision 15 @@ -215,13 +215,13 @@ proc finalize_testing {} { if {[sqlite3_memory_used]>0} { puts "Unfreed memory: [sqlite3_memory_used] bytes" incr nErr - ifcapable memdebug||(mem3&&debug) { + ifcapable memdebug||mem5||(mem3&&debug) { puts "Writing unfreed memory log to \"./memleak.txt\"" sqlite3_memdebug_dump ./memleak.txt } } else { puts "All memory allocations freed - no leaks" - ifcapable memdebug { + ifcapable memdebug||mem5 { sqlite3_memdebug_dump ./memusage.txt } } diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index e7befd8fc4..5d796fb634 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -208,6 +208,7 @@ foreach file { mem1.c mem2.c mem3.c + mem5.c mutex.c mutex_os2.c mutex_unix.c