aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mem2.c10
-rw-r--r--src/test_malloc.c127
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++){