Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch lsm_env-xsize Excluding Merge-Ins
This is equivalent to a diff from 28a10397d1 to 1eb4aaa4c2
2012-07-07
| ||
11:44 | merged in lsm_env-xsize branch. check-in: 3dd0037efb user: stephan tags: trunk | |
11:43 | Added license header to test_mem.c Closed-Leaf check-in: 1eb4aaa4c2 user: stephan tags: lsm_env-xsize | |
11:30 | Updates to test_mem.c. Add the "mtv.tcl" script to the tool/ directory. check-in: 4c5516a180 user: dan tags: lsm_env-xsize | |
2012-07-06
| ||
22:38 | Minor internal doc correction. check-in: 2ee70dc7a3 user: stephan tags: trunk | |
21:58 | Create new branch named "lsm_env-xsize" check-in: 6d31a9d20c user: stephan tags: lsm_env-xsize | |
17:42 | Add file "shm.wiki" with notes regarding shared memory contents. check-in: daac1c7c4e user: dan tags: multi-process | |
2012-07-04
| ||
09:44 | Remove unused variable. check-in: 28a10397d1 user: dan tags: trunk | |
2012-07-03
| ||
18:59 | Add OOM test cases. check-in: e5f3a7f3bb user: dan tags: trunk | |
Changes to GNUmakefile.linux.
︙ | ︙ | |||
38 39 40 41 42 43 44 45 46 47 48 49 50 51 | ifeq (clang,$(compiler)) BCC ?= clang -g -Wall endif ######################################################################## # optionally set OPTS to various sqlite4 build options. # OPTS = -DHI_WORLD ######################################################################## # Now include the main rules... include Makefile.linux-gcc ######################################################################## # Force regeneration of sqlite4.h if any makefiles change... parse.h sqlite4.h: $(MAKEFILE_LIST) | > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | ifeq (clang,$(compiler)) BCC ?= clang -g -Wall endif ######################################################################## # optionally set OPTS to various sqlite4 build options. # OPTS = -DHI_WORLD # OPTS += -DLSM_DEBUG_MEM=1 ######################################################################## # Now include the main rules... include Makefile.linux-gcc ######################################################################## # Force regeneration of sqlite4.h if any makefiles change... parse.h sqlite4.h: $(MAKEFILE_LIST) |
︙ | ︙ |
Changes to main.mk.
︙ | ︙ | |||
227 228 229 230 231 232 233 234 235 236 237 238 239 240 | $(TOP)/test/test_utf.c \ $(TOP)/test/test_misc1.c \ $(TOP)/test/test_config.c \ $(TOP)/test/test_func.c \ $(TOP)/test/test_hexio.c \ $(TOP)/test/test_lsm.c \ $(TOP)/test/test_malloc.c \ $(TOP)/test/test_mutex.c \ $(TOP)/test/test_storage.c \ $(TOP)/test/test_storage2.c \ $(TOP)/test/test_thread.c \ $(TOP)/test/test_wsd.c #TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c | > | 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | $(TOP)/test/test_utf.c \ $(TOP)/test/test_misc1.c \ $(TOP)/test/test_config.c \ $(TOP)/test/test_func.c \ $(TOP)/test/test_hexio.c \ $(TOP)/test/test_lsm.c \ $(TOP)/test/test_malloc.c \ $(TOP)/test/test_mem.c \ $(TOP)/test/test_mutex.c \ $(TOP)/test/test_storage.c \ $(TOP)/test/test_storage2.c \ $(TOP)/test/test_thread.c \ $(TOP)/test/test_wsd.c #TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c |
︙ | ︙ | |||
565 566 567 568 569 570 571 572 573 574 | rm -f $(PUBLISH) rm -f *.da *.bb *.bbg gmon.out rm -rf tsrc target_source rm -f testloadext.dll libtestloadext.so rm -f amalgamation-testfixture amalgamation-testfixture.exe rm -f fts3-testfixture fts3-testfixture.exe rm -f testfixture testfixture.exe rm -f threadtest3 threadtest3.exe rm -f sqlite4.c fts?amal.c tclsqlite4.c rm -f sqlite4_analyzer sqlite4_analyzer.exe sqlite4_analyzer.c | > | 566 567 568 569 570 571 572 573 574 575 576 | rm -f $(PUBLISH) rm -f *.da *.bb *.bbg gmon.out rm -rf tsrc target_source rm -f testloadext.dll libtestloadext.so rm -f amalgamation-testfixture amalgamation-testfixture.exe rm -f fts3-testfixture fts3-testfixture.exe rm -f testfixture testfixture.exe rm -f lsmtest rm -f threadtest3 threadtest3.exe rm -f sqlite4.c fts?amal.c tclsqlite4.c rm -f sqlite4_analyzer sqlite4_analyzer.exe sqlite4_analyzer.c |
Changes to src/Makefile.
1 | default: | | | 1 2 3 4 | default: $(MAKE) -C .. all testfixture $(MAKECMDGOALS): $(MAKE) -C .. $@ |
Changes to src/lsm.h.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** ** This file defines the LSM API. */ #ifndef _LSM_H #define _LSM_H #include <stddef.h> | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ************************************************************************* ** ** This file defines the LSM API. */ #ifndef _LSM_H #define _LSM_H #include <stddef.h> #include "sqlite4.h" /* for sqlite4_size_t */ #ifdef __cplusplus extern "C" { #endif /* ** Opaque handle types. */ |
︙ | ︙ | |||
54 55 56 57 58 59 60 61 62 63 64 65 66 67 | int (*xClose)(lsm_file *); int (*xUnlink)(lsm_env*, const char *); /****** memory allocation ****************************************/ void *pMemCtx; void *(*xMalloc)(lsm_env*, int); /* malloc(3) function */ void *(*xRealloc)(lsm_env*, void *, int); /* realloc(3) function */ void (*xFree)(lsm_env*, void *); /* free(3) function */ /****** mutexes ****************************************************/ void *pMutexCtx; int (*xMutexStatic)(lsm_env*,int,lsm_mutex**); /* Obtain a static mutex */ int (*xMutexNew)(lsm_env*, lsm_mutex**); /* Get a new dynamic mutex */ void (*xMutexDel)(lsm_mutex *); /* Delete an allocated mutex */ void (*xMutexEnter)(lsm_mutex *); /* Grab a mutex */ int (*xMutexTry)(lsm_mutex *); /* Attempt to obtain a mutex */ | > > > | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | int (*xClose)(lsm_file *); int (*xUnlink)(lsm_env*, const char *); /****** memory allocation ****************************************/ void *pMemCtx; void *(*xMalloc)(lsm_env*, int); /* malloc(3) function */ void *(*xRealloc)(lsm_env*, void *, int); /* realloc(3) function */ void (*xFree)(lsm_env*, void *); /* free(3) function */ #if 1 sqlite4_size_t (*xSize)(lsm_env*, void *); /* xSize function */ #endif /****** mutexes ****************************************************/ void *pMutexCtx; int (*xMutexStatic)(lsm_env*,int,lsm_mutex**); /* Obtain a static mutex */ int (*xMutexNew)(lsm_env*, lsm_mutex**); /* Get a new dynamic mutex */ void (*xMutexDel)(lsm_mutex *); /* Delete an allocated mutex */ void (*xMutexEnter)(lsm_mutex *); /* Grab a mutex */ int (*xMutexTry)(lsm_mutex *); /* Attempt to obtain a mutex */ |
︙ | ︙ |
Changes to src/lsm_shared.c.
︙ | ︙ | |||
754 755 756 757 758 759 760 | ** must be held in order to call this function. ** ** If successful, *piBlk is set to the block number allocated and LSM_OK is ** returned. Otherwise, *piBlk is zeroed and an lsm error code returned. */ int lsmBlockAllocate(lsm_db *pDb, int *piBlk){ Database *p = pDb->pDatabase; | < < | 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 | ** must be held in order to call this function. ** ** If successful, *piBlk is set to the block number allocated and LSM_OK is ** returned. Otherwise, *piBlk is zeroed and an lsm error code returned. */ int lsmBlockAllocate(lsm_db *pDb, int *piBlk){ Database *p = pDb->pDatabase; Freelist *pFree; /* Database free list */ int iRet = 0; /* Block number of allocated block */ pFree = &p->freelist; if( pFree->nEntry>0 ){ /* The first block on the free list was freed as part of the work done ** to create the snapshot with id iFree. So, we can reuse this block if ** snapshot iFree or later has been checkpointed and all currently ** active clients are reading from snapshot iFree or later. |
︙ | ︙ |
Changes to src/lsm_unix.c.
︙ | ︙ | |||
277 278 279 280 281 282 283 | int prc = unlink(zFile); return prc ? LSM_IOERR_BKPT : LSM_OK; } /**************************************************************************** ** Memory allocation routines. */ | > > > | > > > > > > > | > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | int prc = unlink(zFile); return prc ? LSM_IOERR_BKPT : LSM_OK; } /**************************************************************************** ** Memory allocation routines. */ #define ROUND8(x) (((x)+7)&~7) #define BLOCK_HDR_SIZE ROUND8( sizeof(sqlite4_size_t) ) static void *lsmPosixOsMalloc(lsm_env *pEnv, int N){ unsigned char * m; N += BLOCK_HDR_SIZE; m = (unsigned char *)malloc(N); *((sqlite4_size_t*)m) = N; return m + BLOCK_HDR_SIZE; } static void lsmPosixOsFree(lsm_env *pEnv, void *p){ if(p){ free( ((unsigned char *)p) - BLOCK_HDR_SIZE ); } } static void *lsmPosixOsRealloc(lsm_env *pEnv, void *p, int N){ unsigned char * m = (unsigned char *)p; if(1>N){ lsmPosixOsFree( pEnv, p ); return NULL; }else if(NULL==p){ return lsmPosixOsMalloc(pEnv, N); }else{ void * re = NULL; m -= BLOCK_HDR_SIZE; #if 0 /* arguable: don't shrink */ sqlite4_size_t * sz = (sqlite4_size_t*)m; if(*sz >= (sqlite4_size_t)N){ return p; } #endif re = realloc( m, N + BLOCK_HDR_SIZE ); if(re){ m = (unsigned char *)re; *((sqlite4_size_t*)m) = N; return m + BLOCK_HDR_SIZE; }else{ return NULL; } } } static sqlite4_size_t lsmPosixOsMSize(lsm_env *pEnv, void *p){ unsigned char * m = (unsigned char *)p; return *((sqlite4_size_t*)(m-BLOCK_HDR_SIZE)); } #undef ROUND8 #undef BLOCK_HDR_SIZE #ifdef LSM_MUTEX_PTHREADS /************************************************************************* ** Mutex methods for pthreads based systems. If LSM_MUTEX_PTHREADS is ** missing then a no-op implementation of mutexes found in lsm_mutex.c ** will be used instead. |
︙ | ︙ | |||
488 489 490 491 492 493 494 | lsmPosixOsClose, /* xClose */ lsmPosixOsUnlink, /* xUnlink */ /***** memory allocation *********/ 0, /* pMemCtx */ lsmPosixOsMalloc, /* xMalloc */ lsmPosixOsRealloc, /* xRealloc */ lsmPosixOsFree, /* xFree */ | | > | 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 | lsmPosixOsClose, /* xClose */ lsmPosixOsUnlink, /* xUnlink */ /***** memory allocation *********/ 0, /* pMemCtx */ lsmPosixOsMalloc, /* xMalloc */ lsmPosixOsRealloc, /* xRealloc */ lsmPosixOsFree, /* xFree */ lsmPosixOsMSize, /* xSize */ /***** mutexes *********************/ 0, /* pMutexCtx */ lsmPosixOsMutexStatic, /* xMutexStatic */ lsmPosixOsMutexNew, /* xMutexNew */ lsmPosixOsMutexDel, /* xMutexDel */ lsmPosixOsMutexEnter, /* xMutexEnter */ lsmPosixOsMutexTry, /* xMutexTry */ lsmPosixOsMutexLeave, /* xMutexLeave */ lsmPosixOsMutexHeld, /* xMutexHeld */ lsmPosixOsMutexNotHeld, /* xMutexNotHeld */ }; return &posix_env; } |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
36 37 38 39 40 41 42 | # include "sqlite4.h" # include <stdlib.h> # include <string.h> # include <assert.h> typedef unsigned char u8; #endif #include <ctype.h> | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | # include "sqlite4.h" # include <stdlib.h> # include <string.h> # include <assert.h> typedef unsigned char u8; #endif #include <ctype.h> #include <stdlib.h> /* atexit() */ /* * Windows needs to know which symbols to export. Unix does not. * BUILD_sqlite should be undefined for Unix. */ #ifdef BUILD_sqlite #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT |
︙ | ︙ | |||
2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 | if( !slave ){ return TCL_ERROR; } init_all(slave); return TCL_OK; } /* ** Tclcmd: db_use_legacy_prepare DB BOOLEAN ** ** The first argument to this command must be a database command created by ** [sqlite4]. If the second argument is true, then the handle is configured ** to use the sqlite4_prepare_v2() function to prepare statements. If it | > | 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 | if( !slave ){ return TCL_ERROR; } init_all(slave); return TCL_OK; } /* ** Tclcmd: db_use_legacy_prepare DB BOOLEAN ** ** The first argument to this command must be a database command created by ** [sqlite4]. If the second argument is true, then the handle is configured ** to use the sqlite4_prepare_v2() function to prepare statements. If it |
︙ | ︙ | |||
2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 | extern int Sqlitetestrtree_Init(Tcl_Interp*); extern int Sqlitequota_Init(Tcl_Interp*); extern int SqliteSuperlock_Init(Tcl_Interp*); extern int SqlitetestSyscall_Init(Tcl_Interp*); extern int Sqliteteststorage_Init(Tcl_Interp*); extern int Sqliteteststorage2_Init(Tcl_Interp*); extern int SqlitetestLsm_Init(Tcl_Interp*); Sqliteconfig_Init(interp); Sqlitetest1_Init(interp); Sqlitetest4_Init(interp); Sqlitetest5_Init(interp); Sqlitetest9_Init(interp); Sqlitetest_hexio_Init(interp); Sqlitetest_malloc_Init(interp); Sqlitetest_mutex_Init(interp); SqlitetestThread_Init(interp); Sqliteteststorage_Init(interp); Sqliteteststorage2_Init(interp); SqlitetestLsm_Init(interp); Tcl_CreateObjCommand( interp, "load_testfixture_extensions", init_all_cmd, 0, 0 ); Tcl_CreateObjCommand( interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0 | > > | 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 | extern int Sqlitetestrtree_Init(Tcl_Interp*); extern int Sqlitequota_Init(Tcl_Interp*); extern int SqliteSuperlock_Init(Tcl_Interp*); extern int SqlitetestSyscall_Init(Tcl_Interp*); extern int Sqliteteststorage_Init(Tcl_Interp*); extern int Sqliteteststorage2_Init(Tcl_Interp*); extern int SqlitetestLsm_Init(Tcl_Interp*); extern int Sqlitetest_mem_Init(Tcl_Interp*); Sqliteconfig_Init(interp); Sqlitetest1_Init(interp); Sqlitetest4_Init(interp); Sqlitetest5_Init(interp); Sqlitetest9_Init(interp); Sqlitetest_hexio_Init(interp); Sqlitetest_malloc_Init(interp); Sqlitetest_mutex_Init(interp); SqlitetestThread_Init(interp); Sqliteteststorage_Init(interp); Sqliteteststorage2_Init(interp); SqlitetestLsm_Init(interp); Sqlitetest_mem_Init(interp); Tcl_CreateObjCommand( interp, "load_testfixture_extensions", init_all_cmd, 0, 0 ); Tcl_CreateObjCommand( interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0 |
︙ | ︙ | |||
2987 2988 2989 2990 2991 2992 2993 | Tcl_Interp *interp; /* Call sqlite4_shutdown() once before doing anything else. This is to ** test that sqlite4_shutdown() can be safely called by a process before ** sqlite4_initialize() is. */ sqlite4_shutdown(0); | | | > > | 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 | Tcl_Interp *interp; /* Call sqlite4_shutdown() once before doing anything else. This is to ** test that sqlite4_shutdown() can be safely called by a process before ** sqlite4_initialize() is. */ sqlite4_shutdown(0); /*Tcl_FindExecutable(argv[0]);*/ interp = Tcl_CreateInterp(); #if TCLSH==2 sqlite4_env_config(0, SQLITE4_ENVCONFIG_SINGLETHREAD); #endif init_all(interp); if( argc>=2 ){ int i; char zArgc[32]; sqlite4_snprintf(zArgc, sizeof(zArgc), "%d", argc-(3-TCLSH)); Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY); Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY); Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY); for(i=3-TCLSH; i<argc; i++){ Tcl_SetVar(interp, "argv", argv[i], TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE); } if( TCLSH==1 && Tcl_EvalFile(interp, argv[1])!=TCL_OK ){ const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); if( zInfo==0 ) zInfo = Tcl_GetStringResult(interp); fprintf(stderr,"%s: %s\n", *argv, zInfo); Tcl_DeleteInterp( interp ); return 1; } } if( TCLSH==2 || argc<=1 ){ Tcl_GlobalEval(interp, tclsh_main_loop()); } Tcl_DeleteInterp( interp ); return 0; } #endif /* TCLSH */ |
Changes to test/test_main.c.
︙ | ︙ | |||
180 181 182 183 184 185 186 | #define StmtToDb(X) sqlite4_db_handle(X) /* ** Check a return value to make sure it agrees with the results ** from sqlite4_errcode. */ int sqlite4TestErrCode(Tcl_Interp *interp, sqlite4 *db, int rc){ | < | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | #define StmtToDb(X) sqlite4_db_handle(X) /* ** Check a return value to make sure it agrees with the results ** from sqlite4_errcode. */ int sqlite4TestErrCode(Tcl_Interp *interp, sqlite4 *db, int rc){ if( rc!=SQLITE4_MISUSE && rc!=SQLITE4_OK && sqlite4_errcode(db)!=rc ){ char zBuf[200]; int r2 = sqlite4_errcode(db); sprintf(zBuf, "error code %s (%d) does not match sqlite4_errcode %s (%d)", t1ErrorName(rc), rc, t1ErrorName(r2), r2); Tcl_ResetResult(interp); Tcl_AppendResult(interp, zBuf, 0); |
︙ | ︙ |
Added test/test_mem.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | /* ** 2012 July 7 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** */ #include <stdio.h> #include <assert.h> #include <string.h> #include "sqlite4.h" #define ArraySize(x) ((int)(sizeof(x) / sizeof((x)[0]))) #define MIN(x,y) ((x)<(y) ? (x) : (y)) typedef unsigned int u32; typedef unsigned char u8; typedef long long int i64; typedef unsigned long long int u64; #if defined(__GLIBC__) extern int backtrace(void**,int); extern void backtrace_symbols_fd(void*const*,int,int); # define TM_BACKTRACE 12 #else # define backtrace(A,B) 1 # define backtrace_symbols_fd(A,B,C) #endif typedef struct TmBlockHdr TmBlockHdr; typedef struct TmAgg TmAgg; typedef struct TmGlobal TmGlobal; struct TmGlobal { /* Linked list of all currently outstanding allocations. And a table of ** all allocations, past and present, indexed by backtrace() info. */ TmBlockHdr *pFirst; #ifdef TM_BACKTRACE TmAgg *aHash[10000]; #endif /* Underlying malloc/realloc/free functions */ sqlite4_mem_methods mem; }; struct TmBlockHdr { TmBlockHdr *pNext; TmBlockHdr *pPrev; int nByte; #ifdef TM_BACKTRACE TmAgg *pAgg; #endif u32 iForeGuard; }; #ifdef TM_BACKTRACE struct TmAgg { int nAlloc; /* Number of allocations at this path */ int nByte; /* Total number of bytes allocated */ int nOutAlloc; /* Number of outstanding allocations */ int nOutByte; /* Number of outstanding bytes */ void *aFrame[TM_BACKTRACE]; /* backtrace() output */ TmAgg *pNext; /* Next object in hash-table collision */ }; #endif #define FOREGUARD 0x80F5E153 #define REARGUARD 0xE4676B53 static const u32 rearguard = REARGUARD; #define ROUND8(x) (((x)+7)&~7) #define BLOCK_HDR_SIZE (ROUND8( sizeof(TmBlockHdr) )) static void tmEnterMutex(TmGlobal *pTm){ /*pTm->xEnterMutex(pTm);*/ } static void tmLeaveMutex(TmGlobal *pTm){ /* pTm->xLeaveMutex(pTm); */ } static void *tmMalloc(TmGlobal *pTm, int nByte){ TmBlockHdr *pNew; /* New allocation header block */ u8 *pUser; /* Return value */ int nReq; /* Total number of bytes requested */ assert( sizeof(rearguard)==4 ); nReq = BLOCK_HDR_SIZE + nByte + 4; pNew = (TmBlockHdr *)pTm->mem.xMalloc(pTm->mem.pMemEnv, nReq); memset(pNew, 0, sizeof(TmBlockHdr)); tmEnterMutex(pTm); pNew->iForeGuard = FOREGUARD; pNew->nByte = nByte; pNew->pNext = pTm->pFirst; if( pTm->pFirst ){ pTm->pFirst->pPrev = pNew; } pTm->pFirst = pNew; pUser = &((u8 *)pNew)[BLOCK_HDR_SIZE]; memset(pUser, 0x56, nByte); memcpy(&pUser[nByte], &rearguard, 4); #ifdef TM_BACKTRACE { TmAgg *pAgg; int i; u32 iHash = 0; void *aFrame[TM_BACKTRACE]; memset(aFrame, 0, sizeof(aFrame)); backtrace(aFrame, TM_BACKTRACE); for(i=0; i<ArraySize(aFrame); i++){ iHash += (u64)(aFrame[i]) + (iHash<<3); } iHash = iHash % ArraySize(pTm->aHash); for(pAgg=pTm->aHash[iHash]; pAgg; pAgg=pAgg->pNext){ if( memcmp(pAgg->aFrame, aFrame, sizeof(aFrame))==0 ) break; } if( !pAgg ){ pAgg = (TmAgg *)pTm->mem.xMalloc(pTm->mem.pMemEnv, sizeof(TmAgg)); memset(pAgg, 0, sizeof(TmAgg)); memcpy(pAgg->aFrame, aFrame, sizeof(aFrame)); pAgg->pNext = pTm->aHash[iHash]; pTm->aHash[iHash] = pAgg; } pAgg->nAlloc++; pAgg->nByte += nByte; pAgg->nOutAlloc++; pAgg->nOutByte += nByte; pNew->pAgg = pAgg; } #endif tmLeaveMutex(pTm); return pUser; } static void tmFree(TmGlobal *pTm, void *p){ if( p ){ TmBlockHdr *pHdr; u8 *pUser = (u8 *)p; tmEnterMutex(pTm); pHdr = (TmBlockHdr *)&pUser[BLOCK_HDR_SIZE * -1]; assert( pHdr->iForeGuard==FOREGUARD ); assert( 0==memcmp(&pUser[pHdr->nByte], &rearguard, 4) ); if( pHdr->pPrev ){ assert( pHdr->pPrev->pNext==pHdr ); pHdr->pPrev->pNext = pHdr->pNext; }else{ assert( pHdr==pTm->pFirst ); pTm->pFirst = pHdr->pNext; } if( pHdr->pNext ){ assert( pHdr->pNext->pPrev==pHdr ); pHdr->pNext->pPrev = pHdr->pPrev; } #ifdef TM_BACKTRACE pHdr->pAgg->nOutAlloc--; pHdr->pAgg->nOutByte -= pHdr->nByte; #endif tmLeaveMutex(pTm); memset(pUser, 0x58, pHdr->nByte); memset(pHdr, 0x57, sizeof(TmBlockHdr)); pTm->mem.xFree(pTm->mem.pMemEnv, pHdr); } } static void *tmRealloc(TmGlobal *pTm, void *p, int nByte){ void *pNew; pNew = tmMalloc(pTm, nByte); if( pNew && p ){ TmBlockHdr *pHdr; u8 *pUser = (u8 *)p; pHdr = (TmBlockHdr *)&pUser[BLOCK_HDR_SIZE * -1]; memcpy(pNew, p, MIN(nByte, pHdr->nByte)); tmFree(pTm, p); } return pNew; } static void tmMallocCheck( TmGlobal *pTm, int *pnLeakAlloc, int *pnLeakByte, FILE *pFile ){ TmBlockHdr *pHdr; int nLeak = 0; int nByte = 0; if( pTm==0 ) return; for(pHdr=pTm->pFirst; pHdr; pHdr=pHdr->pNext){ nLeak++; nByte += pHdr->nByte; } if( pnLeakAlloc ) *pnLeakAlloc = nLeak; if( pnLeakByte ) *pnLeakByte = nByte; #ifdef TM_BACKTRACE if( pFile ){ int i; fprintf(pFile, "LEAKS\n"); for(i=0; i<ArraySize(pTm->aHash); i++){ TmAgg *pAgg; for(pAgg=pTm->aHash[i]; pAgg; pAgg=pAgg->pNext){ if( pAgg->nOutAlloc ){ int j; fprintf(pFile, "%d %d ", pAgg->nOutByte, pAgg->nOutAlloc); for(j=0; j<TM_BACKTRACE; j++){ fprintf(pFile, "%p ", pAgg->aFrame[j]); } fprintf(pFile, "\n"); } } } fprintf(pFile, "\nALLOCATIONS\n"); for(i=0; i<ArraySize(pTm->aHash); i++){ TmAgg *pAgg; for(pAgg=pTm->aHash[i]; pAgg; pAgg=pAgg->pNext){ int j; fprintf(pFile, "%d %d ", pAgg->nByte, pAgg->nAlloc); for(j=0; j<TM_BACKTRACE; j++) fprintf(pFile, "%p ", pAgg->aFrame[j]); fprintf(pFile, "\n"); } } } #else (void)pFile; #endif } static void *tmLsmEnvXMalloc(void *p, sqlite4_size_t n){ return tmMalloc( (TmGlobal*) p, (int)n ); } static void tmLsmEnvXFree(void *p, void *ptr){ tmFree( (TmGlobal *)p, ptr ); } static void *tmLsmEnvXRealloc(void *ptr, void * mem, int n){ return tmRealloc((TmGlobal*)ptr, mem, n); } static sqlite4_size_t tmLsmXSize(void *p, void *ptr){ if(NULL==ptr){ return 0; }else{ unsigned char * pUc = (unsigned char *)ptr; TmBlockHdr * pBlock = (TmBlockHdr*)(pUc-BLOCK_HDR_SIZE); assert( pBlock->nByte > 0 ); return (sqlite4_size_t) pBlock->nByte; } } static int tmInitStub(void* ignored){ assert("Set breakpoint here."); return 0; } static void tmVoidStub(void* ignored){} int testMallocInstall(sqlite4_env *pEnv){ TmGlobal *pGlobal; /* Object containing allocation hash */ sqlite4_mem_methods allocator; /* This malloc system */ sqlite4_mem_methods orig; /* Underlying malloc system */ /* Allocate and populate a TmGlobal structure. sqlite4_malloc cannot be ** used to allocate the TmGlobal struct as this would cause the environment ** to move to "initialized" state and the SQLITE4_ENVCONFIG_MALLOC ** to fail. */ sqlite4_env_config(pEnv, SQLITE4_ENVCONFIG_GETMALLOC, &orig); pGlobal = (TmGlobal *)orig.xMalloc(orig.pMemEnv, sizeof(TmGlobal)); memset(pGlobal, 0, sizeof(TmGlobal)); memcpy(&pGlobal->mem, &orig, sizeof(orig)); /* Set up pEnv to the use the new TmGlobal */ allocator.xRealloc = tmLsmEnvXRealloc; allocator.xMalloc = tmLsmEnvXMalloc; allocator.xFree = tmLsmEnvXFree; allocator.xSize = tmLsmXSize; allocator.xInit = tmInitStub; allocator.xShutdown = tmVoidStub; allocator.xBeginBenign = tmVoidStub; allocator.xEndBenign = tmVoidStub; allocator.pMemEnv = pGlobal; return sqlite4_env_config(pEnv, SQLITE4_ENVCONFIG_MALLOC, &allocator); } int testMallocUninstall(sqlite4_env *pEnv){ TmGlobal *pGlobal; /* Object containing allocation hash */ sqlite4_mem_methods allocator; /* This malloc system */ int rc; sqlite4_env_config(pEnv, SQLITE4_ENVCONFIG_GETMALLOC, &allocator); assert( allocator.xMalloc==tmLsmEnvXMalloc ); pGlobal = (TmGlobal *)allocator.pMemEnv; rc = sqlite4_env_config(pEnv, SQLITE4_ENVCONFIG_MALLOC, &pGlobal->mem); if( rc==SQLITE4_OK ){ sqlite4_free(pEnv, pGlobal); } return rc; } void testMallocCheck( sqlite4_env *pEnv, int *pnLeakAlloc, int *pnLeakByte, FILE *pFile ){ TmGlobal *pGlobal; sqlite4_mem_methods allocator; /* This malloc system */ sqlite4_env_config(pEnv, SQLITE4_ENVCONFIG_GETMALLOC, &allocator); assert( allocator.xMalloc==tmLsmEnvXMalloc ); pGlobal = (TmGlobal *)allocator.pMemEnv; tmMallocCheck(pGlobal, pnLeakAlloc, pnLeakByte, pFile); } #include <tcl.h> /* ** testmem install ** testmem uninstall ** testmem report ?FILENAME? */ static int testmem_cmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite4_env *pEnv; /* SQLite 4 environment to work with */ int iOpt; const char *azSub[] = {"install", "uninstall", "report", 0}; if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "sub-command"); return TCL_ERROR; } if( Tcl_GetIndexFromObj(interp, objv[1], azSub, "sub-command", 0, &iOpt) ){ return TCL_ERROR; } pEnv = sqlite4_env_default(); switch( iOpt ){ case 0: { int rc; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } rc = testMallocInstall(pEnv); if( rc!=SQLITE4_OK ){ Tcl_AppendResult(interp, "Failed to install testmem wrapper", 0); return TCL_ERROR; } break; } case 1: if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } testMallocUninstall(pEnv); break; case 2: { int nLeakAlloc = 0; int nLeakByte = 0; FILE *pReport = 0; Tcl_Obj *pRes; if( objc!=2 && objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "?filename?"); return TCL_ERROR; } if( objc==3 ){ const char *zFile = Tcl_GetString(objv[2]); pReport = fopen(zFile, "w"); if( !pReport ){ Tcl_AppendResult(interp, "Failed to open file: ", zFile, 0); return TCL_ERROR; } } testMallocCheck(pEnv, &nLeakAlloc, &nLeakByte, pReport); if( pReport ) fclose(pReport); pRes = Tcl_NewObj(); Tcl_ListObjAppendElement(interp, pRes, Tcl_NewIntObj(nLeakAlloc)); Tcl_ListObjAppendElement(interp, pRes, Tcl_NewIntObj(nLeakByte)); Tcl_SetObjResult(interp, pRes); break; } } return TCL_OK; } int Sqlitetest_mem_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "testmem", testmem_cmd, 0, 0); return TCL_OK; } |
Changes to test/tester.tcl.
︙ | ︙ | |||
264 265 266 267 268 269 270 | # Parse any options specified in the $argv array. This script accepts the # following options: # # --pause # --soft-heap-limit=NN # --maxerror=NN # --malloctrace=N | < < | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | # Parse any options specified in the $argv array. This script accepts the # following options: # # --pause # --soft-heap-limit=NN # --maxerror=NN # --malloctrace=N # --binarylog=N # --soak=N # --file-retries=N # --file-retry-delay=N # --start=[$permutation:]$testfile # --match=$pattern # set cmdlinearg(soft-heap-limit) 0 set cmdlinearg(maxerror) 1000 set cmdlinearg(malloctrace) 0 set cmdlinearg(binarylog) 0 set cmdlinearg(soak) 0 set cmdlinearg(file-retries) 0 set cmdlinearg(file-retry-delay) 0 set cmdlinearg(start) "" set cmdlinearg(match) "" |
︙ | ︙ | |||
301 302 303 304 305 306 307 | foreach {dummy cmdlinearg(soft-heap-limit)} [split $a =] break } {^-+maxerror=.+$} { foreach {dummy cmdlinearg(maxerror)} [split $a =] break } {^-+malloctrace=.+$} { foreach {dummy cmdlinearg(malloctrace)} [split $a =] break | < < < < < < < | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | foreach {dummy cmdlinearg(soft-heap-limit)} [split $a =] break } {^-+maxerror=.+$} { foreach {dummy cmdlinearg(maxerror)} [split $a =] break } {^-+malloctrace=.+$} { foreach {dummy cmdlinearg(malloctrace)} [split $a =] break } {^-+binarylog=.+$} { foreach {dummy cmdlinearg(binarylog)} [split $a =] break } {^-+soak=.+$} { foreach {dummy cmdlinearg(soak)} [split $a =] break set ::G(issoak) $cmdlinearg(soak) |
︙ | ︙ | |||
351 352 353 354 355 356 357 | } set argv $leftover # Install the malloc layer used to inject OOM errors. And the 'automatic' # extensions. This only needs to be done once for the process. # sqlite4_shutdown | | > < < < < < < | 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | } set argv $leftover # Install the malloc layer used to inject OOM errors. And the 'automatic' # extensions. This only needs to be done once for the process. # sqlite4_shutdown # install_malloc_faultsim 1 if {$cmdlinearg(malloctrace)} { testmem install } kvwrap install sqlite4_initialize #autoinstall_test_functions # If the --binarylog option was specified, create the logging VFS. This # call installs the new VFS as the default for all SQLite connections. # if {$cmdlinearg(binarylog)} { vfslog new binarylog {} vfslog.bin } } # Create a test database # proc reset_db {} { catch {db close} forcedelete test.db |
︙ | ︙ | |||
740 741 742 743 744 745 746 | show_memstats puts "Maximum memory usage: [sqlite4_memory_highwater 1] bytes" puts "Current memory usage: [sqlite4_memory_highwater] bytes" if {[info commands sqlite4_memdebug_malloc_count] ne ""} { puts "Number of malloc() : [sqlite4_memdebug_malloc_count] calls" } if {$::cmdlinearg(malloctrace)} { | | < < < | < < < < < | 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | show_memstats puts "Maximum memory usage: [sqlite4_memory_highwater 1] bytes" puts "Current memory usage: [sqlite4_memory_highwater] bytes" if {[info commands sqlite4_memdebug_malloc_count] ne ""} { puts "Number of malloc() : [sqlite4_memdebug_malloc_count] calls" } if {$::cmdlinearg(malloctrace)} { puts "Writing malloc() report to malloc.txt..." testmem report malloc.txt } foreach f [glob -nocomplain test.db-*-journal] { forcedelete $f } foreach f [glob -nocomplain test.db-mj*] { forcedelete $f } |
︙ | ︙ |
Added tool/mtv.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | package require sqlite3 package require Tk ############################################################################# # Code to set up scrollbars for widgets. This is generic, boring stuff. # namespace eval autoscroll { proc scrollable {widget path args} { ::ttk::frame $path set w [$widget ${path}.widget {*}$args] set vs [::ttk::scrollbar ${path}.vs] set hs [::ttk::scrollbar ${path}.hs -orient horizontal] grid $w -row 0 -column 0 -sticky nsew grid rowconfigure $path 0 -weight 1 grid columnconfigure $path 0 -weight 1 set grid [list grid $vs -row 0 -column 1 -sticky nsew] $w configure -yscrollcommand [list ::autoscroll::scrollcommand $grid $vs] $vs configure -command [list $w yview] set grid [list grid $hs -row 1 -column 0 -sticky nsew] $w configure -xscrollcommand [list ::autoscroll::scrollcommand $grid $hs] $hs configure -command [list $w xview] return $w } proc scrollcommand {grid sb args} { $sb set {*}$args set isRequired [expr {[lindex $args 0] != 0.0 || [lindex $args 1] != 1.0}] if {$isRequired && ![winfo ismapped $sb]} { {*}$grid } if {!$isRequired && [winfo ismapped $sb]} { grid forget $sb } } namespace export scrollable } namespace import ::autoscroll::* ############################################################################# proc populate_text_widget {db} { $::O(text) configure -state normal set id [lindex [$::O(tree) selection] 0] set frame [lindex $id end] set line [$db one {SELECT line FROM frame WHERE frame = $frame}] if {$line ne ""} { foreach {file line} [split $line :] {} set content [$db one "SELECT content FROM file WHERE name = '$file'"] $::O(text) delete 0.0 end set iLine 1 foreach L [split $content "\n"] { if {$iLine == $line} { $::O(text) insert end "$L\n" highlight } else { $::O(text) insert end "$L\n" } incr iLine } $::O(text) yview -pickplace ${line}.0 } $::O(text) configure -state disabled } proc populate_index {db} { $::O(text) configure -state normal $::O(text) delete 0.0 end $::O(text) insert end "\n\n" set L [format " % -40s%12s%12s\n" "Test Case" "Allocations" "Bytes"] $::O(text) insert end $L $::O(text) insert end " [string repeat - 64]\n" $db eval { -- SELECT 'TOTAL' AS ztest, sum(ncall) AS calls, sum(nbyte) AS bytes -- FROM malloc -- UNION ALL SELECT ztest AS ztest, sum(ncall) AS calls, sum(nbyte) AS bytes FROM malloc GROUP BY ztest ORDER BY 3 DESC } { set tags [list $ztest] if {$ztest eq $::O(current)} { lappend tags highlight } set L [format " % -40s%12s%12s\n" $ztest $calls $bytes] $::O(text) insert end $L $tags $::O(text) tag bind $ztest <1> [list populate_tree_widget $db $ztest] $::O(text) tag bind $ztest <Enter> [list $::O(text) configure -cursor hand2] $::O(text) tag bind $ztest <Leave> [list $::O(text) configure -cursor ""] } $::O(text) configure -state disabled } proc sort_tree_compare {iLeft iRight} { global O switch -- [expr (int($O(tree_sort)/2))] { 0 { set left [$O(tree) item $iLeft -text] set right [$O(tree) item $iRight -text] set res [string compare $left $right] } 1 { set left [lindex [$O(tree) item $iLeft -values] 0] set right [lindex [$O(tree) item $iRight -values] 0] set res [expr $left - $right] } 2 { set left [lindex [$O(tree) item $iLeft -values] 1] set right [lindex [$O(tree) item $iRight -values] 1] set res [expr $left - $right] } } if {$O(tree_sort)&0x01} { set res [expr -1 * $res] } return $res } proc sort_tree {iMode} { global O if {$O(tree_sort) == $iMode} { incr O(tree_sort) } else { set O(tree_sort) $iMode } set T $O(tree) set items [$T children {}] set items [lsort -command sort_tree_compare $items] for {set ii 0} {$ii < [llength $items]} {incr ii} { $T move [lindex $items $ii] {} $ii } } proc trim_frames {stack} { while {[info exists ::O(ignore.[lindex $stack 0])]} { set stack [lrange $stack 1 end] } return $stack } proc populate_tree_widget {db zTest} { $::O(tree) delete [$::O(tree) children {}] for {set ii 0} {$ii < 15} {incr ii} { $db eval { SELECT sum(ncall) AS calls, sum(nbyte) AS bytes, trim_frames(lrange(lstack, 0, $ii)) AS stack FROM malloc WHERE (zTest = $zTest OR $zTest = 'TOTAL') AND llength(lstack)>$ii GROUP BY stack HAVING stack != '' } { set parent_id [lrange $stack 0 end-1] set frame [lindex $stack end] set line [$db one {SELECT line FROM frame WHERE frame = $frame}] set line [lindex [split $line /] end] set v [list $calls $bytes] catch { $::O(tree) insert $parent_id end -id $stack -text $line -values $v } } } set ::O(current) $zTest populate_index $db } set O(tree_sort) 0 ::ttk::panedwindow .pan -orient horizontal set O(tree) [scrollable ::ttk::treeview .pan.tree] frame .pan.right set O(text) [scrollable text .pan.right.text] button .pan.right.index -command {populate_index mddb} -text "Show Index" pack .pan.right.index -side top -fill x pack .pan.right.text -fill both -expand true $O(text) tag configure highlight -background wheat $O(text) configure -wrap none -height 35 .pan add .pan.tree .pan add .pan.right $O(tree) configure -columns {calls bytes} $O(tree) heading #0 -text Line -anchor w -command {sort_tree 0} $O(tree) heading calls -text Calls -anchor w -command {sort_tree 2} $O(tree) heading bytes -text Bytes -anchor w -command {sort_tree 4} $O(tree) column #0 -width 150 $O(tree) column calls -width 100 $O(tree) column bytes -width 100 pack .pan -fill both -expand 1 #-------------------------------------------------------------------- # Open the database containing the malloc data. The user specifies the # database to use by passing the file-name on the command line. # proc lsmtest_report_read {zReport} { sqlite3 mddb :memory: mddb eval { PRAGMA journal_mode=OFF; CREATE TABLE malloc(zTest, nCall, nByte, lStack); CREATE TABLE frame(frame PRIMARY KEY, function, line); CREATE TABLE file(name PRIMARY KEY, content); } set fd [open $zReport] set data [read $fd] close $fd set topic "" foreach zLine [split $data "\n"] { set list [split $zLine " "] if {[string is integer [lindex $list 0]]} { set nByte [lindex $list 0] set nCall [lindex $list 1] set lStack [lrange $list 2 end] mddb eval { INSERT INTO malloc VALUES($topic, $nCall, $nByte, $lStack) } foreach f $lStack { set aFrame($f) "" } } else { set topic [lindex $list 0] } } foreach k [array names aFrame] { set res [exec addr2line -f -e ./testfixture $k] set function [lindex $res 0] set addr [lindex $res 1] mddb eval { INSERT INTO frame VALUES($k, $function, $addr) } set aFile([lindex [split $addr :] 0]) "" } foreach f [array names aFile] { catch { set fd [open $f] set text [read $fd] close $fd mddb eval { INSERT INTO file VALUES($f, $text) } } } } proc open_database {} { set zFilename [lindex $::argv 0] if {$zFilename eq ""} { set zFilename malloc.txt } lsmtest_report_read $zFilename wm title . $zFilename mddb function lrange -argcount 3 lrange mddb function llength -argcount 1 llength mddb function trim_frames -argcount 1 trim_frames mddb eval { SELECT frame FROM frame WHERE line LIKE '%mem.c:%' OR function LIKE '%Malloc' OR function LIKE '%MallocRaw' OR function LIKE '%MallocZero' OR function LIKE '%Realloc' } { set ::O(ignore.$frame) 1 } } open_database bind $O(tree) <<TreeviewSelect>> [list populate_text_widget mddb] populate_tree_widget mddb [mddb one {SELECT zTest FROM malloc LIMIT 1}] |