| 141 |
Kevin |
1 |
/*
|
|
|
2 |
* mdriver.c - CS:APP Malloc Lab Driver
|
|
|
3 |
*
|
|
|
4 |
* Uses a collection of trace files to tests a malloc/free/realloc
|
|
|
5 |
* implementation in mm.c.
|
|
|
6 |
*
|
|
|
7 |
* Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved.
|
|
|
8 |
* May not be used, modified, or copied without permission.
|
|
|
9 |
*/
|
|
|
10 |
#include <stdio.h>
|
|
|
11 |
#include <stdlib.h>
|
|
|
12 |
#include <unistd.h>
|
|
|
13 |
#include <errno.h>
|
|
|
14 |
#include <string.h>
|
|
|
15 |
#include <assert.h>
|
|
|
16 |
#include <float.h>
|
|
|
17 |
#include <time.h>
|
|
|
18 |
|
|
|
19 |
#include "mm.h"
|
|
|
20 |
#include "memlib.h"
|
|
|
21 |
#include "fsecs.h"
|
|
|
22 |
#include "config.h"
|
|
|
23 |
|
|
|
24 |
/**********************
|
|
|
25 |
* Constants and macros
|
|
|
26 |
**********************/
|
|
|
27 |
|
|
|
28 |
/* Misc */
|
|
|
29 |
#define MAXLINE 1024 /* max string size */
|
|
|
30 |
#define HDRLINES 4 /* number of header lines in a trace file */
|
|
|
31 |
#define LINENUM(i) (i+5) /* cnvt trace request nums to linenums (origin 1) */
|
|
|
32 |
|
|
|
33 |
/* Returns true if p is ALIGNMENT-byte aligned */
|
|
|
34 |
#define IS_ALIGNED(p) ((((unsigned int)(p)) % ALIGNMENT) == 0)
|
|
|
35 |
|
|
|
36 |
/******************************
|
|
|
37 |
* The key compound data types
|
|
|
38 |
*****************************/
|
|
|
39 |
|
|
|
40 |
/* Records the extent of each block's payload */
|
|
|
41 |
typedef struct range_t {
|
|
|
42 |
char *lo; /* low payload address */
|
|
|
43 |
char *hi; /* high payload address */
|
|
|
44 |
struct range_t *next; /* next list element */
|
|
|
45 |
} range_t;
|
|
|
46 |
|
|
|
47 |
/* Characterizes a single trace operation (allocator request) */
|
|
|
48 |
typedef struct {
|
|
|
49 |
enum {ALLOC, FREE, REALLOC} type; /* type of request */
|
|
|
50 |
int index; /* index for free() to use later */
|
|
|
51 |
int size; /* byte size of alloc/realloc request */
|
|
|
52 |
} traceop_t;
|
|
|
53 |
|
|
|
54 |
/* Holds the information for one trace file*/
|
|
|
55 |
typedef struct {
|
|
|
56 |
int sugg_heapsize; /* suggested heap size (unused) */
|
|
|
57 |
int num_ids; /* number of alloc/realloc ids */
|
|
|
58 |
int num_ops; /* number of distinct requests */
|
|
|
59 |
int weight; /* weight for this trace (unused) */
|
|
|
60 |
traceop_t *ops; /* array of requests */
|
|
|
61 |
char **blocks; /* array of ptrs returned by malloc/realloc... */
|
|
|
62 |
size_t *block_sizes; /* ... and a corresponding array of payload sizes */
|
|
|
63 |
} trace_t;
|
|
|
64 |
|
|
|
65 |
/*
|
|
|
66 |
* Holds the params to the xxx_speed functions, which are timed by fcyc.
|
|
|
67 |
* This struct is necessary because fcyc accepts only a pointer array
|
|
|
68 |
* as input.
|
|
|
69 |
*/
|
|
|
70 |
typedef struct {
|
|
|
71 |
trace_t *trace;
|
|
|
72 |
range_t *ranges;
|
|
|
73 |
} speed_t;
|
|
|
74 |
|
|
|
75 |
/* Summarizes the important stats for some malloc function on some trace */
|
|
|
76 |
typedef struct {
|
|
|
77 |
/* defined for both libc malloc and student malloc package (mm.c) */
|
|
|
78 |
double ops; /* number of ops (malloc/free/realloc) in the trace */
|
|
|
79 |
int valid; /* was the trace processed correctly by the allocator? */
|
|
|
80 |
double secs; /* number of secs needed to run the trace */
|
|
|
81 |
|
|
|
82 |
/* defined only for the student malloc package */
|
|
|
83 |
double util; /* space utilization for this trace (always 0 for libc) */
|
|
|
84 |
|
|
|
85 |
/* Note: secs and util are only defined if valid is true */
|
|
|
86 |
} stats_t;
|
|
|
87 |
|
|
|
88 |
/********************
|
|
|
89 |
* Global variables
|
|
|
90 |
*******************/
|
|
|
91 |
int verbose = 0; /* global flag for verbose output */
|
|
|
92 |
static int errors = 0; /* number of errs found when running student malloc */
|
|
|
93 |
char msg[MAXLINE]; /* for whenever we need to compose an error message */
|
|
|
94 |
|
|
|
95 |
/* Directory where default tracefiles are found */
|
|
|
96 |
static char tracedir[MAXLINE] = TRACEDIR;
|
|
|
97 |
|
|
|
98 |
/* The filenames of the default tracefiles */
|
|
|
99 |
static char *default_tracefiles[] = {
|
|
|
100 |
DEFAULT_TRACEFILES, NULL
|
|
|
101 |
};
|
|
|
102 |
|
|
|
103 |
|
|
|
104 |
/*********************
|
|
|
105 |
* Function prototypes
|
|
|
106 |
*********************/
|
|
|
107 |
|
|
|
108 |
/* these functions manipulate range lists */
|
|
|
109 |
static int add_range(range_t **ranges, char *lo, int size,
|
|
|
110 |
int tracenum, int opnum);
|
|
|
111 |
static void remove_range(range_t **ranges, char *lo);
|
|
|
112 |
static void clear_ranges(range_t **ranges);
|
|
|
113 |
|
|
|
114 |
/* These functions read, allocate, and free storage for traces */
|
|
|
115 |
static trace_t *read_trace(char *tracedir, char *filename);
|
|
|
116 |
static void free_trace(trace_t *trace);
|
|
|
117 |
|
|
|
118 |
/* Routines for evaluating the correctness and speed of libc malloc */
|
|
|
119 |
static int eval_libc_valid(trace_t *trace, int tracenum);
|
|
|
120 |
static void eval_libc_speed(void *ptr);
|
|
|
121 |
|
|
|
122 |
/* Routines for evaluating correctnes, space utilization, and speed
|
|
|
123 |
of the student's malloc package in mm.c */
|
|
|
124 |
static int eval_mm_valid(trace_t *trace, int tracenum, range_t **ranges);
|
|
|
125 |
static double eval_mm_util(trace_t *trace, int tracenum, range_t **ranges);
|
|
|
126 |
static void eval_mm_speed(void *ptr);
|
|
|
127 |
|
|
|
128 |
/* Various helper routines */
|
|
|
129 |
static void printresults(int n, stats_t *stats);
|
|
|
130 |
static void usage(void);
|
|
|
131 |
static void unix_error(char *msg);
|
|
|
132 |
static void malloc_error(int tracenum, int opnum, char *msg);
|
|
|
133 |
static void app_error(char *msg);
|
|
|
134 |
|
|
|
135 |
/**************
|
|
|
136 |
* Main routine
|
|
|
137 |
**************/
|
|
|
138 |
int main(int argc, char **argv)
|
|
|
139 |
{
|
|
|
140 |
int i;
|
|
|
141 |
char c;
|
|
|
142 |
char **tracefiles = NULL; /* null-terminated array of trace file names */
|
|
|
143 |
int num_tracefiles = 0; /* the number of traces in that array */
|
|
|
144 |
trace_t *trace = NULL; /* stores a single trace file in memory */
|
|
|
145 |
range_t *ranges = NULL; /* keeps track of block extents for one trace */
|
|
|
146 |
stats_t *libc_stats = NULL;/* libc stats for each trace */
|
|
|
147 |
stats_t *mm_stats = NULL; /* mm (i.e. student) stats for each trace */
|
|
|
148 |
speed_t speed_params; /* input parameters to the xx_speed routines */
|
|
|
149 |
|
|
|
150 |
int team_check = 1; /* If set, check team structure (reset by -a) */
|
|
|
151 |
int run_libc = 0; /* If set, run libc malloc (set by -l) */
|
|
|
152 |
int autograder = 0; /* If set, emit summary info for autograder (-g) */
|
|
|
153 |
int use_mmap = 0; /* If set, have memlib use mmap() instead malloc() */
|
|
|
154 |
|
|
|
155 |
/* temporaries used to compute the performance index */
|
|
|
156 |
double secs, ops, util, avg_mm_util, avg_mm_throughput, p1, p2, perfindex;
|
|
|
157 |
int numcorrect;
|
|
|
158 |
|
|
|
159 |
/*
|
|
|
160 |
* Read and interpret the command line arguments
|
|
|
161 |
*/
|
|
|
162 |
while ((c = getopt(argc, argv, "nf:t:hvVgal")) != EOF) {
|
|
|
163 |
switch (c) {
|
|
|
164 |
case 'n':
|
|
|
165 |
use_mmap = 1;
|
|
|
166 |
break;
|
|
|
167 |
case 'g': /* Generate summary info for the autograder */
|
|
|
168 |
autograder = 1;
|
|
|
169 |
break;
|
|
|
170 |
case 'f': /* Use one specific trace file only (relative to curr dir) */
|
|
|
171 |
num_tracefiles = 1;
|
|
|
172 |
if ((tracefiles = realloc(tracefiles, 2*sizeof(char *))) == NULL)
|
|
|
173 |
unix_error("ERROR: realloc failed in main");
|
|
|
174 |
strcpy(tracedir, "./");
|
|
|
175 |
tracefiles[0] = strdup(optarg);
|
|
|
176 |
tracefiles[1] = NULL;
|
|
|
177 |
break;
|
|
|
178 |
case 't': /* Directory where the traces are located */
|
|
|
179 |
if (num_tracefiles == 1) /* ignore if -f already encountered */
|
|
|
180 |
break;
|
|
|
181 |
strcpy(tracedir, optarg);
|
|
|
182 |
if (tracedir[strlen(tracedir)-1] != '/')
|
|
|
183 |
strcat(tracedir, "/"); /* path always ends with "/" */
|
|
|
184 |
break;
|
|
|
185 |
case 'a': /* Don't check team structure */
|
|
|
186 |
team_check = 0;
|
|
|
187 |
break;
|
|
|
188 |
case 'l': /* Run libc malloc */
|
|
|
189 |
run_libc = 1;
|
|
|
190 |
break;
|
|
|
191 |
case 'v': /* Print per-trace performance breakdown */
|
|
|
192 |
verbose = 1;
|
|
|
193 |
break;
|
|
|
194 |
case 'V': /* Be more verbose than -v */
|
|
|
195 |
verbose = 2;
|
|
|
196 |
break;
|
|
|
197 |
case 'h': /* Print this message */
|
|
|
198 |
usage();
|
|
|
199 |
exit(0);
|
|
|
200 |
default:
|
|
|
201 |
usage();
|
|
|
202 |
exit(1);
|
|
|
203 |
}
|
|
|
204 |
}
|
|
|
205 |
|
|
|
206 |
/*
|
|
|
207 |
* Check and print team info
|
|
|
208 |
*/
|
|
|
209 |
if (team_check) {
|
|
|
210 |
/* Students must fill in their team information */
|
|
|
211 |
if (!strcmp(team.teamname, "")) {
|
|
|
212 |
printf("ERROR: Please provide the information about your team in mm.c.\n");
|
|
|
213 |
exit(1);
|
|
|
214 |
} else
|
|
|
215 |
printf("Team Name:%s\n", team.teamname);
|
|
|
216 |
if ((*team.name1 == '\0') || (*team.id1 == '\0')) {
|
|
|
217 |
printf("ERROR. You must fill in all team member 1 fields!\n");
|
|
|
218 |
exit(1);
|
|
|
219 |
}
|
|
|
220 |
else
|
|
|
221 |
printf("Member 1 :%s:%s\n", team.name1, team.id1);
|
|
|
222 |
|
|
|
223 |
if (((*team.name2 != '\0') && (*team.id2 == '\0')) ||
|
|
|
224 |
((*team.name2 == '\0') && (*team.id2 != '\0'))) {
|
|
|
225 |
printf("ERROR. You must fill in all or none of the team member 2 ID fields!\n");
|
|
|
226 |
exit(1);
|
|
|
227 |
}
|
|
|
228 |
else if (*team.name2 != '\0')
|
|
|
229 |
printf("Member 2 :%s:%s\n", team.name2, team.id2);
|
|
|
230 |
}
|
|
|
231 |
|
|
|
232 |
/*
|
|
|
233 |
* If no -f command line arg, then use the entire set of tracefiles
|
|
|
234 |
* defined in default_traces[]
|
|
|
235 |
*/
|
|
|
236 |
if (tracefiles == NULL) {
|
|
|
237 |
tracefiles = default_tracefiles;
|
|
|
238 |
num_tracefiles = sizeof(default_tracefiles) / sizeof(char *) - 1;
|
|
|
239 |
printf("Using default tracefiles in %s\n", tracedir);
|
|
|
240 |
}
|
|
|
241 |
|
|
|
242 |
/* Initialize the timing package */
|
|
|
243 |
init_fsecs();
|
|
|
244 |
|
|
|
245 |
/*
|
|
|
246 |
* Optionally run and evaluate the libc malloc package
|
|
|
247 |
*/
|
|
|
248 |
if (run_libc) {
|
|
|
249 |
if (verbose > 1)
|
|
|
250 |
printf("\nTesting libc malloc\n");
|
|
|
251 |
|
|
|
252 |
/* Allocate libc stats array, with one stats_t struct per tracefile */
|
|
|
253 |
libc_stats = (stats_t *)calloc(num_tracefiles, sizeof(stats_t));
|
|
|
254 |
if (libc_stats == NULL)
|
|
|
255 |
unix_error("libc_stats calloc in main failed");
|
|
|
256 |
|
|
|
257 |
/* Evaluate the libc malloc package using the K-best scheme */
|
|
|
258 |
for (i=0; i < num_tracefiles; i++) {
|
|
|
259 |
trace = read_trace(tracedir, tracefiles[i]);
|
|
|
260 |
libc_stats[i].ops = trace->num_ops;
|
|
|
261 |
if (verbose > 1)
|
|
|
262 |
printf("Checking libc malloc for correctness, ");
|
|
|
263 |
libc_stats[i].valid = eval_libc_valid(trace, i);
|
|
|
264 |
if (libc_stats[i].valid) {
|
|
|
265 |
speed_params.trace = trace;
|
|
|
266 |
if (verbose > 1)
|
|
|
267 |
printf("and performance.\n");
|
|
|
268 |
libc_stats[i].secs = fsecs(eval_libc_speed, &speed_params);
|
|
|
269 |
}
|
|
|
270 |
free_trace(trace);
|
|
|
271 |
}
|
|
|
272 |
|
|
|
273 |
/* Display the libc results in a compact table */
|
|
|
274 |
if (verbose) {
|
|
|
275 |
printf("\nResults for libc malloc:\n");
|
|
|
276 |
printresults(num_tracefiles, libc_stats);
|
|
|
277 |
}
|
|
|
278 |
}
|
|
|
279 |
|
|
|
280 |
/*
|
|
|
281 |
* Always run and evaluate the student's mm package
|
|
|
282 |
*/
|
|
|
283 |
if (verbose > 1)
|
|
|
284 |
printf("\nTesting mm malloc\n");
|
|
|
285 |
|
|
|
286 |
/* Allocate the mm stats array, with one stats_t struct per tracefile */
|
|
|
287 |
mm_stats = (stats_t *)calloc(num_tracefiles, sizeof(stats_t));
|
|
|
288 |
if (mm_stats == NULL)
|
|
|
289 |
unix_error("mm_stats calloc in main failed");
|
|
|
290 |
|
|
|
291 |
/* Initialize the simulated memory system in memlib.c */
|
|
|
292 |
mem_init(use_mmap);
|
|
|
293 |
|
|
|
294 |
/* Evaluate student's mm malloc package using the K-best scheme */
|
|
|
295 |
for (i=0; i < num_tracefiles; i++) {
|
|
|
296 |
trace = read_trace(tracedir, tracefiles[i]);
|
|
|
297 |
mm_stats[i].ops = trace->num_ops;
|
|
|
298 |
if (verbose > 1)
|
|
|
299 |
printf("Checking mm_malloc for correctness, ");
|
|
|
300 |
mm_stats[i].valid = eval_mm_valid(trace, i, &ranges);
|
|
|
301 |
if (mm_stats[i].valid) {
|
|
|
302 |
if (verbose > 1)
|
|
|
303 |
printf("efficiency, ");
|
|
|
304 |
mm_stats[i].util = eval_mm_util(trace, i, &ranges);
|
|
|
305 |
speed_params.trace = trace;
|
|
|
306 |
speed_params.ranges = ranges;
|
|
|
307 |
if (verbose > 1)
|
|
|
308 |
printf("and performance.\n");
|
|
|
309 |
mm_stats[i].secs = fsecs(eval_mm_speed, &speed_params);
|
|
|
310 |
}
|
|
|
311 |
free_trace(trace);
|
|
|
312 |
}
|
|
|
313 |
|
|
|
314 |
/* Display the mm results in a compact table */
|
|
|
315 |
if (verbose) {
|
|
|
316 |
printf("\nResults for mm malloc:\n");
|
|
|
317 |
printresults(num_tracefiles, mm_stats);
|
|
|
318 |
printf("\n");
|
|
|
319 |
}
|
|
|
320 |
|
|
|
321 |
/*
|
|
|
322 |
* Accumulate the aggregate statistics for the student's mm package
|
|
|
323 |
*/
|
|
|
324 |
secs = 0;
|
|
|
325 |
ops = 0;
|
|
|
326 |
util = 0;
|
|
|
327 |
numcorrect = 0;
|
|
|
328 |
for (i=0; i < num_tracefiles; i++) {
|
|
|
329 |
secs += mm_stats[i].secs;
|
|
|
330 |
ops += mm_stats[i].ops;
|
|
|
331 |
util += mm_stats[i].util;
|
|
|
332 |
if (mm_stats[i].valid)
|
|
|
333 |
numcorrect++;
|
|
|
334 |
}
|
|
|
335 |
avg_mm_util = util/num_tracefiles;
|
|
|
336 |
|
|
|
337 |
/*
|
|
|
338 |
* Compute and print the performance index
|
|
|
339 |
*/
|
|
|
340 |
if (errors == 0) {
|
|
|
341 |
avg_mm_throughput = ops/secs;
|
|
|
342 |
|
|
|
343 |
p1 = UTIL_WEIGHT * avg_mm_util;
|
|
|
344 |
if (avg_mm_throughput > AVG_LIBC_THRUPUT) {
|
|
|
345 |
p2 = (double)(1.0 - UTIL_WEIGHT);
|
|
|
346 |
}
|
|
|
347 |
else {
|
|
|
348 |
p2 = ((double) (1.0 - UTIL_WEIGHT)) *
|
|
|
349 |
(avg_mm_throughput/AVG_LIBC_THRUPUT);
|
|
|
350 |
}
|
|
|
351 |
|
|
|
352 |
perfindex = (p1 + p2)*100.0;
|
|
|
353 |
printf("Perf index = %.0f (util) + %.0f (thru) = %.0f/100\n",
|
|
|
354 |
p1*100,
|
|
|
355 |
p2*100,
|
|
|
356 |
perfindex);
|
|
|
357 |
|
|
|
358 |
}
|
|
|
359 |
else { /* There were errors */
|
|
|
360 |
perfindex = 0.0;
|
|
|
361 |
printf("Terminated with %d errors\n", errors);
|
|
|
362 |
}
|
|
|
363 |
|
|
|
364 |
if (autograder) {
|
|
|
365 |
printf("correct:%d\n", numcorrect);
|
|
|
366 |
printf("perfidx:%.0f\n", perfindex);
|
|
|
367 |
}
|
|
|
368 |
|
|
|
369 |
exit(0);
|
|
|
370 |
}
|
|
|
371 |
|
|
|
372 |
|
|
|
373 |
/*****************************************************************
|
|
|
374 |
* The following routines manipulate the range list, which keeps
|
|
|
375 |
* track of the extent of every allocated block payload. We use the
|
|
|
376 |
* range list to detect any overlapping allocated blocks.
|
|
|
377 |
****************************************************************/
|
|
|
378 |
|
|
|
379 |
/*
|
|
|
380 |
* add_range - As directed by request opnum in trace tracenum,
|
|
|
381 |
* we've just called the student's mm_malloc to allocate a block of
|
|
|
382 |
* size bytes at addr lo. After checking the block for correctness,
|
|
|
383 |
* we create a range struct for this block and add it to the range list.
|
|
|
384 |
*/
|
|
|
385 |
static int add_range(range_t **ranges, char *lo, int size,
|
|
|
386 |
int tracenum, int opnum)
|
|
|
387 |
{
|
|
|
388 |
char *hi = lo + size - 1;
|
|
|
389 |
range_t *p;
|
|
|
390 |
char msg[MAXLINE];
|
|
|
391 |
|
|
|
392 |
assert(size > 0);
|
|
|
393 |
|
|
|
394 |
/* Payload addresses must be ALIGNMENT-byte aligned */
|
|
|
395 |
if (!IS_ALIGNED(lo)) {
|
|
|
396 |
sprintf(msg, "Payload address (%p) not aligned to %d bytes",
|
|
|
397 |
lo, ALIGNMENT);
|
|
|
398 |
malloc_error(tracenum, opnum, msg);
|
|
|
399 |
return 0;
|
|
|
400 |
}
|
|
|
401 |
|
|
|
402 |
/* The payload must lie within the extent of the heap */
|
|
|
403 |
if ((lo < (char *)mem_heap_lo()) || (lo > (char *)mem_heap_hi()) ||
|
|
|
404 |
(hi < (char *)mem_heap_lo()) || (hi > (char *)mem_heap_hi())) {
|
|
|
405 |
sprintf(msg, "Payload (%p:%p) lies outside heap (%p:%p)",
|
|
|
406 |
lo, hi, mem_heap_lo(), mem_heap_hi());
|
|
|
407 |
malloc_error(tracenum, opnum, msg);
|
|
|
408 |
return 0;
|
|
|
409 |
}
|
|
|
410 |
|
|
|
411 |
/* The payload must not overlap any other payloads */
|
|
|
412 |
for (p = *ranges; p != NULL; p = p->next) {
|
|
|
413 |
if ((lo >= p->lo && lo <= p-> hi) ||
|
|
|
414 |
(hi >= p->lo && hi <= p->hi)) {
|
|
|
415 |
sprintf(msg, "Payload (%p:%p) overlaps another payload (%p:%p)\n",
|
|
|
416 |
lo, hi, p->lo, p->hi);
|
|
|
417 |
malloc_error(tracenum, opnum, msg);
|
|
|
418 |
return 0;
|
|
|
419 |
}
|
|
|
420 |
}
|
|
|
421 |
|
|
|
422 |
/*
|
|
|
423 |
* Everything looks OK, so remember the extent of this block
|
|
|
424 |
* by creating a range struct and adding it the range list.
|
|
|
425 |
*/
|
|
|
426 |
if ((p = (range_t *)malloc(sizeof(range_t))) == NULL)
|
|
|
427 |
unix_error("malloc error in add_range");
|
|
|
428 |
p->next = *ranges;
|
|
|
429 |
p->lo = lo;
|
|
|
430 |
p->hi = hi;
|
|
|
431 |
*ranges = p;
|
|
|
432 |
return 1;
|
|
|
433 |
}
|
|
|
434 |
|
|
|
435 |
/*
|
|
|
436 |
* remove_range - Free the range record of block whose payload starts at lo
|
|
|
437 |
*/
|
|
|
438 |
static void remove_range(range_t **ranges, char *lo)
|
|
|
439 |
{
|
|
|
440 |
range_t *p;
|
|
|
441 |
range_t **prevpp = ranges;
|
|
|
442 |
int size;
|
|
|
443 |
|
|
|
444 |
for (p = *ranges; p != NULL; p = p->next) {
|
|
|
445 |
if (p->lo == lo) {
|
|
|
446 |
*prevpp = p->next;
|
|
|
447 |
size = p->hi - p->lo + 1;
|
|
|
448 |
free(p);
|
|
|
449 |
break;
|
|
|
450 |
}
|
|
|
451 |
prevpp = &(p->next);
|
|
|
452 |
}
|
|
|
453 |
}
|
|
|
454 |
|
|
|
455 |
/*
|
|
|
456 |
* clear_ranges - free all of the range records for a trace
|
|
|
457 |
*/
|
|
|
458 |
static void clear_ranges(range_t **ranges)
|
|
|
459 |
{
|
|
|
460 |
range_t *p;
|
|
|
461 |
range_t *pnext;
|
|
|
462 |
|
|
|
463 |
for (p = *ranges; p != NULL; p = pnext) {
|
|
|
464 |
pnext = p->next;
|
|
|
465 |
free(p);
|
|
|
466 |
}
|
|
|
467 |
*ranges = NULL;
|
|
|
468 |
}
|
|
|
469 |
|
|
|
470 |
|
|
|
471 |
/**********************************************
|
|
|
472 |
* The following routines manipulate tracefiles
|
|
|
473 |
*********************************************/
|
|
|
474 |
|
|
|
475 |
/*
|
|
|
476 |
* read_trace - read a trace file and store it in memory
|
|
|
477 |
*/
|
|
|
478 |
static trace_t *read_trace(char *tracedir, char *filename)
|
|
|
479 |
{
|
|
|
480 |
FILE *tracefile;
|
|
|
481 |
trace_t *trace;
|
|
|
482 |
char type[MAXLINE];
|
|
|
483 |
char path[MAXLINE];
|
|
|
484 |
unsigned index, size;
|
|
|
485 |
unsigned max_index = 0;
|
|
|
486 |
unsigned op_index;
|
|
|
487 |
|
|
|
488 |
if (verbose > 1)
|
|
|
489 |
printf("Reading tracefile: %s\n", filename);
|
|
|
490 |
|
|
|
491 |
/* Allocate the trace record */
|
|
|
492 |
if ((trace = (trace_t *) malloc(sizeof(trace_t))) == NULL)
|
|
|
493 |
unix_error("malloc 1 failed in read_trance");
|
|
|
494 |
|
|
|
495 |
/* Read the trace file header */
|
|
|
496 |
strcpy(path, tracedir);
|
|
|
497 |
strcat(path, filename);
|
|
|
498 |
if ((tracefile = fopen(path, "r")) == NULL) {
|
|
|
499 |
sprintf(msg, "Could not open %s in read_trace", path);
|
|
|
500 |
unix_error(msg);
|
|
|
501 |
}
|
|
|
502 |
fscanf(tracefile, "%d", &(trace->sugg_heapsize)); /* not used */
|
|
|
503 |
fscanf(tracefile, "%d", &(trace->num_ids));
|
|
|
504 |
fscanf(tracefile, "%d", &(trace->num_ops));
|
|
|
505 |
fscanf(tracefile, "%d", &(trace->weight)); /* not used */
|
|
|
506 |
|
|
|
507 |
/* We'll store each request line in the trace in this array */
|
|
|
508 |
if ((trace->ops =
|
|
|
509 |
(traceop_t *)malloc(trace->num_ops * sizeof(traceop_t))) == NULL)
|
|
|
510 |
unix_error("malloc 2 failed in read_trace");
|
|
|
511 |
|
|
|
512 |
/* We'll keep an array of pointers to the allocated blocks here... */
|
|
|
513 |
if ((trace->blocks =
|
|
|
514 |
(char **)malloc(trace->num_ids * sizeof(char *))) == NULL)
|
|
|
515 |
unix_error("malloc 3 failed in read_trace");
|
|
|
516 |
|
|
|
517 |
/* ... along with the corresponding byte sizes of each block */
|
|
|
518 |
if ((trace->block_sizes =
|
|
|
519 |
(size_t *)malloc(trace->num_ids * sizeof(size_t))) == NULL)
|
|
|
520 |
unix_error("malloc 4 failed in read_trace");
|
|
|
521 |
|
|
|
522 |
/* read every request line in the trace file */
|
|
|
523 |
index = 0;
|
|
|
524 |
op_index = 0;
|
|
|
525 |
while (fscanf(tracefile, "%s", type) != EOF) {
|
|
|
526 |
switch(type[0]) {
|
|
|
527 |
case 'a':
|
|
|
528 |
fscanf(tracefile, "%u %u", &index, &size);
|
|
|
529 |
trace->ops[op_index].type = ALLOC;
|
|
|
530 |
trace->ops[op_index].index = index;
|
|
|
531 |
trace->ops[op_index].size = size;
|
|
|
532 |
max_index = (index > max_index) ? index : max_index;
|
|
|
533 |
break;
|
|
|
534 |
case 'r':
|
|
|
535 |
fscanf(tracefile, "%u %u", &index, &size);
|
|
|
536 |
trace->ops[op_index].type = REALLOC;
|
|
|
537 |
trace->ops[op_index].index = index;
|
|
|
538 |
trace->ops[op_index].size = size;
|
|
|
539 |
max_index = (index > max_index) ? index : max_index;
|
|
|
540 |
break;
|
|
|
541 |
case 'f':
|
|
|
542 |
fscanf(tracefile, "%ud", &index);
|
|
|
543 |
trace->ops[op_index].type = FREE;
|
|
|
544 |
trace->ops[op_index].index = index;
|
|
|
545 |
break;
|
|
|
546 |
default:
|
|
|
547 |
printf("Bogus type character (%c) in tracefile %s\n",
|
|
|
548 |
type[0], path);
|
|
|
549 |
exit(1);
|
|
|
550 |
}
|
|
|
551 |
op_index++;
|
|
|
552 |
|
|
|
553 |
}
|
|
|
554 |
fclose(tracefile);
|
|
|
555 |
assert(max_index == trace->num_ids - 1);
|
|
|
556 |
assert(trace->num_ops == op_index);
|
|
|
557 |
|
|
|
558 |
return trace;
|
|
|
559 |
}
|
|
|
560 |
|
|
|
561 |
/*
|
|
|
562 |
* free_trace - Free the trace record and the three arrays it points
|
|
|
563 |
* to, all of which were allocated in read_trace().
|
|
|
564 |
*/
|
|
|
565 |
void free_trace(trace_t *trace)
|
|
|
566 |
{
|
|
|
567 |
free(trace->ops); /* free the three arrays... */
|
|
|
568 |
free(trace->blocks);
|
|
|
569 |
free(trace->block_sizes);
|
|
|
570 |
free(trace); /* and the trace record itself... */
|
|
|
571 |
}
|
|
|
572 |
|
|
|
573 |
/**********************************************************************
|
|
|
574 |
* The following functions evaluate the correctness, space utilization,
|
|
|
575 |
* and throughput of the libc and mm malloc packages.
|
|
|
576 |
**********************************************************************/
|
|
|
577 |
|
|
|
578 |
/*
|
|
|
579 |
* eval_mm_valid - Check the mm malloc package for correctness
|
|
|
580 |
*/
|
|
|
581 |
static int eval_mm_valid(trace_t *trace, int tracenum, range_t **ranges)
|
|
|
582 |
{
|
|
|
583 |
int i, j;
|
|
|
584 |
int index;
|
|
|
585 |
int size;
|
|
|
586 |
int oldsize;
|
|
|
587 |
char *newp;
|
|
|
588 |
char *oldp;
|
|
|
589 |
char *p;
|
|
|
590 |
|
|
|
591 |
/* Reset the heap and free any records in the range list */
|
|
|
592 |
mem_reset_brk();
|
|
|
593 |
clear_ranges(ranges);
|
|
|
594 |
|
|
|
595 |
/* Call the mm package's init function */
|
|
|
596 |
if (mm_init() < 0) {
|
|
|
597 |
malloc_error(tracenum, 0, "mm_init failed.");
|
|
|
598 |
return 0;
|
|
|
599 |
}
|
|
|
600 |
|
|
|
601 |
/* Interpret each operation in the trace in order */
|
|
|
602 |
for (i = 0; i < trace->num_ops; i++) {
|
|
|
603 |
index = trace->ops[i].index;
|
|
|
604 |
size = trace->ops[i].size;
|
|
|
605 |
|
|
|
606 |
switch (trace->ops[i].type) {
|
|
|
607 |
|
|
|
608 |
case ALLOC: /* mm_malloc */
|
|
|
609 |
|
|
|
610 |
/* Call the student's malloc */
|
|
|
611 |
if ((p = mm_malloc(size)) == NULL) {
|
|
|
612 |
malloc_error(tracenum, i, "mm_malloc failed.");
|
|
|
613 |
return 0;
|
|
|
614 |
}
|
|
|
615 |
|
|
|
616 |
/*
|
|
|
617 |
* Test the range of the new block for correctness and add it
|
|
|
618 |
* to the range list if OK. The block must be be aligned properly,
|
|
|
619 |
* and must not overlap any currently allocated block.
|
|
|
620 |
*/
|
|
|
621 |
if (add_range(ranges, p, size, tracenum, i) == 0)
|
|
|
622 |
return 0;
|
|
|
623 |
|
|
|
624 |
/* ADDED: cgw
|
|
|
625 |
* fill range with low byte of index. This will be used later
|
|
|
626 |
* if we realloc the block and wish to make sure that the old
|
|
|
627 |
* data was copied to the new block
|
|
|
628 |
*/
|
|
|
629 |
memset(p, index & 0xFF, size);
|
|
|
630 |
|
|
|
631 |
/* Remember region */
|
|
|
632 |
trace->blocks[index] = p;
|
|
|
633 |
trace->block_sizes[index] = size;
|
|
|
634 |
break;
|
|
|
635 |
|
|
|
636 |
case REALLOC: /* mm_realloc */
|
|
|
637 |
|
|
|
638 |
/* Call the student's realloc */
|
|
|
639 |
oldp = trace->blocks[index];
|
|
|
640 |
if ((newp = mm_realloc(oldp, size)) == NULL) {
|
|
|
641 |
malloc_error(tracenum, i, "mm_realloc failed.");
|
|
|
642 |
return 0;
|
|
|
643 |
}
|
|
|
644 |
|
|
|
645 |
/* Remove the old region from the range list */
|
|
|
646 |
remove_range(ranges, oldp);
|
|
|
647 |
|
|
|
648 |
/* Check new block for correctness and add it to range list */
|
|
|
649 |
if (add_range(ranges, newp, size, tracenum, i) == 0)
|
|
|
650 |
return 0;
|
|
|
651 |
|
|
|
652 |
/* ADDED: cgw
|
|
|
653 |
* Make sure that the new block contains the data from the old
|
|
|
654 |
* block and then fill in the new block with the low order byte
|
|
|
655 |
* of the new index
|
|
|
656 |
*/
|
|
|
657 |
oldsize = trace->block_sizes[index];
|
|
|
658 |
if (size < oldsize) oldsize = size;
|
|
|
659 |
for (j = 0; j < oldsize; j++) {
|
|
|
660 |
if (newp[j] != (index & 0xFF)) {
|
|
|
661 |
malloc_error(tracenum, i, "mm_realloc did not preserve the "
|
|
|
662 |
"data from old block");
|
|
|
663 |
return 0;
|
|
|
664 |
}
|
|
|
665 |
}
|
|
|
666 |
memset(newp, index & 0xFF, size);
|
|
|
667 |
|
|
|
668 |
/* Remember region */
|
|
|
669 |
trace->blocks[index] = newp;
|
|
|
670 |
trace->block_sizes[index] = size;
|
|
|
671 |
break;
|
|
|
672 |
|
|
|
673 |
case FREE: /* mm_free */
|
|
|
674 |
|
|
|
675 |
/* Remove region from list and call student's free function */
|
|
|
676 |
p = trace->blocks[index];
|
|
|
677 |
remove_range(ranges, p);
|
|
|
678 |
mm_free(p);
|
|
|
679 |
break;
|
|
|
680 |
|
|
|
681 |
default:
|
|
|
682 |
app_error("Nonexistent request type in eval_mm_valid");
|
|
|
683 |
}
|
|
|
684 |
|
|
|
685 |
}
|
|
|
686 |
|
|
|
687 |
/* As far as we know, this is a valid malloc package */
|
|
|
688 |
return 1;
|
|
|
689 |
}
|
|
|
690 |
|
|
|
691 |
/*
|
|
|
692 |
* eval_mm_util - Evaluate the space utilization of the student's package
|
|
|
693 |
* The idea is to remember the high water mark "hwm" of the heap for
|
|
|
694 |
* an optimal allocator, i.e., no gaps and no internal fragmentation.
|
|
|
695 |
* Utilization is the ratio hwm/heapsize, where heapsize is the
|
|
|
696 |
* size of the heap in bytes after running the student's malloc
|
|
|
697 |
* package on the trace. Note that our implementation of mem_sbrk()
|
|
|
698 |
* doesn't allow the students to decrement the brk pointer, so brk
|
|
|
699 |
* is always the high water mark of the heap.
|
|
|
700 |
*
|
|
|
701 |
*/
|
|
|
702 |
static double eval_mm_util(trace_t *trace, int tracenum, range_t **ranges)
|
|
|
703 |
{
|
|
|
704 |
int i;
|
|
|
705 |
int index;
|
|
|
706 |
int size, newsize, oldsize;
|
|
|
707 |
int max_total_size = 0;
|
|
|
708 |
int total_size = 0;
|
|
|
709 |
char *p;
|
|
|
710 |
char *newp, *oldp;
|
|
|
711 |
|
|
|
712 |
/* initialize the heap and the mm malloc package */
|
|
|
713 |
mem_reset_brk();
|
|
|
714 |
if (mm_init() < 0)
|
|
|
715 |
app_error("mm_init failed in eval_mm_util");
|
|
|
716 |
|
|
|
717 |
for (i = 0; i < trace->num_ops; i++) {
|
|
|
718 |
switch (trace->ops[i].type) {
|
|
|
719 |
|
|
|
720 |
case ALLOC: /* mm_alloc */
|
|
|
721 |
index = trace->ops[i].index;
|
|
|
722 |
size = trace->ops[i].size;
|
|
|
723 |
|
|
|
724 |
if ((p = mm_malloc(size)) == NULL)
|
|
|
725 |
app_error("mm_malloc failed in eval_mm_util");
|
|
|
726 |
|
|
|
727 |
/* Remember region and size */
|
|
|
728 |
trace->blocks[index] = p;
|
|
|
729 |
trace->block_sizes[index] = size;
|
|
|
730 |
|
|
|
731 |
/* Keep track of current total size
|
|
|
732 |
* of all allocated blocks */
|
|
|
733 |
total_size += size;
|
|
|
734 |
|
|
|
735 |
/* Update statistics */
|
|
|
736 |
max_total_size = (total_size > max_total_size) ?
|
|
|
737 |
total_size : max_total_size;
|
|
|
738 |
break;
|
|
|
739 |
|
|
|
740 |
case REALLOC: /* mm_realloc */
|
|
|
741 |
index = trace->ops[i].index;
|
|
|
742 |
newsize = trace->ops[i].size;
|
|
|
743 |
oldsize = trace->block_sizes[index];
|
|
|
744 |
|
|
|
745 |
oldp = trace->blocks[index];
|
|
|
746 |
if ((newp = mm_realloc(oldp,newsize)) == NULL)
|
|
|
747 |
app_error("mm_realloc failed in eval_mm_util");
|
|
|
748 |
|
|
|
749 |
/* Remember region and size */
|
|
|
750 |
trace->blocks[index] = newp;
|
|
|
751 |
trace->block_sizes[index] = newsize;
|
|
|
752 |
|
|
|
753 |
/* Keep track of current total size
|
|
|
754 |
* of all allocated blocks */
|
|
|
755 |
total_size += (newsize - oldsize);
|
|
|
756 |
|
|
|
757 |
/* Update statistics */
|
|
|
758 |
max_total_size = (total_size > max_total_size) ?
|
|
|
759 |
total_size : max_total_size;
|
|
|
760 |
break;
|
|
|
761 |
|
|
|
762 |
case FREE: /* mm_free */
|
|
|
763 |
index = trace->ops[i].index;
|
|
|
764 |
size = trace->block_sizes[index];
|
|
|
765 |
p = trace->blocks[index];
|
|
|
766 |
|
|
|
767 |
mm_free(p);
|
|
|
768 |
|
|
|
769 |
/* Keep track of current total size
|
|
|
770 |
* of all allocated blocks */
|
|
|
771 |
total_size -= size;
|
|
|
772 |
|
|
|
773 |
break;
|
|
|
774 |
|
|
|
775 |
default:
|
|
|
776 |
app_error("Nonexistent request type in eval_mm_util");
|
|
|
777 |
|
|
|
778 |
}
|
|
|
779 |
}
|
|
|
780 |
|
|
|
781 |
return ((double)max_total_size / (double)mem_heapsize());
|
|
|
782 |
}
|
|
|
783 |
|
|
|
784 |
|
|
|
785 |
/*
|
|
|
786 |
* eval_mm_speed - This is the function that is used by fcyc()
|
|
|
787 |
* to measure the running time of the mm malloc package.
|
|
|
788 |
*/
|
|
|
789 |
static void eval_mm_speed(void *ptr)
|
|
|
790 |
{
|
|
|
791 |
int i, index, size, newsize;
|
|
|
792 |
char *p, *newp, *oldp, *block;
|
|
|
793 |
trace_t *trace = ((speed_t *)ptr)->trace;
|
|
|
794 |
|
|
|
795 |
/* Reset the heap and initialize the mm package */
|
|
|
796 |
mem_reset_brk();
|
|
|
797 |
if (mm_init() < 0)
|
|
|
798 |
app_error("mm_init failed in eval_mm_speed");
|
|
|
799 |
|
|
|
800 |
/* Interpret each trace request */
|
|
|
801 |
for (i = 0; i < trace->num_ops; i++)
|
|
|
802 |
switch (trace->ops[i].type) {
|
|
|
803 |
|
|
|
804 |
case ALLOC: /* mm_malloc */
|
|
|
805 |
index = trace->ops[i].index;
|
|
|
806 |
size = trace->ops[i].size;
|
|
|
807 |
if ((p = mm_malloc(size)) == NULL)
|
|
|
808 |
app_error("mm_malloc error in eval_mm_speed");
|
|
|
809 |
trace->blocks[index] = p;
|
|
|
810 |
break;
|
|
|
811 |
|
|
|
812 |
case REALLOC: /* mm_realloc */
|
|
|
813 |
index = trace->ops[i].index;
|
|
|
814 |
newsize = trace->ops[i].size;
|
|
|
815 |
oldp = trace->blocks[index];
|
|
|
816 |
if ((newp = mm_realloc(oldp,newsize)) == NULL)
|
|
|
817 |
app_error("mm_realloc error in eval_mm_speed");
|
|
|
818 |
trace->blocks[index] = newp;
|
|
|
819 |
break;
|
|
|
820 |
|
|
|
821 |
case FREE: /* mm_free */
|
|
|
822 |
index = trace->ops[i].index;
|
|
|
823 |
block = trace->blocks[index];
|
|
|
824 |
mm_free(block);
|
|
|
825 |
break;
|
|
|
826 |
|
|
|
827 |
default:
|
|
|
828 |
app_error("Nonexistent request type in eval_mm_valid");
|
|
|
829 |
}
|
|
|
830 |
}
|
|
|
831 |
|
|
|
832 |
/*
|
|
|
833 |
* eval_libc_valid - We run this function to make sure that the
|
|
|
834 |
* libc malloc can run to completion on the set of traces.
|
|
|
835 |
* We'll be conservative and terminate if any libc malloc call fails.
|
|
|
836 |
*
|
|
|
837 |
*/
|
|
|
838 |
static int eval_libc_valid(trace_t *trace, int tracenum)
|
|
|
839 |
{
|
|
|
840 |
int i, newsize;
|
|
|
841 |
char *p, *newp, *oldp;
|
|
|
842 |
|
|
|
843 |
for (i = 0; i < trace->num_ops; i++) {
|
|
|
844 |
switch (trace->ops[i].type) {
|
|
|
845 |
|
|
|
846 |
case ALLOC: /* malloc */
|
|
|
847 |
if ((p = malloc(trace->ops[i].size)) == NULL) {
|
|
|
848 |
malloc_error(tracenum, i, "libc malloc failed");
|
|
|
849 |
unix_error("System message");
|
|
|
850 |
}
|
|
|
851 |
trace->blocks[trace->ops[i].index] = p;
|
|
|
852 |
break;
|
|
|
853 |
|
|
|
854 |
case REALLOC: /* realloc */
|
|
|
855 |
newsize = trace->ops[i].size;
|
|
|
856 |
oldp = trace->blocks[trace->ops[i].index];
|
|
|
857 |
if ((newp = realloc(oldp, newsize)) == NULL) {
|
|
|
858 |
malloc_error(tracenum, i, "libc realloc failed");
|
|
|
859 |
unix_error("System message");
|
|
|
860 |
}
|
|
|
861 |
trace->blocks[trace->ops[i].index] = newp;
|
|
|
862 |
break;
|
|
|
863 |
|
|
|
864 |
case FREE: /* free */
|
|
|
865 |
free(trace->blocks[trace->ops[i].index]);
|
|
|
866 |
break;
|
|
|
867 |
|
|
|
868 |
default:
|
|
|
869 |
app_error("invalid operation type in eval_libc_valid");
|
|
|
870 |
}
|
|
|
871 |
}
|
|
|
872 |
|
|
|
873 |
return 1;
|
|
|
874 |
}
|
|
|
875 |
|
|
|
876 |
/*
|
|
|
877 |
* eval_libc_speed - This is the function that is used by fcyc() to
|
|
|
878 |
* measure the running time of the libc malloc package on the set
|
|
|
879 |
* of traces.
|
|
|
880 |
*/
|
|
|
881 |
static void eval_libc_speed(void *ptr)
|
|
|
882 |
{
|
|
|
883 |
int i;
|
|
|
884 |
int index, size, newsize;
|
|
|
885 |
char *p, *newp, *oldp, *block;
|
|
|
886 |
trace_t *trace = ((speed_t *)ptr)->trace;
|
|
|
887 |
|
|
|
888 |
for (i = 0; i < trace->num_ops; i++) {
|
|
|
889 |
switch (trace->ops[i].type) {
|
|
|
890 |
case ALLOC: /* malloc */
|
|
|
891 |
index = trace->ops[i].index;
|
|
|
892 |
size = trace->ops[i].size;
|
|
|
893 |
if ((p = malloc(size)) == NULL)
|
|
|
894 |
unix_error("malloc failed in eval_libc_speed");
|
|
|
895 |
trace->blocks[index] = p;
|
|
|
896 |
break;
|
|
|
897 |
|
|
|
898 |
case REALLOC: /* realloc */
|
|
|
899 |
index = trace->ops[i].index;
|
|
|
900 |
newsize = trace->ops[i].size;
|
|
|
901 |
oldp = trace->blocks[index];
|
|
|
902 |
if ((newp = realloc(oldp, newsize)) == NULL)
|
|
|
903 |
unix_error("realloc failed in eval_libc_speed\n");
|
|
|
904 |
|
|
|
905 |
trace->blocks[index] = newp;
|
|
|
906 |
break;
|
|
|
907 |
|
|
|
908 |
case FREE: /* free */
|
|
|
909 |
index = trace->ops[i].index;
|
|
|
910 |
block = trace->blocks[index];
|
|
|
911 |
free(block);
|
|
|
912 |
break;
|
|
|
913 |
}
|
|
|
914 |
}
|
|
|
915 |
}
|
|
|
916 |
|
|
|
917 |
/*************************************
|
|
|
918 |
* Some miscellaneous helper routines
|
|
|
919 |
************************************/
|
|
|
920 |
|
|
|
921 |
|
|
|
922 |
/*
|
|
|
923 |
* printresults - prints a performance summary for some malloc package
|
|
|
924 |
*/
|
|
|
925 |
static void printresults(int n, stats_t *stats)
|
|
|
926 |
{
|
|
|
927 |
int i;
|
|
|
928 |
double secs = 0;
|
|
|
929 |
double ops = 0;
|
|
|
930 |
double util = 0;
|
|
|
931 |
|
|
|
932 |
/* Print the individual results for each trace */
|
|
|
933 |
printf("%5s%7s %5s%8s%10s%6s\n",
|
|
|
934 |
"trace", " valid", "util", "ops", "secs", "Kops");
|
|
|
935 |
for (i=0; i < n; i++) {
|
|
|
936 |
if (stats[i].valid) {
|
|
|
937 |
printf("%2d%10s%5.0f%%%8.0f%10.6f%6.0f\n",
|
|
|
938 |
i,
|
|
|
939 |
"yes",
|
|
|
940 |
stats[i].util*100.0,
|
|
|
941 |
stats[i].ops,
|
|
|
942 |
stats[i].secs,
|
|
|
943 |
(stats[i].ops/1e3)/stats[i].secs);
|
|
|
944 |
secs += stats[i].secs;
|
|
|
945 |
ops += stats[i].ops;
|
|
|
946 |
util += stats[i].util;
|
|
|
947 |
}
|
|
|
948 |
else {
|
|
|
949 |
printf("%2d%10s%6s%8s%10s%6s\n",
|
|
|
950 |
i,
|
|
|
951 |
"no",
|
|
|
952 |
"-",
|
|
|
953 |
"-",
|
|
|
954 |
"-",
|
|
|
955 |
"-");
|
|
|
956 |
}
|
|
|
957 |
}
|
|
|
958 |
|
|
|
959 |
/* Print the aggregate results for the set of traces */
|
|
|
960 |
if (errors == 0) {
|
|
|
961 |
printf("%12s%5.0f%%%8.0f%10.6f%6.0f\n",
|
|
|
962 |
"Total ",
|
|
|
963 |
(util/n)*100.0,
|
|
|
964 |
ops,
|
|
|
965 |
secs,
|
|
|
966 |
(ops/1e3)/secs);
|
|
|
967 |
}
|
|
|
968 |
else {
|
|
|
969 |
printf("%12s%6s%8s%10s%6s\n",
|
|
|
970 |
"Total ",
|
|
|
971 |
"-",
|
|
|
972 |
"-",
|
|
|
973 |
"-",
|
|
|
974 |
"-");
|
|
|
975 |
}
|
|
|
976 |
|
|
|
977 |
}
|
|
|
978 |
|
|
|
979 |
/*
|
|
|
980 |
* app_error - Report an arbitrary application error
|
|
|
981 |
*/
|
|
|
982 |
void app_error(char *msg)
|
|
|
983 |
{
|
|
|
984 |
printf("%s\n", msg);
|
|
|
985 |
exit(1);
|
|
|
986 |
}
|
|
|
987 |
|
|
|
988 |
/*
|
|
|
989 |
* unix_error - Report a Unix-style error
|
|
|
990 |
*/
|
|
|
991 |
void unix_error(char *msg)
|
|
|
992 |
{
|
|
|
993 |
printf("%s: %s\n", msg, strerror(errno));
|
|
|
994 |
exit(1);
|
|
|
995 |
}
|
|
|
996 |
|
|
|
997 |
/*
|
|
|
998 |
* malloc_error - Report an error returned by the mm_malloc package
|
|
|
999 |
*/
|
|
|
1000 |
void malloc_error(int tracenum, int opnum, char *msg)
|
|
|
1001 |
{
|
|
|
1002 |
errors++;
|
|
|
1003 |
printf("ERROR [trace %d, line %d]: %s\n", tracenum, LINENUM(opnum), msg);
|
|
|
1004 |
}
|
|
|
1005 |
|
|
|
1006 |
/*
|
|
|
1007 |
* usage - Explain the command line arguments
|
|
|
1008 |
*/
|
|
|
1009 |
static void usage(void)
|
|
|
1010 |
{
|
|
|
1011 |
fprintf(stderr, "Usage: mdriver [-hvVal] [-f <file>] [-t <dir>]\n");
|
|
|
1012 |
fprintf(stderr, "Options\n");
|
|
|
1013 |
fprintf(stderr, "\t-a Don't check the team structure.\n");
|
|
|
1014 |
fprintf(stderr, "\t-f <file> Use <file> as the trace file.\n");
|
|
|
1015 |
fprintf(stderr, "\t-g Generate summary info for autograder.\n");
|
|
|
1016 |
fprintf(stderr, "\t-h Print this message.\n");
|
|
|
1017 |
fprintf(stderr, "\t-l Run libc malloc as well.\n");
|
|
|
1018 |
fprintf(stderr, "\t-t <dir> Directory to find default traces.\n");
|
|
|
1019 |
fprintf(stderr, "\t-v Print per-trace performance breakdowns.\n");
|
|
|
1020 |
fprintf(stderr, "\t-V Print additional debug info.\n");
|
|
|
1021 |
fprintf(stderr, "\t-n Don't randomize addresses.\n");
|
|
|
1022 |
}
|