From 9cdeda34930cba606725ce1497b72e006e1b1c54 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Fri, 23 Oct 2026 12:41:14 +0000 Subject: init malloc lab --- malloclab-handout/mdriver.c | 1017 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1017 insertions(+) create mode 100644 malloclab-handout/mdriver.c (limited to 'malloclab-handout/mdriver.c') diff --git a/malloclab-handout/mdriver.c b/malloclab-handout/mdriver.c new file mode 100644 index 0000000..3aa8a3c --- /dev/null +++ b/malloclab-handout/mdriver.c @@ -0,0 +1,1017 @@ +/* + * mdriver.c - CS:APP Malloc Lab Driver + * + * Uses a collection of trace files to tests a malloc/free/realloc + * implementation in mm.c. + * + * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. + * May not be used, modified, or copied without permission. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mm.h" +#include "memlib.h" +#include "fsecs.h" +#include "config.h" + +/********************** + * Constants and macros + **********************/ + +/* Misc */ +#define MAXLINE 1024 /* max string size */ +#define HDRLINES 4 /* number of header lines in a trace file */ +#define LINENUM(i) (i+5) /* cnvt trace request nums to linenums (origin 1) */ + +/* Returns true if p is ALIGNMENT-byte aligned */ +#define IS_ALIGNED(p) ((((unsigned int)(p)) % ALIGNMENT) == 0) + +/****************************** + * The key compound data types + *****************************/ + +/* Records the extent of each block's payload */ +typedef struct range_t { + char *lo; /* low payload address */ + char *hi; /* high payload address */ + struct range_t *next; /* next list element */ +} range_t; + +/* Characterizes a single trace operation (allocator request) */ +typedef struct { + enum {ALLOC, FREE, REALLOC} type; /* type of request */ + int index; /* index for free() to use later */ + int size; /* byte size of alloc/realloc request */ +} traceop_t; + +/* Holds the information for one trace file*/ +typedef struct { + int sugg_heapsize; /* suggested heap size (unused) */ + int num_ids; /* number of alloc/realloc ids */ + int num_ops; /* number of distinct requests */ + int weight; /* weight for this trace (unused) */ + traceop_t *ops; /* array of requests */ + char **blocks; /* array of ptrs returned by malloc/realloc... */ + size_t *block_sizes; /* ... and a corresponding array of payload sizes */ +} trace_t; + +/* + * Holds the params to the xxx_speed functions, which are timed by fcyc. + * This struct is necessary because fcyc accepts only a pointer array + * as input. + */ +typedef struct { + trace_t *trace; + range_t *ranges; +} speed_t; + +/* Summarizes the important stats for some malloc function on some trace */ +typedef struct { + /* defined for both libc malloc and student malloc package (mm.c) */ + double ops; /* number of ops (malloc/free/realloc) in the trace */ + int valid; /* was the trace processed correctly by the allocator? */ + double secs; /* number of secs needed to run the trace */ + + /* defined only for the student malloc package */ + double util; /* space utilization for this trace (always 0 for libc) */ + + /* Note: secs and util are only defined if valid is true */ +} stats_t; + +/******************** + * Global variables + *******************/ +int verbose = 0; /* global flag for verbose output */ +static int errors = 0; /* number of errs found when running student malloc */ +char msg[MAXLINE]; /* for whenever we need to compose an error message */ + +/* Directory where default tracefiles are found */ +static char tracedir[MAXLINE] = TRACEDIR; + +/* The filenames of the default tracefiles */ +static char *default_tracefiles[] = { + DEFAULT_TRACEFILES, NULL +}; + + +/********************* + * Function prototypes + *********************/ + +/* these functions manipulate range lists */ +static int add_range(range_t **ranges, char *lo, int size, + int tracenum, int opnum); +static void remove_range(range_t **ranges, char *lo); +static void clear_ranges(range_t **ranges); + +/* These functions read, allocate, and free storage for traces */ +static trace_t *read_trace(char *tracedir, char *filename); +static void free_trace(trace_t *trace); + +/* Routines for evaluating the correctness and speed of libc malloc */ +static int eval_libc_valid(trace_t *trace, int tracenum); +static void eval_libc_speed(void *ptr); + +/* Routines for evaluating correctnes, space utilization, and speed + of the student's malloc package in mm.c */ +static int eval_mm_valid(trace_t *trace, int tracenum, range_t **ranges); +static double eval_mm_util(trace_t *trace, int tracenum, range_t **ranges); +static void eval_mm_speed(void *ptr); + +/* Various helper routines */ +static void printresults(int n, stats_t *stats); +static void usage(void); +static void unix_error(char *msg); +static void malloc_error(int tracenum, int opnum, char *msg); +static void app_error(char *msg); + +/************** + * Main routine + **************/ +int main(int argc, char **argv) +{ + int i; + char c; + char **tracefiles = NULL; /* null-terminated array of trace file names */ + int num_tracefiles = 0; /* the number of traces in that array */ + trace_t *trace = NULL; /* stores a single trace file in memory */ + range_t *ranges = NULL; /* keeps track of block extents for one trace */ + stats_t *libc_stats = NULL;/* libc stats for each trace */ + stats_t *mm_stats = NULL; /* mm (i.e. student) stats for each trace */ + speed_t speed_params; /* input parameters to the xx_speed routines */ + + int team_check = 1; /* If set, check team structure (reset by -a) */ + int run_libc = 0; /* If set, run libc malloc (set by -l) */ + int autograder = 0; /* If set, emit summary info for autograder (-g) */ + + /* temporaries used to compute the performance index */ + double secs, ops, util, avg_mm_util, avg_mm_throughput, p1, p2, perfindex; + int numcorrect; + + /* + * Read and interpret the command line arguments + */ + while ((c = getopt(argc, argv, "f:t:hvVgal")) != EOF) { + switch (c) { + case 'g': /* Generate summary info for the autograder */ + autograder = 1; + break; + case 'f': /* Use one specific trace file only (relative to curr dir) */ + num_tracefiles = 1; + if ((tracefiles = realloc(tracefiles, 2*sizeof(char *))) == NULL) + unix_error("ERROR: realloc failed in main"); + strcpy(tracedir, "./"); + tracefiles[0] = strdup(optarg); + tracefiles[1] = NULL; + break; + case 't': /* Directory where the traces are located */ + if (num_tracefiles == 1) /* ignore if -f already encountered */ + break; + strcpy(tracedir, optarg); + if (tracedir[strlen(tracedir)-1] != '/') + strcat(tracedir, "/"); /* path always ends with "/" */ + break; + case 'a': /* Don't check team structure */ + team_check = 0; + break; + case 'l': /* Run libc malloc */ + run_libc = 1; + break; + case 'v': /* Print per-trace performance breakdown */ + verbose = 1; + break; + case 'V': /* Be more verbose than -v */ + verbose = 2; + break; + case 'h': /* Print this message */ + usage(); + exit(0); + default: + usage(); + exit(1); + } + } + + /* + * Check and print team info + */ + if (team_check) { + /* Students must fill in their team information */ + if (!strcmp(team.teamname, "")) { + printf("ERROR: Please provide the information about your team in mm.c.\n"); + exit(1); + } else + printf("Team Name:%s\n", team.teamname); + if ((*team.name1 == '\0') || (*team.id1 == '\0')) { + printf("ERROR. You must fill in all team member 1 fields!\n"); + exit(1); + } + else + printf("Member 1 :%s:%s\n", team.name1, team.id1); + + if (((*team.name2 != '\0') && (*team.id2 == '\0')) || + ((*team.name2 == '\0') && (*team.id2 != '\0'))) { + printf("ERROR. You must fill in all or none of the team member 2 ID fields!\n"); + exit(1); + } + else if (*team.name2 != '\0') + printf("Member 2 :%s:%s\n", team.name2, team.id2); + } + + /* + * If no -f command line arg, then use the entire set of tracefiles + * defined in default_traces[] + */ + if (tracefiles == NULL) { + tracefiles = default_tracefiles; + num_tracefiles = sizeof(default_tracefiles) / sizeof(char *) - 1; + printf("Using default tracefiles in %s\n", tracedir); + } + + /* Initialize the timing package */ + init_fsecs(); + + /* + * Optionally run and evaluate the libc malloc package + */ + if (run_libc) { + if (verbose > 1) + printf("\nTesting libc malloc\n"); + + /* Allocate libc stats array, with one stats_t struct per tracefile */ + libc_stats = (stats_t *)calloc(num_tracefiles, sizeof(stats_t)); + if (libc_stats == NULL) + unix_error("libc_stats calloc in main failed"); + + /* Evaluate the libc malloc package using the K-best scheme */ + for (i=0; i < num_tracefiles; i++) { + trace = read_trace(tracedir, tracefiles[i]); + libc_stats[i].ops = trace->num_ops; + if (verbose > 1) + printf("Checking libc malloc for correctness, "); + libc_stats[i].valid = eval_libc_valid(trace, i); + if (libc_stats[i].valid) { + speed_params.trace = trace; + if (verbose > 1) + printf("and performance.\n"); + libc_stats[i].secs = fsecs(eval_libc_speed, &speed_params); + } + free_trace(trace); + } + + /* Display the libc results in a compact table */ + if (verbose) { + printf("\nResults for libc malloc:\n"); + printresults(num_tracefiles, libc_stats); + } + } + + /* + * Always run and evaluate the student's mm package + */ + if (verbose > 1) + printf("\nTesting mm malloc\n"); + + /* Allocate the mm stats array, with one stats_t struct per tracefile */ + mm_stats = (stats_t *)calloc(num_tracefiles, sizeof(stats_t)); + if (mm_stats == NULL) + unix_error("mm_stats calloc in main failed"); + + /* Initialize the simulated memory system in memlib.c */ + mem_init(); + + /* Evaluate student's mm malloc package using the K-best scheme */ + for (i=0; i < num_tracefiles; i++) { + trace = read_trace(tracedir, tracefiles[i]); + mm_stats[i].ops = trace->num_ops; + if (verbose > 1) + printf("Checking mm_malloc for correctness, "); + mm_stats[i].valid = eval_mm_valid(trace, i, &ranges); + if (mm_stats[i].valid) { + if (verbose > 1) + printf("efficiency, "); + mm_stats[i].util = eval_mm_util(trace, i, &ranges); + speed_params.trace = trace; + speed_params.ranges = ranges; + if (verbose > 1) + printf("and performance.\n"); + mm_stats[i].secs = fsecs(eval_mm_speed, &speed_params); + } + free_trace(trace); + } + + /* Display the mm results in a compact table */ + if (verbose) { + printf("\nResults for mm malloc:\n"); + printresults(num_tracefiles, mm_stats); + printf("\n"); + } + + /* + * Accumulate the aggregate statistics for the student's mm package + */ + secs = 0; + ops = 0; + util = 0; + numcorrect = 0; + for (i=0; i < num_tracefiles; i++) { + secs += mm_stats[i].secs; + ops += mm_stats[i].ops; + util += mm_stats[i].util; + if (mm_stats[i].valid) + numcorrect++; + } + avg_mm_util = util/num_tracefiles; + + /* + * Compute and print the performance index + */ + if (errors == 0) { + avg_mm_throughput = ops/secs; + + p1 = UTIL_WEIGHT * avg_mm_util; + if (avg_mm_throughput > AVG_LIBC_THRUPUT) { + p2 = (double)(1.0 - UTIL_WEIGHT); + } + else { + p2 = ((double) (1.0 - UTIL_WEIGHT)) * + (avg_mm_throughput/AVG_LIBC_THRUPUT); + } + + perfindex = (p1 + p2)*100.0; + printf("Perf index = %.0f (util) + %.0f (thru) = %.0f/100\n", + p1*100, + p2*100, + perfindex); + + } + else { /* There were errors */ + perfindex = 0.0; + printf("Terminated with %d errors\n", errors); + } + + if (autograder) { + printf("correct:%d\n", numcorrect); + printf("perfidx:%.0f\n", perfindex); + } + + exit(0); +} + + +/***************************************************************** + * The following routines manipulate the range list, which keeps + * track of the extent of every allocated block payload. We use the + * range list to detect any overlapping allocated blocks. + ****************************************************************/ + +/* + * add_range - As directed by request opnum in trace tracenum, + * we've just called the student's mm_malloc to allocate a block of + * size bytes at addr lo. After checking the block for correctness, + * we create a range struct for this block and add it to the range list. + */ +static int add_range(range_t **ranges, char *lo, int size, + int tracenum, int opnum) +{ + char *hi = lo + size - 1; + range_t *p; + char msg[MAXLINE]; + + assert(size > 0); + + /* Payload addresses must be ALIGNMENT-byte aligned */ + if (!IS_ALIGNED(lo)) { + sprintf(msg, "Payload address (%p) not aligned to %d bytes", + lo, ALIGNMENT); + malloc_error(tracenum, opnum, msg); + return 0; + } + + /* The payload must lie within the extent of the heap */ + if ((lo < (char *)mem_heap_lo()) || (lo > (char *)mem_heap_hi()) || + (hi < (char *)mem_heap_lo()) || (hi > (char *)mem_heap_hi())) { + sprintf(msg, "Payload (%p:%p) lies outside heap (%p:%p)", + lo, hi, mem_heap_lo(), mem_heap_hi()); + malloc_error(tracenum, opnum, msg); + return 0; + } + + /* The payload must not overlap any other payloads */ + for (p = *ranges; p != NULL; p = p->next) { + if ((lo >= p->lo && lo <= p-> hi) || + (hi >= p->lo && hi <= p->hi)) { + sprintf(msg, "Payload (%p:%p) overlaps another payload (%p:%p)\n", + lo, hi, p->lo, p->hi); + malloc_error(tracenum, opnum, msg); + return 0; + } + } + + /* + * Everything looks OK, so remember the extent of this block + * by creating a range struct and adding it the range list. + */ + if ((p = (range_t *)malloc(sizeof(range_t))) == NULL) + unix_error("malloc error in add_range"); + p->next = *ranges; + p->lo = lo; + p->hi = hi; + *ranges = p; + return 1; +} + +/* + * remove_range - Free the range record of block whose payload starts at lo + */ +static void remove_range(range_t **ranges, char *lo) +{ + range_t *p; + range_t **prevpp = ranges; + int size; + + for (p = *ranges; p != NULL; p = p->next) { + if (p->lo == lo) { + *prevpp = p->next; + size = p->hi - p->lo + 1; + free(p); + break; + } + prevpp = &(p->next); + } +} + +/* + * clear_ranges - free all of the range records for a trace + */ +static void clear_ranges(range_t **ranges) +{ + range_t *p; + range_t *pnext; + + for (p = *ranges; p != NULL; p = pnext) { + pnext = p->next; + free(p); + } + *ranges = NULL; +} + + +/********************************************** + * The following routines manipulate tracefiles + *********************************************/ + +/* + * read_trace - read a trace file and store it in memory + */ +static trace_t *read_trace(char *tracedir, char *filename) +{ + FILE *tracefile; + trace_t *trace; + char type[MAXLINE]; + char path[MAXLINE]; + unsigned index, size; + unsigned max_index = 0; + unsigned op_index; + + if (verbose > 1) + printf("Reading tracefile: %s\n", filename); + + /* Allocate the trace record */ + if ((trace = (trace_t *) malloc(sizeof(trace_t))) == NULL) + unix_error("malloc 1 failed in read_trance"); + + /* Read the trace file header */ + strcpy(path, tracedir); + strcat(path, filename); + if ((tracefile = fopen(path, "r")) == NULL) { + sprintf(msg, "Could not open %s in read_trace", path); + unix_error(msg); + } + fscanf(tracefile, "%d", &(trace->sugg_heapsize)); /* not used */ + fscanf(tracefile, "%d", &(trace->num_ids)); + fscanf(tracefile, "%d", &(trace->num_ops)); + fscanf(tracefile, "%d", &(trace->weight)); /* not used */ + + /* We'll store each request line in the trace in this array */ + if ((trace->ops = + (traceop_t *)malloc(trace->num_ops * sizeof(traceop_t))) == NULL) + unix_error("malloc 2 failed in read_trace"); + + /* We'll keep an array of pointers to the allocated blocks here... */ + if ((trace->blocks = + (char **)malloc(trace->num_ids * sizeof(char *))) == NULL) + unix_error("malloc 3 failed in read_trace"); + + /* ... along with the corresponding byte sizes of each block */ + if ((trace->block_sizes = + (size_t *)malloc(trace->num_ids * sizeof(size_t))) == NULL) + unix_error("malloc 4 failed in read_trace"); + + /* read every request line in the trace file */ + index = 0; + op_index = 0; + while (fscanf(tracefile, "%s", type) != EOF) { + switch(type[0]) { + case 'a': + fscanf(tracefile, "%u %u", &index, &size); + trace->ops[op_index].type = ALLOC; + trace->ops[op_index].index = index; + trace->ops[op_index].size = size; + max_index = (index > max_index) ? index : max_index; + break; + case 'r': + fscanf(tracefile, "%u %u", &index, &size); + trace->ops[op_index].type = REALLOC; + trace->ops[op_index].index = index; + trace->ops[op_index].size = size; + max_index = (index > max_index) ? index : max_index; + break; + case 'f': + fscanf(tracefile, "%ud", &index); + trace->ops[op_index].type = FREE; + trace->ops[op_index].index = index; + break; + default: + printf("Bogus type character (%c) in tracefile %s\n", + type[0], path); + exit(1); + } + op_index++; + + } + fclose(tracefile); + assert(max_index == trace->num_ids - 1); + assert(trace->num_ops == op_index); + + return trace; +} + +/* + * free_trace - Free the trace record and the three arrays it points + * to, all of which were allocated in read_trace(). + */ +void free_trace(trace_t *trace) +{ + free(trace->ops); /* free the three arrays... */ + free(trace->blocks); + free(trace->block_sizes); + free(trace); /* and the trace record itself... */ +} + +/********************************************************************** + * The following functions evaluate the correctness, space utilization, + * and throughput of the libc and mm malloc packages. + **********************************************************************/ + +/* + * eval_mm_valid - Check the mm malloc package for correctness + */ +static int eval_mm_valid(trace_t *trace, int tracenum, range_t **ranges) +{ + int i, j; + int index; + int size; + int oldsize; + char *newp; + char *oldp; + char *p; + + /* Reset the heap and free any records in the range list */ + mem_reset_brk(); + clear_ranges(ranges); + + /* Call the mm package's init function */ + if (mm_init() < 0) { + malloc_error(tracenum, 0, "mm_init failed."); + return 0; + } + + /* Interpret each operation in the trace in order */ + for (i = 0; i < trace->num_ops; i++) { + index = trace->ops[i].index; + size = trace->ops[i].size; + + switch (trace->ops[i].type) { + + case ALLOC: /* mm_malloc */ + + /* Call the student's malloc */ + if ((p = mm_malloc(size)) == NULL) { + malloc_error(tracenum, i, "mm_malloc failed."); + return 0; + } + + /* + * Test the range of the new block for correctness and add it + * to the range list if OK. The block must be be aligned properly, + * and must not overlap any currently allocated block. + */ + if (add_range(ranges, p, size, tracenum, i) == 0) + return 0; + + /* ADDED: cgw + * fill range with low byte of index. This will be used later + * if we realloc the block and wish to make sure that the old + * data was copied to the new block + */ + memset(p, index & 0xFF, size); + + /* Remember region */ + trace->blocks[index] = p; + trace->block_sizes[index] = size; + break; + + case REALLOC: /* mm_realloc */ + + /* Call the student's realloc */ + oldp = trace->blocks[index]; + if ((newp = mm_realloc(oldp, size)) == NULL) { + malloc_error(tracenum, i, "mm_realloc failed."); + return 0; + } + + /* Remove the old region from the range list */ + remove_range(ranges, oldp); + + /* Check new block for correctness and add it to range list */ + if (add_range(ranges, newp, size, tracenum, i) == 0) + return 0; + + /* ADDED: cgw + * Make sure that the new block contains the data from the old + * block and then fill in the new block with the low order byte + * of the new index + */ + oldsize = trace->block_sizes[index]; + if (size < oldsize) oldsize = size; + for (j = 0; j < oldsize; j++) { + if (newp[j] != (index & 0xFF)) { + malloc_error(tracenum, i, "mm_realloc did not preserve the " + "data from old block"); + return 0; + } + } + memset(newp, index & 0xFF, size); + + /* Remember region */ + trace->blocks[index] = newp; + trace->block_sizes[index] = size; + break; + + case FREE: /* mm_free */ + + /* Remove region from list and call student's free function */ + p = trace->blocks[index]; + remove_range(ranges, p); + mm_free(p); + break; + + default: + app_error("Nonexistent request type in eval_mm_valid"); + } + + } + + /* As far as we know, this is a valid malloc package */ + return 1; +} + +/* + * eval_mm_util - Evaluate the space utilization of the student's package + * The idea is to remember the high water mark "hwm" of the heap for + * an optimal allocator, i.e., no gaps and no internal fragmentation. + * Utilization is the ratio hwm/heapsize, where heapsize is the + * size of the heap in bytes after running the student's malloc + * package on the trace. Note that our implementation of mem_sbrk() + * doesn't allow the students to decrement the brk pointer, so brk + * is always the high water mark of the heap. + * + */ +static double eval_mm_util(trace_t *trace, int tracenum, range_t **ranges) +{ + int i; + int index; + int size, newsize, oldsize; + int max_total_size = 0; + int total_size = 0; + char *p; + char *newp, *oldp; + + /* initialize the heap and the mm malloc package */ + mem_reset_brk(); + if (mm_init() < 0) + app_error("mm_init failed in eval_mm_util"); + + for (i = 0; i < trace->num_ops; i++) { + switch (trace->ops[i].type) { + + case ALLOC: /* mm_alloc */ + index = trace->ops[i].index; + size = trace->ops[i].size; + + if ((p = mm_malloc(size)) == NULL) + app_error("mm_malloc failed in eval_mm_util"); + + /* Remember region and size */ + trace->blocks[index] = p; + trace->block_sizes[index] = size; + + /* Keep track of current total size + * of all allocated blocks */ + total_size += size; + + /* Update statistics */ + max_total_size = (total_size > max_total_size) ? + total_size : max_total_size; + break; + + case REALLOC: /* mm_realloc */ + index = trace->ops[i].index; + newsize = trace->ops[i].size; + oldsize = trace->block_sizes[index]; + + oldp = trace->blocks[index]; + if ((newp = mm_realloc(oldp,newsize)) == NULL) + app_error("mm_realloc failed in eval_mm_util"); + + /* Remember region and size */ + trace->blocks[index] = newp; + trace->block_sizes[index] = newsize; + + /* Keep track of current total size + * of all allocated blocks */ + total_size += (newsize - oldsize); + + /* Update statistics */ + max_total_size = (total_size > max_total_size) ? + total_size : max_total_size; + break; + + case FREE: /* mm_free */ + index = trace->ops[i].index; + size = trace->block_sizes[index]; + p = trace->blocks[index]; + + mm_free(p); + + /* Keep track of current total size + * of all allocated blocks */ + total_size -= size; + + break; + + default: + app_error("Nonexistent request type in eval_mm_util"); + + } + } + + return ((double)max_total_size / (double)mem_heapsize()); +} + + +/* + * eval_mm_speed - This is the function that is used by fcyc() + * to measure the running time of the mm malloc package. + */ +static void eval_mm_speed(void *ptr) +{ + int i, index, size, newsize; + char *p, *newp, *oldp, *block; + trace_t *trace = ((speed_t *)ptr)->trace; + + /* Reset the heap and initialize the mm package */ + mem_reset_brk(); + if (mm_init() < 0) + app_error("mm_init failed in eval_mm_speed"); + + /* Interpret each trace request */ + for (i = 0; i < trace->num_ops; i++) + switch (trace->ops[i].type) { + + case ALLOC: /* mm_malloc */ + index = trace->ops[i].index; + size = trace->ops[i].size; + if ((p = mm_malloc(size)) == NULL) + app_error("mm_malloc error in eval_mm_speed"); + trace->blocks[index] = p; + break; + + case REALLOC: /* mm_realloc */ + index = trace->ops[i].index; + newsize = trace->ops[i].size; + oldp = trace->blocks[index]; + if ((newp = mm_realloc(oldp,newsize)) == NULL) + app_error("mm_realloc error in eval_mm_speed"); + trace->blocks[index] = newp; + break; + + case FREE: /* mm_free */ + index = trace->ops[i].index; + block = trace->blocks[index]; + mm_free(block); + break; + + default: + app_error("Nonexistent request type in eval_mm_valid"); + } +} + +/* + * eval_libc_valid - We run this function to make sure that the + * libc malloc can run to completion on the set of traces. + * We'll be conservative and terminate if any libc malloc call fails. + * + */ +static int eval_libc_valid(trace_t *trace, int tracenum) +{ + int i, newsize; + char *p, *newp, *oldp; + + for (i = 0; i < trace->num_ops; i++) { + switch (trace->ops[i].type) { + + case ALLOC: /* malloc */ + if ((p = malloc(trace->ops[i].size)) == NULL) { + malloc_error(tracenum, i, "libc malloc failed"); + unix_error("System message"); + } + trace->blocks[trace->ops[i].index] = p; + break; + + case REALLOC: /* realloc */ + newsize = trace->ops[i].size; + oldp = trace->blocks[trace->ops[i].index]; + if ((newp = realloc(oldp, newsize)) == NULL) { + malloc_error(tracenum, i, "libc realloc failed"); + unix_error("System message"); + } + trace->blocks[trace->ops[i].index] = newp; + break; + + case FREE: /* free */ + free(trace->blocks[trace->ops[i].index]); + break; + + default: + app_error("invalid operation type in eval_libc_valid"); + } + } + + return 1; +} + +/* + * eval_libc_speed - This is the function that is used by fcyc() to + * measure the running time of the libc malloc package on the set + * of traces. + */ +static void eval_libc_speed(void *ptr) +{ + int i; + int index, size, newsize; + char *p, *newp, *oldp, *block; + trace_t *trace = ((speed_t *)ptr)->trace; + + for (i = 0; i < trace->num_ops; i++) { + switch (trace->ops[i].type) { + case ALLOC: /* malloc */ + index = trace->ops[i].index; + size = trace->ops[i].size; + if ((p = malloc(size)) == NULL) + unix_error("malloc failed in eval_libc_speed"); + trace->blocks[index] = p; + break; + + case REALLOC: /* realloc */ + index = trace->ops[i].index; + newsize = trace->ops[i].size; + oldp = trace->blocks[index]; + if ((newp = realloc(oldp, newsize)) == NULL) + unix_error("realloc failed in eval_libc_speed\n"); + + trace->blocks[index] = newp; + break; + + case FREE: /* free */ + index = trace->ops[i].index; + block = trace->blocks[index]; + free(block); + break; + } + } +} + +/************************************* + * Some miscellaneous helper routines + ************************************/ + + +/* + * printresults - prints a performance summary for some malloc package + */ +static void printresults(int n, stats_t *stats) +{ + int i; + double secs = 0; + double ops = 0; + double util = 0; + + /* Print the individual results for each trace */ + printf("%5s%7s %5s%8s%10s%6s\n", + "trace", " valid", "util", "ops", "secs", "Kops"); + for (i=0; i < n; i++) { + if (stats[i].valid) { + printf("%2d%10s%5.0f%%%8.0f%10.6f%6.0f\n", + i, + "yes", + stats[i].util*100.0, + stats[i].ops, + stats[i].secs, + (stats[i].ops/1e3)/stats[i].secs); + secs += stats[i].secs; + ops += stats[i].ops; + util += stats[i].util; + } + else { + printf("%2d%10s%6s%8s%10s%6s\n", + i, + "no", + "-", + "-", + "-", + "-"); + } + } + + /* Print the aggregate results for the set of traces */ + if (errors == 0) { + printf("%12s%5.0f%%%8.0f%10.6f%6.0f\n", + "Total ", + (util/n)*100.0, + ops, + secs, + (ops/1e3)/secs); + } + else { + printf("%12s%6s%8s%10s%6s\n", + "Total ", + "-", + "-", + "-", + "-"); + } + +} + +/* + * app_error - Report an arbitrary application error + */ +void app_error(char *msg) +{ + printf("%s\n", msg); + exit(1); +} + +/* + * unix_error - Report a Unix-style error + */ +void unix_error(char *msg) +{ + printf("%s: %s\n", msg, strerror(errno)); + exit(1); +} + +/* + * malloc_error - Report an error returned by the mm_malloc package + */ +void malloc_error(int tracenum, int opnum, char *msg) +{ + errors++; + printf("ERROR [trace %d, line %d]: %s\n", tracenum, LINENUM(opnum), msg); +} + +/* + * usage - Explain the command line arguments + */ +static void usage(void) +{ + fprintf(stderr, "Usage: mdriver [-hvVal] [-f ] [-t ]\n"); + fprintf(stderr, "Options\n"); + fprintf(stderr, "\t-a Don't check the team structure.\n"); + fprintf(stderr, "\t-f Use as the trace file.\n"); + fprintf(stderr, "\t-g Generate summary info for autograder.\n"); + fprintf(stderr, "\t-h Print this message.\n"); + fprintf(stderr, "\t-l Run libc malloc as well.\n"); + fprintf(stderr, "\t-t Directory to find default traces.\n"); + fprintf(stderr, "\t-v Print per-trace performance breakdowns.\n"); + fprintf(stderr, "\t-V Print additional debug info.\n"); +} -- cgit v1.3.1-4-g156e