@ -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 |