Initial
This commit is contained in:
32
Makefile
Executable file
32
Makefile
Executable file
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# Students' Makefile for the Malloc Lab
|
||||
#
|
||||
TEAM = MA
|
||||
VERSION = 1
|
||||
HANDINDIR = /afs/cs.cmu.edu/academic/class/15213-f01/malloclab/handin
|
||||
|
||||
CC = gcc
|
||||
CWI = -Wno-unused-variable -Wno-format
|
||||
CFLAGS = -Wall -O2 -m32 $(CWI)
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
52
README
Executable file
52
README
Executable file
@@ -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
|
||||
|
||||
279
clock.c
Executable file
279
clock.c
Executable file
@@ -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;
|
||||
}
|
||||
|
||||
22
clock.h
Executable file
22
clock.h
Executable file
@@ -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();
|
||||
70
config.h
Executable file
70
config.h
Executable file
@@ -0,0 +1,70 @@
|
||||
#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 "./traces/"
|
||||
|
||||
/*
|
||||
* This is the list of default tracefiles in TRACEDIR that the driver
|
||||
* will use for testing. Modify this if you want to add or delete
|
||||
* traces from the driver's test suite. For example, if you don't want
|
||||
* your students to implement realloc, you can delete the last two
|
||||
* traces.
|
||||
*/
|
||||
#define DEFAULT_TRACEFILES \
|
||||
"amptjp-bal.rep",\
|
||||
"cccp-bal.rep",\
|
||||
"cp-decl-bal.rep",\
|
||||
"expr-bal.rep",\
|
||||
"coalescing-bal.rep",\
|
||||
"random-bal.rep",\
|
||||
"random2-bal.rep",\
|
||||
"binary-bal.rep",\
|
||||
"binary2-bal.rep"
|
||||
|
||||
/*
|
||||
* 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 18944E3 /* 9000 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 */
|
||||
251
fcyc.c
Executable file
251
fcyc.c
Executable file
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
68
fcyc.h
Executable file
68
fcyc.h
Executable file
@@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
57
fsecs.c
Executable file
57
fsecs.c
Executable file
@@ -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
|
||||
}
|
||||
|
||||
|
||||
4
fsecs.h
Executable file
4
fsecs.h
Executable file
@@ -0,0 +1,4 @@
|
||||
typedef void (*fsecs_test_funct)(void *);
|
||||
|
||||
void init_fsecs(void);
|
||||
double fsecs(fsecs_test_funct f, void *argp);
|
||||
106
ftimer.c
Executable file
106
ftimer.c
Executable file
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
14
ftimer.h
Executable file
14
ftimer.h
Executable file
@@ -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);
|
||||
|
||||
101
memlib.c
Executable file
101
memlib.c
Executable file
@@ -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();
|
||||
}
|
||||
11
memlib.h
Executable file
11
memlib.h
Executable file
@@ -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);
|
||||
|
||||
212
mm.c
Executable file
212
mm.c
Executable file
@@ -0,0 +1,212 @@
|
||||
// the allocator uses an implicit free list to manage memory blocks.
|
||||
// it provides functionalities for allocation (mm_malloc), deallocation (mm_free), and heap initialization (mm_init). adjacent free blocks are coalesced to reduce fragmentation.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "mm.h"
|
||||
#include "memlib.h"
|
||||
|
||||
team_t team = {
|
||||
"MA", "Marvin Aleksa", "marvin.aleksa@stud.uni-due.de", "", ""
|
||||
};
|
||||
|
||||
#define SIZE_T_SIZE (ALIGN(sizeof(size_t))) // align to size_t bytes
|
||||
#define ALIGN(size) (((size) + (7)) & ~0x7) // align to 8 bytes
|
||||
#define WSIZE 4 // single word size
|
||||
#define DSIZE 8 // double word size
|
||||
#define CHUNKSIZE (1<<12) // initial heap size
|
||||
#define PACK(size, alloc) ((size) | (alloc)) // pack size and allocated bit
|
||||
#define GET(p) (*(unsigned int *)(p)) // read a word from address
|
||||
#define PUT(p, val) (*(unsigned int *)(p) = (val)) // write a word to address
|
||||
#define GET_SIZE(p) (GET(p) & ~0x7) // get size from address
|
||||
#define GET_ALLOC(p) (GET(p) & 0x1) // get alloc bit from address
|
||||
#define HDRP(bp) ((char *)(bp) - WSIZE) // get address of block header
|
||||
#define FTRP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE) // get address of block footer
|
||||
#define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE))) // get address of previous block
|
||||
#define PREV_BLKP(bp) ((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE))) // get address of next block
|
||||
#define MAX(x, y) ((x) > (y) ? (x) : (y)) // get maximum value
|
||||
|
||||
|
||||
|
||||
// pointer to first block
|
||||
static char *heap_listp = 0;
|
||||
|
||||
|
||||
|
||||
// find_fit - find a fit for a block with asize bytes.
|
||||
static void *find_fit(size_t asize) {
|
||||
char *bp;
|
||||
|
||||
// iterate through heap to find free block
|
||||
for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)) {
|
||||
if (!GET_ALLOC(HDRP(bp)) && (GET_SIZE(HDRP(bp)) >= asize)) {
|
||||
return bp;
|
||||
}
|
||||
}
|
||||
return NULL; // no fit found
|
||||
}
|
||||
|
||||
|
||||
|
||||
// place - place block of asize bytes at start of free block bp and split if remainder would be at least minimum block size.
|
||||
static void place(void *bp, size_t asize) {
|
||||
size_t csize = GET_SIZE(HDRP(bp)); // current block size
|
||||
|
||||
if ((csize - asize) >= (2 * DSIZE)) { // if remaining size is enough for a new block
|
||||
PUT(HDRP(bp), PACK(asize, 1)); // mark block allocated
|
||||
PUT(FTRP(bp), PACK(asize, 1));
|
||||
bp = NEXT_BLKP(bp);
|
||||
PUT(HDRP(bp), PACK(csize - asize, 0)); // create new free block
|
||||
PUT(FTRP(bp), PACK(csize - asize, 0));
|
||||
} else { // dont split
|
||||
PUT(HDRP(bp), PACK(csize, 1));
|
||||
PUT(FTRP(bp), PACK(csize, 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// coalesce - boundary tag coalescing. return pointer to coalesced block.
|
||||
static void *coalesce(void *bp) {
|
||||
size_t prev_alloc = GET_ALLOC(FTRP(PREV_BLKP(bp)));
|
||||
size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));
|
||||
size_t size = GET_SIZE(HDRP(bp));
|
||||
|
||||
if (prev_alloc && next_alloc) { // c1: both adjacent blocks allocated
|
||||
return bp;
|
||||
} else if (prev_alloc && !next_alloc) { // c2: next block free
|
||||
size += GET_SIZE(HDRP(NEXT_BLKP(bp)));
|
||||
PUT(HDRP(bp), PACK(size, 0));
|
||||
PUT(FTRP(bp), PACK(size, 0));
|
||||
} else if (!prev_alloc && next_alloc) { // c3: previous block free
|
||||
size += GET_SIZE(HDRP(PREV_BLKP(bp)));
|
||||
PUT(FTRP(bp), PACK(size, 0));
|
||||
PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0));
|
||||
bp = PREV_BLKP(bp);
|
||||
} else { // c4: both blocks free
|
||||
size += GET_SIZE(HDRP(PREV_BLKP(bp))) +
|
||||
GET_SIZE(FTRP(NEXT_BLKP(bp)));
|
||||
PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0));
|
||||
PUT(FTRP(NEXT_BLKP(bp)), PACK(size, 0));
|
||||
bp = PREV_BLKP(bp);
|
||||
}
|
||||
|
||||
return bp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// extend_heap - extend heap with free block and return its block pointer.
|
||||
static void *extend_heap(size_t words) {
|
||||
char *bp;
|
||||
size_t size;
|
||||
|
||||
// allocate even number of words to maintain alignment
|
||||
size = (words % 2) ? (words + 1) * WSIZE : words * WSIZE;
|
||||
if ((long)(bp = mem_sbrk(size)) == -1)
|
||||
return NULL;
|
||||
|
||||
// initialize free block header/footer + epilogue header
|
||||
PUT(HDRP(bp), PACK(size, 0)); // free block header
|
||||
PUT(FTRP(bp), PACK(size, 0)); // free block footer
|
||||
PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1)); // new epilogue header
|
||||
|
||||
// coalesce if previous block free
|
||||
return coalesce(bp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// mm_init - initialize the malloc package.
|
||||
int mm_init(void) {
|
||||
// initialize heap with prologue block, initial free block, epilogue block
|
||||
if ((heap_listp = mem_sbrk(4 * WSIZE)) == (void *)-1){
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUT(heap_listp, 0); // alignment padding
|
||||
PUT(heap_listp + (1 * WSIZE), PACK(DSIZE, 1)); // prologue header
|
||||
PUT(heap_listp + (2 * WSIZE), PACK(DSIZE, 1)); // prologue footer
|
||||
PUT(heap_listp + (3 * WSIZE), PACK(0, 1)); // epilogue header
|
||||
heap_listp += (2 * WSIZE);
|
||||
|
||||
// extend empty heap with free block of CHUNKSIZE bytes
|
||||
if (extend_heap(CHUNKSIZE / WSIZE) == NULL){
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// mm_malloc - allocate a block of memory with at least the requested size. the block will be aligned to 8 bytes.
|
||||
void *mm_malloc(size_t size) {
|
||||
size_t asize; // adjusted block size
|
||||
size_t extendsize; // amount to extend the heap if no fit found
|
||||
char *bp;
|
||||
|
||||
// ignore spurious requests
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
// adjust block size to include overhead and alignment requirements
|
||||
if (size <= DSIZE)
|
||||
asize = 2 * DSIZE; // minimum block size
|
||||
else
|
||||
asize = DSIZE * ((size + (DSIZE) + (DSIZE - 1)) / DSIZE);
|
||||
|
||||
// search free list for a fit
|
||||
if ((bp = find_fit(asize)) != NULL) {
|
||||
place(bp, asize);
|
||||
return bp;
|
||||
}
|
||||
|
||||
// no fit found. get more memory and place block
|
||||
extendsize = MAX(asize, CHUNKSIZE);
|
||||
if ((bp = extend_heap(extendsize / WSIZE)) == NULL)
|
||||
return NULL;
|
||||
|
||||
place(bp, asize);
|
||||
return bp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// mm_free - frees a block and coalesces it with adjacent free blocks if possible.
|
||||
void mm_free(void *ptr) {
|
||||
if (ptr == NULL) {
|
||||
return; // ignore null pointers
|
||||
}
|
||||
|
||||
// get size of block and mark as free
|
||||
size_t size = GET_SIZE(HDRP(ptr));
|
||||
PUT(HDRP(ptr), PACK(size, 0)); // update header to indicate free
|
||||
PUT(FTRP(ptr), PACK(size, 0)); // update footer to indicate free
|
||||
|
||||
// coalesce block with adjacent free blocks
|
||||
coalesce(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;
|
||||
}
|
||||
84
mm.c_xd
Executable file
84
mm.c_xd
Executable file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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
|
||||
"MA",
|
||||
// First member's full name
|
||||
"Marvin Aleksa",
|
||||
// First member's email address
|
||||
"marvin.aleksa@stud.uni-due.de",
|
||||
// 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){
|
||||
// ATTENTION: You do not need to implement realloc for this assignment
|
||||
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;
|
||||
}
|
||||
23
mm.h
Executable file
23
mm.h
Executable file
@@ -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;
|
||||
|
||||
210
mm_v1.c
Executable file
210
mm_v1.c
Executable file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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 <stdint.h>
|
||||
|
||||
#include "mm.h"
|
||||
#include "memlib.h"
|
||||
|
||||
team_t team = {
|
||||
/* Team name */
|
||||
"MA",
|
||||
/* First member's full name */
|
||||
"Marvin Aleksa",
|
||||
/* First member's email address */
|
||||
"marvin.aleksa@stud.uni-due.de",
|
||||
/* Second member's full name (leave blank if none) */
|
||||
"",
|
||||
/* Second member's email address (leave blank if none) */
|
||||
""
|
||||
};
|
||||
|
||||
typedef uint32_t t4; // 4 byte wide unsigned data type
|
||||
typedef uint64_t t8; // 8 byte wide unsigned data type
|
||||
|
||||
/* single word (4) or double word (8) alignment */
|
||||
#define AL 8 // word length to align to
|
||||
#define BS AL*1 // target block size
|
||||
|
||||
/* rounds up to the nearest multiple of ALIGNMENT */
|
||||
#define ALIGN(size) (((size) + (AL-1)) & ~0x7)
|
||||
#define ALIGN_ADDR(addr) (void *)ALIGN((int)addr)
|
||||
#define SIZE_T_SIZE (ALIGN(sizeof(t8)))
|
||||
|
||||
#define SET_ALL0(x) ((x) & ~1)
|
||||
#define SET_ALL1(x) ((x) | 1)
|
||||
#define GET_LENG(x) ((x) & ~1)
|
||||
#define GET_ALLC(x) ((x) & 1)
|
||||
|
||||
void *heap = NULL;
|
||||
void *epil = NULL;
|
||||
|
||||
void *find_unused(size_t size) {
|
||||
// Start traversing from the beginning of the heap
|
||||
t8 *current = (t8 *)heap;
|
||||
|
||||
while (current < (t8 *)mem_heap_hi()) {
|
||||
size_t block_size = GET_LENG(*current);
|
||||
|
||||
// Check if the block is free and large enough
|
||||
if (!GET_ALLC(*current) && block_size >= size) {
|
||||
return (void *)(current + 1); // Return pointer to payload
|
||||
}
|
||||
|
||||
// Move to the next block
|
||||
current = (t8 *)((char *)current + block_size);
|
||||
}
|
||||
|
||||
// No suitable block found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* mm_init - initialize the malloc package. */
|
||||
int mm_init(void) {
|
||||
// printf("\n");
|
||||
heap = mem_sbrk(3*AL);
|
||||
if (heap == (void *)-1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// printf("heap start: %p - %p\n", heap, ALIGN_ADDR(heap));
|
||||
t8 *plhd = heap;
|
||||
*plhd = (t8)SET_ALL1(2*AL);
|
||||
// printf("plhd start: %p - %p\n", plhd, ALIGN_ADDR(plhd));
|
||||
// printf("plhd value: %llu\n", GET_LENG(*plhd));
|
||||
// printf("plhd alloc: %llu\n", GET_ALLC(*plhd));
|
||||
|
||||
t8 *plft = heap+8;
|
||||
*plft = (t8)(2*AL);
|
||||
// printf("plft start: %p - %p\n", plft, ALIGN_ADDR(plft));
|
||||
// printf("plft value: %llu\n", GET_LENG(*plft));
|
||||
// printf("plft alloc: %llu\n", GET_ALLC(*plft));
|
||||
|
||||
t8 *elhd = heap+16;
|
||||
*elhd = SET_ALL1(0*AL);
|
||||
// printf("elhd start: %p - %p\n", elhd, ALIGN_ADDR(elhd));
|
||||
// printf("elhd value: %llu\n", GET_LENG(*elhd));
|
||||
// printf("elhd alloc: %llu\n", GET_ALLC(*elhd));
|
||||
|
||||
epil = elhd;
|
||||
// printf("epil start: %p - %p\n", epil, ALIGN_ADDR(epil));
|
||||
// printf("epil value: %llu\n", GET_LENG(*(t8 *)epil));
|
||||
// printf("epil alloc: %llu\n", GET_ALLC(*(t8 *)epil));
|
||||
|
||||
// printf("\n");
|
||||
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) {
|
||||
// printf("malloc: request for %u\n", size);
|
||||
int alsize = ALIGN(size);
|
||||
// printf("malloc: aligned to %lli\n", ALIGN((t8)size));
|
||||
int fbsize = alsize+(2*AL);
|
||||
// printf("malloc: full block size %i - %i\n", fbsize, ALIGN(fbsize));
|
||||
|
||||
void *chk = mem_sbrk(fbsize);
|
||||
if (chk == (void *)-1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t8 *newblock_hd = epil;
|
||||
*newblock_hd = (t8)SET_ALL1(fbsize);
|
||||
// printf("malloc: new block header starts %p - %p\n", newblock_hd, ALIGN_ADDR(newblock_hd));
|
||||
|
||||
void *newblock_pl = epil+8;
|
||||
// printf("malloc: new block payload starts %p - %p\n", newblock_pl, ALIGN_ADDR(newblock_pl));
|
||||
|
||||
t8 *newblock_ft = epil+8+alsize;
|
||||
*newblock_ft = (t8)SET_ALL0(fbsize);
|
||||
// printf("malloc: new block footer %p - %p\n", newblock_ft, ALIGN_ADDR(newblock_ft));
|
||||
|
||||
epil = epil+fbsize;
|
||||
t8 *nepil = epil;
|
||||
*nepil = (t8)(SET_ALL1(0));
|
||||
// printf("malloc: new epilogue %p - %p\n", epil, ALIGN_ADDR(epil));
|
||||
|
||||
// printf("\n");
|
||||
return newblock_pl;
|
||||
// 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) {
|
||||
if (ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Adjust pointer to get the header of the block
|
||||
t8 *block_header = (t8 *)ptr - 1;
|
||||
|
||||
// Mark the block as free
|
||||
*block_header = SET_ALL0(*block_header);
|
||||
|
||||
// Get the footer for the block
|
||||
size_t block_size = GET_LENG(*block_header);
|
||||
t8 *block_footer = (t8 *)((char *)block_header + block_size - sizeof(t8));
|
||||
*block_footer = *block_header;
|
||||
|
||||
// Try coalescing with previous block if it's free
|
||||
t8 *prev_footer = (t8 *)((char *)block_header - sizeof(t8));
|
||||
if (prev_footer >= (t8 *)mem_heap_lo() && !GET_ALLC(*prev_footer)) {
|
||||
size_t prev_size = GET_LENG(*prev_footer);
|
||||
t8 *prev_header = (t8 *)((char *)block_header - prev_size);
|
||||
|
||||
size_t new_size = prev_size + block_size;
|
||||
*prev_header = SET_ALL0(new_size);
|
||||
*block_footer = *prev_header;
|
||||
|
||||
block_header = prev_header;
|
||||
block_size = new_size;
|
||||
}
|
||||
|
||||
// Try coalescing with next block if it's free
|
||||
t8 *next_header = (t8 *)((char *)block_header + block_size);
|
||||
if (next_header < (t8 *)mem_heap_hi() && !GET_ALLC(*next_header)) {
|
||||
size_t next_size = GET_LENG(*next_header);
|
||||
t8 *next_footer = (t8 *)((char *)next_header + next_size - sizeof(t8));
|
||||
|
||||
size_t new_size = block_size + next_size;
|
||||
*block_header = SET_ALL0(new_size);
|
||||
*next_footer = *block_header;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
168
mm_v2.c
Executable file
168
mm_v2.c
Executable file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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 <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mm.h"
|
||||
#include "memlib.h"
|
||||
|
||||
team_t team = {
|
||||
/* Team name */
|
||||
"MA",
|
||||
/* First member's full name */
|
||||
"Marvin Aleksa",
|
||||
/* First member's email address */
|
||||
"marvin.aleksa@stud.uni-due.de",
|
||||
/* Second member's full name (leave blank if none) */
|
||||
"",
|
||||
/* Second member's email address (leave blank if none) */
|
||||
""
|
||||
};
|
||||
|
||||
typedef uint16_t t2; // 2 byte wide unsigned data type
|
||||
typedef uint32_t t4; // 4 byte wide unsigned data type
|
||||
typedef uint64_t t8; // 8 byte wide unsigned data type
|
||||
|
||||
typedef struct {
|
||||
uint32_t len;
|
||||
uint32_t plen;
|
||||
} Header;
|
||||
|
||||
/* single word (4) or double word (8) alignment */
|
||||
#define AL 8 // word length to align to
|
||||
#define HH 2048 // heap increase increment
|
||||
|
||||
/* rounds up to the nearest multiple of ALIGNMENT */
|
||||
#define ALIGN(size) (((size) + (AL-1)) & ~0x7)
|
||||
#define ALIGN_ADDR(addr) (void *)ALIGN((int)addr)
|
||||
#define SIZE_T_SIZE (ALIGN(sizeof(t8)))
|
||||
|
||||
#define SET_ALL0(x) ((x) & ~1)
|
||||
#define SET_ALL1(x) ((x) | 1)
|
||||
#define GET_LENG(x) ((x) & ~1)
|
||||
#define GET_ALLC(x) ((x) & 1)
|
||||
|
||||
void *heap = NULL;
|
||||
void *curs = NULL;
|
||||
|
||||
/* mm_init - initialize the malloc package. */
|
||||
int mm_init(void) {
|
||||
printf("\n");
|
||||
heap = mem_sbrk( HH );
|
||||
if (heap == (void *)-1) {
|
||||
return -1;
|
||||
}
|
||||
curs = heap;
|
||||
|
||||
printf("init -> first heap addr %p (%p)\n", mem_heap_lo(), ALIGN_ADDR(mem_heap_lo()));
|
||||
// printf("init -> first heap addr %p\n", heap);
|
||||
printf("init -> heap cursor at %p\n", curs);
|
||||
printf("init -> heap size %i\n", mem_heapsize());
|
||||
printf("init -> final heap addr %p\n", mem_heap_hi());
|
||||
|
||||
printf("\n");
|
||||
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 nbs = ALIGN(size); //new block size
|
||||
printf("malloc -> %i requested, aligned to %i\n", size, nbs);
|
||||
nbs += 2 * sizeof( t8 );
|
||||
printf("malloc -> extended to %i for overhead\n", nbs);
|
||||
if( ( nbs ) <= ( mem_heap_hi() - curs ) ){
|
||||
printf("malloc -> %i requested, %i available\n", nbs, ( mem_heap_hi() - curs ));
|
||||
printf("malloc -> heap size %i\n", mem_heapsize());
|
||||
} else {
|
||||
printf("malloc -> %i requested, %i available, allocating extra %i bytes\n", nbs, ( mem_heap_hi() - curs ), HH);
|
||||
printf("malloc -> new heap size %i\n", mem_heapsize());
|
||||
heap = mem_sbrk( HH );
|
||||
}
|
||||
|
||||
curs = curs + sizeof(t8) + size;
|
||||
|
||||
printf("\n");
|
||||
return curs;
|
||||
// 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) {
|
||||
if (ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Adjust pointer to get the header of the block
|
||||
t8 *block_header = (t8 *)ptr - 1;
|
||||
|
||||
// Mark the block as free
|
||||
*block_header = SET_ALL0(*block_header);
|
||||
|
||||
// Get the footer for the block
|
||||
size_t block_size = GET_LENG(*block_header);
|
||||
t8 *block_footer = (t8 *)((char *)block_header + block_size - sizeof(t8));
|
||||
*block_footer = *block_header;
|
||||
|
||||
// Try coalescing with previous block if it's free
|
||||
t8 *prev_footer = (t8 *)((char *)block_header - sizeof(t8));
|
||||
if (prev_footer >= (t8 *)mem_heap_lo() && !GET_ALLC(*prev_footer)) {
|
||||
size_t prev_size = GET_LENG(*prev_footer);
|
||||
t8 *prev_header = (t8 *)((char *)block_header - prev_size);
|
||||
|
||||
size_t new_size = prev_size + block_size;
|
||||
*prev_header = SET_ALL0(new_size);
|
||||
*block_footer = *prev_header;
|
||||
|
||||
block_header = prev_header;
|
||||
block_size = new_size;
|
||||
}
|
||||
|
||||
// Try coalescing with next block if it's free
|
||||
t8 *next_header = (t8 *)((char *)block_header + block_size);
|
||||
if (next_header < (t8 *)mem_heap_hi() && !GET_ALLC(*next_header)) {
|
||||
size_t next_size = GET_LENG(*next_header);
|
||||
t8 *next_footer = (t8 *)((char *)next_header + next_size - sizeof(t8));
|
||||
|
||||
size_t new_size = block_size + next_size;
|
||||
*block_header = SET_ALL0(new_size);
|
||||
*next_footer = *block_header;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
116
mm_v3.c
Executable file
116
mm_v3.c
Executable file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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 <stdint.h>
|
||||
|
||||
#include "mm.h"
|
||||
#include "memlib.h"
|
||||
|
||||
team_t team = {
|
||||
/* Team name */
|
||||
"MA",
|
||||
/* First member's full name */
|
||||
"Marvin Aleksa",
|
||||
/* First member's email address */
|
||||
"marvin.aleksa@stud.uni-due.de",
|
||||
/* Second member's full name (leave blank if none) */
|
||||
"",
|
||||
/* Second member's email address (leave blank if none) */
|
||||
""
|
||||
};
|
||||
|
||||
typedef uint32_t t4; // 4 byte wide unsigned data type
|
||||
typedef uint64_t t8; // 8 byte wide unsigned data type
|
||||
|
||||
typedef struct {
|
||||
uint32_t ln;
|
||||
void *nx;
|
||||
} Header;
|
||||
|
||||
/* single word (4) or double word (8) alignment */
|
||||
#define AL 8 // word length to align to
|
||||
#define PS 4096 // pagesize
|
||||
#define BS AL*1 // target block size
|
||||
|
||||
/* rounds up to the nearest multiple of ALIGNMENT */
|
||||
#define ALIGN(size) (((size) + (AL-1)) & ~0x7)
|
||||
#define ALIGN_ADDR(addr) (void *)ALIGN((int)addr)
|
||||
#define SIZE_T_SIZE (ALIGN(sizeof(t8)))
|
||||
|
||||
#define SET_ALL0(x) ((x) & ~1)
|
||||
#define SET_ALL1(x) ((x) | 1)
|
||||
#define GET_LENG(x) ((x) & ~1)
|
||||
#define GET_ALLC(x) ((x) & 1)
|
||||
|
||||
void *heap = NULL;
|
||||
|
||||
/* mm_init - initialize the malloc package. */
|
||||
int mm_init(void) {
|
||||
// printf("init -> allocating initial heap at %i bytes\n", PS);
|
||||
heap = mem_sbrk(PS);
|
||||
// printf("init -> heap starts at %u + %i bytes\n", mem_heap_lo(), mem_heapsize());
|
||||
// printf(" ends at %u\n", mem_heap_hi());
|
||||
|
||||
Header *first = heap;
|
||||
Header *final = mem_heap_hi();
|
||||
first->ln = SET_ALL1(16);
|
||||
first->nx = final;
|
||||
// printf("init -> first block at %u with ln %i and next %u\n", first, first->ln, first->nx);
|
||||
final->ln = SET_ALL1(0);
|
||||
final->nx = NULL;
|
||||
// printf("init -> final block at %u with ln %i and next %u\n", final, final->ln, final->nx);
|
||||
|
||||
|
||||
// printf("\n");
|
||||
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) {
|
||||
// printf("malloc -> %i requested, aligned to + overhead %i\n", size, ALIGN( size ) + 8);
|
||||
|
||||
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);
|
||||
}
|
||||
// printf("\n");
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
16
short1-bal.rep
Executable file
16
short1-bal.rep
Executable file
@@ -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
|
||||
16
short2-bal.rep
Executable file
16
short2-bal.rep
Executable file
@@ -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
|
||||
5698
traces/amptjp-bal.rep
Executable file
5698
traces/amptjp-bal.rep
Executable file
File diff suppressed because it is too large
Load Diff
12004
traces/binary-bal.rep
Executable file
12004
traces/binary-bal.rep
Executable file
File diff suppressed because it is too large
Load Diff
24004
traces/binary2-bal.rep
Executable file
24004
traces/binary2-bal.rep
Executable file
File diff suppressed because it is too large
Load Diff
5852
traces/cccp-bal.rep
Executable file
5852
traces/cccp-bal.rep
Executable file
File diff suppressed because it is too large
Load Diff
14404
traces/coalescing-bal.rep
Executable file
14404
traces/coalescing-bal.rep
Executable file
File diff suppressed because it is too large
Load Diff
6652
traces/cp-decl-bal.rep
Executable file
6652
traces/cp-decl-bal.rep
Executable file
File diff suppressed because it is too large
Load Diff
5384
traces/expr-bal.rep
Executable file
5384
traces/expr-bal.rep
Executable file
File diff suppressed because it is too large
Load Diff
4804
traces/random-bal.rep
Executable file
4804
traces/random-bal.rep
Executable file
File diff suppressed because it is too large
Load Diff
4804
traces/random2-bal.rep
Executable file
4804
traces/random2-bal.rep
Executable file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user