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;
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) {
mem_at++;
mem_ab += info->byte;
+ mem_hw += info->byte;
+
+ PEAK_MEM;
return data;
}
info = ((struct memblock_t*)ptrn - 1);
mem_db += info->byte;
+ mem_hw -= info->byte;
mem_dt++;
if (info->prev)
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) {
- util_debug("MEM", "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));
+ }
}
- util_debug("MEM", "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,
+ mem_dt,
+ (float)(mem_ab) / 1048576.0f,
+ (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)
+ );
+ }
}
/*
* Some string utility functions, because strdup uses malloc, and we want
* to track all memory (without replacing malloc).
*/
-char *util_strdup(const char *s) {
+char *_util_Estrdup(const char *s, const char *file, size_t line) {
+ size_t len = 0;
+ char *ptr = NULL;
+
+ /* in case of -DNOTRACK */
+ (void)file;
+ (void)line;
+
+ if (!s)
+ return NULL;
+
+ if ((len = strlen(s)) && (ptr = (char*)mem_af(len+1, line, file))) {
+ memcpy(ptr, s, len);
+ ptr[len] = '\0';
+ }
+ return ptr;
+}
+
+char *_util_Estrdup_empty(const char *s, const char *file, size_t line) {
size_t len = 0;
char *ptr = NULL;
+ /* in case of -DNOTRACK */
+ (void)file;
+ (void)line;
+
if (!s)
return NULL;
- if ((len = strlen(s)) && (ptr = (char*)mem_a(len+1))) {
+ len = strlen(s);
+ if ((ptr = (char*)mem_af(len+1, line, file))) {
memcpy(ptr, s, len);
ptr[len] = '\0';
}
if (!(node = (hash_node_t*)mem_a(sizeof(hash_node_t))))
return NULL;
- if (!(node->key = util_strdup(key))) {
+ if (!(node->key = util_strdupe(key))) {
mem_d(node);
return NULL;
}
* Free all allocated data in a hashtable, this is quite the amount
* of work.
*/
-void util_htdel(hash_table_t *ht) {
+void util_htrem(hash_table_t *ht, void (*callback)(void *data)) {
size_t i = 0;
for (; i < ht->size; i++) {
hash_node_t *n = ht->table[i];
while (n) {
if (n->key)
mem_d(n->key);
+ if (callback)
+ callback(n->value);
p = n;
n = n->next;
mem_d(p);
mem_d(ht);
}
+void util_htrmh(hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)) {
+ hash_node_t **pair = &ht->table[bin];
+ hash_node_t *tmp;
+
+ while (*pair && (*pair)->key && strcmp(key, (*pair)->key) > 0)
+ pair = &(*pair)->next;
+
+ tmp = *pair;
+ if (!tmp || !tmp->key || strcmp(key, tmp->key) != 0)
+ return;
+
+ if (cb)
+ (*cb)(tmp->value);
+
+ *pair = tmp->next;
+ mem_d(tmp->key);
+ mem_d(tmp);
+}
+
+void util_htrm(hash_table_t *ht, const char *key, void (*cb)(void*)) {
+ util_htrmh(ht, key, util_hthash(ht, key), cb);
+}
+
+void util_htdel(hash_table_t *ht) {
+ util_htrem(ht, NULL);
+}
+
/*
* A basic implementation of a hash-set. Unlike a hashtable, a hash
* set doesn't maintain key-value pairs. It simply maintains a key