Files
csapp2025/malloclab/mdriver.c
2025-05-21 14:41:01 +08:00

1388 lines
39 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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");
}