#include "squid.h" #include "hash.h" #if HAVE_UNISTD_H #include #endif #if HAVE_STDIO_H #include #endif #if HAVE_CTYPE_H #include #endif #if HAVE_STRINGS_H #include #endif static hash_table *mem_table = NULL; static hash_link *mem_entry; struct rusage myusage; #ifdef WITH_LIB #include "Mem.h" #include extern void sizeToPoolInit(); extern MemPool *sizeToPool(size_t size); #endif extern char *malloc_options; void my_free(char *, int, void *); FILE *fp; char *fn; int initsiz; int maxsiz; int minchunk; HASHCMP ptrcmp; char mbuf[256]; char abuf[32]; char *p; int size; void *addr; int amt; int i; int a; int run_stats = 0; void *my_xmalloc(size_t); void *my_xcalloc(int, size_t); int my_xfree(void *); #define xmalloc my_xmalloc #define xcalloc my_xcalloc #define xfree my_xfree int *size2id_array[2]; int size2id_len = 0; int size2id_alloc = 0; typedef struct { char orig_ptr[32]; void *my_ptr; #ifdef WITH_LIB MemPool *pool; #endif int size; } memitem; struct { int mallocs, frees, callocs, reallocs; } mstat; memitem *mi; void size2id(size_t, memitem *); void badformat(); void init_stats(), print_stats(); void my_hash_insert(hash_table * h, const char *k, memitem * item); static void *xmemAlloc(memitem * item); static void xmemFree(memitem * item); int ptrcmp(const void *a, const void *b) { return (strcmp(a, b)); } main(int argc, char **argv) { char c; extern char *optarg; malloc_options = "A"; a = 0; while ((c = getopt(argc, argv, "f:i:M:l:m:r:N")) != -1) { switch (c) { case 'N': mem_pools_on = 0; break; case 'r': run_stats = atoi(optarg); break; case 'f': fn = strdup(optarg); fp = fopen(fn, "r"); break; case 'i': initsiz = atoi(optarg); break; case 'l': mem_max_size = atoi(optarg) * 1024 * 1024; break; case 'M': maxsiz = atoi(optarg); break; case 'm': minchunk = atoi(optarg); break; default: fprintf(stderr, "Usage: %s -f file -M maxsiz -i initsiz -m minchunk", argv[0]); exit(1); } } if (!fp) { fprintf(stderr, "%s pummels %s\n%s . o O ( You't supply a valid tracefile.)\n", argv[0], getenv("USER"), argv[0]); exit(1); } #ifdef WITH_LIB sizeToPoolInit(); #endif mem_table = hash_create(ptrcmp, 229, hash4); /* small hash table */ init_stats(); while (fgets(mbuf, 256, fp) != NULL) { if (run_stats > 0 && (++a) % run_stats == 0) print_stats(); p = NULL; switch (mbuf[0]) { case 'm': /* malloc */ p = strtok(&mbuf[2], ":"); if (!p) badformat(); size = atoi(p); p = strtok(NULL, "\n"); if (!p) badformat(); mi = malloc(sizeof(memitem)); strcpy(mi->orig_ptr, p); mi->size = size; size2id(size, mi); mi->my_ptr = xmemAlloc(mi); /* (void *)xmalloc(size); */ assert(mi->my_ptr); my_hash_insert(mem_table, mi->orig_ptr, mi); mstat.mallocs++; break; case 'c': /* calloc */ p = strtok(&mbuf[2], ":"); if (!p) badformat(); amt = atoi(p); p = strtok(NULL, ":"); if (!p) badformat(); size = atoi(p); p = strtok(NULL, "\n"); if (!p) badformat(); mi = malloc(sizeof(memitem)); strcpy(mi->orig_ptr, p); size2id(size, mi); mi->size = amt * size; mi->my_ptr = xmemAlloc(mi); /*(void *)xmalloc(amt*size); */ assert(mi->my_ptr); my_hash_insert(mem_table, mi->orig_ptr, mi); mstat.callocs++; break; case 'r': p = strtok(&mbuf[2], ":"); if (!p) badformat(); strcpy(abuf, p); p = strtok(NULL, ":"); if (!p) badformat(); mem_entry = hash_lookup(mem_table, p); if (mem_entry == NULL) { fprintf(stderr, "invalid realloc (%s)!\n", p); break; } mi = (memitem *) (mem_entry->item); assert(mi->pool); assert(mi->my_ptr); xmemFree(mi); /* xfree(mi->my_ptr); */ size2id(atoi(p), mi); /* we don't need it here I guess? */ strcpy(mi->orig_ptr, abuf); p = strtok(NULL, "\n"); if (!p) badformat(); mi->my_ptr = xmemAlloc(mi); /* (char *)xmalloc(atoi(p)); */ assert(mi->my_ptr); mstat.reallocs++; break; case 'f': p = strtok(&mbuf[2], "\n"); mem_entry = hash_lookup(mem_table, p); if (mem_entry == NULL) { if (p[0] != '0') fprintf(stderr, "invalid free (%s) at line %d!\n", p, a); break; } mi = (memitem *) (mem_entry->item); assert(mi->pool); assert(mi->my_ptr); xmemFree(mi); /* xfree(mi->my_ptr); */ hash_unlink(mem_table, mem_entry, 1); free(mi); mstat.frees++; break; default: fprintf(stderr, "%s pummels %s.bad.format\n", argv[0], fn); exit(1); } } fclose(fp); print_stats(); } void * my_xmalloc(size_t a) { return NULL; } void * my_xcalloc(int a, size_t b) { return NULL; } int my_xfree(void *p) { return 0; } void init_stats() { } void print_stats() { #ifdef WITH_LIB memReport(stdout); #endif getrusage(RUSAGE_SELF, &myusage); printf("m/c/f/r=%d/%d/%d/%d\n", mstat.mallocs, mstat.callocs, mstat.frees, mstat.reallocs); #if 0 printf("types : %d\n", size2id_len); #endif printf("user time used : %d.%d\n", (int) myusage.ru_utime.tv_sec, (int) myusage.ru_utime.tv_usec); printf("system time used : %d.%d\n", (int) myusage.ru_stime.tv_sec, (int) myusage.ru_stime.tv_usec); printf("max resident set size : %d\n", (int) myusage.ru_maxrss); printf("page faults : %d\n", (int) myusage.ru_majflt); } void size2id(size_t sz, memitem * mi) { #ifdef WITH_LIB mi->pool = sizeToPool(sz); assert(mi->pool); #endif return; } void badformat() { fprintf(stderr, "pummel.bad.format\n"); exit(1); } /* unused code, saved for parts */ const char * make_nam(int id, int size) { const char *buf = malloc(30); /* argh */ sprintf((char *) buf, "pl:%d/%d", id, size); return buf; } void my_hash_insert(hash_table * h, const char *k, memitem * item) { memitem *l; assert(item->pool); assert(item->my_ptr); hash_insert(h, k, item); } static void * xmemAlloc(memitem * item) { extern MemPool *StringPool; assert(item && item->pool); if (StringPool == item->pool) return memStringAlloc(item->pool, item->size); else return memAlloc(item->pool); } static void xmemFree(memitem * item) { extern MemPool *StringPool; assert(item && item->pool); if (StringPool == item->pool) return memStringFree(item->pool, item->my_ptr, item->size); else return memFree(item->pool, item->my_ptr); } void my_free(char *file, int line, void *ptr) { #if 0 fprintf(stderr, "{%s:%d:%p", file, line, ptr); #endif free(ptr); #if 0 fprintf(stderr, "}\n"); #endif }