diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mem2.c | 10 | ||||
-rw-r--r-- | src/test_malloc.c | 127 |
2 files changed, 135 insertions, 2 deletions
diff --git a/src/mem2.c b/src/mem2.c index 41d9720fd..56da91462 100644 --- a/src/mem2.c +++ b/src/mem2.c @@ -12,7 +12,7 @@ ** This file contains the C functions that implement a memory ** allocation subsystem for use by SQLite. ** -** $Id: mem2.c,v 1.22 2008/02/19 15:15:16 drh Exp $ +** $Id: mem2.c,v 1.23 2008/03/21 14:22:44 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -107,6 +107,7 @@ static struct { ** The number of levels of backtrace to save in new allocations. */ int nBacktrace; + void (*xBacktrace)(int, int, void **); /* ** Title text to insert in front of each block @@ -286,6 +287,9 @@ void *sqlite3_malloc(int nByte){ void *aAddr[40]; pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1; memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*)); + if( mem.xBacktrace ){ + mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]); + } }else{ pHdr->nBacktrace = 0; } @@ -389,6 +393,10 @@ void sqlite3MemdebugBacktrace(int depth){ mem.nBacktrace = depth; } +void sqlite3MemdebugBacktraceCallback(void (*xBacktrace)(int, int, void **)){ + mem.xBacktrace = xBacktrace; +} + /* ** Set the title string for subsequent allocations. */ diff --git a/src/test_malloc.c b/src/test_malloc.c index c0daf4690..ce2f718be 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.17 2008/03/18 13:01:38 drh Exp $ +** $Id: test_malloc.c,v 1.18 2008/03/21 14:22:44 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -507,6 +507,130 @@ static int test_memdebug_settitle( return TCL_OK; } +#define MALLOC_LOG_FRAMES 5 +static Tcl_HashTable aMallocLog; +static int mallocLogEnabled = 0; + +typedef struct MallocLog MallocLog; +struct MallocLog { + int nCall; + int nByte; +}; + +static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){ + if( mallocLogEnabled ){ + MallocLog *pLog; + Tcl_HashEntry *pEntry; + int isNew; + + int aKey[MALLOC_LOG_FRAMES]; + int nKey = sizeof(int)*MALLOC_LOG_FRAMES; + + memset(aKey, 0, nKey); + if( (sizeof(void*)*nFrame)<nKey ){ + nKey = nFrame*sizeof(void*); + } + memcpy(aKey, aFrame, nKey); + + pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew); + if( isNew ){ + pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog)); + memset(pLog, 0, sizeof(MallocLog)); + Tcl_SetHashValue(pEntry, (ClientData)pLog); + }else{ + pLog = (MallocLog *)Tcl_GetHashValue(pEntry); + } + + pLog->nCall++; + pLog->nByte += nByte; + } +} + +static int test_memdebug_log( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + static int isInit = 0; + int iSub; + + enum MB_enum { MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR }; + static const char *MB_strs[] = { "start", "stop", "dump", "clear" }; + + if( !isInit ){ +#ifdef SQLITE_MEMDEBUG + extern void sqlite3MemdebugBacktraceCallback( + void (*xBacktrace)(int, int, void **)); + sqlite3MemdebugBacktraceCallback(test_memdebug_callback); +#endif + Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES); + isInit = 1; + } + + if( objc<2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ..."); + } + if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){ + return TCL_ERROR; + } + + switch( (enum MB_enum)iSub ){ + case MB_LOG_START: + mallocLogEnabled = 1; + break; + case MB_LOG_STOP: + mallocLogEnabled = 0; + break; + case MB_LOG_DUMP: { + Tcl_HashSearch search; + Tcl_HashEntry *pEntry; + Tcl_Obj *pRet = Tcl_NewObj(); + + assert(sizeof(int)==sizeof(void*)); + + for( + pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); + pEntry; + pEntry=Tcl_NextHashEntry(&search) + ){ + Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2]; + MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); + int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry); + int ii; + + apElem[0] = Tcl_NewIntObj(pLog->nCall); + apElem[1] = Tcl_NewIntObj(pLog->nByte); + for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){ + apElem[ii+2] = Tcl_NewIntObj(aKey[ii]); + } + + Tcl_ListObjAppendElement(interp, pRet, + Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem) + ); + } + + Tcl_SetObjResult(interp, pRet); + break; + } + case MB_LOG_CLEAR: { + Tcl_HashSearch search; + Tcl_HashEntry *pEntry; + for( + pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); + pEntry; + pEntry=Tcl_NextHashEntry(&search) + ){ + MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); + Tcl_Free((char *)pLog); + } + Tcl_DeleteHashTable(&aMallocLog); + Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES); + } + } + + return TCL_OK; +} /* ** Register commands with the TCL interpreter. @@ -529,6 +653,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){ { "sqlite3_memdebug_pending", test_memdebug_pending }, { "sqlite3_memdebug_settitle", test_memdebug_settitle }, { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count }, + { "sqlite3_memdebug_log", test_memdebug_log }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ |