aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--malloclab-handout.tarbin0 -> 92160 bytes
-rw-r--r--malloclab-handout/Makefile30
-rw-r--r--malloclab-handout/README52
-rw-r--r--malloclab-handout/clock.c279
-rw-r--r--malloclab-handout/clock.h22
-rw-r--r--malloclab-handout/config.h72
-rw-r--r--malloclab-handout/fcyc.c251
-rw-r--r--malloclab-handout/fcyc.h68
-rw-r--r--malloclab-handout/fsecs.c57
-rw-r--r--malloclab-handout/fsecs.h4
-rw-r--r--malloclab-handout/ftimer.c106
-rw-r--r--malloclab-handout/ftimer.h14
-rw-r--r--malloclab-handout/mdriver.c1017
-rw-r--r--malloclab-handout/memlib.c101
-rw-r--r--malloclab-handout/memlib.h11
-rw-r--r--malloclab-handout/mm.c110
-rw-r--r--malloclab-handout/mm.h23
-rw-r--r--malloclab-handout/short1-bal.rep16
-rw-r--r--malloclab-handout/short2-bal.rep16
19 files changed, 2249 insertions, 0 deletions
diff --git a/malloclab-handout.tar b/malloclab-handout.tar
new file mode 100644
index 0000000..a6b6392
--- /dev/null
+++ b/malloclab-handout.tar
Binary files differ
diff --git a/malloclab-handout/Makefile b/malloclab-handout/Makefile
new file mode 100644
index 0000000..3d5dc9e
--- /dev/null
+++ b/malloclab-handout/Makefile
@@ -0,0 +1,30 @@
+#
+# Students' Makefile for the Malloc Lab
+#
+TEAM = bovik
+VERSION = 1
+HANDINDIR = /afs/cs.cmu.edu/academic/class/15213-f01/malloclab/handin
+
+CC = gcc
+CFLAGS = -Wall -O2 -m32
+
+OBJS = mdriver.o mm.o memlib.o fsecs.o fcyc.o clock.o ftimer.o
+
+mdriver: $(OBJS)
+ $(CC) $(CFLAGS) -o mdriver $(OBJS)
+
+mdriver.o: mdriver.c fsecs.h fcyc.h clock.h memlib.h config.h mm.h
+memlib.o: memlib.c memlib.h
+mm.o: mm.c mm.h memlib.h
+fsecs.o: fsecs.c fsecs.h config.h
+fcyc.o: fcyc.c fcyc.h
+ftimer.o: ftimer.c ftimer.h config.h
+clock.o: clock.c clock.h
+
+handin:
+ cp mm.c $(HANDINDIR)/$(TEAM)-$(VERSION)-mm.c
+
+clean:
+ rm -f *~ *.o mdriver
+
+
diff --git a/malloclab-handout/README b/malloclab-handout/README
new file mode 100644
index 0000000..12c238a
--- /dev/null
+++ b/malloclab-handout/README
@@ -0,0 +1,52 @@
+#####################################################################
+# CS:APP Malloc Lab
+# Handout files for students
+#
+# Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved.
+# May not be used, modified, or copied without permission.
+#
+######################################################################
+
+***********
+Main Files:
+***********
+
+mm.{c,h}
+ Your solution malloc package. mm.c is the file that you
+ will be handing in, and is the only file you should modify.
+
+mdriver.c
+ The malloc driver that tests your mm.c file
+
+short{1,2}-bal.rep
+ Two tiny tracefiles to help you get started.
+
+Makefile
+ Builds the driver
+
+**********************************
+Other support files for the driver
+**********************************
+
+config.h Configures the malloc lab driver
+fsecs.{c,h} Wrapper function for the different timer packages
+clock.{c,h} Routines for accessing the Pentium and Alpha cycle counters
+fcyc.{c,h} Timer functions based on cycle counters
+ftimer.{c,h} Timer functions based on interval timers and gettimeofday()
+memlib.{c,h} Models the heap and sbrk function
+
+*******************************
+Building and running the driver
+*******************************
+To build the driver, type "make" to the shell.
+
+To run the driver on a tiny test trace:
+
+ unix> mdriver -V -f short1-bal.rep
+
+The -V option prints out helpful tracing and summary information.
+
+To get a list of the driver flags:
+
+ unix> mdriver -h
+
diff --git a/malloclab-handout/clock.c b/malloclab-handout/clock.c
new file mode 100644
index 0000000..f35135b
--- /dev/null
+++ b/malloclab-handout/clock.c
@@ -0,0 +1,279 @@
+/*
+ * clock.c - Routines for using the cycle counters on x86,
+ * Alpha, and Sparc boxes.
+ *
+ * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved.
+ * May not be used, modified, or copied without permission.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/times.h>
+#include "clock.h"
+
+
+/*******************************************************
+ * Machine dependent functions
+ *
+ * Note: the constants __i386__ and __alpha
+ * are set by GCC when it calls the C preprocessor
+ * You can verify this for yourself using gcc -v.
+ *******************************************************/
+
+#if defined(__i386__)
+/*******************************************************
+ * Pentium versions of start_counter() and get_counter()
+ *******************************************************/
+
+
+/* $begin x86cyclecounter */
+/* Initialize the cycle counter */
+static unsigned cyc_hi = 0;
+static unsigned cyc_lo = 0;
+
+
+/* Set *hi and *lo to the high and low order bits of the cycle counter.
+ Implementation requires assembly code to use the rdtsc instruction. */
+void access_counter(unsigned *hi, unsigned *lo)
+{
+ asm("rdtsc; movl %%edx,%0; movl %%eax,%1" /* Read cycle counter */
+ : "=r" (*hi), "=r" (*lo) /* and move results to */
+ : /* No input */ /* the two outputs */
+ : "%edx", "%eax");
+}
+
+/* Record the current value of the cycle counter. */
+void start_counter()
+{
+ access_counter(&cyc_hi, &cyc_lo);
+}
+
+/* Return the number of cycles since the last call to start_counter. */
+double get_counter()
+{
+ unsigned ncyc_hi, ncyc_lo;
+ unsigned hi, lo, borrow;
+ double result;
+
+ /* Get cycle counter */
+ access_counter(&ncyc_hi, &ncyc_lo);
+
+ /* Do double precision subtraction */
+ lo = ncyc_lo - cyc_lo;
+ borrow = lo > ncyc_lo;
+ hi = ncyc_hi - cyc_hi - borrow;
+ result = (double) hi * (1 << 30) * 4 + lo;
+ if (result < 0) {
+ fprintf(stderr, "Error: counter returns neg value: %.0f\n", result);
+ }
+ return result;
+}
+/* $end x86cyclecounter */
+
+#elif defined(__alpha)
+
+/****************************************************
+ * Alpha versions of start_counter() and get_counter()
+ ***************************************************/
+
+/* Initialize the cycle counter */
+static unsigned cyc_hi = 0;
+static unsigned cyc_lo = 0;
+
+
+/* Use Alpha cycle timer to compute cycles. Then use
+ measured clock speed to compute seconds
+*/
+
+/*
+ * counterRoutine is an array of Alpha instructions to access
+ * the Alpha's processor cycle counter. It uses the rpcc
+ * instruction to access the counter. This 64 bit register is
+ * divided into two parts. The lower 32 bits are the cycles
+ * used by the current process. The upper 32 bits are wall
+ * clock cycles. These instructions read the counter, and
+ * convert the lower 32 bits into an unsigned int - this is the
+ * user space counter value.
+ * NOTE: The counter has a very limited time span. With a
+ * 450MhZ clock the counter can time things for about 9
+ * seconds. */
+static unsigned int counterRoutine[] =
+{
+ 0x601fc000u,
+ 0x401f0000u,
+ 0x6bfa8001u
+};
+
+/* Cast the above instructions into a function. */
+static unsigned int (*counter)(void)= (void *)counterRoutine;
+
+
+void start_counter()
+{
+ /* Get cycle counter */
+ cyc_hi = 0;
+ cyc_lo = counter();
+}
+
+double get_counter()
+{
+ unsigned ncyc_hi, ncyc_lo;
+ unsigned hi, lo, borrow;
+ double result;
+ ncyc_lo = counter();
+ ncyc_hi = 0;
+ lo = ncyc_lo - cyc_lo;
+ borrow = lo > ncyc_lo;
+ hi = ncyc_hi - cyc_hi - borrow;
+ result = (double) hi * (1 << 30) * 4 + lo;
+ if (result < 0) {
+ fprintf(stderr, "Error: Cycle counter returning negative value: %.0f\n", result);
+ }
+ return result;
+}
+
+#else
+
+/****************************************************************
+ * All the other platforms for which we haven't implemented cycle
+ * counter routines. Newer models of sparcs (v8plus) have cycle
+ * counters that can be accessed from user programs, but since there
+ * are still many sparc boxes out there that don't support this, we
+ * haven't provided a Sparc version here.
+ ***************************************************************/
+
+void start_counter()
+{
+ printf("ERROR: You are trying to use a start_counter routine in clock.c\n");
+ printf("that has not been implemented yet on this platform.\n");
+ printf("Please choose another timing package in config.h.\n");
+ exit(1);
+}
+
+double get_counter()
+{
+ printf("ERROR: You are trying to use a get_counter routine in clock.c\n");
+ printf("that has not been implemented yet on this platform.\n");
+ printf("Please choose another timing package in config.h.\n");
+ exit(1);
+}
+#endif
+
+
+
+
+/*******************************
+ * Machine-independent functions
+ ******************************/
+double ovhd()
+{
+ /* Do it twice to eliminate cache effects */
+ int i;
+ double result;
+
+ for (i = 0; i < 2; i++) {
+ start_counter();
+ result = get_counter();
+ }
+ return result;
+}
+
+/* $begin mhz */
+/* Estimate the clock rate by measuring the cycles that elapse */
+/* while sleeping for sleeptime seconds */
+double mhz_full(int verbose, int sleeptime)
+{
+ double rate;
+
+ start_counter();
+ sleep(sleeptime);
+ rate = get_counter() / (1e6*sleeptime);
+ if (verbose)
+ printf("Processor clock rate ~= %.1f MHz\n", rate);
+ return rate;
+}
+/* $end mhz */
+
+/* Version using a default sleeptime */
+double mhz(int verbose)
+{
+ return mhz_full(verbose, 2);
+}
+
+/** Special counters that compensate for timer interrupt overhead */
+
+static double cyc_per_tick = 0.0;
+
+#define NEVENT 100
+#define THRESHOLD 1000
+#define RECORDTHRESH 3000
+
+/* Attempt to see how much time is used by timer interrupt */
+static void callibrate(int verbose)
+{
+ double oldt;
+ struct tms t;
+ clock_t oldc;
+ int e = 0;
+
+ times(&t);
+ oldc = t.tms_utime;
+ start_counter();
+ oldt = get_counter();
+ while (e <NEVENT) {
+ double newt = get_counter();
+
+ if (newt-oldt >= THRESHOLD) {
+ clock_t newc;
+ times(&t);
+ newc = t.tms_utime;
+ if (newc > oldc) {
+ double cpt = (newt-oldt)/(newc-oldc);
+ if ((cyc_per_tick == 0.0 || cyc_per_tick > cpt) && cpt > RECORDTHRESH)
+ cyc_per_tick = cpt;
+ /*
+ if (verbose)
+ printf("Saw event lasting %.0f cycles and %d ticks. Ratio = %f\n",
+ newt-oldt, (int) (newc-oldc), cpt);
+ */
+ e++;
+ oldc = newc;
+ }
+ oldt = newt;
+ }
+ }
+ if (verbose)
+ printf("Setting cyc_per_tick to %f\n", cyc_per_tick);
+}
+
+static clock_t start_tick = 0;
+
+void start_comp_counter()
+{
+ struct tms t;
+
+ if (cyc_per_tick == 0.0)
+ callibrate(0);
+ times(&t);
+ start_tick = t.tms_utime;
+ start_counter();
+}
+
+double get_comp_counter()
+{
+ double time = get_counter();
+ double ctime;
+ struct tms t;
+ clock_t ticks;
+
+ times(&t);
+ ticks = t.tms_utime - start_tick;
+ ctime = time - ticks*cyc_per_tick;
+ /*
+ printf("Measured %.0f cycles. Ticks = %d. Corrected %.0f cycles\n",
+ time, (int) ticks, ctime);
+ */
+ return ctime;
+}
+
diff --git a/malloclab-handout/clock.h b/malloclab-handout/clock.h
new file mode 100644
index 0000000..54d26ac
--- /dev/null
+++ b/malloclab-handout/clock.h
@@ -0,0 +1,22 @@
+/* Routines for using cycle counter */
+
+/* Start the counter */
+void start_counter();
+
+/* Get # cycles since counter started */
+double get_counter();
+
+/* Measure overhead for counter */
+double ovhd();
+
+/* Determine clock rate of processor (using a default sleeptime) */
+double mhz(int verbose);
+
+/* Determine clock rate of processor, having more control over accuracy */
+double mhz_full(int verbose, int sleeptime);
+
+/** Special counters that compensate for timer interrupt overhead */
+
+void start_comp_counter();
+
+double get_comp_counter();
diff --git a/malloclab-handout/config.h b/malloclab-handout/config.h
new file mode 100644
index 0000000..f2ff5d8
--- /dev/null
+++ b/malloclab-handout/config.h
@@ -0,0 +1,72 @@
+#ifndef __CONFIG_H_
+#define __CONFIG_H_
+
+/*
+ * config.h - malloc lab configuration file
+ *
+ * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved.
+ * May not be used, modified, or copied without permission.
+ */
+
+/*
+ * This is the default path where the driver will look for the
+ * default tracefiles. You can override it at runtime with the -t flag.
+ */
+#define TRACEDIR "/afs/cs/project/ics2/im/labs/malloclab/traces/"
+
+/*
+ * This is the list of default tracefiles in TRACEDIR that the driver
+ * will use for testing. Modify this if you want to add or delete
+ * traces from the driver's test suite. For example, if you don't want
+ * your students to implement realloc, you can delete the last two
+ * traces.
+ */
+#define DEFAULT_TRACEFILES \
+ "amptjp-bal.rep",\
+ "cccp-bal.rep",\
+ "cp-decl-bal.rep",\
+ "expr-bal.rep",\
+ "coalescing-bal.rep",\
+ "random-bal.rep",\
+ "random2-bal.rep",\
+ "binary-bal.rep",\
+ "binary2-bal.rep",\
+ "realloc-bal.rep",\
+ "realloc2-bal.rep"
+
+/*
+ * This constant gives the estimated performance of the libc malloc
+ * package using our traces on some reference system, typically the
+ * same kind of system the students use. Its purpose is to cap the
+ * contribution of throughput to the performance index. Once the
+ * students surpass the AVG_LIBC_THRUPUT, they get no further benefit
+ * to their score. This deters students from building extremely fast,
+ * but extremely stupid malloc packages.
+ */
+#define AVG_LIBC_THRUPUT 600E3 /* 600 Kops/sec */
+
+ /*
+ * This constant determines the contributions of space utilization
+ * (UTIL_WEIGHT) and throughput (1 - UTIL_WEIGHT) to the performance
+ * index.
+ */
+#define UTIL_WEIGHT .60
+
+/*
+ * Alignment requirement in bytes (either 4 or 8)
+ */
+#define ALIGNMENT 8
+
+/*
+ * Maximum heap size in bytes
+ */
+#define MAX_HEAP (20*(1<<20)) /* 20 MB */
+
+/*****************************************************************************
+ * Set exactly one of these USE_xxx constants to "1" to select a timing method
+ *****************************************************************************/
+#define USE_FCYC 0 /* cycle counter w/K-best scheme (x86 & Alpha only) */
+#define USE_ITIMER 0 /* interval timer (any Unix box) */
+#define USE_GETTOD 1 /* gettimeofday (any Unix box) */
+
+#endif /* __CONFIG_H */
diff --git a/malloclab-handout/fcyc.c b/malloclab-handout/fcyc.c
new file mode 100644
index 0000000..420b306
--- /dev/null
+++ b/malloclab-handout/fcyc.c
@@ -0,0 +1,251 @@
+/*
+ * fcyc.c - Estimate the time (in CPU cycles) used by a function f
+ *
+ * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved.
+ * May not be used, modified, or copied without permission.
+ *
+ * Uses the cycle timer routines in clock.c to estimate the
+ * the time in CPU cycles for a function f.
+ */
+#include <stdlib.h>
+#include <sys/times.h>
+#include <stdio.h>
+
+#include "fcyc.h"
+#include "clock.h"
+
+/* Default values */
+#define K 3 /* Value of K in K-best scheme */
+#define MAXSAMPLES 20 /* Give up after MAXSAMPLES */
+#define EPSILON 0.01 /* K samples should be EPSILON of each other*/
+#define COMPENSATE 0 /* 1-> try to compensate for clock ticks */
+#define CLEAR_CACHE 0 /* Clear cache before running test function */
+#define CACHE_BYTES (1<<19) /* Max cache size in bytes */
+#define CACHE_BLOCK 32 /* Cache block size in bytes */
+
+static int kbest = K;
+static int maxsamples = MAXSAMPLES;
+static double epsilon = EPSILON;
+static int compensate = COMPENSATE;
+static int clear_cache = CLEAR_CACHE;
+static int cache_bytes = CACHE_BYTES;
+static int cache_block = CACHE_BLOCK;
+
+static int *cache_buf = NULL;
+
+static double *values = NULL;
+static int samplecount = 0;
+
+/* for debugging only */
+#define KEEP_VALS 0
+#define KEEP_SAMPLES 0
+
+#if KEEP_SAMPLES
+static double *samples = NULL;
+#endif
+
+/*
+ * init_sampler - Start new sampling process
+ */
+static void init_sampler()
+{
+ if (values)
+ free(values);
+ values = calloc(kbest, sizeof(double));
+#if KEEP_SAMPLES
+ if (samples)
+ free(samples);
+ /* Allocate extra for wraparound analysis */
+ samples = calloc(maxsamples+kbest, sizeof(double));
+#endif
+ samplecount = 0;
+}
+
+/*
+ * add_sample - Add new sample
+ */
+static void add_sample(double val)
+{
+ int pos = 0;
+ if (samplecount < kbest) {
+ pos = samplecount;
+ values[pos] = val;
+ } else if (val < values[kbest-1]) {
+ pos = kbest-1;
+ values[pos] = val;
+ }
+#if KEEP_SAMPLES
+ samples[samplecount] = val;
+#endif
+ samplecount++;
+ /* Insertion sort */
+ while (pos > 0 && values[pos-1] > values[pos]) {
+ double temp = values[pos-1];
+ values[pos-1] = values[pos];
+ values[pos] = temp;
+ pos--;
+ }
+}
+
+/*
+ * has_converged- Have kbest minimum measurements converged within epsilon?
+ */
+static int has_converged()
+{
+ return
+ (samplecount >= kbest) &&
+ ((1 + epsilon)*values[0] >= values[kbest-1]);
+}
+
+/*
+ * clear - Code to clear cache
+ */
+static volatile int sink = 0;
+
+static void clear()
+{
+ int x = sink;
+ int *cptr, *cend;
+ int incr = cache_block/sizeof(int);
+ if (!cache_buf) {
+ cache_buf = malloc(cache_bytes);
+ if (!cache_buf) {
+ fprintf(stderr, "Fatal error. Malloc returned null when trying to clear cache\n");
+ exit(1);
+ }
+ }
+ cptr = (int *) cache_buf;
+ cend = cptr + cache_bytes/sizeof(int);
+ while (cptr < cend) {
+ x += *cptr;
+ cptr += incr;
+ }
+ sink = x;
+}
+
+/*
+ * fcyc - Use K-best scheme to estimate the running time of function f
+ */
+double fcyc(test_funct f, void *argp)
+{
+ double result;
+ init_sampler();
+ if (compensate) {
+ do {
+ double cyc;
+ if (clear_cache)
+ clear();
+ start_comp_counter();
+ f(argp);
+ cyc = get_comp_counter();
+ add_sample(cyc);
+ } while (!has_converged() && samplecount < maxsamples);
+ } else {
+ do {
+ double cyc;
+ if (clear_cache)
+ clear();
+ start_counter();
+ f(argp);
+ cyc = get_counter();
+ add_sample(cyc);
+ } while (!has_converged() && samplecount < maxsamples);
+ }
+#ifdef DEBUG
+ {
+ int i;
+ printf(" %d smallest values: [", kbest);
+ for (i = 0; i < kbest; i++)
+ printf("%.0f%s", values[i], i==kbest-1 ? "]\n" : ", ");
+ }
+#endif
+ result = values[0];
+#if !KEEP_VALS
+ free(values);
+ values = NULL;
+#endif
+ return result;
+}
+
+
+/*************************************************************
+ * Set the various parameters used by the measurement routines
+ ************************************************************/
+
+/*
+ * set_fcyc_clear_cache - When set, will run code to clear cache
+ * before each measurement.
+ * Default = 0
+ */
+void set_fcyc_clear_cache(int clear)
+{
+ clear_cache = clear;
+}
+
+/*
+ * set_fcyc_cache_size - Set size of cache to use when clearing cache
+ * Default = 1<<19 (512KB)
+ */
+void set_fcyc_cache_size(int bytes)
+{
+ if (bytes != cache_bytes) {
+ cache_bytes = bytes;
+ if (cache_buf) {
+ free(cache_buf);
+ cache_buf = NULL;
+ }
+ }
+}
+
+/*
+ * set_fcyc_cache_block - Set size of cache block
+ * Default = 32
+ */
+void set_fcyc_cache_block(int bytes) {
+ cache_block = bytes;
+}
+
+
+/*
+ * set_fcyc_compensate- When set, will attempt to compensate for
+ * timer interrupt overhead
+ * Default = 0
+ */
+void set_fcyc_compensate(int compensate_arg)
+{
+ compensate = compensate_arg;
+}
+
+/*
+ * set_fcyc_k - Value of K in K-best measurement scheme
+ * Default = 3
+ */
+void set_fcyc_k(int k)
+{
+ kbest = k;
+}
+
+/*
+ * set_fcyc_maxsamples - Maximum number of samples attempting to find
+ * K-best within some tolerance.
+ * When exceeded, just return best sample found.
+ * Default = 20
+ */
+void set_fcyc_maxsamples(int maxsamples_arg)
+{
+ maxsamples = maxsamples_arg;
+}
+
+/*
+ * set_fcyc_epsilon - Tolerance required for K-best
+ * Default = 0.01
+ */
+void set_fcyc_epsilon(double epsilon_arg)
+{
+ epsilon = epsilon_arg;
+}
+
+
+
+
+
diff --git a/malloclab-handout/fcyc.h b/malloclab-handout/fcyc.h
new file mode 100644
index 0000000..d398278
--- /dev/null
+++ b/malloclab-handout/fcyc.h
@@ -0,0 +1,68 @@
+/*
+ * fcyc.h - prototypes for the routines in fcyc.c that estimate the
+ * time in CPU cycles used by a test function f
+ *
+ * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved.
+ * May not be used, modified, or copied without permission.
+ *
+ */
+
+/* The test function takes a generic pointer as input */
+typedef void (*test_funct)(void *);
+
+/* Compute number of cycles used by test function f */
+double fcyc(test_funct f, void* argp);
+
+/*********************************************************
+ * Set the various parameters used by measurement routines
+ *********************************************************/
+
+/*
+ * set_fcyc_clear_cache - When set, will run code to clear cache
+ * before each measurement.
+ * Default = 0
+ */
+void set_fcyc_clear_cache(int clear);
+
+/*
+ * set_fcyc_cache_size - Set size of cache to use when clearing cache
+ * Default = 1<<19 (512KB)
+ */
+void set_fcyc_cache_size(int bytes);
+
+/*
+ * set_fcyc_cache_block - Set size of cache block
+ * Default = 32
+ */
+void set_fcyc_cache_block(int bytes);
+
+/*
+ * set_fcyc_compensate- When set, will attempt to compensate for
+ * timer interrupt overhead
+ * Default = 0
+ */
+void set_fcyc_compensate(int compensate_arg);
+
+/*
+ * set_fcyc_k - Value of K in K-best measurement scheme
+ * Default = 3
+ */
+void set_fcyc_k(int k);
+
+/*
+ * set_fcyc_maxsamples - Maximum number of samples attempting to find
+ * K-best within some tolerance.
+ * When exceeded, just return best sample found.
+ * Default = 20
+ */
+void set_fcyc_maxsamples(int maxsamples_arg);
+
+/*
+ * set_fcyc_epsilon - Tolerance required for K-best
+ * Default = 0.01
+ */
+void set_fcyc_epsilon(double epsilon_arg);
+
+
+
+
diff --git a/malloclab-handout/fsecs.c b/malloclab-handout/fsecs.c
new file mode 100644
index 0000000..ae2346d
--- /dev/null
+++ b/malloclab-handout/fsecs.c
@@ -0,0 +1,57 @@
+/****************************
+ * High-level timing wrappers
+ ****************************/
+#include <stdio.h>
+#include "fsecs.h"
+#include "fcyc.h"
+#include "clock.h"
+#include "ftimer.h"
+#include "config.h"
+
+static double Mhz; /* estimated CPU clock frequency */
+
+extern int verbose; /* -v option in mdriver.c */
+
+/*
+ * init_fsecs - initialize the timing package
+ */
+void init_fsecs(void)
+{
+ Mhz = 0; /* keep gcc -Wall happy */
+
+#if USE_FCYC
+ if (verbose)
+ printf("Measuring performance with a cycle counter.\n");
+
+ /* set key parameters for the fcyc package */
+ set_fcyc_maxsamples(20);
+ set_fcyc_clear_cache(1);
+ set_fcyc_compensate(1);
+ set_fcyc_epsilon(0.01);
+ set_fcyc_k(3);
+ Mhz = mhz(verbose > 0);
+#elif USE_ITIMER
+ if (verbose)
+ printf("Measuring performance with the interval timer.\n");
+#elif USE_GETTOD
+ if (verbose)
+ printf("Measuring performance with gettimeofday().\n");
+#endif
+}
+
+/*
+ * fsecs - Return the running time of a function f (in seconds)
+ */
+double fsecs(fsecs_test_funct f, void *argp)
+{
+#if USE_FCYC
+ double cycles = fcyc(f, argp);
+ return cycles/(Mhz*1e6);
+#elif USE_ITIMER
+ return ftimer_itimer(f, argp, 10);
+#elif USE_GETTOD
+ return ftimer_gettod(f, argp, 10);
+#endif
+}
+
+
diff --git a/malloclab-handout/fsecs.h b/malloclab-handout/fsecs.h
new file mode 100644
index 0000000..59e095d
--- /dev/null
+++ b/malloclab-handout/fsecs.h
@@ -0,0 +1,4 @@
+typedef void (*fsecs_test_funct)(void *);
+
+void init_fsecs(void);
+double fsecs(fsecs_test_funct f, void *argp);
diff --git a/malloclab-handout/ftimer.c b/malloclab-handout/ftimer.c
new file mode 100644
index 0000000..ea08560
--- /dev/null
+++ b/malloclab-handout/ftimer.c
@@ -0,0 +1,106 @@
+/*
+ * ftimer.c - Estimate the time (in seconds) used by a function f
+ *
+ * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved.
+ * May not be used, modified, or copied without permission.
+ *
+ * Function timers that estimate the running time (in seconds) of a function f.
+ * ftimer_itimer: version that uses the interval timer
+ * ftimer_gettod: version that uses gettimeofday
+ */
+#include <stdio.h>
+#include <sys/time.h>
+#include "ftimer.h"
+
+/* function prototypes */
+static void init_etime(void);
+static double get_etime(void);
+
+/*
+ * ftimer_itimer - Use the interval timer to estimate the running time
+ * of f(argp). Return the average of n runs.
+ */
+double ftimer_itimer(ftimer_test_funct f, void *argp, int n)
+{
+ double start, tmeas;
+ int i;
+
+ init_etime();
+ start = get_etime();
+ for (i = 0; i < n; i++)
+ f(argp);
+ tmeas = get_etime() - start;
+ return tmeas / n;
+}
+
+/*
+ * ftimer_gettod - Use gettimeofday to estimate the running time of
+ * f(argp). Return the average of n runs.
+ */
+double ftimer_gettod(ftimer_test_funct f, void *argp, int n)
+{
+ int i;
+ struct timeval stv, etv;
+ double diff;
+
+ gettimeofday(&stv, NULL);
+ for (i = 0; i < n; i++)
+ f(argp);
+ gettimeofday(&etv,NULL);
+ diff = 1E3*(etv.tv_sec - stv.tv_sec) + 1E-3*(etv.tv_usec-stv.tv_usec);
+ diff /= n;
+ return (1E-3*diff);
+}
+
+
+/*
+ * Routines for manipulating the Unix interval timer
+ */
+
+/* The initial value of the interval timer */
+#define MAX_ETIME 86400
+
+/* static variables that hold the initial value of the interval timer */
+static struct itimerval first_u; /* user time */
+static struct itimerval first_r; /* real time */
+static struct itimerval first_p; /* prof time*/
+
+/* init the timer */
+static void init_etime(void)
+{
+ first_u.it_interval.tv_sec = 0;
+ first_u.it_interval.tv_usec = 0;
+ first_u.it_value.tv_sec = MAX_ETIME;
+ first_u.it_value.tv_usec = 0;
+ setitimer(ITIMER_VIRTUAL, &first_u, NULL);
+
+ first_r.it_interval.tv_sec = 0;
+ first_r.it_interval.tv_usec = 0;
+ first_r.it_value.tv_sec = MAX_ETIME;
+ first_r.it_value.tv_usec = 0;
+ setitimer(ITIMER_REAL, &first_r, NULL);
+
+ first_p.it_interval.tv_sec = 0;
+ first_p.it_interval.tv_usec = 0;
+ first_p.it_value.tv_sec = MAX_ETIME;
+ first_p.it_value.tv_usec = 0;
+ setitimer(ITIMER_PROF, &first_p, NULL);
+}
+
+/* return elapsed real seconds since call to init_etime */
+static double get_etime(void) {
+ struct itimerval v_curr;
+ struct itimerval r_curr;
+ struct itimerval p_curr;
+
+ getitimer(ITIMER_VIRTUAL, &v_curr);
+ getitimer(ITIMER_REAL,&r_curr);
+ getitimer(ITIMER_PROF,&p_curr);
+
+ return (double) ((first_p.it_value.tv_sec - r_curr.it_value.tv_sec) +
+ (first_p.it_value.tv_usec - r_curr.it_value.tv_usec)*1e-6);
+}
+
+
+
+
diff --git a/malloclab-handout/ftimer.h b/malloclab-handout/ftimer.h
new file mode 100644
index 0000000..3400603
--- /dev/null
+++ b/malloclab-handout/ftimer.h
@@ -0,0 +1,14 @@
+/*
+ * Function timers
+ */
+typedef void (*ftimer_test_funct)(void *);
+
+/* Estimate the running time of f(argp) using the Unix interval timer.
+ Return the average of n runs */
+double ftimer_itimer(ftimer_test_funct f, void *argp, int n);
+
+
+/* Estimate the running time of f(argp) using gettimeofday
+ Return the average of n runs */
+double ftimer_gettod(ftimer_test_funct f, void *argp, int n);
+
diff --git a/malloclab-handout/mdriver.c b/malloclab-handout/mdriver.c
new file mode 100644
index 0000000..3aa8a3c
--- /dev/null
+++ b/malloclab-handout/mdriver.c
@@ -0,0 +1,1017 @@
+/*
+ * mdriver.c - CS:APP Malloc Lab Driver
+ *
+ * Uses a collection of trace files to tests a malloc/free/realloc
+ * implementation in mm.c.
+ *
+ * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved.
+ * May not be used, modified, or copied without permission.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <float.h>
+#include <time.h>
+
+#include "mm.h"
+#include "memlib.h"
+#include "fsecs.h"
+#include "config.h"
+
+/**********************
+ * Constants and macros
+ **********************/
+
+/* Misc */
+#define MAXLINE 1024 /* max string size */
+#define HDRLINES 4 /* number of header lines in a trace file */
+#define LINENUM(i) (i+5) /* cnvt trace request nums to linenums (origin 1) */
+
+/* Returns true if p is ALIGNMENT-byte aligned */
+#define IS_ALIGNED(p) ((((unsigned int)(p)) % ALIGNMENT) == 0)
+
+/******************************
+ * The key compound data types
+ *****************************/
+
+/* Records the extent of each block's payload */
+typedef struct range_t {
+ char *lo; /* low payload address */
+ char *hi; /* high payload address */
+ struct range_t *next; /* next list element */
+} range_t;
+
+/* Characterizes a single trace operation (allocator request) */
+typedef struct {
+ enum {ALLOC, FREE, REALLOC} type; /* type of request */
+ int index; /* index for free() to use later */
+ int size; /* byte size of alloc/realloc request */
+} traceop_t;
+
+/* Holds the information for one trace file*/
+typedef struct {
+ int sugg_heapsize; /* suggested heap size (unused) */
+ int num_ids; /* number of alloc/realloc ids */
+ int num_ops; /* number of distinct requests */
+ int weight; /* weight for this trace (unused) */
+ traceop_t *ops; /* array of requests */
+ char **blocks; /* array of ptrs returned by malloc/realloc... */
+ size_t *block_sizes; /* ... and a corresponding array of payload sizes */
+} trace_t;
+
+/*
+ * Holds the params to the xxx_speed functions, which are timed by fcyc.
+ * This struct is necessary because fcyc accepts only a pointer array
+ * as input.
+ */
+typedef struct {
+ trace_t *trace;
+ range_t *ranges;
+} speed_t;
+
+/* Summarizes the important stats for some malloc function on some trace */
+typedef struct {
+ /* defined for both libc malloc and student malloc package (mm.c) */
+ double ops; /* number of ops (malloc/free/realloc) in the trace */
+ int valid; /* was the trace processed correctly by the allocator? */
+ double secs; /* number of secs needed to run the trace */
+
+ /* defined only for the student malloc package */
+ double util; /* space utilization for this trace (always 0 for libc) */
+
+ /* Note: secs and util are only defined if valid is true */
+} stats_t;
+
+/********************
+ * Global variables
+ *******************/
+int verbose = 0; /* global flag for verbose output */
+static int errors = 0; /* number of errs found when running student malloc */
+char msg[MAXLINE]; /* for whenever we need to compose an error message */
+
+/* Directory where default tracefiles are found */
+static char tracedir[MAXLINE] = TRACEDIR;
+
+/* The filenames of the default tracefiles */
+static char *default_tracefiles[] = {
+ DEFAULT_TRACEFILES, NULL
+};
+
+
+/*********************
+ * Function prototypes
+ *********************/
+
+/* these functions manipulate range lists */
+static int add_range(range_t **ranges, char *lo, int size,
+ int tracenum, int opnum);
+static void remove_range(range_t **ranges, char *lo);
+static void clear_ranges(range_t **ranges);
+
+/* These functions read, allocate, and free storage for traces */
+static trace_t *read_trace(char *tracedir, char *filename);
+static void free_trace(trace_t *trace);
+
+/* Routines for evaluating the correctness and speed of libc malloc */
+static int eval_libc_valid(trace_t *trace, int tracenum);
+static void eval_libc_speed(void *ptr);
+
+/* Routines for evaluating correctnes, space utilization, and speed
+ of the student's malloc package in mm.c */
+static int eval_mm_valid(trace_t *trace, int tracenum, range_t **ranges);
+static double eval_mm_util(trace_t *trace, int tracenum, range_t **ranges);
+static void eval_mm_speed(void *ptr);
+
+/* Various helper routines */
+static void printresults(int n, stats_t *stats);
+static void usage(void);
+static void unix_error(char *msg);
+static void malloc_error(int tracenum, int opnum, char *msg);
+static void app_error(char *msg);
+
+/**************
+ * Main routine
+ **************/
+int main(int argc, char **argv)
+{
+ int i;
+ char c;
+ char **tracefiles = NULL; /* null-terminated array of trace file names */
+ int num_tracefiles = 0; /* the number of traces in that array */
+ trace_t *trace = NULL; /* stores a single trace file in memory */
+ range_t *ranges = NULL; /* keeps track of block extents for one trace */
+ stats_t *libc_stats = NULL;/* libc stats for each trace */
+ stats_t *mm_stats = NULL; /* mm (i.e. student) stats for each trace */
+ speed_t speed_params; /* input parameters to the xx_speed routines */
+
+ int team_check = 1; /* If set, check team structure (reset by -a) */
+ int run_libc = 0; /* If set, run libc malloc (set by -l) */
+ int autograder = 0; /* If set, emit summary info for autograder (-g) */
+
+ /* temporaries used to compute the performance index */
+ double secs, ops, util, avg_mm_util, avg_mm_throughput, p1, p2, perfindex;
+ int numcorrect;
+
+ /*
+ * Read and interpret the command line arguments
+ */
+ while ((c = getopt(argc, argv, "f:t:hvVgal")) != EOF) {
+ switch (c) {
+ case 'g': /* Generate summary info for the autograder */
+ autograder = 1;
+ break;
+ case 'f': /* Use one specific trace file only (relative to curr dir) */
+ num_tracefiles = 1;
+ if ((tracefiles = realloc(tracefiles, 2*sizeof(char *))) == NULL)
+ unix_error("ERROR: realloc failed in main");
+ strcpy(tracedir, "./");
+ tracefiles[0] = strdup(optarg);
+ tracefiles[1] = NULL;
+ break;
+ case 't': /* Directory where the traces are located */
+ if (num_tracefiles == 1) /* ignore if -f already encountered */
+ break;
+ strcpy(tracedir, optarg);
+ if (tracedir[strlen(tracedir)-1] != '/')
+ strcat(tracedir, "/"); /* path always ends with "/" */
+ break;
+ case 'a': /* Don't check team structure */
+ team_check = 0;
+ break;
+ case 'l': /* Run libc malloc */
+ run_libc = 1;
+ break;
+ case 'v': /* Print per-trace performance breakdown */
+ verbose = 1;
+ break;
+ case 'V': /* Be more verbose than -v */
+ verbose = 2;
+ break;
+ case 'h': /* Print this message */
+ usage();
+ exit(0);
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ /*
+ * Check and print team info
+ */
+ if (team_check) {
+ /* Students must fill in their team information */
+ if (!strcmp(team.teamname, "")) {
+ printf("ERROR: Please provide the information about your team in mm.c.\n");
+ exit(1);
+ } else
+ printf("Team Name:%s\n", team.teamname);
+ if ((*team.name1 == '\0') || (*team.id1 == '\0')) {
+ printf("ERROR. You must fill in all team member 1 fields!\n");
+ exit(1);
+ }
+ else
+ printf("Member 1 :%s:%s\n", team.name1, team.id1);
+
+ if (((*team.name2 != '\0') && (*team.id2 == '\0')) ||
+ ((*team.name2 == '\0') && (*team.id2 != '\0'))) {
+ printf("ERROR. You must fill in all or none of the team member 2 ID fields!\n");
+ exit(1);
+ }
+ else if (*team.name2 != '\0')
+ printf("Member 2 :%s:%s\n", team.name2, team.id2);
+ }
+
+ /*
+ * If no -f command line arg, then use the entire set of tracefiles
+ * defined in default_traces[]
+ */
+ if (tracefiles == NULL) {
+ tracefiles = default_tracefiles;
+ num_tracefiles = sizeof(default_tracefiles) / sizeof(char *) - 1;
+ printf("Using default tracefiles in %s\n", tracedir);
+ }
+
+ /* Initialize the timing package */
+ init_fsecs();
+
+ /*
+ * Optionally run and evaluate the libc malloc package
+ */
+ if (run_libc) {
+ if (verbose > 1)
+ printf("\nTesting libc malloc\n");
+
+ /* Allocate libc stats array, with one stats_t struct per tracefile */
+ libc_stats = (stats_t *)calloc(num_tracefiles, sizeof(stats_t));
+ if (libc_stats == NULL)
+ unix_error("libc_stats calloc in main failed");
+
+ /* Evaluate the libc malloc package using the K-best scheme */
+ for (i=0; i < num_tracefiles; i++) {
+ trace = read_trace(tracedir, tracefiles[i]);
+ libc_stats[i].ops = trace->num_ops;
+ if (verbose > 1)
+ printf("Checking libc malloc for correctness, ");
+ libc_stats[i].valid = eval_libc_valid(trace, i);
+ if (libc_stats[i].valid) {
+ speed_params.trace = trace;
+ if (verbose > 1)
+ printf("and performance.\n");
+ libc_stats[i].secs = fsecs(eval_libc_speed, &speed_params);
+ }
+ free_trace(trace);
+ }
+
+ /* Display the libc results in a compact table */
+ if (verbose) {
+ printf("\nResults for libc malloc:\n");
+ printresults(num_tracefiles, libc_stats);
+ }
+ }
+
+ /*
+ * Always run and evaluate the student's mm package
+ */
+ if (verbose > 1)
+ printf("\nTesting mm malloc\n");
+
+ /* Allocate the mm stats array, with one stats_t struct per tracefile */
+ mm_stats = (stats_t *)calloc(num_tracefiles, sizeof(stats_t));
+ if (mm_stats == NULL)
+ unix_error("mm_stats calloc in main failed");
+
+ /* Initialize the simulated memory system in memlib.c */
+ mem_init();
+
+ /* Evaluate student's mm malloc package using the K-best scheme */
+ for (i=0; i < num_tracefiles; i++) {
+ trace = read_trace(tracedir, tracefiles[i]);
+ mm_stats[i].ops = trace->num_ops;
+ if (verbose > 1)
+ printf("Checking mm_malloc for correctness, ");
+ mm_stats[i].valid = eval_mm_valid(trace, i, &ranges);
+ if (mm_stats[i].valid) {
+ if (verbose > 1)
+ printf("efficiency, ");
+ mm_stats[i].util = eval_mm_util(trace, i, &ranges);
+ speed_params.trace = trace;
+ speed_params.ranges = ranges;
+ if (verbose > 1)
+ printf("and performance.\n");
+ mm_stats[i].secs = fsecs(eval_mm_speed, &speed_params);
+ }
+ free_trace(trace);
+ }
+
+ /* Display the mm results in a compact table */
+ if (verbose) {
+ printf("\nResults for mm malloc:\n");
+ printresults(num_tracefiles, mm_stats);
+ printf("\n");
+ }
+
+ /*
+ * Accumulate the aggregate statistics for the student's mm package
+ */
+ secs = 0;
+ ops = 0;
+ util = 0;
+ numcorrect = 0;
+ for (i=0; i < num_tracefiles; i++) {
+ secs += mm_stats[i].secs;
+ ops += mm_stats[i].ops;
+ util += mm_stats[i].util;
+ if (mm_stats[i].valid)
+ numcorrect++;
+ }
+ avg_mm_util = util/num_tracefiles;
+
+ /*
+ * Compute and print the performance index
+ */
+ if (errors == 0) {
+ avg_mm_throughput = ops/secs;
+
+ p1 = UTIL_WEIGHT * avg_mm_util;
+ if (avg_mm_throughput > AVG_LIBC_THRUPUT) {
+ p2 = (double)(1.0 - UTIL_WEIGHT);
+ }
+ else {
+ p2 = ((double) (1.0 - UTIL_WEIGHT)) *
+ (avg_mm_throughput/AVG_LIBC_THRUPUT);
+ }
+
+ perfindex = (p1 + p2)*100.0;
+ printf("Perf index = %.0f (util) + %.0f (thru) = %.0f/100\n",
+ p1*100,
+ p2*100,
+ perfindex);
+
+ }
+ else { /* There were errors */
+ perfindex = 0.0;
+ printf("Terminated with %d errors\n", errors);
+ }
+
+ if (autograder) {
+ printf("correct:%d\n", numcorrect);
+ printf("perfidx:%.0f\n", perfindex);
+ }
+
+ exit(0);
+}
+
+
+/*****************************************************************
+ * The following routines manipulate the range list, which keeps
+ * track of the extent of every allocated block payload. We use the
+ * range list to detect any overlapping allocated blocks.
+ ****************************************************************/
+
+/*
+ * add_range - As directed by request opnum in trace tracenum,
+ * we've just called the student's mm_malloc to allocate a block of
+ * size bytes at addr lo. After checking the block for correctness,
+ * we create a range struct for this block and add it to the range list.
+ */
+static int add_range(range_t **ranges, char *lo, int size,
+ int tracenum, int opnum)
+{
+ char *hi = lo + size - 1;
+ range_t *p;
+ char msg[MAXLINE];
+
+ assert(size > 0);
+
+ /* Payload addresses must be ALIGNMENT-byte aligned */
+ if (!IS_ALIGNED(lo)) {
+ sprintf(msg, "Payload address (%p) not aligned to %d bytes",
+ lo, ALIGNMENT);
+ malloc_error(tracenum, opnum, msg);
+ return 0;
+ }
+
+ /* The payload must lie within the extent of the heap */
+ if ((lo < (char *)mem_heap_lo()) || (lo > (char *)mem_heap_hi()) ||
+ (hi < (char *)mem_heap_lo()) || (hi > (char *)mem_heap_hi())) {
+ sprintf(msg, "Payload (%p:%p) lies outside heap (%p:%p)",
+ lo, hi, mem_heap_lo(), mem_heap_hi());
+ malloc_error(tracenum, opnum, msg);
+ return 0;
+ }
+
+ /* The payload must not overlap any other payloads */
+ for (p = *ranges; p != NULL; p = p->next) {
+ if ((lo >= p->lo && lo <= p-> hi) ||
+ (hi >= p->lo && hi <= p->hi)) {
+ sprintf(msg, "Payload (%p:%p) overlaps another payload (%p:%p)\n",
+ lo, hi, p->lo, p->hi);
+ malloc_error(tracenum, opnum, msg);
+ return 0;
+ }
+ }
+
+ /*
+ * Everything looks OK, so remember the extent of this block
+ * by creating a range struct and adding it the range list.
+ */
+ if ((p = (range_t *)malloc(sizeof(range_t))) == NULL)
+ unix_error("malloc error in add_range");
+ p->next = *ranges;
+ p->lo = lo;
+ p->hi = hi;
+ *ranges = p;
+ return 1;
+}
+
+/*
+ * remove_range - Free the range record of block whose payload starts at lo
+ */
+static void remove_range(range_t **ranges, char *lo)
+{
+ range_t *p;
+ range_t **prevpp = ranges;
+ int size;
+
+ for (p = *ranges; p != NULL; p = p->next) {
+ if (p->lo == lo) {
+ *prevpp = p->next;
+ size = p->hi - p->lo + 1;
+ free(p);
+ break;
+ }
+ prevpp = &(p->next);
+ }
+}
+
+/*
+ * clear_ranges - free all of the range records for a trace
+ */
+static void clear_ranges(range_t **ranges)
+{
+ range_t *p;
+ range_t *pnext;
+
+ for (p = *ranges; p != NULL; p = pnext) {
+ pnext = p->next;
+ free(p);
+ }
+ *ranges = NULL;
+}
+
+
+/**********************************************
+ * The following routines manipulate tracefiles
+ *********************************************/
+
+/*
+ * read_trace - read a trace file and store it in memory
+ */
+static trace_t *read_trace(char *tracedir, char *filename)
+{
+ FILE *tracefile;
+ trace_t *trace;
+ char type[MAXLINE];
+ char path[MAXLINE];
+ unsigned index, size;
+ unsigned max_index = 0;
+ unsigned op_index;
+
+ if (verbose > 1)
+ printf("Reading tracefile: %s\n", filename);
+
+ /* Allocate the trace record */
+ if ((trace = (trace_t *) malloc(sizeof(trace_t))) == NULL)
+ unix_error("malloc 1 failed in read_trance");
+
+ /* Read the trace file header */
+ strcpy(path, tracedir);
+ strcat(path, filename);
+ if ((tracefile = fopen(path, "r")) == NULL) {
+ sprintf(msg, "Could not open %s in read_trace", path);
+ unix_error(msg);
+ }
+ fscanf(tracefile, "%d", &(trace->sugg_heapsize)); /* not used */
+ fscanf(tracefile, "%d", &(trace->num_ids));
+ fscanf(tracefile, "%d", &(trace->num_ops));
+ fscanf(tracefile, "%d", &(trace->weight)); /* not used */
+
+ /* We'll store each request line in the trace in this array */
+ if ((trace->ops =
+ (traceop_t *)malloc(trace->num_ops * sizeof(traceop_t))) == NULL)
+ unix_error("malloc 2 failed in read_trace");
+
+ /* We'll keep an array of pointers to the allocated blocks here... */
+ if ((trace->blocks =
+ (char **)malloc(trace->num_ids * sizeof(char *))) == NULL)
+ unix_error("malloc 3 failed in read_trace");
+
+ /* ... along with the corresponding byte sizes of each block */
+ if ((trace->block_sizes =
+ (size_t *)malloc(trace->num_ids * sizeof(size_t))) == NULL)
+ unix_error("malloc 4 failed in read_trace");
+
+ /* read every request line in the trace file */
+ index = 0;
+ op_index = 0;
+ while (fscanf(tracefile, "%s", type) != EOF) {
+ switch(type[0]) {
+ case 'a':
+ fscanf(tracefile, "%u %u", &index, &size);
+ trace->ops[op_index].type = ALLOC;
+ trace->ops[op_index].index = index;
+ trace->ops[op_index].size = size;
+ max_index = (index > max_index) ? index : max_index;
+ break;
+ case 'r':
+ fscanf(tracefile, "%u %u", &index, &size);
+ trace->ops[op_index].type = REALLOC;
+ trace->ops[op_index].index = index;
+ trace->ops[op_index].size = size;
+ max_index = (index > max_index) ? index : max_index;
+ break;
+ case 'f':
+ fscanf(tracefile, "%ud", &index);
+ trace->ops[op_index].type = FREE;
+ trace->ops[op_index].index = index;
+ break;
+ default:
+ printf("Bogus type character (%c) in tracefile %s\n",
+ type[0], path);
+ exit(1);
+ }
+ op_index++;
+
+ }
+ fclose(tracefile);
+ assert(max_index == trace->num_ids - 1);
+ assert(trace->num_ops == op_index);
+
+ return trace;
+}
+
+/*
+ * free_trace - Free the trace record and the three arrays it points
+ * to, all of which were allocated in read_trace().
+ */
+void free_trace(trace_t *trace)
+{
+ free(trace->ops); /* free the three arrays... */
+ free(trace->blocks);
+ free(trace->block_sizes);
+ free(trace); /* and the trace record itself... */
+}
+
+/**********************************************************************
+ * The following functions evaluate the correctness, space utilization,
+ * and throughput of the libc and mm malloc packages.
+ **********************************************************************/
+
+/*
+ * eval_mm_valid - Check the mm malloc package for correctness
+ */
+static int eval_mm_valid(trace_t *trace, int tracenum, range_t **ranges)
+{
+ int i, j;
+ int index;
+ int size;
+ int oldsize;
+ char *newp;
+ char *oldp;
+ char *p;
+
+ /* Reset the heap and free any records in the range list */
+ mem_reset_brk();
+ clear_ranges(ranges);
+
+ /* Call the mm package's init function */
+ if (mm_init() < 0) {
+ malloc_error(tracenum, 0, "mm_init failed.");
+ return 0;
+ }
+
+ /* Interpret each operation in the trace in order */
+ for (i = 0; i < trace->num_ops; i++) {
+ index = trace->ops[i].index;
+ size = trace->ops[i].size;
+
+ switch (trace->ops[i].type) {
+
+ case ALLOC: /* mm_malloc */
+
+ /* Call the student's malloc */
+ if ((p = mm_malloc(size)) == NULL) {
+ malloc_error(tracenum, i, "mm_malloc failed.");
+ return 0;
+ }
+
+ /*
+ * Test the range of the new block for correctness and add it
+ * to the range list if OK. The block must be be aligned properly,
+ * and must not overlap any currently allocated block.
+ */
+ if (add_range(ranges, p, size, tracenum, i) == 0)
+ return 0;
+
+ /* ADDED: cgw
+ * fill range with low byte of index. This will be used later
+ * if we realloc the block and wish to make sure that the old
+ * data was copied to the new block
+ */
+ memset(p, index & 0xFF, size);
+
+ /* Remember region */
+ trace->blocks[index] = p;
+ trace->block_sizes[index] = size;
+ break;
+
+ case REALLOC: /* mm_realloc */
+
+ /* Call the student's realloc */
+ oldp = trace->blocks[index];
+ if ((newp = mm_realloc(oldp, size)) == NULL) {
+ malloc_error(tracenum, i, "mm_realloc failed.");
+ return 0;
+ }
+
+ /* Remove the old region from the range list */
+ remove_range(ranges, oldp);
+
+ /* Check new block for correctness and add it to range list */
+ if (add_range(ranges, newp, size, tracenum, i) == 0)
+ return 0;
+
+ /* ADDED: cgw
+ * Make sure that the new block contains the data from the old
+ * block and then fill in the new block with the low order byte
+ * of the new index
+ */
+ oldsize = trace->block_sizes[index];
+ if (size < oldsize) oldsize = size;
+ for (j = 0; j < oldsize; j++) {
+ if (newp[j] != (index & 0xFF)) {
+ malloc_error(tracenum, i, "mm_realloc did not preserve the "
+ "data from old block");
+ return 0;
+ }
+ }
+ memset(newp, index & 0xFF, size);
+
+ /* Remember region */
+ trace->blocks[index] = newp;
+ trace->block_sizes[index] = size;
+ break;
+
+ case FREE: /* mm_free */
+
+ /* Remove region from list and call student's free function */
+ p = trace->blocks[index];
+ remove_range(ranges, p);
+ mm_free(p);
+ break;
+
+ default:
+ app_error("Nonexistent request type in eval_mm_valid");
+ }
+
+ }
+
+ /* As far as we know, this is a valid malloc package */
+ return 1;
+}
+
+/*
+ * eval_mm_util - Evaluate the space utilization of the student's package
+ * The idea is to remember the high water mark "hwm" of the heap for
+ * an optimal allocator, i.e., no gaps and no internal fragmentation.
+ * Utilization is the ratio hwm/heapsize, where heapsize is the
+ * size of the heap in bytes after running the student's malloc
+ * package on the trace. Note that our implementation of mem_sbrk()
+ * doesn't allow the students to decrement the brk pointer, so brk
+ * is always the high water mark of the heap.
+ *
+ */
+static double eval_mm_util(trace_t *trace, int tracenum, range_t **ranges)
+{
+ int i;
+ int index;
+ int size, newsize, oldsize;
+ int max_total_size = 0;
+ int total_size = 0;
+ char *p;
+ char *newp, *oldp;
+
+ /* initialize the heap and the mm malloc package */
+ mem_reset_brk();
+ if (mm_init() < 0)
+ app_error("mm_init failed in eval_mm_util");
+
+ for (i = 0; i < trace->num_ops; i++) {
+ switch (trace->ops[i].type) {
+
+ case ALLOC: /* mm_alloc */
+ index = trace->ops[i].index;
+ size = trace->ops[i].size;
+
+ if ((p = mm_malloc(size)) == NULL)
+ app_error("mm_malloc failed in eval_mm_util");
+
+ /* Remember region and size */
+ trace->blocks[index] = p;
+ trace->block_sizes[index] = size;
+
+ /* Keep track of current total size
+ * of all allocated blocks */
+ total_size += size;
+
+ /* Update statistics */
+ max_total_size = (total_size > max_total_size) ?
+ total_size : max_total_size;
+ break;
+
+ case REALLOC: /* mm_realloc */
+ index = trace->ops[i].index;
+ newsize = trace->ops[i].size;
+ oldsize = trace->block_sizes[index];
+
+ oldp = trace->blocks[index];
+ if ((newp = mm_realloc(oldp,newsize)) == NULL)
+ app_error("mm_realloc failed in eval_mm_util");
+
+ /* Remember region and size */
+ trace->blocks[index] = newp;
+ trace->block_sizes[index] = newsize;
+
+ /* Keep track of current total size
+ * of all allocated blocks */
+ total_size += (newsize - oldsize);
+
+ /* Update statistics */
+ max_total_size = (total_size > max_total_size) ?
+ total_size : max_total_size;
+ break;
+
+ case FREE: /* mm_free */
+ index = trace->ops[i].index;
+ size = trace->block_sizes[index];
+ p = trace->blocks[index];
+
+ mm_free(p);
+
+ /* Keep track of current total size
+ * of all allocated blocks */
+ total_size -= size;
+
+ break;
+
+ default:
+ app_error("Nonexistent request type in eval_mm_util");
+
+ }
+ }
+
+ return ((double)max_total_size / (double)mem_heapsize());
+}
+
+
+/*
+ * eval_mm_speed - This is the function that is used by fcyc()
+ * to measure the running time of the mm malloc package.
+ */
+static void eval_mm_speed(void *ptr)
+{
+ int i, index, size, newsize;
+ char *p, *newp, *oldp, *block;
+ trace_t *trace = ((speed_t *)ptr)->trace;
+
+ /* Reset the heap and initialize the mm package */
+ mem_reset_brk();
+ if (mm_init() < 0)
+ app_error("mm_init failed in eval_mm_speed");
+
+ /* Interpret each trace request */
+ for (i = 0; i < trace->num_ops; i++)
+ switch (trace->ops[i].type) {
+
+ case ALLOC: /* mm_malloc */
+ index = trace->ops[i].index;
+ size = trace->ops[i].size;
+ if ((p = mm_malloc(size)) == NULL)
+ app_error("mm_malloc error in eval_mm_speed");
+ trace->blocks[index] = p;
+ break;
+
+ case REALLOC: /* mm_realloc */
+ index = trace->ops[i].index;
+ newsize = trace->ops[i].size;
+ oldp = trace->blocks[index];
+ if ((newp = mm_realloc(oldp,newsize)) == NULL)
+ app_error("mm_realloc error in eval_mm_speed");
+ trace->blocks[index] = newp;
+ break;
+
+ case FREE: /* mm_free */
+ index = trace->ops[i].index;
+ block = trace->blocks[index];
+ mm_free(block);
+ break;
+
+ default:
+ app_error("Nonexistent request type in eval_mm_valid");
+ }
+}
+
+/*
+ * eval_libc_valid - We run this function to make sure that the
+ * libc malloc can run to completion on the set of traces.
+ * We'll be conservative and terminate if any libc malloc call fails.
+ *
+ */
+static int eval_libc_valid(trace_t *trace, int tracenum)
+{
+ int i, newsize;
+ char *p, *newp, *oldp;
+
+ for (i = 0; i < trace->num_ops; i++) {
+ switch (trace->ops[i].type) {
+
+ case ALLOC: /* malloc */
+ if ((p = malloc(trace->ops[i].size)) == NULL) {
+ malloc_error(tracenum, i, "libc malloc failed");
+ unix_error("System message");
+ }
+ trace->blocks[trace->ops[i].index] = p;
+ break;
+
+ case REALLOC: /* realloc */
+ newsize = trace->ops[i].size;
+ oldp = trace->blocks[trace->ops[i].index];
+ if ((newp = realloc(oldp, newsize)) == NULL) {
+ malloc_error(tracenum, i, "libc realloc failed");
+ unix_error("System message");
+ }
+ trace->blocks[trace->ops[i].index] = newp;
+ break;
+
+ case FREE: /* free */
+ free(trace->blocks[trace->ops[i].index]);
+ break;
+
+ default:
+ app_error("invalid operation type in eval_libc_valid");
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * eval_libc_speed - This is the function that is used by fcyc() to
+ * measure the running time of the libc malloc package on the set
+ * of traces.
+ */
+static void eval_libc_speed(void *ptr)
+{
+ int i;
+ int index, size, newsize;
+ char *p, *newp, *oldp, *block;
+ trace_t *trace = ((speed_t *)ptr)->trace;
+
+ for (i = 0; i < trace->num_ops; i++) {
+ switch (trace->ops[i].type) {
+ case ALLOC: /* malloc */
+ index = trace->ops[i].index;
+ size = trace->ops[i].size;
+ if ((p = malloc(size)) == NULL)
+ unix_error("malloc failed in eval_libc_speed");
+ trace->blocks[index] = p;
+ break;
+
+ case REALLOC: /* realloc */
+ index = trace->ops[i].index;
+ newsize = trace->ops[i].size;
+ oldp = trace->blocks[index];
+ if ((newp = realloc(oldp, newsize)) == NULL)
+ unix_error("realloc failed in eval_libc_speed\n");
+
+ trace->blocks[index] = newp;
+ break;
+
+ case FREE: /* free */
+ index = trace->ops[i].index;
+ block = trace->blocks[index];
+ free(block);
+ break;
+ }
+ }
+}
+
+/*************************************
+ * Some miscellaneous helper routines
+ ************************************/
+
+
+/*
+ * printresults - prints a performance summary for some malloc package
+ */
+static void printresults(int n, stats_t *stats)
+{
+ int i;
+ double secs = 0;
+ double ops = 0;
+ double util = 0;
+
+ /* Print the individual results for each trace */
+ printf("%5s%7s %5s%8s%10s%6s\n",
+ "trace", " valid", "util", "ops", "secs", "Kops");
+ for (i=0; i < n; i++) {
+ if (stats[i].valid) {
+ printf("%2d%10s%5.0f%%%8.0f%10.6f%6.0f\n",
+ i,
+ "yes",
+ stats[i].util*100.0,
+ stats[i].ops,
+ stats[i].secs,
+ (stats[i].ops/1e3)/stats[i].secs);
+ secs += stats[i].secs;
+ ops += stats[i].ops;
+ util += stats[i].util;
+ }
+ else {
+ printf("%2d%10s%6s%8s%10s%6s\n",
+ i,
+ "no",
+ "-",
+ "-",
+ "-",
+ "-");
+ }
+ }
+
+ /* Print the aggregate results for the set of traces */
+ if (errors == 0) {
+ printf("%12s%5.0f%%%8.0f%10.6f%6.0f\n",
+ "Total ",
+ (util/n)*100.0,
+ ops,
+ secs,
+ (ops/1e3)/secs);
+ }
+ else {
+ printf("%12s%6s%8s%10s%6s\n",
+ "Total ",
+ "-",
+ "-",
+ "-",
+ "-");
+ }
+
+}
+
+/*
+ * app_error - Report an arbitrary application error
+ */
+void app_error(char *msg)
+{
+ printf("%s\n", msg);
+ exit(1);
+}
+
+/*
+ * unix_error - Report a Unix-style error
+ */
+void unix_error(char *msg)
+{
+ printf("%s: %s\n", msg, strerror(errno));
+ exit(1);
+}
+
+/*
+ * malloc_error - Report an error returned by the mm_malloc package
+ */
+void malloc_error(int tracenum, int opnum, char *msg)
+{
+ errors++;
+ printf("ERROR [trace %d, line %d]: %s\n", tracenum, LINENUM(opnum), msg);
+}
+
+/*
+ * usage - Explain the command line arguments
+ */
+static void usage(void)
+{
+ fprintf(stderr, "Usage: mdriver [-hvVal] [-f <file>] [-t <dir>]\n");
+ fprintf(stderr, "Options\n");
+ fprintf(stderr, "\t-a Don't check the team structure.\n");
+ fprintf(stderr, "\t-f <file> Use <file> as the trace file.\n");
+ fprintf(stderr, "\t-g Generate summary info for autograder.\n");
+ fprintf(stderr, "\t-h Print this message.\n");
+ fprintf(stderr, "\t-l Run libc malloc as well.\n");
+ fprintf(stderr, "\t-t <dir> Directory to find default traces.\n");
+ fprintf(stderr, "\t-v Print per-trace performance breakdowns.\n");
+ fprintf(stderr, "\t-V Print additional debug info.\n");
+}
diff --git a/malloclab-handout/memlib.c b/malloclab-handout/memlib.c
new file mode 100644
index 0000000..82cd4f7
--- /dev/null
+++ b/malloclab-handout/memlib.c
@@ -0,0 +1,101 @@
+/*
+ * memlib.c - a module that simulates the memory system. Needed because it
+ * allows us to interleave calls from the student's malloc package
+ * with the system's malloc package in libc.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <errno.h>
+
+#include "memlib.h"
+#include "config.h"
+
+/* private variables */
+static char *mem_start_brk; /* points to first byte of heap */
+static char *mem_brk; /* points to last byte of heap */
+static char *mem_max_addr; /* largest legal heap address */
+
+/*
+ * mem_init - initialize the memory system model
+ */
+void mem_init(void)
+{
+ /* allocate the storage we will use to model the available VM */
+ if ((mem_start_brk = (char *)malloc(MAX_HEAP)) == NULL) {
+ fprintf(stderr, "mem_init_vm: malloc error\n");
+ exit(1);
+ }
+
+ mem_max_addr = mem_start_brk + MAX_HEAP; /* max legal heap address */
+ mem_brk = mem_start_brk; /* heap is empty initially */
+}
+
+/*
+ * mem_deinit - free the storage used by the memory system model
+ */
+void mem_deinit(void)
+{
+ free(mem_start_brk);
+}
+
+/*
+ * mem_reset_brk - reset the simulated brk pointer to make an empty heap
+ */
+void mem_reset_brk()
+{
+ mem_brk = mem_start_brk;
+}
+
+/*
+ * mem_sbrk - simple model of the sbrk function. Extends the heap
+ * by incr bytes and returns the start address of the new area. In
+ * this model, the heap cannot be shrunk.
+ */
+void *mem_sbrk(int incr)
+{
+ char *old_brk = mem_brk;
+
+ if ( (incr < 0) || ((mem_brk + incr) > mem_max_addr)) {
+ errno = ENOMEM;
+ fprintf(stderr, "ERROR: mem_sbrk failed. Ran out of memory...\n");
+ return (void *)-1;
+ }
+ mem_brk += incr;
+ return (void *)old_brk;
+}
+
+/*
+ * mem_heap_lo - return address of the first heap byte
+ */
+void *mem_heap_lo()
+{
+ return (void *)mem_start_brk;
+}
+
+/*
+ * mem_heap_hi - return address of last heap byte
+ */
+void *mem_heap_hi()
+{
+ return (void *)(mem_brk - 1);
+}
+
+/*
+ * mem_heapsize() - returns the heap size in bytes
+ */
+size_t mem_heapsize()
+{
+ return (size_t)(mem_brk - mem_start_brk);
+}
+
+/*
+ * mem_pagesize() - returns the page size of the system
+ */
+size_t mem_pagesize()
+{
+ return (size_t)getpagesize();
+}
diff --git a/malloclab-handout/memlib.h b/malloclab-handout/memlib.h
new file mode 100644
index 0000000..247c732
--- /dev/null
+++ b/malloclab-handout/memlib.h
@@ -0,0 +1,11 @@
+#include <unistd.h>
+
+void mem_init(void);
+void mem_deinit(void);
+void *mem_sbrk(int incr);
+void mem_reset_brk(void);
+void *mem_heap_lo(void);
+void *mem_heap_hi(void);
+size_t mem_heapsize(void);
+size_t mem_pagesize(void);
+
diff --git a/malloclab-handout/mm.c b/malloclab-handout/mm.c
new file mode 100644
index 0000000..a482a43
--- /dev/null
+++ b/malloclab-handout/mm.c
@@ -0,0 +1,110 @@
+/*
+ * mm-naive.c - The fastest, least memory-efficient malloc package.
+ *
+ * In this naive approach, a block is allocated by simply incrementing
+ * the brk pointer. A block is pure payload. There are no headers or
+ * footers. Blocks are never coalesced or reused. Realloc is
+ * implemented directly using mm_malloc and mm_free.
+ *
+ * NOTE TO STUDENTS: Replace this header comment with your own header
+ * comment that gives a high level description of your solution.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "mm.h"
+#include "memlib.h"
+
+/*********************************************************
+ * NOTE TO STUDENTS: Before you do anything else, please
+ * provide your team information in the following struct.
+ ********************************************************/
+team_t team = {
+ /* Team name */
+ "ateam",
+ /* First member's full name */
+ "Harry Bovik",
+ /* First member's email address */
+ "bovik@cs.cmu.edu",
+ /* Second member's full name (leave blank if none) */
+ "",
+ /* Second member's email address (leave blank if none) */
+ ""
+};
+
+/* single word (4) or double word (8) alignment */
+#define ALIGNMENT 8
+
+/* rounds up to the nearest multiple of ALIGNMENT */
+#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7)
+
+
+#define SIZE_T_SIZE (ALIGN(sizeof(size_t)))
+
+/*
+ * mm_init - initialize the malloc package.
+ */
+int mm_init(void)
+{
+ return 0;
+}
+
+/*
+ * mm_malloc - Allocate a block by incrementing the brk pointer.
+ * Always allocate a block whose size is a multiple of the alignment.
+ */
+void *mm_malloc(size_t size)
+{
+ int newsize = ALIGN(size + SIZE_T_SIZE);
+ void *p = mem_sbrk(newsize);
+ if (p == (void *)-1)
+ return NULL;
+ else {
+ *(size_t *)p = size;
+ return (void *)((char *)p + SIZE_T_SIZE);
+ }
+}
+
+/*
+ * mm_free - Freeing a block does nothing.
+ */
+void mm_free(void *ptr)
+{
+}
+
+/*
+ * mm_realloc - Implemented simply in terms of mm_malloc and mm_free
+ */
+void *mm_realloc(void *ptr, size_t size)
+{
+ void *oldptr = ptr;
+ void *newptr;
+ size_t copySize;
+
+ newptr = mm_malloc(size);
+ if (newptr == NULL)
+ return NULL;
+ copySize = *(size_t *)((char *)oldptr - SIZE_T_SIZE);
+ if (size < copySize)
+ copySize = size;
+ memcpy(newptr, oldptr, copySize);
+ mm_free(oldptr);
+ return newptr;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/malloclab-handout/mm.h b/malloclab-handout/mm.h
new file mode 100644
index 0000000..d41eef7
--- /dev/null
+++ b/malloclab-handout/mm.h
@@ -0,0 +1,23 @@
+#include <stdio.h>
+
+extern int mm_init (void);
+extern void *mm_malloc (size_t size);
+extern void mm_free (void *ptr);
+extern void *mm_realloc(void *ptr, size_t size);
+
+
+/*
+ * Students work in teams of one or two. Teams enter their team name,
+ * personal names and login IDs in a struct of this
+ * type in their bits.c file.
+ */
+typedef struct {
+ char *teamname; /* ID1+ID2 or ID1 */
+ char *name1; /* full name of first member */
+ char *id1; /* login ID of first member */
+ char *name2; /* full name of second member (if any) */
+ char *id2; /* login ID of second member */
+} team_t;
+
+extern team_t team;
+
diff --git a/malloclab-handout/short1-bal.rep b/malloclab-handout/short1-bal.rep
new file mode 100644
index 0000000..6ec0c4c
--- /dev/null
+++ b/malloclab-handout/short1-bal.rep
@@ -0,0 +1,16 @@
+20000
+6
+12
+1
+a 0 2040
+a 1 2040
+f 1
+a 2 48
+a 3 4072
+f 3
+a 4 4072
+f 0
+f 2
+a 5 4072
+f 4
+f 5
diff --git a/malloclab-handout/short2-bal.rep b/malloclab-handout/short2-bal.rep
new file mode 100644
index 0000000..4ff7c3c
--- /dev/null
+++ b/malloclab-handout/short2-bal.rep
@@ -0,0 +1,16 @@
+20000
+6
+12
+1
+a 0 2040
+a 1 4010
+a 2 48
+a 3 4072
+a 4 4072
+a 5 4072
+f 0
+f 1
+f 2
+f 3
+f 4
+f 5