Gather memory allocation statistics and print them at the end if verbose.

This commit is contained in:
Dag-Erling Smørgrav 2014-10-30 11:05:01 +00:00 committed by des
parent 4a4726f9d6
commit bf087fd70e
3 changed files with 41 additions and 1 deletions

3
t/t.h
View file

@ -116,5 +116,8 @@ extern const uint8_t t_seq8[256];
*/ */
extern int t_malloc_fail; extern int t_malloc_fail;
extern int t_malloc_fatal; extern int t_malloc_fatal;
#ifdef _IONBF /* proxy for <stdio.h> */
void t_malloc_printstats(FILE *);
#endif
#endif #endif

View file

@ -203,5 +203,12 @@ main(int argc, char *argv[])
/* clean up and exit */ /* clean up and exit */
t_cleanup(); t_cleanup();
for (n = 0; n < t_plan_len; ++n) {
free(t_plan[n]->desc);
free(t_plan[n]);
}
free(t_plan);
if (verbose)
t_malloc_printstats(stderr);
exit(fail > 0 ? 1 : 0); exit(fail > 0 ? 1 : 0);
} }

View file

@ -34,6 +34,7 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -91,6 +92,8 @@ struct bucket {
void *top; /* top of bucket */ void *top; /* top of bucket */
void *free; /* first free block */ void *free; /* first free block */
void *unused; /* first never-used block */ void *unused; /* first never-used block */
unsigned long nalloc;
unsigned long nfree;
}; };
struct mapping { struct mapping {
@ -104,6 +107,7 @@ static struct bucket buckets[BUCKET_MAX_SHIFT + 1];
/* mapping metadata */ /* mapping metadata */
static struct mapping *mappings; static struct mapping *mappings;
unsigned long nmapalloc, nmapfree;
/* if non-zero, all allocations fail */ /* if non-zero, all allocations fail */
int t_malloc_fail; int t_malloc_fail;
@ -128,6 +132,7 @@ t_malloc_null(void)
b->top = b->base + BUCKET_SIZE; b->top = b->base + BUCKET_SIZE;
b->free = b->unused = b->base; b->free = b->unused = b->base;
} }
++b->nalloc;
return (b->base); return (b->base);
} }
@ -154,6 +159,7 @@ t_malloc_mapped(size_t size)
m->next = mappings; m->next = mappings;
m->prev = NULL; m->prev = NULL;
mappings = m; mappings = m;
++nmapalloc;
return (m->base); return (m->base);
} }
@ -205,6 +211,7 @@ t_malloc_bucket(size_t size)
} }
/* done! */ /* done! */
++b->nalloc;
return (p); return (p);
} }
@ -340,8 +347,10 @@ free(void *p)
unsigned int shift; unsigned int shift;
/* was this a zero-size allocation? */ /* was this a zero-size allocation? */
if (p == buckets[0].base) if (p == buckets[0].base) {
++buckets[0].nfree;
return; return;
}
/* was this a direct mapping? */ /* was this a direct mapping? */
for (m = mappings; m != NULL; m = m->next) { for (m = mappings; m != NULL; m = m->next) {
@ -357,6 +366,7 @@ free(void *p)
mappings = m->next; mappings = m->next;
/* fall through and free metadata */ /* fall through and free metadata */
p = m; p = m;
++nmapfree;
break; break;
} }
assert(p < m->base || p >= m->top); assert(p < m->base || p >= m->top);
@ -372,6 +382,7 @@ free(void *p)
/* connect the block to the free list */ /* connect the block to the free list */
*(char **)p = b->free; *(char **)p = b->free;
b->free = p; b->free = p;
++b->nfree;
return; return;
} }
} }
@ -379,3 +390,22 @@ free(void *p)
/* oops */ /* oops */
abort(); abort();
} }
/*
* Print allocator statistics
*/
void
t_malloc_printstats(FILE *f)
{
struct bucket *b;
unsigned int shift;
fprintf(f, "%6s %9s %9s %9s\n", "bucket", "alloc", "free", "leak");
for (shift = 0; shift <= BUCKET_MAX_SHIFT; ++shift) {
b = &buckets[shift];
if (b->nalloc > 0)
fprintf(f, " 1^%-3u %9lu %9lu %9lu\n",
shift, b->nalloc, b->nfree,
b->nalloc - b->nfree);
}
}