Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
services:
default:
image: gcc:12
init: true
command: tail -f /dev/null
working_dir: /workspace
network_mode: bridge
cpus: '0.5'
mem_limit: 512mb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"instance_id": "cmu_15-213__malloc_lab",
"course_id": "cmu_15-213",
"timeout_minutes": 20,
"tags": ["c", "malloc", "memory", "systems"],
"artifacts": [
"mm.c",
"mdriver",
"*.log"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/bin/bash
set -euo pipefail

# Verify read-only files were not modified by the agent.
if [ -f .readonly_hashes ]; then
if ! sha256sum -c .readonly_hashes > /dev/null 2>&1; then
echo "FAIL: read-only files were modified"
exit 1
fi
fi

make clean > /dev/null 2>&1 || true
make > /dev/null 2>&1

MIN_PERF=100

for trace in short1-bal.rep short2-bal.rep; do
echo "=== Running $trace ==="
OUTPUT=$(./mdriver -V -f "$trace" 2>&1)
echo "$OUTPUT"

# Extract "Perf index = ... = XX/100" from mdriver output
PERF=$(echo "$OUTPUT" | grep -oP 'Perf index = .* = \K[0-9]+(?=/100)')
if [ -z "$PERF" ]; then
echo "FAIL: could not parse Perf index from $trace"
exit 1
fi
if [ "$PERF" -lt "$MIN_PERF" ]; then
echo "FAIL: $trace Perf index $PERF < $MIN_PERF"
exit 1
fi
echo "OK: $trace Perf index $PERF >= $MIN_PERF"
done

echo "PASS: malloc lab traces passed"
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash
set -euo pipefail

# Ensure the lab builds on 64-bit toolchains by removing -m32.
if grep -q "-m32" Makefile; then
sed -i "s/ -m32//g" Makefile
fi

# Hash all read-only files to detect tampering during evaluation.
# Only mm.c may be modified by the student.
sha256sum \
Makefile mdriver.c memlib.c memlib.h mm.h config.h \
clock.c clock.h fcyc.c fcyc.h fsecs.c fsecs.h ftimer.c ftimer.h \
short1-bal.rep short2-bal.rep \
> .readonly_hashes
214 changes: 214 additions & 0 deletions benchmarks/courselab_bench/data/cmu_15-213/task_malloc_lab/sol.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
#!/bin/bash
set -euo pipefail

# Reference solution script: write a correct implicit-free-list allocator,
# build, and run all traces.
cat > mm.c << 'EOF'
/*
* mm.c - Implicit free list allocator with boundary tags and coalescing.
*
* Each block has a header and footer containing the block size and
* an allocated/free bit. The list is searched using first-fit.
* Free blocks are coalesced immediately upon being freed.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>

#include "mm.h"
#include "memlib.h"

team_t team = {
"ref_team",
"Reference Solution",
"[email protected]",
"",
""
};

/* Basic constants and macros */
#define WSIZE 4 /* Word and header/footer size (bytes) */
#define DSIZE 8 /* Double word size (bytes) */
#define CHUNKSIZE (1<<12) /* Extend heap by this amount (bytes) */
#define ALIGNMENT 8

#define MAX(x, y) ((x) > (y) ? (x) : (y))

/* Pack a size and allocated bit into a word */
#define PACK(size, alloc) ((size) | (alloc))

/* Read and write a word at address p */
#define GET(p) (*(unsigned int *)(p))
#define PUT(p, val) (*(unsigned int *)(p) = (val))

/* Read the size and allocated fields from address p */
#define GET_SIZE(p) (GET(p) & ~0x7)
#define GET_ALLOC(p) (GET(p) & 0x1)

/* Given block ptr bp, compute address of its header and footer */
#define HDRP(bp) ((char *)(bp) - WSIZE)
#define FTRP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE)

/* Given block ptr bp, compute address of next and previous blocks */
#define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE)))
#define PREV_BLKP(bp) ((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE)))

static char *heap_listp;

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) {
return bp;
}
else if (prev_alloc && !next_alloc) {
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) {
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 {
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;
}

static void *extend_heap(size_t words)
{
char *bp;
size_t size;

size = (words % 2) ? (words + 1) * WSIZE : words * WSIZE;
if ((long)(bp = mem_sbrk(size)) == -1)
return NULL;

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 */

return coalesce(bp);
}

int mm_init(void)
{
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);

if (extend_heap(CHUNKSIZE / WSIZE) == NULL)
return -1;
return 0;
}

static void *find_fit(size_t asize)
{
void *bp;
for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)) {
if (!GET_ALLOC(HDRP(bp)) && (asize <= GET_SIZE(HDRP(bp))))
return bp;
}
return NULL;
}

static void place(void *bp, size_t asize)
{
size_t csize = GET_SIZE(HDRP(bp));

if ((csize - asize) >= (2 * DSIZE)) {
PUT(HDRP(bp), PACK(asize, 1));
PUT(FTRP(bp), PACK(asize, 1));
bp = NEXT_BLKP(bp);
PUT(HDRP(bp), PACK(csize - asize, 0));
PUT(FTRP(bp), PACK(csize - asize, 0));
}
else {
PUT(HDRP(bp), PACK(csize, 1));
PUT(FTRP(bp), PACK(csize, 1));
}
}

void *mm_malloc(size_t size)
{
size_t asize;
size_t extendsize;
char *bp;

if (size == 0)
return NULL;

if (size <= DSIZE)
asize = 2 * DSIZE;
else
asize = DSIZE * ((size + DSIZE + (DSIZE - 1)) / DSIZE);

if ((bp = find_fit(asize)) != NULL) {
place(bp, asize);
return bp;
}

extendsize = MAX(asize, CHUNKSIZE);
if ((bp = extend_heap(extendsize / WSIZE)) == NULL)
return NULL;
place(bp, asize);
return bp;
}

void mm_free(void *ptr)
{
size_t size = GET_SIZE(HDRP(ptr));
PUT(HDRP(ptr), PACK(size, 0));
PUT(FTRP(ptr), PACK(size, 0));
coalesce(ptr);
}

void *mm_realloc(void *ptr, size_t size)
{
void *newptr;
size_t copySize;

if (ptr == NULL)
return mm_malloc(size);
if (size == 0) {
mm_free(ptr);
return NULL;
}

newptr = mm_malloc(size);
if (newptr == NULL)
return NULL;
copySize = GET_SIZE(HDRP(ptr)) - DSIZE;
if (size < copySize)
copySize = size;
memcpy(newptr, ptr, copySize);
mm_free(ptr);
return newptr;
}
EOF

make clean > /dev/null 2>&1 || true
make > /dev/null 2>&1

TRACES="short1-bal.rep short2-bal.rep alloc_reuse-bal.rep coalesce-bal.rep"
for trace in $TRACES; do
./mdriver -f "$trace" > /dev/null 2>&1
done

echo "PASS: reference solution completed"
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#
# Students' Makefile for the Malloc Lab
#
TEAM = bovik
VERSION = 1
HANDINDIR = /afs/cs.cmu.edu/academic/class/15213-f01/malloclab/handin

CC = gcc
CFLAGS = -Wall -O2

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


Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#####################################################################
# CS:APP Malloc Lab
# Directions to Instructors
#
# Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved.
# May not be used, modified, or copied without permission.
#
######################################################################

This directory contains the files that you will need to run the CS:APP
malloc lab, which develops a student's understanding of pointers,
system-level programming, and memory managment.

************
1. Overview
************

In this lab, students write their own storage allocator, in particular
implementations of the malloc, free, and realloc functions. A
trace-driven driver (mdriver) evaluates the quality of the student's
implementation in terms of space utilization and throughput.
Loading
Loading