This lab will leverage the same handout as before. You can also use your code from the prior lab as your starting point.
Edit the Makefile and change the following two lines
#Part 1
CPPFLAGS += -DMALLOC_LAB_IMPLICIT
#Part 2
#CPPFLAGS += -DMALLOC_LAB_EXPLICIT
You will only be modifying the mm.c
source code file. All other files should be left unchanged.
This should be functionally equivalent to your last lab; however, you must now change your implicit list to an explicit free list.
We must now manage next and free pointers which logically represent a doubly-linked list of free blocks. These pointers consume part of the payload of a free block. When a block is allocated, it will NOT have these pointers.
Here's a picture of how your heap may look after mm_init
.
root base
| |
v v
+---+---+---+---+---+---+---+---+---+---+---+---+
| | | | 4 |nextPtr|prevPtr| | 4 | 0 |
+---+---+---+---+---+---+---+---+---+---+---+---+
0 1 2 3 4 5 6
typedef uint32_t tag;
typedef uint64_t word;
typedef uint8_t byte;
typedef byte* address;
#define ALIGNMENT (2 * sizeof (word))
#define WORD_SIZE sizeof(word)
#define OVERHEAD (2 * sizeof (tag))
#define MIN_BLOCK_SIZE 4
static inline uint32_t sizeOf (tag* base) {
return *base & (uint32_t)-2;
}
static inline bool isAllocated (tag* base) {
return *base & (uint32_t)1;
}
static inline tag* header (address base) {
return (tag*)base - 1;
}
static inline tag* footer (address base) {
return (tag*)(base + sizeOf (header (base)) * sizeof (word) - 2 * sizeof (tag));
}
static inline address nextBlock (address base) {
return base + sizeOf (header(base)) * sizeof (word);
}
static inline tag* prevFooter (address base) {
return header(base) - 1;
}
static inline tag* nextHeader (address base) {
return footer(base) + 1;
}
static inline address prevBlock (address base) {
return base - sizeOf (prevFooter (base)) * sizeof(word);
}
static inline address* nextPtr (address base) {
return (address*)base;
}
static inline address* prevPtr (address base) {
return (address*)base + 1;
}
Dynamic memory allocators are notoriously tricky beasts to program correctly and efficiently. This is hard. They are difficult to program correctly because they involve a lot of untyped pointer manipulation. You will find it extremely useful to write a heap checker that scans the heap and checks it for consistency.
Some examples of what a heap checker might check are:
You are also tasked with writing a heap checker. It will consist of a single function located in mm.c
int mm_check(void);
The heap checker should check for any invariants or consistency conditions you consider prudent. It will return a non-zero value IFF your heap is consistent. You are not limited to the listed suggestions nor are you required to check all of them; however, you will be graded based on the quality of heap checker you choose to submit. Please note: it will also help reduced debugging time by iteratively writing it and adding error messages within mm_check
if it does fail.
This consistency checker is for your own debugging during development. When you submit mm.c
, be sure to remove any calls to mm_check
as they will slow down your throughput score.
I provide a nifty little tool called mdriver
which is capable of measuring your implementation for correctness, space utilization, and throughput. The driver program is controlled by a set of trace files which are located in my public directory. Each trace contains a sequence of allocation, reallocation, and free directions that instruct the driver to call your mm_malloc
, mm_realloc
, and mm_free
routines, respectively. Two “short” traces are provided as part of the handout tarball.
The driver driver
accepts the following command line arguments:
-f <tracefile>
— Run the driver with the specified trace file-h
— Print a summary of command line arguments-l
— Run and measure libc
’s implementation in addition to your own-v
— Verbose output. Prints a performance breakdown for each trace file in a compact table-V
— More verbose output. Prints additional diagnostic information as each trace file is processed. Useful during debugging for determining which trace file is causing your malloc package to fail.-g
— Enable auto-grading output. Note: on the Linux lab machines, this will only approximate your grade. Submit to Autolab to see your exact auto-graded score.mm.c
malloc
, calloc
, free
, realloc
, sbrk
, brk
, or any variants are forbidden.static
compound data structures such as arrays, structs, unions, trees, or lists in your mm.c
program. However, you are allowed to declare global scalar variables such as integers, floats, and pointers in mm.c
0
)You will receive a grade of zero if you break any of the aforementioned rules or if your code is buggy and crashes the driver. Otherwise your grade will be calculated as follows:
\[ P = wU + (1-w) min(1, \frac{T}{T_{libc}}) \]
U is space utilization
T is throughput
w is the weight in which to favor space utilization over throughput (w = 0.6)
Style (10 points) — Code properly decomposed into functions and use as few global variables as possible. Your code should begin with a header comment that describes the structure of your heap “data structure”. How does your allocator manipulate the free list? Each function should be preceded by a header comment that describes what the function does (and how it does it). Finally, your heap consistency checker mm_check
should be documented and well-commented.
To earn full credit on this lab, you must achieve a minimum utilization of 75% and throughput of 600Kops on autolab.
Upload/submit mm.c
to autolab
mdriver -f
to use tiny trace files to simplify debugging and testing. Two small trace files are included (short1-bal.rep
, short2-bal.rep
)mdriver
-v
and -V
options. The -v
option will give a detailed summary for each trace file. The -V
option will also indicate when each trace file is read (which will help with isolating errors).-g
and use a debugger (feel free to edit the Makefile as necessary).malloc
and free
to work with the sample files first.realloc
(start with a combination of malloc
and free
, then enhance)-pg
and run your program you can then run your program and run gprof <name-of-file.out>
. Invoke man gprof
for basic/simple usage and documentation