Commit 414018ea authored by Adam Blank's avatar Adam Blank
Browse files

Initial commit

parents
No related merge requests found
Showing with 1200 additions and 0 deletions
+1200 -0
#
# Makefile for the malloc lab driver
#
CC = clang
CFLAGS = -Werror -Wall -Wextra -O3 -g -DDRIVER
all: bin/mdriver-implicit bin/mdriver-explicit
bin/mdriver-implicit: out/mdriver-implicit.o out/mm-implicit.o out/memlib.o out/fsecs.o out/fcyc.o out/clock.o out/ftimer.o
$(CC) $(CFLAGS) $^ -o $@
bin/mdriver-explicit: out/mdriver-explicit.o out/mm-explicit.o out/memlib.o out/fsecs.o out/fcyc.o out/clock.o out/ftimer.o
$(CC) $(CFLAGS) $^ -o $@
out/mdriver-implicit.o: driver/mdriver.c
$(CC) $(CFLAGS) -c -DSTAGE0 $^ -o $@
out/mdriver-explicit.o: driver/mdriver.c
$(CC) $(CFLAGS) -c -DSTAGE1 $^ -o $@
out/%.o: src/%.c
$(CC) $(CFLAGS) -Iinclude -c $^ -o $@
out/%.o: driver/%.c
$(CC) $(CFLAGS) -c $^ -o $@
clean:
rm -f *~ out/*.o bin/*
/*
* clock.c - Routines for using the cycle counters on x86
*
* 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 <string.h>
#include <unistd.h>
#include <sys/times.h>
#include "clock.h"
/*******************************************************
* Machine dependent functions
*
* Note: the constants __i386__ and __x86_64__
* are set by GCC when it calls the C preprocessor
* You can verify this for yourself using gcc -v.
*******************************************************/
#if defined(__i386__) || defined(__x86_64__)
/*******************************************************
* 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" /* Put cycle counter in %edx:%eax */
: "=d" (*hi), "=a" (*lo));
}
/* 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 */
#else
#error Timer code requires x86
#endif
/*******************************
* Machine-independent functions
******************************/
/* $begin mhz */
/* Get the clock rate from /proc */
double mhz_full(int verbose, int sleeptime)
{
(void) sleeptime;
FILE *fp = fopen("/proc/cpuinfo", "r");
// Hack to keep this working on labradoodle.
double mhz = 2000.0;
fclose(fp);
if (verbose)
printf("Processor clock rate ~= %.1f MHz\n", mhz);
return mhz;
#if 0
double rate;
start_counter();
sleep(sleeptime);
rate = get_counter() / (1e6*sleeptime);
if (verbose)
printf("Processor clock rate ~= %.1f MHz\n", rate);
return rate;
#endif
}
/* $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;
}
/* Routines for using cycle counter */
/* Start the counter */
void start_counter();
/* Get # cycles since counter started */
double get_counter();
/* 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();
#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.
*
* The first four test correctness. The last several test utilization
* and performance.
*/
#define DEFAULT_TRACEFILES \
"corners.rep", \
"short2.rep", \
"malloc.rep", \
"coalescing-bal.rep", \
"fs.rep", \
"hostname.rep", \
"login.rep", \
"ls.rep", \
"perl.rep", \
"random-bal.rep", \
"rm.rep", \
"xterm.rep"
/*
* Students get 0 points for this point or below (ops / sec)
*/
#define MIN_SPEED 0E3
/*
* Students can get more points for building faster allocators, up to
* this point (in ops / sec)
*/
#define MAX_SPEED 40000E3
/*
* Students get 0 points for this allocation fraction or below
*/
#define MIN_SPACE 0.61
/*
* Students can get more points for building more efficient allocators,
* up to this point (1 is perfect).
*/
#define MAX_SPACE 0.85
/*
* Alignment requirement in bytes (either 4 or 8)
*/
#define ALIGNMENT 16
/*****************************************************************************
* Set exactly one of these USE_xxx constants to "1" to select a timing method
*****************************************************************************/
#define USE_FCYC 1 /* cycle counter w/K-best scheme (x86 & Alpha only) */
#define USE_ITIMER 0 /* interval timer (any Unix box) */
#define USE_GETTOD 0 /* gettimeofday (any Unix box) */
#endif /* __CONFIG_H */
/*
* 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"
#define UNSET (-1)
static int kbest = UNSET;
static int maxsamples = UNSET;
static double epsilon = UNSET;
static int compensate = UNSET;
static int clear_cache = UNSET;
static int cache_bytes = UNSET;
static int cache_block = UNSET;
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)
{
if (
kbest == UNSET ||
maxsamples == UNSET ||
epsilon == UNSET ||
compensate == UNSET ||
clear_cache == UNSET ||
(clear_cache && (cache_bytes == UNSET || cache_block == UNSET))
) {
fprintf(stderr, "fcyc parameters not set\n");
exit(1);
}
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;
}
/*
* 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);
/****************************
* 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)
{
#if USE_FCYC
if (verbose)
printf("Measuring performance with a cycle counter.\n");
/* set key parameters for the fcyc package */
set_fcyc_k(10);
set_fcyc_maxsamples(100);
set_fcyc_epsilon(0.01);
set_fcyc_compensate(0);
set_fcyc_clear_cache(1);
set_fcyc_cache_size(1 << 19);
set_fcyc_cache_block(64);
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
}
typedef void (*fsecs_test_funct)(void *);
void init_fsecs(void);
double fsecs(fsecs_test_funct f, void *argp);
/*
* 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);
}
/*
* 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);
This diff is collapsed.
#include <stddef.h>
void mem_init(void);
void mem_deinit(void);
void *mem_sbrk(ssize_t incr);
void mem_reset_brk(void);
void *mem_heap_lo(void);
void *mem_heap_hi(void);
size_t mem_heapsize(void);
#ifndef MM_H
#define MM_H
#include <stdio.h>
#include <stdbool.h>
extern bool 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);
extern void *mm_calloc(size_t nmemb, size_t size);
extern void mm_checkheap();
#endif /* MM_H */
/*
* 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 <stdint.h>
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include "memlib.h"
#define MAX_HEAP (100*(1<<20)) /* 100 MB */
/* private variables */
static uint8_t *heap;
static uint8_t *mem_brk;
/*
* mem_init - initialize the memory system model
*/
void mem_init() {
heap = mmap(
(void *) 0x800000000, /* suggested start*/
MAX_HEAP, /* length */
PROT_READ | PROT_WRITE, /* heap can be read or written */
MAP_PRIVATE | MAP_ANONYMOUS, /* initialize region with zeros */
-1, /* fd (unused) */
0 /* offset (unused) */
);
/* Fill heap with garbage since it is uninitialized. */
memset(heap, 0xCC, MAX_HEAP);
/* Heap is initially empty. */
mem_reset_brk();
}
/*
* mem_deinit - free the storage used by the memory system model
*/
void mem_deinit() {
munmap(heap, MAX_HEAP);
}
/*
* mem_reset_brk - reset the simulated brk pointer to make an empty heap
*/
void mem_reset_brk() {
mem_brk = heap;
}
/*
* 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(ssize_t incr) {
void *old_brk = mem_brk;
if (incr < 0 || mem_brk + incr > heap + MAX_HEAP) {
errno = ENOMEM;
fprintf(stderr, "ERROR: mem_sbrk failed. Ran out of memory...\n");
return (void *) -1;
}
mem_brk += incr;
return old_brk;
}
/*
* mem_heap_lo - return address of the first heap byte
*/
void *mem_heap_lo() {
return heap;
}
/*
* mem_heap_hi - return address of last heap byte
*/
void *mem_heap_hi()
{
return mem_brk - 1;
}
/*
* mem_heapsize() - returns the heap size in bytes
*/
size_t mem_heapsize()
{
return mem_brk - heap;
}
/*
* mm-implicit.c - The best malloc package EVAR!
*
* TODO (bug): mm_realloc and mm_calloc don't seem to be working...
* TODO (bug): The allocator doesn't re-use space very well...
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <unistd.h>
#include "mm.h"
#include "memlib.h"
typedef uint64_t word_t;
const size_t ALIGNMENT = 2 * sizeof(word_t);
typedef struct {
size_t header;
/*
* We don't know what the size of the payload will be, so we will
* declare it as a zero-length array. This allow us to obtain a
* pointer to the start of the payload.
*/
word_t payload[];
} block_t;
static block_t *mm_heap_first = NULL;
static block_t *mm_heap_last = NULL;
static size_t round_up(size_t size, size_t n) {
return n * ((size + (n-1)) / n);
}
static size_t get_size(block_t *block) {
return block->header & ~0x7;
}
static void set_header(block_t *block, size_t size, bool is_allocated) {
block->header = size | is_allocated;
}
static bool is_allocated(block_t *block) {
return block->header & 0x1;
}
block_t *find_fit(size_t size) {
for (block_t *curr = mm_heap_first; mm_heap_last && curr <= mm_heap_last; curr = ((void *)curr + get_size(curr))) {
size_t curr_size = get_size(curr);
if (!is_allocated(curr) && curr_size >= size) {
return curr;
}
}
return NULL;
}
bool mm_init(void) {
mm_heap_first = mem_sbrk(8);
set_header(mm_heap_first, 8, true);
mm_heap_last = NULL;
return true;
}
void *mm_malloc(size_t size) {
size_t asize = round_up(size + sizeof(word_t), ALIGNMENT);
block_t *block = find_fit(asize);
if (!block) {
void * ptr = mem_sbrk(asize);
if (ptr == (void *)-1) {
return NULL;
}
mm_heap_last = (block_t *)ptr;
block = mm_heap_last;
set_header(block, asize, true);
}
set_header(block, get_size(block), true);
return block->payload;
}
void mm_free(void *ptr) {
if (!ptr) {
return;
}
block_t *block = (block_t *)(ptr - offsetof(block_t, payload));
size_t block_size = get_size(block);
set_header(block, block_size, false);
}
/*
* mm_realloc - Change the size of the block by mm_mallocing a new block,
* copying its data, and mm_freeing the old block.
**/
void *mm_realloc(void *old_ptr, size_t size) {
(void)old_ptr;
(void)size;
return NULL;
}
/*
* mm_calloc - Allocate the block and set it to zero.
*/
void *mm_calloc(size_t nmemb, size_t size) {
(void)nmemb;
(void)size;
return NULL;
}
/*
* mm_checkheap - So simple, it doesn't need a checker!
*/
void mm_checkheap() {
}
/*
* mm-explicit.c - The best malloc package EVAR!
*
* TODO (bug): Uh..this is an implicit list???
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <unistd.h>
#include "mm.h"
#include "memlib.h"
typedef uint64_t word_t;
const size_t ALIGNMENT = 2 * sizeof(word_t);
typedef struct {
size_t header;
/*
* We don't know what the size of the payload will be, so we will
* declare it as a zero-length array. This allow us to obtain a
* pointer to the start of the payload.
*/
word_t payload[];
} block_t;
static block_t *mm_heap_first = NULL;
static block_t *mm_heap_last = NULL;
static size_t round_up(size_t size, size_t n) {
return n * ((size + (n-1)) / n);
}
static size_t get_size(block_t *block) {
return block->header & ~0x7;
}
static void set_header(block_t *block, size_t size, bool is_allocated) {
block->header = size | is_allocated;
}
static bool is_allocated(block_t *block) {
return block->header & 0x1;
}
block_t *find_fit(size_t size) {
for (block_t *curr = mm_heap_first; mm_heap_last && curr <= mm_heap_last; curr = ((void *)curr + get_size(curr))) {
size_t curr_size = get_size(curr);
if (!is_allocated(curr) && curr_size >= size) {
return curr;
}
}
return NULL;
}
bool mm_init(void) {
mm_heap_first = mem_sbrk(8);
set_header(mm_heap_first, 8, true);
mm_heap_last = NULL;
return true;
}
void *mm_malloc(size_t size) {
size_t asize = round_up(size + sizeof(word_t), ALIGNMENT);
block_t *block = find_fit(asize);
if (!block) {
void * ptr = mem_sbrk(asize);
if (ptr == (void *)-1) {
return NULL;
}
mm_heap_last = (block_t *)ptr;
block = mm_heap_last;
set_header(block, asize, true);
}
set_header(block, get_size(block), true);
return block->payload;
}
void mm_free(void *ptr) {
if (!ptr) {
return;
}
block_t *block = (block_t *)(ptr - offsetof(block_t, payload));
size_t block_size = get_size(block);
set_header(block, block_size, false);
}
/*
* mm_realloc - Change the size of the block by mm_mallocing a new block,
* copying its data, and mm_freeing the old block.
**/
void *mm_realloc(void *old_ptr, size_t size) {
(void)old_ptr;
(void)size;
return NULL;
}
/*
* mm_calloc - Allocate the block and set it to zero.
*/
void *mm_calloc(size_t nmemb, size_t size) {
(void)nmemb;
(void)size;
return NULL;
}
/*
* mm_checkheap - So simple, it doesn't need a checker!
*/
void mm_checkheap() {
}
This diff is collapsed.
0
11
15
0
f -1
a 1 1
a 2 2
a 3 3
a 4 4
a 5 100000
r 6 10
a 7 100
r 7 200
a 8 100
r 8 50
a 9 100
r 9 100
a 10 100
r 10 0
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment