From f2b21158d801e96b5f8d7c9491186267dc75a4dc Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Mon, 15 Apr 2013 20:54:53 +0000 Subject: [PATCH 1/1] Rewrote memory tracking, now prints highest water mark (most used memory at a given time during compile). Changes all byte representation to MB representation. Added ability to print the contents of the leaked memory to the console when -debug is on (infact the lost messages only print during -debug), -memchk simply reports the memory info at the end (it is also printed when -debug). You can set the memory dump columns with -memdumpcols=# where # is the number of columns you want (default is 16) --- main.c | 11 ++++++-- opts.c | 2 ++ opts.def | 1 + util.c | 85 ++++++++++++++++++++++++++++++++++++++++++++------------ 4 files changed, 78 insertions(+), 21 deletions(-) diff --git a/main.c b/main.c index 0c2020c..9da3769 100644 --- a/main.c +++ b/main.c @@ -146,9 +146,10 @@ static bool options_parse(int argc, char **argv) { bool argend = false; size_t itr; char buffer[1024]; - char *redirout = NULL; - char *redirerr = NULL; - char *config = NULL; + char *redirout = NULL; + char *redirerr = NULL; + char *config = NULL; + char *memdumpcols = NULL; while (!argend && argc > 1) { char *argarg; @@ -223,6 +224,10 @@ static bool options_parse(int argc, char **argv) { config = argarg; continue; } + if (options_long_gcc("memdumpcols", &argc, &argv, &memdumpcols)) { + OPTS_OPTION_U16(OPTION_MEMDUMPCOLS) = (uint16_t)strtol(memdumpcols, NULL, 10); + continue; + } /* show defaults (like pathscale) */ if (!strcmp(argv[0]+1, "show-defaults")) { diff --git a/opts.c b/opts.c index 5a1ee1c..e37ba73 100644 --- a/opts.c +++ b/opts.c @@ -64,6 +64,7 @@ static void opts_setdefault() { opts_set(opts.flags, BAIL_ON_WERROR, true); opts_set(opts.flags, LEGACY_VECTOR_MATHS, true); opts_set(opts.flags, DARKPLACES_STRING_TABLE_BUG, true); + } void opts_backup_non_Wall() { @@ -96,6 +97,7 @@ void opts_init(const char *output, int standard, size_t arraysize) { OPTS_OPTION_STR(OPTION_OUTPUT) = (char*)output; OPTS_OPTION_U32(OPTION_STANDARD) = standard; OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE) = arraysize; + OPTS_OPTION_U16(OPTION_MEMDUMPCOLS) = 16; } static bool opts_setflag_all(const char *name, bool on, uint32_t *flags, const opts_flag_def *list, size_t listsize) { diff --git a/opts.def b/opts.def index 90e6fce..f7b5cf1 100644 --- a/opts.def +++ b/opts.def @@ -109,6 +109,7 @@ GMQCC_DEFINE_FLAG(G) GMQCC_DEFINE_FLAG(STANDARD) GMQCC_DEFINE_FLAG(DEBUG) + GMQCC_DEFINE_FLAG(MEMDUMPCOLS) GMQCC_DEFINE_FLAG(MEMCHK) GMQCC_DEFINE_FLAG(DUMPFIN) GMQCC_DEFINE_FLAG(DUMP) diff --git a/util.c b/util.c index c692760..92f8e5e 100644 --- a/util.c +++ b/util.c @@ -30,6 +30,8 @@ uint64_t mem_ab = 0; uint64_t mem_db = 0; uint64_t mem_at = 0; uint64_t mem_dt = 0; +uint64_t mem_pk = 0; +uint64_t mem_hw = 0; struct memblock_t { const char *file; @@ -39,6 +41,12 @@ struct memblock_t { struct memblock_t *prev; }; +#define PEAK_MEM \ + do { \ + if (mem_hw > mem_pk) \ + mem_pk = mem_hw; \ + } while (0) + static struct memblock_t *mem_start = NULL; void *util_memory_a(size_t byte, unsigned int line, const char *file) { @@ -56,6 +64,9 @@ void *util_memory_a(size_t byte, unsigned int line, const char *file) { mem_at++; mem_ab += info->byte; + mem_hw += info->byte; + + PEAK_MEM; return data; } @@ -67,6 +78,7 @@ void util_memory_d(void *ptrn) { info = ((struct memblock_t*)ptrn - 1); mem_db += info->byte; + mem_hw -= info->byte; mem_dt++; if (info->prev) @@ -122,37 +134,74 @@ void *util_memory_r(void *ptrn, size_t byte, unsigned int line, const char *file mem_start = newinfo; mem_ab -= oldinfo->byte; + mem_hw -= oldinfo->byte; mem_ab += newinfo->byte; + mem_hw += newinfo->byte; + + PEAK_MEM; free(oldinfo); return newinfo+1; } +static void util_dumpmem(struct memblock_t *memory, uint16_t cols) { + uint32_t i, j; + for (i = 0; i < memory->byte + ((memory->byte % cols) ? (cols - memory->byte % cols) : 0); i++) { + if (i % cols == 0) con_out(" 0x%06X: ", i); + if (i < memory->byte) con_out("%02X " , 0xFF & ((char*)(memory + 1))[i]); + else con_out(" "); + + if ((uint16_t)(i % cols) == (cols - 1)) { + for (j = i - (cols - 1); j <= i; j++) { + con_out("%c", + (j >= memory->byte) + ? ' ' + : (isprint(((char*)(memory + 1))[j])) + ? 0xFF & ((char*)(memory + 1)) [j] + : '.' + ); + } + con_out("\n"); + } + } +} + void util_meminfo() { struct memblock_t *info; - if (!OPTS_OPTION_BOOL(OPTION_MEMCHK)) - return; - for (info = mem_start; info; info = info->next) { - con_out("lost: % 8u (bytes) at %s:%u\n", - info->byte, - info->file, - info->line); + if (OPTS_OPTION_BOOL(OPTION_DEBUG)) { + for (info = mem_start; info; info = info->next) { + con_out("lost: %u (bytes) at %s:%u\n", + info->byte, + info->file, + info->line); + + util_dumpmem(info, OPTS_OPTION_U16(OPTION_MEMDUMPCOLS)); + } } - con_out("Memory information:\n\ - Total allocations: %llu\n\ - Total deallocations: %llu\n\ - Total allocated: %llu (bytes)\n\ - Total deallocated: %llu (bytes)\n\ - Leaks found: lost %llu (bytes) in %d allocations\n", - mem_at, mem_dt, - mem_ab, mem_db, - (mem_ab - mem_db), - (mem_at - mem_dt) - ); + if (OPTS_OPTION_BOOL(OPTION_DEBUG) || + OPTS_OPTION_BOOL(OPTION_MEMCHK)) { + con_out("Memory information:\n\ + Total allocations: %llu\n\ + Total deallocations: %llu\n\ + Total allocated: %f (MB)\n\ + Total deallocated: %f (MB)\n\ + Total peak memory: %f (MB)\n\ + Total leaked memory: %f (MB) in %llu allocations\n", + mem_at, + (float)(mem_dt) / 1048576.0f, + mem_ab, + (float)(mem_db) / 1048576.0f, + (float)(mem_pk) / 1048576.0f, + (float)(mem_ab - mem_db) / 1048576.0f, + + /* could be more clever */ + (mem_at - mem_dt) + ); + } } /* -- 2.39.2