@ -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 | |||||
@ -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 | |||||
@ -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; | |||||
} | |||||
@ -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(); |
@ -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 "/home/aqua/桌面/malloclab" | |||||
/* | |||||
* 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 */ |
@ -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; | |||||
} | |||||
@ -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); | |||||
@ -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 | |||||
} | |||||
@ -0,0 +1,4 @@ | |||||
typedef void (*fsecs_test_funct)(void *); | |||||
void init_fsecs(void); | |||||
double fsecs(fsecs_test_funct f, void *argp); |
@ -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); | |||||
} | |||||
@ -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); | |||||
@ -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(); | |||||
} |
@ -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); | |||||
@ -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; | |||||
} | |||||
@ -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; | |||||
@ -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 |
@ -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 |
@ -0,0 +1,42 @@ | |||||
all: synthetic-traces balanced-traces check-balance | |||||
synthetic-traces: | |||||
./gen_binary.pl | |||||
./gen_binary2.pl | |||||
./gen_coalescing.pl | |||||
./gen_random.pl | |||||
./gen_realloc.pl | |||||
./gen_realloc2.pl | |||||
balanced-traces: | |||||
./checktrace.pl < amptjp.rep > amptjp-bal.rep | |||||
./checktrace.pl < binary.rep > binary-bal.rep | |||||
./checktrace.pl < binary2.rep > binary2-bal.rep | |||||
./checktrace.pl < cccp.rep > cccp-bal.rep | |||||
./checktrace.pl < coalescing.rep > coalescing-bal.rep | |||||
./checktrace.pl < cp-decl.rep > cp-decl-bal.rep | |||||
./checktrace.pl < expr.rep > expr-bal.rep | |||||
./checktrace.pl < realloc.rep > realloc-bal.rep | |||||
./checktrace.pl < realloc2.rep > realloc2-bal.rep | |||||
./checktrace.pl < random.rep > random-bal.rep | |||||
./checktrace.pl < random2.rep > random2-bal.rep | |||||
./checktrace.pl < short1.rep > short1-bal.rep | |||||
./checktrace.pl < short2.rep > short2-bal.rep | |||||
check-balance: | |||||
./checktrace.pl -s < amptjp-bal.rep | |||||
./checktrace.pl -s < binary-bal.rep | |||||
./checktrace.pl -s < binary2-bal.rep | |||||
./checktrace.pl -s < cccp-bal.rep | |||||
./checktrace.pl -s < coalescing-bal.rep | |||||
./checktrace.pl -s < cp-decl-bal.rep | |||||
./checktrace.pl -s < expr-bal.rep | |||||
./checktrace.pl -s < realloc-bal.rep | |||||
./checktrace.pl -s < realloc2-bal.rep | |||||
./checktrace.pl -s < random-bal.rep | |||||
./checktrace.pl -s < random2-bal.rep | |||||
./checktrace.pl -s < short1-bal.rep | |||||
./checktrace.pl -s < short2-bal.rep | |||||
clean: | |||||
rm -f *~ |
@ -0,0 +1,116 @@ | |||||
##################################################################### | |||||
# CS:APP Malloc Lab | |||||
# Traces | |||||
# | |||||
# Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. | |||||
# May not be used, modified, or copied without permission. | |||||
# | |||||
###################################################################### | |||||
This directory contains traces of allocate and free requests that are | |||||
used by the test harness to evaluate the student malloc packages. | |||||
********* | |||||
1. Files | |||||
********* | |||||
*.rep Original traces | |||||
*-bal.rep Balanced versions of the original traces | |||||
gen_XXX.pl Perl script that generates *.rep | |||||
checktrace.pl Checks trace for consistency and outputs a balanced version | |||||
Makefile Generates traces | |||||
Note: A "balanced" trace has a matching free request for each allocate | |||||
request. | |||||
********************** | |||||
2. Building the traces | |||||
********************** | |||||
To rebuild the traces from scratch, type | |||||
unix> make | |||||
******************** | |||||
3. Trace file format | |||||
******************** | |||||
A trace file is an ASCII file. It begins with a 4-line header: | |||||
<sugg_heapsize> /* suggested heap size (unused) */ | |||||
<num_ids> /* number of request id's */ | |||||
<num_ops> /* number of requests (operations) */ | |||||
<weight> /* weight for this trace (unused) */ | |||||
The header is followed by num_ops text lines. Each line denotes either | |||||
an allocate [a], reallocate [r], or free [f] request. The <alloc_id> | |||||
is an integer that uniquely identifies an allocate or reallocate | |||||
request. | |||||
a <id> <bytes> /* ptr_<id> = malloc(<bytes>) */ | |||||
r <id> <bytes> /* realloc(ptr_<id>, <bytes>) */ | |||||
f <id> /* free(ptr_<id>) */ | |||||
For example, the following trace file: | |||||
<beginning of file> | |||||
20000 | |||||
3 | |||||
8 | |||||
1 | |||||
a 0 512 | |||||
a 1 128 | |||||
r 0 640 | |||||
a 2 128 | |||||
f 1 | |||||
r 0 768 | |||||
f 0 | |||||
f 2 | |||||
<end of file> | |||||
is balanced. It has a recommended heap size of 20000 bytes (ignored), | |||||
three distinct request ids (0, 1, and 2), eight different requests | |||||
(one per line), and a weight of 1 (ignored). | |||||
************************ | |||||
4. Description of traces | |||||
************************ | |||||
* short{1,2}-bal.rep | |||||
Tiny synthetic tracefiles for debugging | |||||
* {amptjp,cccp,cp-decl,expr}-bal.rep | |||||
Traces generated from real programs. | |||||
* {binary,binary2}-bal.rep | |||||
The allocation pattern is to alternatively allocate a small-sized | |||||
chunk of memory and a large-sized chunk. The small-sized chunks | |||||
(either 16 or 64 ) are deliberately set to be power of 2 while the | |||||
large-size chunks (either 112 or 448) are not a power of 2. Defeats | |||||
buddy algorithms. However, a simple-minded algorithm might prevail in | |||||
this scenario because a first-fit scheme will be good enough. | |||||
* coalescing-bal.rep | |||||
Repeatedly allocate two equal-sized chunks (4095 in size) and release | |||||
them, and then immediately allocate and free a chunk twice as big | |||||
(8190). This tests if the students' algorithm ever really releases | |||||
memory and does coalescing. The size is chosen to give advantage to | |||||
tree-based or segrated fits algorithms where there is no header or | |||||
footer overhead. | |||||
* {random,random2}-bal.rep | |||||
Random allocate and free requesets that simply test the correctness | |||||
and robustness of the algorithm. | |||||
* {realloc,realloc2}-bal.rep | |||||
Reallocate previously allocated blocks interleaved by other allocation | |||||
request. The purpose is to test whether a certain amount of internal | |||||
fragments are allocated or not. Naive realloc implementations that | |||||
always realloc a brand new block will suffer. | |||||
@ -0,0 +1,155 @@ | |||||
#!/usr/bin/perl | |||||
#!/usr/local/bin/perl | |||||
use Getopt::Std; | |||||
####################################################################### | |||||
# checktrace - trace file consistency checker and balancer. | |||||
# | |||||
# Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. | |||||
# May not be used, modified, or copied without permission. | |||||
# | |||||
# This script reads a Malloc Lab trace file, checks it for consistency, | |||||
# and outputs a balanced version by appending any necessary free requests. | |||||
# | |||||
####################################################################### | |||||
$| = 1; # autoflush output on every print statement | |||||
# | |||||
# void usage(void) - print help message and terminate | |||||
# | |||||
sub usage | |||||
{ | |||||
printf STDERR "$_[0]\n"; | |||||
printf STDERR "Usage: $0 [-hs]\n"; | |||||
printf STDERR "Options:\n"; | |||||
printf STDERR " -h Print this message\n"; | |||||
printf STDERR " -s Emit only a brief summary\n"; | |||||
die "\n" ; | |||||
} | |||||
############## | |||||
# Main routine | |||||
############## | |||||
# | |||||
# Parse and check the command line arguments | |||||
# | |||||
getopts('hs'); | |||||
if ($opt_h) { | |||||
usage(""); | |||||
} | |||||
$summary = $opt_s; | |||||
# | |||||
# HASH keeps a running tally of outstanding alloc/realloc | |||||
# requests. When a free request is encountered, the corresponding | |||||
# hash entry is deleted. When we are finished reading the trace, | |||||
# what is left are the unmatched alloc/realloc requests. | |||||
# | |||||
%HASH = (); | |||||
# Read the trace header values | |||||
$heap_size = <STDIN>; | |||||
chomp($heap_size); | |||||
$num_blocks = <STDIN>; | |||||
chomp($num_blocks); | |||||
$old_num_ops = <STDIN>; | |||||
chomp($old_num_ops); | |||||
$weight = <STDIN>; | |||||
chomp($weight); | |||||
# | |||||
# Find any allocate requests that don't have a matching free requests | |||||
# | |||||
$linenum = 4; | |||||
$requestnum = 0; | |||||
while ($line = <STDIN>) { | |||||
chomp($line); | |||||
$linenum++; | |||||
($cmd, $id, $size) = split(" ", $line); | |||||
# ignore blank lines | |||||
if (!$cmd) { | |||||
next; | |||||
} | |||||
# save the line for output later | |||||
$lines[$requestnum++] = $line; | |||||
#ignore realloc requests, as long as they are preceeded by an alloc request | |||||
if ($cmd eq "r") { | |||||
if (!$HASH{$id}) { | |||||
die "$0: ERROR[$linenum]: realloc without previous alloc\n"; | |||||
} | |||||
next; | |||||
} | |||||
if ($cmd eq "a" and $HASH{$id} eq "a") { | |||||
die "$0: ERROR[$linenum]: allocate with no intervening free.\n"; | |||||
} | |||||
if ($cmd eq "a" and $HASH{$id} eq "f") { | |||||
die "$0: ERROR[$linenum]: reused ID $id.\n"; | |||||
} | |||||
if ($cmd eq "f" and !exists($HASH{$id})) { | |||||
die "$0: ERROR[$linenum]: freeing unallocated block.\n"; | |||||
next; | |||||
} | |||||
if ($cmd eq "f" and !$HASH{$id} eq "f") { | |||||
die "$0: ERROR[$linenum]: freeing already freed block.\n"; | |||||
next; | |||||
} | |||||
if ($cmd eq "f") { | |||||
delete $HASH{$id}; | |||||
} | |||||
else { | |||||
$HASH{$id} = $cmd; | |||||
} | |||||
} | |||||
# | |||||
# If called with -s argument , print a brief balance summary and exit | |||||
# | |||||
if ($summary) { | |||||
if (!%HASH) { | |||||
print "Balanced trace.\n"; | |||||
} | |||||
else { | |||||
print "Unbalanced tree.\n"; | |||||
} | |||||
exit; | |||||
} | |||||
# | |||||
# Output a balanced version of the trace | |||||
# | |||||
$new_ops = keys %HASH; | |||||
$new_num_ops = $old_num_ops + $new_ops; | |||||
print "$heap_size\n"; | |||||
print "$num_blocks\n"; | |||||
print "$new_num_ops\n"; | |||||
print "$weight\n"; | |||||
# print the old requests | |||||
foreach $item (@lines) { | |||||
print "$item\n"; | |||||
} | |||||
# print a set of free requests that will balance the trace | |||||
foreach $key (sort keys %HASH) { | |||||
if ($HASH{$key} ne "a" and $HASH{$key} ne "r") { | |||||
die "$0: ERROR: Invalid free request in residue.\n"; | |||||
} | |||||
print "f $key\n"; | |||||
} | |||||
exit; |
@ -0,0 +1,39 @@ | |||||
#!/usr/bin/perl | |||||
#!/usr/local/bin/perl | |||||
$out_filename = "binary.rep"; | |||||
$blk_size1 = 64; | |||||
$blk_size2 = 512 - $blk_size1; | |||||
$num_iters = 2000; | |||||
# Open output file | |||||
open OUTFILE, ">$out_filename" or die "Cannot create $out_filename\n"; | |||||
# Calculate misc parameters | |||||
$blk_size12 = $blk_size1 + $blk_size2; | |||||
$suggested_heap_size = ($blk_size1 + $blk_size2 + $blk_size12)*$num_iters + 100; | |||||
$num_blocks = 3*$num_iters; | |||||
$num_ops = 4*$num_iters; | |||||
print OUTFILE "$suggested_heap_size\n"; | |||||
print OUTFILE "$num_blocks\n"; | |||||
print OUTFILE "$num_ops\n"; | |||||
print OUTFILE "1\n"; | |||||
for ($i = 0; $i < $num_iters; $i += 1) { | |||||
$seq1 = 2*$i; | |||||
$seq2 = 2*$i + 1; | |||||
print OUTFILE "a $seq1 $blk_size1\n"; | |||||
print OUTFILE "a $seq2 $blk_size2\n"; | |||||
} | |||||
for ($i = 0; $i < $num_iters; $i += 1) { | |||||
$fseq = 2*$i + 1; | |||||
print OUTFILE "f $fseq\n"; | |||||
} | |||||
for ($i = 0; $i < $num_iters; $i += 1) { | |||||
$aseq = 2*$num_iters + $i; | |||||
print OUTFILE "a $aseq $blk_size12\n"; | |||||
} | |||||
close OUTFILE; | |||||
@ -0,0 +1,38 @@ | |||||
#!/usr/bin/perl | |||||
$out_filename = "binary2.rep"; | |||||
$blk_size1 = 16; | |||||
$blk_size2 = 128 - $blk_size1; | |||||
$num_iters = 4000; | |||||
# Open output file | |||||
open OUTFILE, ">$out_filename" or die "Cannot create $out_filename\n"; | |||||
# Calculate misc parameters | |||||
$blk_size12 = $blk_size1 + $blk_size2; | |||||
$suggested_heap_size = ($blk_size1 + $blk_size2 + $blk_size12)*$num_iters + 100; | |||||
$num_blocks = 3*$num_iters; | |||||
$num_ops = 4*$num_iters; | |||||
print OUTFILE "$suggested_heap_size\n"; | |||||
print OUTFILE "$num_blocks\n"; | |||||
print OUTFILE "$num_ops\n"; | |||||
print OUTFILE "1\n"; | |||||
for ($i = 0; $i < $num_iters; $i += 1) { | |||||
$seq1 = 2*$i; | |||||
$seq2 = 2*$i + 1; | |||||
print OUTFILE "a $seq1 $blk_size1\n"; | |||||
print OUTFILE "a $seq2 $blk_size2\n"; | |||||
} | |||||
for ($i = 0; $i < $num_iters; $i += 1) { | |||||
$fseq = 2*$i + 1; | |||||
print OUTFILE "f $fseq\n"; | |||||
} | |||||
for ($i = 0; $i < $num_iters; $i += 1) { | |||||
$aseq = 2*$num_iters + $i; | |||||
print OUTFILE "a $aseq $blk_size12\n"; | |||||
} | |||||
close OUTFILE; | |||||
@ -0,0 +1,36 @@ | |||||
#!/usr/bin/perl | |||||
#!/usr/local/bin/perl | |||||
$out_filename = "coalescing.rep"; | |||||
$blk_size = 4095; | |||||
$num_iters = 2400; | |||||
# Open output file | |||||
open OUTFILE, ">$out_filename" or die "Cannot create $out_filename\n"; | |||||
# Calculate misc parameters | |||||
$blk_size2 = 2*$blk_size; | |||||
$suggested_heap_size = 2*$blk_size*$num_iters + 100; | |||||
$num_blocks = 3*$num_iters; | |||||
$num_ops = 6*$num_iters; | |||||
print OUTFILE "$suggested_heap_size\n"; | |||||
print OUTFILE "$num_blocks\n"; | |||||
print OUTFILE "$num_ops\n"; | |||||
print OUTFILE "1\n"; | |||||
for ($i = 0; $i < $num_iters; $i += 1) { | |||||
$blk1 = 3*$i; | |||||
$blk2 = $blk1 + 1; | |||||
$blk3 = $blk1 + 2; | |||||
print OUTFILE "a $blk1 $blk_size\n"; | |||||
print OUTFILE "a $blk2 $blk_size\n"; | |||||
print OUTFILE "f $blk1\n"; | |||||
print OUTFILE "f $blk2\n"; | |||||
print OUTFILE "a $blk3 $blk_size2\n"; | |||||
print OUTFILE "f $blk3\n"; | |||||
} | |||||
close OUTFILE; | |||||
@ -0,0 +1,62 @@ | |||||
#!/usr/bin/perl | |||||
#!/usr/local/bin/perl | |||||
$out_filename = $argv[0]; | |||||
$out_filename = "random.rep" unless $out_filename; | |||||
$num_blocks = $argv[1]; | |||||
# $num_blocks = 1200 unless $num_blocks; | |||||
$num_blocks = 2400 unless $num_blocks; | |||||
$max_blk_size = $argv[2]; | |||||
$max_blk_size = 32768 unless $max_blk_size; | |||||
#print "Output file: $out_filename\n"; | |||||
#print "Number of blocks: $num_blocks\n"; | |||||
#print "Max block size: $max_blk_size\n"; | |||||
# Create trace | |||||
# Make a series of malloc()s | |||||
for ($i = 0; $i < $num_blocks; $i += 1) { | |||||
$size = int(rand $max_blk_size); | |||||
$op = {}; | |||||
$op->{type} = "a"; | |||||
$op->{seq} = $i; | |||||
$op->{size} = $size; | |||||
$total_block_size += $size; | |||||
push @trace, $op; | |||||
} | |||||
# Insert free()s in proper places | |||||
for ($i = 0; $i < $num_blocks; $i += 1) { | |||||
for ($minval = $i; $minval < $num_blocks + $i; $minval += 1) { | |||||
if (($trace[$minval]->{type} eq "a") && ($trace[$minval]->{seq} == $i)) { | |||||
last; | |||||
} | |||||
} | |||||
$pos = int(rand($num_blocks + $i - $minval - 1) + $minval + 1); | |||||
$op = {}; | |||||
$op->{type} = "f"; | |||||
$op->{seq} = $i; | |||||
splice @trace, $pos, 0, $op; | |||||
} | |||||
# Open output file | |||||
open OUTFILE, ">$out_filename" or die "Cannot create $out_filename\n"; | |||||
# Calculate misc parameters | |||||
$suggested_heap_size = $total_block_size + 100; | |||||
$num_ops = 2*$num_blocks; | |||||
print OUTFILE "$suggested_heap_size\n"; | |||||
print OUTFILE "$num_blocks\n"; | |||||
print OUTFILE "$num_ops\n"; | |||||
print OUTFILE "1\n"; | |||||
for ($i = 0; $i < 2*$num_blocks; $i += 1) { | |||||
if ($trace[$i]->{type} eq "a") { | |||||
print OUTFILE "$trace[$i]->{type} $trace[$i]->{seq} $trace[$i]->{size}\n"; | |||||
} else { | |||||
print OUTFILE "$trace[$i]->{type} $trace[$i]->{seq}\n"; | |||||
} | |||||
} | |||||
close OUTFILE; | |||||
@ -0,0 +1,57 @@ | |||||
#!/usr/bin/perl | |||||
#!/usr/local/bin/perl | |||||
$out_filename = "realloc.rep"; | |||||
$realloc_size = 512; | |||||
$size_increment = 128; | |||||
$malloc_size = 128; | |||||
$num_iters = 4800; | |||||
# Open output file | |||||
open OUTFILE, ">$out_filename" or die "Cannot create $out_filename\n"; | |||||
# Calculate misc parameters | |||||
$suggested_heap_size = num_iters* ($realloc_size+$size_increment*2 )+100; | |||||
$num_blocks = $num_iters+1; | |||||
$num_ops = ($num_iters )*3 +1; | |||||
$blk = 1; | |||||
print OUTFILE "$suggested_heap_size\n"; | |||||
print OUTFILE "$num_blocks\n"; | |||||
print OUTFILE "$num_ops\n"; | |||||
print OUTFILE "1\n"; | |||||
print OUTFILE "a 0 $realloc_size\n"; | |||||
print OUTFILE "a $blk $malloc_size\n"; | |||||
for ($i = 1; $i < $num_iters; $i += 1) { | |||||
$blk += 1; | |||||
$realloc_size += $size_increment; | |||||
print OUTFILE "r 0 $realloc_size\n"; | |||||
print OUTFILE "a $blk $malloc_size\n"; | |||||
$prevblk = $blk-1; | |||||
print OUTFILE "f $prevblk\n"; | |||||
} | |||||
$finalblk = $blk; | |||||
print OUTFILE "f $finalblk\n"; | |||||
print OUTFILE "f 0"; | |||||
print OUTFILE | |||||
close OUTFILE; | |||||
@ -0,0 +1,46 @@ | |||||
#!/usr/bin/perl | |||||
#!/usr/local/bin/perl | |||||
$out_filename = "realloc2.rep"; | |||||
$realloc_size = 4092; | |||||
$size_increment = 5; | |||||
$malloc_size = 16; | |||||
$num_iters = 4800; | |||||
# Open output file | |||||
open OUTFILE, ">$out_filename" or die "Cannot create $out_filename\n"; | |||||
# Calculate misc parameters | |||||
$suggested_heap_size = $realloc_size+$size_increment*($num_iters-1)+$malloc_size*$num_iters+100; | |||||
$num_blocks = $num_iters + 1; | |||||
$num_ops = 3 * $num_iters + 1; | |||||
$blk = 1; | |||||
print OUTFILE "$suggested_heap_size\n"; | |||||
print OUTFILE "$num_blocks\n"; | |||||
print OUTFILE "$num_ops\n"; | |||||
print OUTFILE "1\n"; | |||||
print OUTFILE "a 0 $realloc_size\n"; | |||||
print OUTFILE "a $blk $malloc_size\n"; | |||||
for ($i = 1; $i < $num_iters; $i += 1) { | |||||
$blk += 1; | |||||
$realloc_size += $size_increment; | |||||
print OUTFILE "r 0 $realloc_size\n"; | |||||
print OUTFILE "a $blk $malloc_size\n"; | |||||
$prevblk = $blk-1; | |||||
print OUTFILE "f $prevblk\n"; | |||||
} | |||||
$finalblk = $blk; | |||||
print OUTFILE "f $finalblk\n"; | |||||
print OUTFILE "f 0"; | |||||
print OUTFILE | |||||
close OUTFILE; |
@ -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 |
@ -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 |
@ -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 |
@ -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 |