Bring in basecode from the development repo.
This commit is contained in:
commit
65b71e11e5
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
bin/
|
||||
build/
|
||||
*~
|
||||
*.out
|
29
.gitlab-ci.yml
Normal file
29
.gitlab-ci.yml
Normal file
|
@ -0,0 +1,29 @@
|
|||
image: hwrunner:latest
|
||||
variables:
|
||||
GIT_SSL_NO_VERIFY: "true"
|
||||
EXEC: sfmm
|
||||
HW_DIR: hw3
|
||||
CPU_LIMIT: 60
|
||||
FILE_LIMIT: 1000000
|
||||
before_script:
|
||||
- make clean all -C ${HW_DIR}
|
||||
stages:
|
||||
- build
|
||||
- run
|
||||
- test
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- echo "Build done"
|
||||
run:
|
||||
stage: run
|
||||
script:
|
||||
- ulimit -t ${CPU_LIMIT}
|
||||
- ulimit -f ${FILE_LIMIT}
|
||||
- cd ${HW_DIR} && bin/${EXEC}
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- ulimit -t ${CPU_LIMIT}
|
||||
- ulimit -f ${FILE_LIMIT}
|
||||
- cd ${HW_DIR} && bin/${EXEC}_tests -S --verbose=0 --timeout 30
|
58
hw3/Makefile
Normal file
58
hw3/Makefile
Normal file
|
@ -0,0 +1,58 @@
|
|||
CC := gcc
|
||||
SRCD := src
|
||||
TSTD := tests
|
||||
BLDD := build
|
||||
BIND := bin
|
||||
INCD := include
|
||||
LIBD := lib
|
||||
|
||||
ALL_SRCF := $(shell find $(SRCD) -type f -name *.c)
|
||||
ALL_LIBF := $(shell find $(LIBD) -type f -name *.o)
|
||||
ALL_OBJF := $(patsubst $(SRCD)/%,$(BLDD)/%,$(ALL_SRCF:.c=.o))
|
||||
FUNC_FILES := $(filter-out build/main.o, $(ALL_OBJF))
|
||||
|
||||
TEST_SRC := $(shell find $(TSTD) -type f -name *.c)
|
||||
|
||||
INC := -I $(INCD)
|
||||
|
||||
CFLAGS := -Wall -Werror -Wno-unused-function -MMD
|
||||
COLORF := -DCOLOR
|
||||
DFLAGS := -g -DDEBUG -DCOLOR
|
||||
PRINT_STAMENTS := -DERROR -DSUCCESS -DWARN -DINFO
|
||||
|
||||
STD := -std=c99
|
||||
TEST_LIB := -lcriterion
|
||||
LIBS := -lm
|
||||
|
||||
CFLAGS += $(STD)
|
||||
|
||||
EXEC := sfmm
|
||||
TEST := $(EXEC)_tests
|
||||
|
||||
.PHONY: clean all setup debug
|
||||
|
||||
all: setup $(BIND)/$(EXEC) $(BIND)/$(TEST)
|
||||
|
||||
debug: CFLAGS += $(DFLAGS) $(PRINT_STAMENTS) $(COLORF)
|
||||
debug: all
|
||||
|
||||
setup: $(BIND) $(BLDD)
|
||||
$(BIND):
|
||||
mkdir -p $(BIND)
|
||||
$(BLDD):
|
||||
mkdir -p $(BLDD)
|
||||
|
||||
$(BIND)/$(EXEC): $(ALL_OBJF) $(ALL_LIBF)
|
||||
$(CC) $^ -o $@ $(LIBS)
|
||||
|
||||
$(BIND)/$(TEST): $(FUNC_FILES) $(TEST_SRC) $(ALL_LIBF)
|
||||
$(CC) $(CFLAGS) $(INC) $(FUNC_FILES) $(TEST_SRC) $(ALL_LIBF) $(TEST_LIB) $(LIBS) -o $@
|
||||
|
||||
$(BLDD)/%.o: $(SRCD)/%.c
|
||||
$(CC) $(CFLAGS) $(INC) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf $(BLDD) $(BIND)
|
||||
|
||||
.PRECIOUS: $(BLDD)/*.d
|
||||
-include $(BLDD)/*.d
|
46
hw3/hw3.sublime-project
Normal file
46
hw3/hw3.sublime-project
Normal file
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"folders":
|
||||
[
|
||||
{
|
||||
"path":".",
|
||||
"name":"Project Base"
|
||||
},
|
||||
{
|
||||
"path": "src",
|
||||
"name": "C Source",
|
||||
"follow_symlinks": false,
|
||||
"file_include_patterns":["*.c"],
|
||||
},
|
||||
{
|
||||
"path": "include",
|
||||
"name": "C Headers",
|
||||
"follow_symlinks": false,
|
||||
"file_include_patterns":["*.h"],
|
||||
},
|
||||
{
|
||||
"path": "tests",
|
||||
"name": "Tests",
|
||||
}
|
||||
],
|
||||
"settings":
|
||||
{
|
||||
},
|
||||
"build_systems":
|
||||
[
|
||||
{
|
||||
"name": "Release (full build)",
|
||||
"working_dir":"$project_path",
|
||||
"shell_cmd": "make clean all",
|
||||
},
|
||||
{
|
||||
"name": "Debug (full build)",
|
||||
"working_dir":"$project_path",
|
||||
"shell_cmd": "make clean debug",
|
||||
},
|
||||
{
|
||||
"name": "Test",
|
||||
"working_dir":"$project_path",
|
||||
"shell_cmd": "bin/${project_base_name}_tests}",
|
||||
}
|
||||
]
|
||||
}
|
88
hw3/include/debug.h
Normal file
88
hw3/include/debug.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define NL "\n"
|
||||
|
||||
#ifdef COLOR
|
||||
#define KNRM "\033[0m"
|
||||
#define KRED "\033[1;31m"
|
||||
#define KGRN "\033[1;32m"
|
||||
#define KYEL "\033[1;33m"
|
||||
#define KBLU "\033[1;34m"
|
||||
#define KMAG "\033[1;35m"
|
||||
#define KCYN "\033[1;36m"
|
||||
#define KWHT "\033[1;37m"
|
||||
#define KBWN "\033[0;33m"
|
||||
#else
|
||||
#define KNRM ""
|
||||
#define KRED ""
|
||||
#define KGRN ""
|
||||
#define KYEL ""
|
||||
#define KBLU ""
|
||||
#define KMAG ""
|
||||
#define KCYN ""
|
||||
#define KWHT ""
|
||||
#define KBWN ""
|
||||
#endif
|
||||
|
||||
#ifdef VERBOSE
|
||||
#define DEBUG
|
||||
#define INFO
|
||||
#define WARN
|
||||
#define ERROR
|
||||
#define SUCCESS
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug(S, ...) \
|
||||
do { \
|
||||
fprintf(stderr, KMAG "DEBUG: %s:%s:%d " KNRM S NL, __FILE__, \
|
||||
__extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define debug(S, ...)
|
||||
#endif
|
||||
|
||||
#ifdef INFO
|
||||
#define info(S, ...) \
|
||||
do { \
|
||||
fprintf(stderr, KBLU "INFO: %s:%s:%d " KNRM S NL, __FILE__, \
|
||||
__extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define info(S, ...)
|
||||
#endif
|
||||
|
||||
#ifdef WARN
|
||||
#define warn(S, ...) \
|
||||
do { \
|
||||
fprintf(stderr, KYEL "WARN: %s:%s:%d " KNRM S NL, __FILE__, \
|
||||
__extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define warn(S, ...)
|
||||
#endif
|
||||
|
||||
#ifdef SUCCESS
|
||||
#define success(S, ...) \
|
||||
do { \
|
||||
fprintf(stderr, KGRN "SUCCESS: %s:%s:%d " KNRM S NL, __FILE__, \
|
||||
__extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define success(S, ...)
|
||||
#endif
|
||||
|
||||
#ifdef ERROR
|
||||
#define error(S, ...) \
|
||||
do { \
|
||||
fprintf(stderr, KRED "ERROR: %s:%s:%d " KNRM S NL, __FILE__, \
|
||||
__extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define error(S, ...)
|
||||
#endif
|
||||
|
||||
#endif /* DEBUG_H */
|
339
hw3/include/sfmm.h
Normal file
339
hw3/include/sfmm.h
Normal file
|
@ -0,0 +1,339 @@
|
|||
/**
|
||||
* === DO NOT MODIFY THIS FILE ===
|
||||
* If you need some other prototypes or constants in a header, please put them
|
||||
* in another header file.
|
||||
*
|
||||
* When we grade, we will be replacing this file with our own copy.
|
||||
* You have been warned.
|
||||
* === DO NOT MODIFY THIS FILE ===
|
||||
*/
|
||||
#ifndef SFMM_H
|
||||
#define SFMM_H
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
|
||||
Format of an allocated memory block
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
| 64-bit-wide row |
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
|
||||
+----------------------------+----------------------+--------+--------+---------+---------+ <- header
|
||||
| payload size | block_size | unused | alloc |prv alloc|in qklst |
|
||||
| (0/1) |(4 LSB's implicitly 0)| (0) | (1) | (0/1) | (0) |
|
||||
| (32 bits) | (28 bits) | 1 bit | 1 bit | 1 bit | 1 bit |
|
||||
+---------------------------------------------------+--------+--------+---------+---------+ <- (aligned)
|
||||
| |
|
||||
| Payload and Padding |
|
||||
| (N rows) |
|
||||
| |
|
||||
| |
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
|
||||
NOTE: For an allocated block, there is no footer (it is used for payload).
|
||||
NOTE: The actual stored header is obfuscated by bitwise XOR'ing with MAGIC.
|
||||
The above diagram shows the un-obfuscated contents.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Format of a memory block in a quick list
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
| 64-bit-wide row |
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
|
||||
+----------------------------+----------------------+--------+--------+---------+---------+ <- header
|
||||
| unused | block_size | unused | alloc |prv alloc|in qklst |
|
||||
| (0) |(4 LSB's implicitly 0)| (0) | (1) | (0/1) | (1) |
|
||||
| (32 bits) | (28 bits) | 1 bit | 1 bit | 1 bit | 1 bit |
|
||||
+---------------------------------------------------+--------+--------+---------+---------+ <- (aligned)
|
||||
| |
|
||||
| Payload and Padding |
|
||||
| (N rows) |
|
||||
| |
|
||||
| |
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
|
||||
NOTE: For a block in a quick list, there is no footer.
|
||||
*/
|
||||
|
||||
/*
|
||||
Format of a free memory block
|
||||
|
||||
|
||||
+----------------------------+----------------------+--------+--------+---------+---------+ <- header
|
||||
| unused | block_size | unused | alloc |prv alloc|in qklst |
|
||||
| (0) |(4 LSB's implicitly 0)| (0) | (0) | (0/1) | (0) |
|
||||
| (32 bits) | (28 bits) | 1 bit | 1 bit | 1 bit | 1 bit |
|
||||
+------------------------------------------------------------+--------+---------+---------+ <- (aligned)
|
||||
| |
|
||||
| Pointer to next free block |
|
||||
| (1 row) |
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
| |
|
||||
| Pointer to previous free block |
|
||||
| (1 row) |
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
| |
|
||||
| Unused |
|
||||
| (N rows) |
|
||||
| |
|
||||
| |
|
||||
+------------------------------------------------------------+--------+---------+---------+ <- footer
|
||||
| unused | block_size | unused | alloc |prv alloc|in qklst |
|
||||
| (0) |(4 LSB's implicitly 0)| (0) | (0) | (0/1) | (0) |
|
||||
| (32 bits) | (28 bits) | 1 bit | 1 bit | 1 bit | 1 bit |
|
||||
+------------------------------------------------------------+--------+---------+---------+ <- (aligned)
|
||||
|
||||
NOTE: For a free block, footer contents must always be identical to header contents.
|
||||
NOTE: The actual stored footer is obfuscated by bitwise XOR'ing with MAGIC.
|
||||
The above diagram shows the un-obfuscated contents.
|
||||
*/
|
||||
|
||||
#define IN_QUICK_LIST 0x1
|
||||
#define PREV_BLOCK_ALLOCATED 0x2
|
||||
#define THIS_BLOCK_ALLOCATED 0x4
|
||||
|
||||
typedef uint32_t sf_size_t;
|
||||
typedef uint64_t sf_header;
|
||||
typedef sf_header sf_footer;
|
||||
|
||||
/*
|
||||
* Structure of a block.
|
||||
* The first field of this structure is actually the footer of the *previous* block.
|
||||
* This must be taken into account when creating sf_block pointers from memory addresses.
|
||||
*/
|
||||
typedef struct sf_block {
|
||||
sf_footer prev_footer; // NOTE: This actually belongs to the *previous* block.
|
||||
sf_header header; // This is where the current block really starts.
|
||||
union {
|
||||
/* A free block contains links to other blocks in a free list. */
|
||||
struct {
|
||||
struct sf_block *next;
|
||||
struct sf_block *prev;
|
||||
} links;
|
||||
/* An allocated block contains a payload (aligned), starting here. */
|
||||
char payload[0]; // Length varies according to block size.
|
||||
} body;
|
||||
} sf_block;
|
||||
|
||||
/*
|
||||
* The heap is designed to keep the payload area of each block aligned to a two-row (16-byte)
|
||||
* boundary. The header of a block precedes the payload area, and is only single-row (8-byte)
|
||||
* aligned. The first block of the heap starts as soon as possible after the beginning of the
|
||||
* heap, subject to the condition that its payload area is two-row aligned.
|
||||
*/
|
||||
|
||||
/*
|
||||
Format of the heap
|
||||
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
| 64-bit-wide row |
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
|
||||
+-----------------------------------------------------------------------------------------+ <- heap start
|
||||
| | (aligned)
|
||||
| Unused |
|
||||
| (1 row) |
|
||||
+----------------------------+----------------------+--------+--------+---------+---------+ <- header
|
||||
| payload size |minimum block_size(32)| unused | alloc |prv alloc|in qklst |
|
||||
| (0) |(4 LSB's implicitly 0)| (0) | (1) | (0/1) | (0) | prologue block
|
||||
| (32 bits) | (28 bits) | 1 bit | 1 bit | 1 bit | 1 bit |
|
||||
+------------------------------------------------------------+--------+---------+---------+ <- (aligned)
|
||||
| |
|
||||
| Unused Payload Area |
|
||||
| (3 rows) |
|
||||
+------------------------------------------------------------+--------+---------+---------+ <- header
|
||||
| payload size | block_size | unused | alloc |prv alloc|in qklst |
|
||||
| (0/1) |(4 LSB's implicitly 0)| (0) | (0/1) | (0/1) | (0/1) | first block
|
||||
| (32 bits) | (28 bits) | 1 bit | 1 bit | 1 bit | 1 bit |
|
||||
+------------------------------------------------------------+--------+---------+---------+ <- (aligned)
|
||||
| |
|
||||
| Payload and Padding |
|
||||
| (N rows) |
|
||||
| |
|
||||
| |
|
||||
+--------------------------------------------+------------------------+---------+---------+
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| Additional allocated and free blocks |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
| payload size | block_size | unused | alloc |prv alloc|in qklst |
|
||||
| (0) | (0) | (0) | (1) | (0/1) | (0) | epilogue
|
||||
| (32 bits) | (28 bits) | 1 bit | 1 bit | 1 bit | 1 bit |
|
||||
+------------------------------------------------------------+--------+---------+---------+ <- heap_end
|
||||
(aligned)
|
||||
|
||||
NOTE: The actual stored epilogue is obfuscated by bitwise XOR'ing with MAGIC.
|
||||
The above diagram shows the un-obfuscated contents.
|
||||
*/
|
||||
|
||||
/* sf_errno: will be set on error */
|
||||
int sf_errno;
|
||||
|
||||
/*
|
||||
* "Quick lists": These are used to hold recently freed blocks of small sizes, so that they
|
||||
* can be used to satisfy allocations without searching lists or splitting blocks.
|
||||
* Blocks on a quick list are marked as allocated, so they are not available for coalescing.
|
||||
* The number of blocks in any individual quick list is limited to QUICK_LIST_MAX.
|
||||
* If adding a block to a quick list would cause it to exceed QUICK_LIST_MAX, then the
|
||||
* list is flushed, returning the existing blocks in the list to the main pool, and then
|
||||
* the block being freed is added to the now-empty list, leaving that list containing one block.
|
||||
*
|
||||
* The quick lists are indexed by (size-MIN_BLOCK_SIZE)/ALIGN_SIZE, starting with blocks of the
|
||||
* minimum block size at index 0, blocks of size MIN_BLOCK_SIZE+ALIGN_SIZE at index 1, and so on.
|
||||
* They are maintained as singly linked lists, using a LIFO discipline.
|
||||
*/
|
||||
|
||||
#define NUM_QUICK_LISTS 10 /* Number of quick lists. */
|
||||
#define QUICK_LIST_MAX 5 /* Maximum number of blocks permitted on a single quick list. */
|
||||
|
||||
struct {
|
||||
int length; // Number of blocks currently in the list.
|
||||
struct sf_block *first; // Pointer to first block in the list.
|
||||
} sf_quick_lists[NUM_QUICK_LISTS];
|
||||
|
||||
/*
|
||||
* Free blocks are maintained in a set of circular, doubly linked lists, segregated by
|
||||
* size class. The first list holds blocks of the minimum size M. The second list holds
|
||||
* blocks of size (M, 2M]. The third list holds blocks whose size is in the interval (2M, 4M].
|
||||
* The fourth list holds blocks whose size is in the interval (4M, 8M], and so on.
|
||||
* This continues up to the interval (128M, 256M], and then the last list holds all blocks
|
||||
* of size greater than 256M.
|
||||
*
|
||||
* Each of the circular, doubly linked lists has a "dummy" block used as the list header.
|
||||
* This dummy block is always linked between the last and the first element of the list.
|
||||
* In an empty list, the next and free pointers of the list header point back to itself.
|
||||
* In a list with something in it, the next pointer of the header points to the first node
|
||||
* in the list and the previous pointer of the header points to the last node in the list.
|
||||
* The header itself is never removed from the list and it contains no data (only the link
|
||||
* fields are used). The reason for doing things this way is to avoid edge cases in insertion
|
||||
* and deletion of nodes from the list.
|
||||
*/
|
||||
|
||||
#define NUM_FREE_LISTS 10
|
||||
struct sf_block sf_free_list_heads[NUM_FREE_LISTS];
|
||||
|
||||
/*
|
||||
* This is your implementation of sf_malloc. It acquires uninitialized memory that
|
||||
* is aligned and padded properly for the underlying system.
|
||||
*
|
||||
* @param size The number of bytes requested to be allocated.
|
||||
*
|
||||
* @return If size is 0, then NULL is returned without setting sf_errno.
|
||||
* If size is nonzero, then if the allocation is successful a pointer to a valid region of
|
||||
* memory of the requested size is returned. If the allocation is not successful, then
|
||||
* NULL is returned and sf_errno is set to ENOMEM.
|
||||
*/
|
||||
void *sf_malloc(sf_size_t size);
|
||||
|
||||
/*
|
||||
* Resizes the memory pointed to by ptr to size bytes.
|
||||
*
|
||||
* @param ptr Address of the memory region to resize.
|
||||
* @param size The minimum size to resize the memory to.
|
||||
*
|
||||
* @return If successful, the pointer to a valid region of memory is
|
||||
* returned, else NULL is returned and sf_errno is set appropriately.
|
||||
*
|
||||
* If sf_realloc is called with an invalid pointer sf_errno should be set to EINVAL.
|
||||
* If there is no memory available sf_realloc should set sf_errno to ENOMEM.
|
||||
*
|
||||
* If sf_realloc is called with a valid pointer and a size of 0 it should free
|
||||
* the allocated block and return NULL without setting sf_errno.
|
||||
*/
|
||||
void *sf_realloc(void *ptr, sf_size_t size);
|
||||
|
||||
/*
|
||||
* Marks a dynamically allocated region as no longer in use.
|
||||
* Adds the newly freed block to the free list.
|
||||
*
|
||||
* @param ptr Address of memory returned by the function sf_malloc.
|
||||
*
|
||||
* If ptr is invalid, the function calls abort() to exit the program.
|
||||
*/
|
||||
void sf_free(void *ptr);
|
||||
|
||||
/*
|
||||
* Get the current amount of internal fragmentation of the heap.
|
||||
*
|
||||
* @return the current amount of internal fragmentation, defined to be the
|
||||
* ratio of the total amount of payload to the total size of allocated blocks.
|
||||
* If there are no allocated blocks, then the returned value should be 0.0.
|
||||
*/
|
||||
double sf_internal_fragmentation();
|
||||
|
||||
/*
|
||||
* Get the peak memory utilization for the heap.
|
||||
*
|
||||
* @return the peak memory utilization over the interval starting from the
|
||||
* time the heap was initialized, up to the current time. The peak memory
|
||||
* utilization at a given time, as defined in the lecture and textbook,
|
||||
* is the ratio of the maximum aggregate payload up to that time, divided
|
||||
* by the current heap size. If the heap has not yet been initialized,
|
||||
* this function should return 0.0.
|
||||
*/
|
||||
double sf_peak_utilization();
|
||||
|
||||
|
||||
/* sfutil.c: Helper functions already created for this assignment. */
|
||||
|
||||
/*
|
||||
* @return The starting address of the heap for your allocator.
|
||||
*/
|
||||
void *sf_mem_start();
|
||||
|
||||
/*
|
||||
* @return The ending address of the heap for your allocator.
|
||||
*/
|
||||
void *sf_mem_end();
|
||||
|
||||
/*
|
||||
* This function increases the size of your heap by adding one page of
|
||||
* memory to the end.
|
||||
*
|
||||
* @return On success, this function returns a pointer to the start of the
|
||||
* additional page, which is the same as the value that would have been returned
|
||||
* by get_heap_end() before the size increase. On error, NULL is returned.
|
||||
*/
|
||||
void *sf_mem_grow();
|
||||
|
||||
/* The size of a page of memory returned by sf_mem_grow(). */
|
||||
#define PAGE_SZ ((sf_size_t)1024)
|
||||
|
||||
/*
|
||||
* @return The "magic number" used to obfuscate header and footer contents
|
||||
* to make it difficult to free a block without having first succesfully
|
||||
* malloc'ed one. To obtain the ability to turn off obfuscation using the
|
||||
* -DWEAK_MAGIC compilation flag, you should not call this function directly
|
||||
* but rather use the preprocessor symbol MAGIC where the magic number is
|
||||
* required.
|
||||
*/
|
||||
sf_header sf_magic();
|
||||
|
||||
/* Define WEAK_MAGIC during compilation to use MAGIC of 0x0 for debugging purposes. */
|
||||
#ifndef WEAK_MAGIC
|
||||
#define MAGIC (sf_magic())
|
||||
#else
|
||||
#define MAGIC ((sf_header)0x0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Display the contents of the heap in a human-readable form.
|
||||
*/
|
||||
void sf_show_block(sf_block *bp);
|
||||
void sf_show_blocks();
|
||||
void sf_show_free_list(int index);
|
||||
void sf_show_free_lists();
|
||||
void sf_show_quick_list(int index);
|
||||
void sf_show_quick_lists();
|
||||
void sf_show_heap();
|
||||
|
||||
#endif
|
BIN
hw3/lib/sfutil.o
Normal file
BIN
hw3/lib/sfutil.o
Normal file
Binary file not shown.
14
hw3/src/main.c
Normal file
14
hw3/src/main.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include <stdio.h>
|
||||
#include "sfmm.h"
|
||||
|
||||
int main(int argc, char const *argv[]) {
|
||||
double* ptr = sf_malloc(sizeof(double));
|
||||
|
||||
*ptr = 320320320e-320;
|
||||
|
||||
printf("%f\n", *ptr);
|
||||
|
||||
sf_free(ptr);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
34
hw3/src/sfmm.c
Normal file
34
hw3/src/sfmm.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* Do not submit your assignment with a main function in this file.
|
||||
* If you submit with a main function in this file, you will get a zero.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "debug.h"
|
||||
#include "sfmm.h"
|
||||
|
||||
void *sf_malloc(sf_size_t size) {
|
||||
// TO BE IMPLEMENTED
|
||||
abort();
|
||||
}
|
||||
|
||||
void sf_free(void *pp) {
|
||||
// TO BE IMPLEMENTED
|
||||
abort();
|
||||
}
|
||||
|
||||
void *sf_realloc(void *pp, sf_size_t rsize) {
|
||||
// TO BE IMPLEMENTED
|
||||
abort();
|
||||
}
|
||||
|
||||
double sf_internal_fragmentation() {
|
||||
// TO BE IMPLEMENTED
|
||||
abort();
|
||||
}
|
||||
|
||||
double sf_peak_utilization() {
|
||||
// TO BE IMPLEMENTED
|
||||
abort();
|
||||
}
|
260
hw3/tests/sfmm_tests.c
Normal file
260
hw3/tests/sfmm_tests.c
Normal file
|
@ -0,0 +1,260 @@
|
|||
#include <criterion/criterion.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include "debug.h"
|
||||
#include "sfmm.h"
|
||||
#define TEST_TIMEOUT 15
|
||||
|
||||
/*
|
||||
* Assert the total number of free blocks of a specified size.
|
||||
* If size == 0, then assert the total number of all free blocks.
|
||||
*/
|
||||
void assert_free_block_count(size_t size, int count) {
|
||||
int cnt = 0;
|
||||
for(int i = 0; i < NUM_FREE_LISTS; i++) {
|
||||
sf_block *bp = sf_free_list_heads[i].body.links.next;
|
||||
while(bp != &sf_free_list_heads[i]) {
|
||||
if(size == 0 || size == ((bp->header ^ MAGIC) & 0xfffffff0))
|
||||
cnt++;
|
||||
bp = bp->body.links.next;
|
||||
}
|
||||
}
|
||||
if(size == 0) {
|
||||
cr_assert_eq(cnt, count, "Wrong number of free blocks (exp=%d, found=%d)",
|
||||
count, cnt);
|
||||
} else {
|
||||
cr_assert_eq(cnt, count, "Wrong number of free blocks of size %ld (exp=%d, found=%d)",
|
||||
size, count, cnt);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Assert the total number of quick list blocks of a specified size.
|
||||
* If size == 0, then assert the total number of all quick list blocks.
|
||||
*/
|
||||
void assert_quick_list_block_count(size_t size, int count) {
|
||||
int cnt = 0;
|
||||
for(int i = 0; i < NUM_QUICK_LISTS; i++) {
|
||||
sf_block *bp = sf_quick_lists[i].first;
|
||||
while(bp != NULL) {
|
||||
if(size == 0 || size == ((bp->header ^ MAGIC) & 0xfffffff0)) {
|
||||
cnt++;
|
||||
if(size != 0) {
|
||||
// Check that the block is in the correct list for its size.
|
||||
int index = (size - 32) >> 4;
|
||||
cr_assert_eq(index, i, "Block %p (size %ld) is in wrong quick list for its size "
|
||||
"(expected %d, was %d)",
|
||||
&bp->header, (bp->header ^ MAGIC) & 0xfffffff0, index, i);
|
||||
}
|
||||
}
|
||||
bp = bp->body.links.next;
|
||||
}
|
||||
}
|
||||
if(size == 0) {
|
||||
cr_assert_eq(cnt, count, "Wrong number of quick list blocks (exp=%d, found=%d)",
|
||||
count, cnt);
|
||||
} else {
|
||||
cr_assert_eq(cnt, count, "Wrong number of quick list blocks of size %ld (exp=%d, found=%d)",
|
||||
size, count, cnt);
|
||||
}
|
||||
}
|
||||
|
||||
Test(sfmm_basecode_suite, malloc_an_int, .timeout = TEST_TIMEOUT) {
|
||||
sf_errno = 0;
|
||||
size_t sz = sizeof(int);
|
||||
int *x = sf_malloc(sz);
|
||||
|
||||
cr_assert_not_null(x, "x is NULL!");
|
||||
|
||||
*x = 4;
|
||||
|
||||
cr_assert(*x == 4, "sf_malloc failed to give proper space for an int!");
|
||||
sf_block *bp = (sf_block *)((char *)x - 16);
|
||||
cr_assert((bp->header >> 32) & 0xffffffff,
|
||||
"Malloc'ed block payload size (%ld) not what was expected (%ld)!",
|
||||
(bp->header >> 32) & 0xffffffff, sz);
|
||||
|
||||
assert_quick_list_block_count(0, 0);
|
||||
assert_free_block_count(0, 1);
|
||||
assert_free_block_count(944, 1);
|
||||
|
||||
cr_assert(sf_errno == 0, "sf_errno is not zero!");
|
||||
cr_assert(sf_mem_start() + PAGE_SZ == sf_mem_end(), "Allocated more than necessary!");
|
||||
}
|
||||
|
||||
Test(sfmm_basecode_suite, malloc_four_pages, .timeout = TEST_TIMEOUT) {
|
||||
sf_errno = 0;
|
||||
|
||||
void *x = sf_malloc(4032);
|
||||
cr_assert_not_null(x, "x is NULL!");
|
||||
assert_quick_list_block_count(0, 0);
|
||||
assert_free_block_count(0, 0);
|
||||
cr_assert(sf_errno == 0, "sf_errno is not 0!");
|
||||
}
|
||||
|
||||
Test(sfmm_basecode_suite, malloc_too_large, .timeout = TEST_TIMEOUT) {
|
||||
sf_errno = 0;
|
||||
void *x = sf_malloc(98304);
|
||||
|
||||
cr_assert_null(x, "x is not NULL!");
|
||||
assert_quick_list_block_count(0, 0);
|
||||
assert_free_block_count(0, 1);
|
||||
assert_free_block_count(24528, 1);
|
||||
cr_assert(sf_errno == ENOMEM, "sf_errno is not ENOMEM!");
|
||||
}
|
||||
|
||||
Test(sfmm_basecode_suite, free_quick, .timeout = TEST_TIMEOUT) {
|
||||
sf_errno = 0;
|
||||
size_t sz_x = 8, sz_y = 32, sz_z = 1;
|
||||
/* void *x = */ sf_malloc(sz_x);
|
||||
void *y = sf_malloc(sz_y);
|
||||
/* void *z = */ sf_malloc(sz_z);
|
||||
|
||||
sf_free(y);
|
||||
|
||||
assert_quick_list_block_count(0, 1);
|
||||
assert_quick_list_block_count(48, 1);
|
||||
assert_free_block_count(0, 1);
|
||||
assert_free_block_count(864, 1);
|
||||
cr_assert(sf_errno == 0, "sf_errno is not zero!");
|
||||
}
|
||||
|
||||
Test(sfmm_basecode_suite, free_no_coalesce, .timeout = TEST_TIMEOUT) {
|
||||
sf_errno = 0;
|
||||
size_t sz_x = 8, sz_y = 200, sz_z = 1;
|
||||
/* void *x = */ sf_malloc(sz_x);
|
||||
void *y = sf_malloc(sz_y);
|
||||
/* void *z = */ sf_malloc(sz_z);
|
||||
|
||||
sf_free(y);
|
||||
|
||||
assert_quick_list_block_count(0, 0);
|
||||
assert_free_block_count(0, 2);
|
||||
assert_free_block_count(224, 1);
|
||||
assert_free_block_count(688, 1);
|
||||
|
||||
cr_assert(sf_errno == 0, "sf_errno is not zero!");
|
||||
}
|
||||
|
||||
Test(sfmm_basecode_suite, free_coalesce, .timeout = TEST_TIMEOUT) {
|
||||
sf_errno = 0;
|
||||
size_t sz_w = 8, sz_x = 200, sz_y = 300, sz_z = 4;
|
||||
/* void *w = */ sf_malloc(sz_w);
|
||||
void *x = sf_malloc(sz_x);
|
||||
void *y = sf_malloc(sz_y);
|
||||
/* void *z = */ sf_malloc(sz_z);
|
||||
|
||||
sf_free(y);
|
||||
sf_free(x);
|
||||
|
||||
assert_quick_list_block_count(0, 0);
|
||||
assert_free_block_count(0, 2);
|
||||
assert_free_block_count(368, 1);
|
||||
assert_free_block_count(544, 1);
|
||||
|
||||
cr_assert(sf_errno == 0, "sf_errno is not zero!");
|
||||
}
|
||||
|
||||
Test(sfmm_basecode_suite, freelist, .timeout = TEST_TIMEOUT) {
|
||||
size_t sz_u = 200, sz_v = 150, sz_w = 50, sz_x = 150, sz_y = 200, sz_z = 250;
|
||||
void *u = sf_malloc(sz_u);
|
||||
/* void *v = */ sf_malloc(sz_v);
|
||||
void *w = sf_malloc(sz_w);
|
||||
/* void *x = */ sf_malloc(sz_x);
|
||||
void *y = sf_malloc(sz_y);
|
||||
/* void *z = */ sf_malloc(sz_z);
|
||||
|
||||
sf_free(u);
|
||||
sf_free(w);
|
||||
sf_free(y);
|
||||
|
||||
assert_quick_list_block_count(0, 1);
|
||||
assert_free_block_count(0, 3);
|
||||
assert_free_block_count(224, 2);
|
||||
assert_free_block_count(848, 1);
|
||||
|
||||
// First block in list should be the most recently freed block not in quick list.
|
||||
int i = 3;
|
||||
sf_block *bp = sf_free_list_heads[i].body.links.next;
|
||||
cr_assert_eq(&bp->header, (char *)y - 8,
|
||||
"Wrong first block in free list %d: (found=%p, exp=%p)",
|
||||
i, &bp->header, (char *)y - 8);
|
||||
}
|
||||
|
||||
Test(sfmm_basecode_suite, realloc_larger_block, .timeout = TEST_TIMEOUT) {
|
||||
size_t sz_x = sizeof(int), sz_y = 10, sz_x1 = sizeof(int) * 20;
|
||||
void *x = sf_malloc(sz_x);
|
||||
/* void *y = */ sf_malloc(sz_y);
|
||||
x = sf_realloc(x, sz_x1);
|
||||
|
||||
cr_assert_not_null(x, "x is NULL!");
|
||||
sf_block *bp = (sf_block *)((char *)x - 16);
|
||||
cr_assert((bp->header ^ MAGIC) & THIS_BLOCK_ALLOCATED, "Allocated bit is not set!");
|
||||
cr_assert(((bp->header ^ MAGIC) & 0xfffffff0) == 96,
|
||||
"Realloc'ed block size (%ld) not what was expected (%ld)!",
|
||||
(bp->header ^ MAGIC) & 0xfffffff0, 96);
|
||||
cr_assert((((bp->header ^ MAGIC) >> 32) & 0xffffffff) == sz_x1,
|
||||
"Realloc'ed block payload size (%ld) not what was expected (%ld)!",
|
||||
(((bp->header ^ MAGIC) >> 32) & 0xffffffff), sz_x1);
|
||||
|
||||
assert_quick_list_block_count(0, 1);
|
||||
assert_quick_list_block_count(32, 1);
|
||||
assert_free_block_count(0, 1);
|
||||
assert_free_block_count(816, 1);
|
||||
}
|
||||
|
||||
Test(sfmm_basecode_suite, realloc_smaller_block_splinter, .timeout = TEST_TIMEOUT) {
|
||||
size_t sz_x = sizeof(int) * 20, sz_y = sizeof(int) * 16;
|
||||
void *x = sf_malloc(sz_x);
|
||||
void *y = sf_realloc(x, sz_y);
|
||||
|
||||
cr_assert_not_null(y, "y is NULL!");
|
||||
cr_assert(x == y, "Payload addresses are different!");
|
||||
|
||||
sf_block *bp = (sf_block *)((char *)x - 16);
|
||||
cr_assert((bp->header ^ MAGIC) & THIS_BLOCK_ALLOCATED, "Allocated bit is not set!");
|
||||
cr_assert(((bp->header ^ MAGIC) & 0xfffffff0) == 96,
|
||||
"Realloc'ed block size (%ld) not what was expected (%ld)!",
|
||||
(bp->header ^ MAGIC) & 0xfffffff0, 96);
|
||||
cr_assert((((bp->header ^ MAGIC) >> 32) & 0xffffffff) == sz_y,
|
||||
"Realloc'ed block payload size (%ld) not what was expected (%ld)!",
|
||||
(((bp->header ^ MAGIC) >> 32) & 0xffffffff), sz_y);
|
||||
|
||||
// There should be only one free block.
|
||||
assert_quick_list_block_count(0, 0);
|
||||
assert_free_block_count(0, 1);
|
||||
assert_free_block_count(880, 1);
|
||||
}
|
||||
|
||||
Test(sfmm_basecode_suite, realloc_smaller_block_free_block, .timeout = TEST_TIMEOUT) {
|
||||
size_t sz_x = sizeof(double) * 8, sz_y = sizeof(int);
|
||||
void *x = sf_malloc(sz_x);
|
||||
void *y = sf_realloc(x, sz_y);
|
||||
|
||||
cr_assert_not_null(y, "y is NULL!");
|
||||
|
||||
sf_block *bp = (sf_block *)((char *)x - 16);
|
||||
cr_assert((bp->header ^ MAGIC) & THIS_BLOCK_ALLOCATED, "Allocated bit is not set!");
|
||||
cr_assert(((bp->header ^ MAGIC) & 0xfffffff0) == 32,
|
||||
"Realloc'ed block size (%ld) not what was expected (%ld)!",
|
||||
(bp->header ^ MAGIC) & 0xfffffff0, 32);
|
||||
cr_assert((((bp->header ^ MAGIC) >> 32) & 0xffffffff) == sz_y,
|
||||
"Realloc'ed block payload size (%ld) not what was expected (%ld)!",
|
||||
(((bp->header ^ MAGIC) >> 32) & 0xffffffff), sz_y);
|
||||
|
||||
// After realloc'ing x, we can return a block of size 48
|
||||
// to the freelist. This block will go into the main freelist and be coalesced.
|
||||
// Note that we don't put split blocks into the quick lists because their sizes are not sizes
|
||||
// that were requested by the client, so they are not very likely to satisfy a new request.
|
||||
assert_quick_list_block_count(0, 0);
|
||||
assert_free_block_count(0, 1);
|
||||
assert_free_block_count(944, 1);
|
||||
}
|
||||
|
||||
//############################################
|
||||
//STUDENT UNIT TESTS SHOULD BE WRITTEN BELOW
|
||||
//DO NOT DELETE THESE COMMENTS
|
||||
//############################################
|
||||
|
||||
//Test(sfmm_student_suite, student_test_1, .timeout = TEST_TIMEOUT) {
|
||||
//}
|
Loading…
Reference in New Issue
Block a user