1388 lines
39 KiB
C
1388 lines
39 KiB
C
/*
|
||
* 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 <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <errno.h>
|
||
#include <string.h>
|
||
#include <assert.h>
|
||
#include <float.h>
|
||
#include <time.h>
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <fcntl.h>
|
||
#ifndef _WIN32
|
||
#include <getopt.h>
|
||
#include <unistd.h>
|
||
#else
|
||
#include "getopt.h"
|
||
#define strdup _strdup
|
||
#define unlink _unlink
|
||
#endif
|
||
|
||
#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) */
|
||
#define MAXHEAP 1024 /* maximum allowed heap size for heapcheck */
|
||
#define MAX_ITER_COUNT 100
|
||
|
||
/* 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 enum { ALLOC, FREE, REALLOC, HEAPCHECK, ERROR_BUG } RequestType;
|
||
typedef struct {
|
||
RequestType 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 */
|
||
int* allocated; /*
|
||
0 : initial value
|
||
1 : allocated block
|
||
2 : freed block
|
||
*/
|
||
int* check; /* used to check the correctness of the heapcheck function */
|
||
} 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;
|
||
|
||
/* Captures the output of the heapcheck function */
|
||
typedef struct {
|
||
int request_id;
|
||
int payload;
|
||
} block_t;
|
||
|
||
/********************
|
||
* Global variables
|
||
*******************/
|
||
int verbose = 1; /* global flag for verbose output */
|
||
static int errors = 0; /* number of errs found when running student malloc */
|
||
char msg[2 * MAXLINE]; /* for whenever we need to compose an error message */
|
||
block_t heap[MAXHEAP]; /* heap to parse output of heapcheck */
|
||
|
||
/* 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(char* exec);
|
||
static int parse_heap(char* file, block_t* heap, int max_blocks, int tracenum, int opnum);
|
||
static void expected_blocks(trace_t* trace);
|
||
static void outputted_blocks(block_t* heap, int heapsize);
|
||
|
||
void eval_libc_speed_ref_prepare(void);
|
||
void eval_libc_speed_ref(void* ptr);
|
||
|
||
void remove_enter(char* ptr);
|
||
|
||
void remove_enter(char* ptr)
|
||
{
|
||
int i;
|
||
int len = (int)strlen(ptr);
|
||
for (i = 0; i < len; i++)
|
||
if (ptr[i] == '\r' || ptr[i] == '\n')
|
||
ptr[i] = 0;
|
||
}
|
||
|
||
/**************
|
||
* Main routine
|
||
**************/
|
||
int main(int argc, char** argv)
|
||
{
|
||
FILE* TRACE_LIST;
|
||
char path[MAXLINE];
|
||
char line[MAXLINE];
|
||
//double ref_malloc_speed;
|
||
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:hvVgl")) != 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 = (char**)realloc(tracefiles, 2 * sizeof(char*))) == NULL) {
|
||
printf("[%s]realloc失败\n", __func__);
|
||
}
|
||
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(argv[0]);
|
||
exit(0);
|
||
default:
|
||
usage(argv[0]);
|
||
exit(1);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* If no -f command line arg, then use the entire set of tracefiles
|
||
* defined in default_traces[]
|
||
*/
|
||
if (tracefiles == NULL) {
|
||
|
||
strcpy(path, tracedir);
|
||
strcat(path, "TRACE_LIST.txt");
|
||
TRACE_LIST = fopen(path, "r");
|
||
if (TRACE_LIST == NULL)
|
||
{
|
||
printf("[%s]没有找到%s文件,使用缺省的trace文件(%s)\n", __func__, path, tracedir);
|
||
tracefiles = default_tracefiles;
|
||
num_tracefiles = sizeof(default_tracefiles) / sizeof(char*) - 1;
|
||
}
|
||
else
|
||
{
|
||
num_tracefiles = 0;
|
||
while (fgets(line, MAXLINE, TRACE_LIST))
|
||
{
|
||
if (line[0] == '#' || line[0] == '/' || line[0] == '\n' || line[0] == '\r') continue;
|
||
tracefiles = realloc(tracefiles, (num_tracefiles + 2) * sizeof(char*));
|
||
remove_enter(line);
|
||
tracefiles[num_tracefiles] = strdup(line);
|
||
tracefiles[num_tracefiles + 1] = NULL;
|
||
num_tracefiles++;
|
||
}
|
||
|
||
fclose(TRACE_LIST);
|
||
printf("[%s]num_tracefiles=%d\n", __func__, num_tracefiles);
|
||
for (i = 0; i < num_tracefiles; i++)
|
||
printf("[%2d]%s\n", i, tracefiles[i]);
|
||
}
|
||
}
|
||
|
||
/* Initialize the timing package */
|
||
init_fsecs();
|
||
/*
|
||
ref_malloc_speed = 0;
|
||
eval_libc_speed_ref_prepare();
|
||
ref_malloc_speed = fsecs(eval_libc_speed_ref,&speed_params);
|
||
|
||
printf("ref_malloc_speed=%f\n",ref_malloc_speed);
|
||
// init_fsecs();
|
||
*/
|
||
/*
|
||
* Optionally run and evaluate the libc malloc package
|
||
*/
|
||
if (run_libc) {
|
||
if (verbose > 1)
|
||
printf("\n[%s]检测libc库函数malloc\n", __func__);
|
||
|
||
/* 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)
|
||
printf("[%s]libc_stats calloc失败\n", __func__);
|
||
|
||
/* 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("[%s]检测libc malloc的正确性, ", __func__);
|
||
libc_stats[i].valid = eval_libc_valid(trace, i);
|
||
if (libc_stats[i].valid) {
|
||
speed_params.trace = trace;
|
||
if (verbose > 1)
|
||
printf("和性能\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("\n[%s]libc malloc的检测结果:\n", __func__);
|
||
printresults(num_tracefiles, libc_stats);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Always run and evaluate the student's mm package
|
||
*/
|
||
if (verbose > 1)
|
||
printf("\n[%s]检测mm文件中的malloc\n", __func__);
|
||
|
||
/* 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)
|
||
printf("[%s]mm_stats calloc失败\n", __func__);
|
||
|
||
/* 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("[%s]检测mm_malloc的正确性, ", __func__);
|
||
mm_stats[i].valid = eval_mm_valid(trace, i, &ranges);
|
||
if (mm_stats[i].valid) {
|
||
if (verbose > 1)
|
||
printf("效率, ");
|
||
mm_stats[i].util = eval_mm_util(trace, i, &ranges);
|
||
speed_params.trace = trace;
|
||
speed_params.ranges = ranges;
|
||
if (verbose > 1)
|
||
printf("和性能.\n");
|
||
// mm_stats[i].secs = 0;
|
||
// for (ii=0;ii<MAX_ITER_COUNT;ii++)
|
||
mm_stats[i].secs = fsecs(eval_mm_speed, &speed_params);
|
||
// mm_stats[i].secs = mm_stats[i].secs/MAX_ITER_COUNT;
|
||
}
|
||
|
||
free_trace(trace);
|
||
}
|
||
|
||
/* Display the mm results in a compact table */
|
||
if (verbose) {
|
||
printf("\n[%s]mm malloc的检测结果:\n", __func__);
|
||
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("[%s]评分 = %.0f (效率%d) + %.0f (性能%d) = %.0f/100\n", __func__,
|
||
p1 * 100, (int)(UTIL_WEIGHT * 100),
|
||
p2 * 100, (int)(100 - UTIL_WEIGHT * 100),
|
||
perfindex);
|
||
|
||
}
|
||
else { /* There were errors */
|
||
perfindex = 0.0;
|
||
printf("[%s]程序因为%d个错误而终止!\n", __func__, errors);
|
||
}
|
||
|
||
if (autograder) {
|
||
printf("[%s]正确:%d\n", __func__, numcorrect);
|
||
printf("[%s]评分:%.0f\n", __func__, 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;
|
||
|
||
assert(size > 0);
|
||
|
||
/* Payload addresses must be ALIGNMENT-byte aligned */
|
||
if (!IS_ALIGNED(lo)) {
|
||
printf("[%s]Payload的地址(%p)没有对齐到%d字节的边界\n", __func__, lo, ALIGNMENT);
|
||
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())) {
|
||
printf("[%s]Payload (%p:%p)处在堆范围之外(%p:%p)\n", __func__, lo, hi, mem_heap_lo(), mem_heap_hi());
|
||
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)) {
|
||
printf("[%s]Payload (%p:%p)与另外的payload重叠了(%p:%p)\n", __func__, lo, hi, p->lo, p->hi);
|
||
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)
|
||
printf("[%s]malloc失败\n", __func__);
|
||
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;
|
||
|
||
for (p = *ranges; p != NULL; p = p->next) {
|
||
if (p->lo == lo) {
|
||
*prevpp = p->next;
|
||
// int 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];
|
||
int index, size;
|
||
int max_index = 0;
|
||
int op_index;
|
||
int i;
|
||
int line_count = 0;
|
||
int retval;
|
||
|
||
if (verbose > 1)
|
||
printf("[%s]读取trace文件: %s\n", __func__, filename);
|
||
|
||
/* Allocate the trace record */
|
||
if ((trace = (trace_t*)malloc(sizeof(trace_t))) == NULL)
|
||
printf("[%s]malloc trace失败\n", __func__);
|
||
|
||
/* Read the trace file header */
|
||
strcpy(path, tracedir);
|
||
strcat(path, filename);
|
||
if ((tracefile = fopen(path, "r")) == NULL) {
|
||
printf("[%s]不能打开文件 %s\n", __func__, path);
|
||
}
|
||
retval = fscanf(tracefile, "%d", &(trace->sugg_heapsize)); /* not used */
|
||
if (retval == 0)
|
||
{
|
||
printf("[%s]读取trace文件格式错误:没有sugg_heapsize\n", __func__);
|
||
}
|
||
retval = fscanf(tracefile, "%d", &(trace->num_ids));
|
||
if (retval == 0)
|
||
{
|
||
printf("[%s]读取trace文件格式错误:没有num_ids\n", __func__);
|
||
}
|
||
retval = fscanf(tracefile, "%d", &(trace->num_ops));
|
||
if (retval == 0)
|
||
{
|
||
printf("[%s]读取trace文件格式错误:没有num_ops\n", __func__);
|
||
}
|
||
retval = fscanf(tracefile, "%d", &(trace->weight)); /* not used */
|
||
if (retval == 0)
|
||
{
|
||
printf("[%s]读取trace文件格式错误:没有weight\n", __func__);
|
||
}
|
||
|
||
line_count = 4;
|
||
/* 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)
|
||
printf("[%s]malloc trace->ops失败\n", __func__);
|
||
|
||
/* We'll keep an array of pointers to the allocated blocks here... */
|
||
if ((trace->blocks =
|
||
(char**)malloc(trace->num_ids * sizeof(char*))) == NULL)
|
||
printf("[%s]malloc trace->blocks失败", __func__);
|
||
memset(trace->blocks, 0, trace->num_ids * sizeof(char*));
|
||
|
||
/* ... along with the corresponding byte sizes of each block */
|
||
if ((trace->block_sizes =
|
||
(size_t*)malloc(trace->num_ids * sizeof(size_t))) == NULL)
|
||
printf("[%s]malloc trace->block_sizes失败", __func__);
|
||
|
||
/* ... along with flags for the heapcheck function */
|
||
if ((trace->allocated =
|
||
(int*)malloc(trace->num_ids * sizeof(int))) == NULL)
|
||
printf("[%s]malloc trace->allocated失败", __func__);
|
||
/* initialize allocated to 0 */
|
||
for (i = 0; i < trace->num_ids; i++)
|
||
trace->allocated[i] = 0;
|
||
|
||
if ((trace->check =
|
||
(int*)malloc(trace->num_ids * sizeof(int))) == NULL)
|
||
printf("[%s]malloc trace->check失败", __func__);
|
||
|
||
/* read every request line in the trace file */
|
||
index = 0;
|
||
op_index = 0;
|
||
while (fscanf(tracefile, "%s", type) != EOF) {
|
||
line_count++;
|
||
switch (type[0]) {
|
||
case 'a':
|
||
if (2 != fscanf(tracefile, "%u %u", &index, &size)) {
|
||
printf("[%s]%d 行,allocation需要两个参数\n", __func__, line_count);
|
||
}
|
||
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;
|
||
|
||
// workaround realloc bug
|
||
trace->blocks[index] = (char *)1;
|
||
break;
|
||
case 'r':
|
||
if (2 != fscanf(tracefile, "%u %u", &index, &size)) {
|
||
printf("[%s]%d 行,relloc需要两个参数\n", __func__, line_count);
|
||
}
|
||
if (trace->blocks[index] == (char*)1)
|
||
{
|
||
trace->ops[op_index].type = REALLOC;
|
||
trace->blocks[index] = (char*)1;
|
||
}
|
||
else
|
||
{
|
||
// workaround realloc bug
|
||
if (verbose > 1)
|
||
printf("[%s]%d 行,尝试realloc一个未初始化的指针(%d),修改为alloc\n", __func__, line_count, index);
|
||
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 'c':
|
||
trace->ops[op_index].type = HEAPCHECK;
|
||
break;
|
||
case 'f':
|
||
if (1 != fscanf(tracefile, "%ud", &index)) {
|
||
printf("[%s]%d 行,free需要一个参数\n", __func__, line_count);
|
||
}
|
||
// workaround free -1 bug
|
||
if (index == -1)
|
||
{
|
||
if (verbose > 1)
|
||
printf("[%s]%d 行,free一个-1指针,跳过\n", __func__, line_count);
|
||
trace->ops[op_index].type = ERROR_BUG;
|
||
}
|
||
else
|
||
trace->ops[op_index].type = FREE;
|
||
trace->ops[op_index].index = index;
|
||
break;
|
||
default:
|
||
printf("[%s]trace文件[%s,%d行]中错误的类型字符(%c)\n", __func__, path, line_count, type[0]);
|
||
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().
|
||
*/
|
||
static 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;
|
||
char tmpfile[L_tmpnam];
|
||
//int fd;
|
||
//int stdoutold;
|
||
int heapsize;
|
||
int request_id;
|
||
int payload;
|
||
char the_char;
|
||
|
||
/* 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) {
|
||
printf("[%s]mm_init失败[tracenum=%d]\n", __func__, tracenum);
|
||
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 */
|
||
//printf("ALLOC\n");
|
||
|
||
/* Call the student's malloc */
|
||
if ((p = mm_malloc(size)) == NULL) {
|
||
printf("[%s]mm_malloc失败[tracenum=%d,i=%d]\n", __func__, tracenum, i);
|
||
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;
|
||
trace->allocated[index] = 1;
|
||
break;
|
||
|
||
case REALLOC: /* mm_realloc */
|
||
//printf("REALLOC\n");
|
||
|
||
/* Call the student's realloc */
|
||
oldp = trace->blocks[index];
|
||
if ((newp = (char*)mm_realloc(oldp, size)) == NULL) {
|
||
printf("[%s]mm_realloc失败[tracenum=%d,i=%d]\n", __func__, tracenum, i);
|
||
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 = (int)trace->block_sizes[index];
|
||
if (size < oldsize) oldsize = size;
|
||
|
||
the_char = (index & 0xFF);
|
||
for (j = 0; j < oldsize; j++) {
|
||
the_char = index & 0xFF;
|
||
if (newp[j] != the_char) {
|
||
printf("[%s]mm_realloc没有保存旧块的数据[tracenum = % d, i = % d]\n", __func__, tracenum, i);
|
||
return 0;
|
||
}
|
||
}
|
||
memset(newp, index & 0xFF, size);
|
||
|
||
/* Remember region */
|
||
trace->blocks[index] = newp;
|
||
trace->block_sizes[index] = size;
|
||
//printf("\nrealloc finish\n");
|
||
break;
|
||
case HEAPCHECK:
|
||
//printf("HEAPCHECK\n");
|
||
/* check the output of the mm_heapcheck routine */
|
||
/* for each allocated block that hasn't been freed yet,
|
||
the mm_heapcheck function should print a line
|
||
in the following format
|
||
|
||
request_id payload_size stuff_for_debugging_not_used
|
||
|
||
*/
|
||
|
||
/* redirect stdout to a temporary file */
|
||
//fd = open(tmpnam(tmpfile),O_RDWR|O_CREAT);
|
||
//if (fd < 0)
|
||
// printf("[%s]不能为heapcheck创建临时文件\n",__func__);
|
||
//fflush(stdout);
|
||
//stdoutold = dup(1);
|
||
//dup2(fd,1);
|
||
//
|
||
///* Call the student's heapcheck */
|
||
//mm_heapcheck();
|
||
//fflush(stdout);
|
||
//close(fd);
|
||
//close(1);
|
||
//
|
||
///* fix stdout */
|
||
//dup2(stdoutold, 1);
|
||
//close(stdoutold);
|
||
|
||
/* parse the output of the heapcheck function */
|
||
heapsize = parse_heap(tmpfile, heap, i, tracenum, i);
|
||
|
||
/* initialize trace for scanning */
|
||
for (j = 0; j < trace->num_ids; j++)
|
||
trace->check[j] = 0;
|
||
|
||
for (j = 0; j < heapsize; j++) {
|
||
request_id = heap[j].request_id;
|
||
payload = heap[j].payload;
|
||
|
||
if (((request_id) > trace->num_ids) || (trace->allocated[request_id] == 0)) {
|
||
printf("[%s]%d 不是一个有效的request_id[tracenum=%d,i=%d]\n", __func__, request_id, tracenum, i);
|
||
expected_blocks(trace);
|
||
outputted_blocks(heap, heapsize);
|
||
return 0;
|
||
}
|
||
|
||
if (trace->allocated[request_id] == 2) {
|
||
printf("[%s]输出块 %d 已经被释放了[tracenum=%d,i=%d]\n", __func__, request_id, tracenum, i);
|
||
expected_blocks(trace);
|
||
outputted_blocks(heap, heapsize);
|
||
return 0;
|
||
}
|
||
|
||
if (trace->check[request_id] == 1) {
|
||
printf("[%s]块 %d 被输出了两次[tracenum=%d,i=%d]\n", __func__, request_id, tracenum, i);
|
||
expected_blocks(trace);
|
||
outputted_blocks(heap, heapsize);
|
||
return 0;
|
||
}
|
||
|
||
if (trace->block_sizes[request_id] != (size_t)payload) {
|
||
printf("[%s]块 %d 的大小不对%d, 应该是 %zu[tracenum=%d,i=%d]\n", __func__, request_id, payload, trace->block_sizes[request_id], tracenum, i);
|
||
expected_blocks(trace);
|
||
outputted_blocks(heap, heapsize);
|
||
return 0;
|
||
}
|
||
|
||
trace->check[request_id] = 1;
|
||
}
|
||
|
||
for (j = 0; j < trace->num_ids; j++)
|
||
if ((trace->allocated[j] == 1) && (trace->check[j] == 0))
|
||
{
|
||
printf("[%s]块 %d 不能被heapcheck输出[tracenum=%d,i=%d]\n", __func__, j, tracenum, i);
|
||
expected_blocks(trace);
|
||
outputted_blocks(heap, heapsize);
|
||
return 0;
|
||
}
|
||
|
||
|
||
break;
|
||
|
||
case FREE: /* mm_free */
|
||
//printf("FREE\n");
|
||
|
||
/* Remove region from list and call student's free function */
|
||
p = trace->blocks[index];
|
||
remove_range(ranges, p);
|
||
mm_free(p);
|
||
|
||
/* mark the appropriate block as freed */
|
||
trace->allocated[index] = 2;
|
||
|
||
break;
|
||
case ERROR_BUG:
|
||
break;
|
||
default:
|
||
printf("[%s]没有request类型\n", __func__);
|
||
}
|
||
|
||
}
|
||
|
||
/* 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)
|
||
printf("[%s]mm_init失败\n", __func__);
|
||
|
||
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)
|
||
printf("[%s]mm_malloc失败\n", __func__);
|
||
|
||
/* 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 = (int)trace->block_sizes[index];
|
||
|
||
oldp = trace->blocks[index];
|
||
if ((newp = (char*)mm_realloc(oldp, newsize)) == NULL)
|
||
printf("[%s]mm_realloc失败\n", __func__);
|
||
|
||
/* 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 HEAPCHECK:
|
||
break;
|
||
|
||
case FREE: /* mm_free */
|
||
index = trace->ops[i].index;
|
||
size = (int)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;
|
||
case ERROR_BUG:
|
||
break;
|
||
default:
|
||
printf("[%s]没有request类型\n", __func__);
|
||
|
||
}
|
||
}
|
||
|
||
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)
|
||
printf("[%s]mm_init失败\n", __func__);
|
||
|
||
/* 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)
|
||
printf("[%s]mm_malloc失败\n", __func__);
|
||
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 = (char*)mm_realloc(oldp, newsize)) == NULL)
|
||
printf("[%s]mm_realloc失败\n", __func__);
|
||
trace->blocks[index] = newp;
|
||
break;
|
||
|
||
case HEAPCHECK:
|
||
break;
|
||
|
||
case FREE: /* mm_free */
|
||
index = trace->ops[i].index;
|
||
block = trace->blocks[index];
|
||
mm_free(block);
|
||
break;
|
||
case ERROR_BUG:
|
||
break;
|
||
default:
|
||
printf("[%s]没有request类型\n", __func__);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 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) {
|
||
printf("[%s]libc malloc失败[tracenum=%d,i=%d]\n", __func__, tracenum, i);
|
||
}
|
||
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 = (char*)realloc(oldp, newsize)) == NULL) {
|
||
printf("[%s]libc realloc失败[tracenum=%d,i=%d]\n", __func__, tracenum, i);
|
||
}
|
||
trace->blocks[trace->ops[i].index] = newp;
|
||
break;
|
||
|
||
case HEAPCHECK:
|
||
break;
|
||
|
||
case FREE: /* free */
|
||
free(trace->blocks[trace->ops[i].index]);
|
||
break;
|
||
case ERROR_BUG:
|
||
break;
|
||
default:
|
||
printf("[%s]无效的操作类型[%d][tracenum=%d,i=%d]\n", __func__, trace->ops[i].type, tracenum, i);
|
||
}
|
||
}
|
||
|
||
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)
|
||
printf("[%s]malloc失败\n", __func__);
|
||
trace->blocks[index] = p;
|
||
break;
|
||
|
||
case REALLOC: /* realloc */
|
||
index = trace->ops[i].index;
|
||
newsize = trace->ops[i].size;
|
||
oldp = trace->blocks[index];
|
||
if ((newp = (char*)realloc(oldp, newsize)) == NULL)
|
||
printf("[%s]realloc失败\n", __func__);
|
||
|
||
trace->blocks[index] = newp;
|
||
break;
|
||
|
||
case HEAPCHECK:
|
||
break;
|
||
|
||
case FREE: /* free */
|
||
index = trace->ops[i].index;
|
||
block = trace->blocks[index];
|
||
free(block);
|
||
break;
|
||
case ERROR_BUG:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
unsigned int rand1_h, rand1_l, rand_div;
|
||
/* 产生一个0~divv-1之间的随机数,同时更新随机数种子 */
|
||
void GenerateRandomNumber(unsigned int divv)
|
||
{
|
||
unsigned long long x = rand1_h;
|
||
x *= 0x6AC690C5;
|
||
x += rand1_l;
|
||
|
||
rand1_h = (unsigned int)x;
|
||
rand1_l = (unsigned int)(x >> 32);
|
||
if (divv == 0) return;
|
||
|
||
rand_div = rand1_h % divv;
|
||
}
|
||
|
||
#define MAX_BENCHMARK_MALLOC_TIMES 10000
|
||
|
||
struct ref_malloc_trace_struct
|
||
{
|
||
int index;
|
||
int size;
|
||
char* p;
|
||
char op;
|
||
} ref_malloc_trace[2 * MAX_BENCHMARK_MALLOC_TIMES];
|
||
/*
|
||
* eval_libc_speed_ref_prepare - This is the function that is used by fcyc() to
|
||
* measure the running time of the libc malloc package on the set
|
||
* of traces.
|
||
*/
|
||
void eval_libc_speed_ref_prepare(void)
|
||
{
|
||
int i, malloc_count, free_count, j, last_free_index;
|
||
char free_flag[MAX_BENCHMARK_MALLOC_TIMES];
|
||
|
||
malloc_count = 0;
|
||
free_count = 0;
|
||
last_free_index = 0;
|
||
|
||
rand1_h = 0x11223344;
|
||
rand1_l = 0x55667788;
|
||
|
||
GenerateRandomNumber(0);
|
||
|
||
memset(ref_malloc_trace, 0, sizeof(ref_malloc_trace));
|
||
memset(free_flag, 0, sizeof(free_flag));
|
||
i = 0;
|
||
while (1)
|
||
{
|
||
GenerateRandomNumber(10);
|
||
//printf("rand_div=%d malloc_count=%d free_count=%d\n",rand_div,malloc_count,free_count);
|
||
if (rand_div >= 6 && malloc_count < MAX_BENCHMARK_MALLOC_TIMES)
|
||
{
|
||
// malloc
|
||
ref_malloc_trace[i].index = malloc_count;
|
||
ref_malloc_trace[i].op = 10;
|
||
free_flag[malloc_count] = 10;
|
||
GenerateRandomNumber(100000);
|
||
ref_malloc_trace[i].size = rand_div + 1;
|
||
//printf("a index=%02d size=%d\n",malloc_count,rand_div+1);
|
||
malloc_count++;
|
||
i++;
|
||
}
|
||
|
||
if (rand_div <= 4 && free_count < MAX_BENCHMARK_MALLOC_TIMES)
|
||
{
|
||
// free
|
||
for (j = last_free_index; j < malloc_count; j++)
|
||
if (free_flag[j] == 10)
|
||
{
|
||
//printf("f index=%02d\n",j);
|
||
last_free_index = j;
|
||
ref_malloc_trace[i].index = j;
|
||
ref_malloc_trace[i].op = 20;
|
||
free_flag[j] = 20;
|
||
i++;
|
||
free_count++;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (malloc_count == MAX_BENCHMARK_MALLOC_TIMES && free_count == MAX_BENCHMARK_MALLOC_TIMES)
|
||
break;
|
||
}
|
||
}
|
||
|
||
void eval_libc_speed_ref(void* ptr)
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < 2 * MAX_BENCHMARK_MALLOC_TIMES; i++)
|
||
{
|
||
if (ref_malloc_trace[i].op == 10)
|
||
{
|
||
//printf("%02d a %d\n",ref_malloc_trace[i].index,ref_malloc_trace[i].size);
|
||
ref_malloc_trace[ref_malloc_trace[i].index].p = (char*)malloc(ref_malloc_trace[i].size);
|
||
}
|
||
if (ref_malloc_trace[i].op == 20)
|
||
{
|
||
//printf("%02d f\n",ref_malloc_trace[i].index);
|
||
free(ref_malloc_trace[ref_malloc_trace[i].index].p);
|
||
}
|
||
}
|
||
}
|
||
|
||
/*************************************
|
||
* 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("[%s] +---------------------------------------------------------+\n", __func__);
|
||
printf("[%s] | trace | 正确性 | 效率 | 操作次数 | 时间(毫秒) | Kops |\n", __func__);
|
||
printf("[%s] +---------------------------------------------------------+\n", __func__);
|
||
for (i = 0; i < n; i++) {
|
||
if (stats[i].valid) {
|
||
printf("[%s] | %5d | %6s | %3.0f%% | %8.0f | %10.6f | %6.0f |\n", __func__,
|
||
i,
|
||
"yes",
|
||
stats[i].util * 100.0,
|
||
stats[i].ops,
|
||
stats[i].secs * 1000,
|
||
(stats[i].ops / 1e3) / stats[i].secs);
|
||
secs += stats[i].secs;
|
||
ops += stats[i].ops;
|
||
util += stats[i].util;
|
||
}
|
||
else {
|
||
printf("[%s] | %5d | no | - | - | - | - |\n", __func__, i);
|
||
}
|
||
}
|
||
|
||
/* Print the aggregate results for the set of traces */
|
||
if (errors == 0) {
|
||
printf("[%s] | 累计 | | %3.0f%% | %8.0f | %10.6f | %6.0f |\n\n", __func__,
|
||
(util / n) * 100.0,
|
||
ops,
|
||
secs * 1000,
|
||
(ops / 1e3) / secs);
|
||
}
|
||
else {
|
||
printf("%12s%6s%10s%12s%6s\n",
|
||
"累计 ",
|
||
"-",
|
||
"-",
|
||
"-",
|
||
"-");
|
||
}
|
||
|
||
}
|
||
|
||
/*
|
||
* parse_heapcheck - Parse the output of the heapcheck into an internal data structure
|
||
* returns -1 on error, 0 on success
|
||
*/
|
||
static int parse_heap(char* file, block_t* heap, int max_blocks, int tracenum, int opnum)
|
||
{
|
||
FILE* fp;
|
||
char line[MAXLINE];
|
||
char str[MAXLINE];
|
||
int i = 0;
|
||
int request_id;
|
||
int payload;
|
||
|
||
fp = fopen(file, "r");
|
||
if (fp == NULL)
|
||
printf("[%s]从临时文件中读取失败\n", __func__);
|
||
|
||
while ((fgets(line, MAXLINE, fp) != NULL)) {
|
||
if (sscanf(line, "%s%d%d", str, &request_id, &payload) == 3)
|
||
if (!strcmp(str, "$BLOCK"))
|
||
{
|
||
/* found a block */
|
||
if (i < MAXHEAP) {
|
||
heap[i].request_id = request_id;
|
||
heap[i].payload = payload;
|
||
i++;
|
||
}
|
||
}
|
||
}
|
||
|
||
fclose(fp);
|
||
unlink(file);
|
||
|
||
return i;
|
||
}
|
||
|
||
|
||
/*
|
||
* Functions to print the expected output and the user input for heapcheck
|
||
*/
|
||
|
||
static void expected_blocks(trace_t* trace)
|
||
{
|
||
int active = 0;
|
||
int j;
|
||
|
||
printf("[%s]期待从HeapCheck中的输出:\n", __func__);
|
||
for (j = 0; j < trace->num_ids; j++)
|
||
if (trace->allocated[j] == 1)
|
||
{
|
||
active++;
|
||
printf("$BLOCK %d %zu\n", j, trace->block_sizes[j]);
|
||
}
|
||
printf("[%s]真正有效的块数 = %d\n", __func__, active);
|
||
}
|
||
|
||
static void outputted_blocks(block_t* heap, int heapsize)
|
||
{
|
||
int i;
|
||
printf("[%s]mm_heapcheck产生的输出\n", __func__);
|
||
for (i = 0; i < heapsize; i++)
|
||
{
|
||
printf("[%s]$BLOCK %d %d\n", __func__, heap[i].request_id, heap[i].payload);
|
||
}
|
||
printf("[%s]输出有效的块数 = %d\n", __func__, heapsize);
|
||
}
|
||
|
||
/*
|
||
* usage - Explain the command line arguments
|
||
*/
|
||
static void usage(char* exec)
|
||
{
|
||
// fprintf(stderr, "Usage: %s [-hvVal] [-f <file>] [-t <dir>]\n", exec);
|
||
fprintf(stderr, "Usage: %s [-hvVl] [-f <file>] [-t <dir>]\n", exec);
|
||
fprintf(stderr, "Options\n");
|
||
// fprintf(stderr, "\t-a 不检查团队信息.\n");
|
||
fprintf(stderr, "\t-f <file> 使用<file>作为trace文件.\n");
|
||
fprintf(stderr, "\t-g 为自动评分创建一个摘要信息.\n");
|
||
fprintf(stderr, "\t-h 打印此信息.\n");
|
||
fprintf(stderr, "\t-l 运行libc malloc的检测.\n");
|
||
fprintf(stderr, "\t-t <dir> 缺省trace存放的目录.\n");
|
||
fprintf(stderr, "\t-v 打印每条trace的性能.\n");
|
||
fprintf(stderr, "\t-V 打印额外的调试信息.\n");
|
||
}
|
||
|
||
|
||
|
||
|
||
|