/*
* Reads a malloc() trace that's been processed by tracemunge, and performs
* the malloc/realloc/frees from that trace in the same sequence so we can
* simulate the effects of changes in malloc algorithms on the application
* which generated the trace.
*/
/* Mark Moraes, D. E. Shaw & Co. */
/*
* TODO! Put a hash function in this code so we can get rid of tracemunge.
* Use better parsing than sscanf. split()?
*/
#include <stdio.h>
#include <string.h>
/*
* ANSI systems had better have this. Non-ANSI systems had better not
* complain about things that are implicitly declared int or void.
*/
#if defined(STDHEADERS)
# include <stdlib.h>
# include <unistd.h>
#endif
#include "zmalloc.h"
char *progname;
/* For getopt() */
extern int getopt();
extern int optind;
extern char *optarg;
#define MAXTIME 100000
static char *bufs[MAXTIME];
static unsigned long sizes[MAXTIME];
unsigned long alloced = 0;
static unsigned long maxalloced = 0;
int verbose = 0;
#ifdef MYMALLOC
extern char *_malloc_loword;
extern char *_malloc_hiword;
#else
extern char *sbrk();
#endif
extern void doline();
void
usage()
{
fprintf(stderr, "Usage: %s [-d] [-m mmapfile] [-T tracefile] [-v]\n",
progname);
exit(1);
}
int
main(argc, argv)
int argc;
char **argv;
{
FILE *trfp = NULL;
int c;
char *before, *after, *trfname = NULL;
unsigned long grew;
int use_mmap = 0;
char buf[1024];
progname = argv[0] ? argv[0] : "(no-argv[0])";
while((c = getopt(argc, argv, "dm:vT:")) != EOF) {
/* optarg has the current argument if the option was followed by ':'*/
switch (c) {
case 'd':
/* Full heap debugging - S-L-O-W */
#ifdef MYMALLOC
mal_debug(3);
#endif
break;
case 'm':
use_mmap = 1;
#ifdef MYMALLOC
mal_mmap(optarg);
#else
fprintf(stderr, "%s: -m option needs CSRI malloc\n",
progname);
#endif
break;
case 'v':
verbose++;
break;
case 'T':
#ifdef MYMALLOC
trfp = fopen(optarg, "w");
if (trfp == NULL) {
perror(progname);
fprintf(stderr, "%s: could not open file `%s' for writing",
progname, optarg);
exit(1);
}
mal_setstatsfile(trfp);
mal_trace(1);
trfname = optarg;
#else
fprintf(stderr, "%s: -T option needs CSRI malloc",
progname);
#endif
break;
case '?':
usage();
break;
}
}
/* Any filenames etc. after all the options */
if (optind < argc) {
usage();
}
#ifndef MYMALLOC
before = sbrk(0);
#endif
while (fgets(buf, sizeof buf, stdin) != NULL) {
doline(buf);
}
#ifndef MYMALLOC
after = sbrk(0);
#else
/* assumes contiguous, ick! should provide a mal_stats function */
before = _malloc_loword;
after = _malloc_hiword;
#endif
grew = after - before;
(void) fprintf(stdout, "Sbrked %ld, MaxAlloced %ld, Wastage %.2f\n",
grew, maxalloced,
grew == 0 ? 0.0 :
(1.0 - ((double) maxalloced) / grew));
#ifdef MYMALLOC
if (verbose)
(void) mal_statsdump(stderr);
#endif
if (trfp) {
if (fflush(trfp) != 0 || fclose(trfp) != 0) {
perror(progname);
fprintf(stderr, "%s: error closing tracefile `%s'",
progname, trfname);
}
}
return 0;
}
void
doline(buf)
char *buf;
{
int n, blk;
switch (buf[0]) {
case '+':
if (buf[1] == '+') {
if (sscanf(buf, "%*[+] %d %*d 0x%*x %*d 0x%*x %d", &n, &blk) == 2 ||
sscanf(buf, "%*[+] %d %*d 0x%*x %d", &n, &blk) == 2) {
if (bufs[blk] == NULL) {
fprintf(stderr, "block %d not yet allocated", blk);
}
bufs[blk] = realloc(bufs[blk], n);
alloced += (n - sizes[blk]);
sizes[blk] = n;
if (alloced > maxalloced)
maxalloced = alloced;
}
} else if (sscanf(buf, "%*[+] %d %*d 0x%*x %d", &n, &blk) == 2) {
if (bufs[blk] != NULL) {
fprintf(stderr, "block %d not yet freed\n", blk);
}
bufs[blk] = malloc(n);
sizes[blk] = n;
alloced += n;
if (alloced > maxalloced)
maxalloced = alloced;
}
break;
case '-':
if (sscanf(buf, "- %*d 0x%*x %d", &blk) == 1) {
if (bufs[blk] == NULL) {
fprintf(stderr, "block %d not yet allocated", blk);
} else {
free(bufs[blk]);
alloced -= sizes[blk];
bufs[blk] = NULL;
sizes[n] = 0;
}
}
break;
case 'a':
case 'h': /* heapstart or heapend */
case 'w':
case 'n':
case '\n':
break;
}
if (verbose)
printf("%lu %s", alloced, buf);
}
syntax highlighted by Code2HTML, v. 0.9.1