⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mtest.c

📁 ICS 课程的Lab6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * mtest.c - test harness for the CS:APP malloc lab * * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. * May not be used, modified, or copied without permission. */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <assert.h>#include <float.h>#include <time.h>#include "mm.h"#include "memlib.h"#include "fsecs.h"#include "config.h"/********************** * Constants and macros **********************//* Misc */#define MAXLINE 128      /* max string size */#define HDRLINES 4       /* number of header lines in a trace file */#define LINENUM(i) (i+5) /* cnvt trace request nums to line nums (origin unity)*//* 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 *//* * List of Default tracefiles.  * Modify this if you want to add or delete traces. */static char *default_tracefiles[] = {      "traces/amptjp-bal.rep",    "traces/cccp-bal.rep",    "traces/cp-decl-bal.rep",    "traces/expr-bal.rep",    "traces/coalescing-bal.rep",    "traces/random-bal.rep",    "traces/random2-bal.rep",    "traces/binary-bal.rep",    "traces/binary2-bal.rep",    "traces/realloc-bal.rep",    "traces/realloc2-bal.rep",     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 *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) */        /* temporaries used to compute the performance index */    double secs, ops, util, avg_mm_util, avg_mm_throughput, p1, p2;    /*      * Read and interpret the command line arguments      */    while ((c = getopt(argc, argv, "f:hvVal")) != EOF) {        switch (c) {        case 'f': /* Use one specific trace file only */            num_tracefiles = 1;            if ((tracefiles = realloc(tracefiles, sizeof(char *))) == NULL)		unix_error("ERROR: realloc failed in main");            tracefiles[0] = strdup(optarg);            tracefiles[1] = NULL;            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.  Fill in information about your team in bits.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 traces.h      */    if (tracefiles == NULL) {        tracefiles = default_tracefiles;        num_tracefiles = sizeof(default_tracefiles) / sizeof(char *) - 1;    }    /* 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(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(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;    for (i=0; i < num_tracefiles; i++) {	secs += mm_stats[i].secs;	ops += mm_stats[i].ops;	util += mm_stats[i].util;    }    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);	}		if (errors == 0)	    printf("Perf index = %.0f (util) + %.0f (thru) = %.0f/100\n",		   p1*100, 		   p2*100, 		   (p1 + p2)*100.0);	else	    printf("Terminated with %d errors\n", errors);	exit(0);    }    else 	exit(1);}/***************************************************************** * 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 *filename){    FILE *tracefile;    trace_t *trace;    char type[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 */    if ((tracefile = fopen(filename, "r")) == NULL)	unix_error("fopen failed in read_trace");    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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -