csap-malloclab

298 阅读2分钟

隐式空闲链表

我是过了书本上的代码实现。writeup是英文版的,很多人可能不会注意到实验需要的trace文件是需要自己配置的。trace文件在这里。另外记得配置config.h文件。

config.h

#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",\
  "realloc-bal.rep",\
  "realloc2-bal.rep"

mm.c

#define WSIZE 4 //单字
#define DSIZE 8 //双字
#define CHUNKSIZE (1<<12) //当内存不够时,向内核申请的堆空间
#define GET(p) (*(unsigned int*)(p))
#define PUT(p, val) (*(unsigned int*)(p) = (val)) //将val放入p开始的4字节中
#define PACK(size, alloc) ((size) | (alloc)) //将块大小和分配为拼凑成字,可作为块的头部或脚部
#define GET_SIZE(p) (GET(p) & ~0x7) //从头部或脚部获取块的大小
#define GET_ALLOC(p) (GET(p) & 0x1) //从头部或脚部获取块的分配信息
#define HDRP(bp) ((char*)(bp) - WSIZE) //获得块的头部指针
#define FTRP(bp) ((char*)(bp) + GET_SIZE(HDRP(bp)) - DSIZE) //获得块的尾部指针
#define NEXT_BLKP(bp) ((char*)(bp) + GET_SIZE(HDRP(bp))) //获得下一个块的指针
#define PREV_BLKP(bp) ((char*)(bp) - GET_SIZE((char*)(bp) - DSIZE)) //获得上一个块的指针


#define MAX(x, y) ((x) > (y) ? (x) : (y))
/* 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)))


static char *heap_listp = 0; //指向第一个块的指针
#ifdef NEXT_FIT
static char *rover;
#endif

static void *extend_heap(size_t words);

static void place(void *bp, size_t asize);

static void *find_fit(size_t asize);

static void *coalesce(void *bp);

/*
 * mm_init - initialize the malloc package.
 */
int mm_init(void) {
    if ((heap_listp = mem_sbrk(4 * WSIZE)) == (void *) -1)
        return -1;
    PUT(heap_listp, 0); //未使用的堆的起始位置
    PUT(heap_listp + WSIZE, PACK(DSIZE, 1)); //序言块头部
    PUT(heap_listp + DSIZE, PACK(DSIZE, 1)); //序言块脚部
    PUT(heap_listp + 3 * WSIZE, PACK(0, 1)); //结尾块头部 结尾块只有头部
    heap_listp += (2 * WSIZE); //heap_listp指向第一个块的有效载荷的开始处
#ifdef NEXT_FIT
    rover = heap_listp;
#endif
    if (extend_heap(CHUNKSIZE / WSIZE) == NULL)
        return -1;
    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) {
    size_t asize;
    size_t extendsize;
    char *bp;
    if (heap_listp == 0) {
        mm_init();
    }

    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;
}

/*
 * mm_free - Freeing a block does nothing.
 */
void mm_free(void *bp) {
    if (bp == 0)
        return;
    size_t size = GET_SIZE(HDRP(bp));
    if (heap_listp == 0) {
        mm_init();
    }

    PUT(HDRP(bp), PACK(size, 0));
    PUT(FTRP(bp), PACK(size, 0));
    coalesce(bp);
}

/*
 * mm_realloc - Implemented simply in terms of mm_malloc and mm_free
 */
void *mm_realloc(void *bp, size_t size) {
    size_t oldsize;
    void *newbp;

    if (size == 0) {
        mm_free(bp);
        return 0;
    }

    if (bp == NULL) return mm_malloc(size);

    newbp = mm_malloc(size);

    if (!newbp) return 0;

    oldsize = GET_SIZE(HDRP(bp));
    if (size < oldsize) oldsize = size;
    memcpy(newbp, bp, oldsize);
    mm_free(bp);
    return newbp;
}

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)); // 释放块的头部
    PUT(FTRP(bp), PACK(size, 0)); // 释放块的脚部
    PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1)); // 设置新的结尾块头部

    return coalesce(bp); //执行合并函数
}

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);
    }
#ifdef NEXT_FIT
    if((rover > (char*)bp) && (rover < NEXT_BLKP(bp)))
        rover = bp;
#endif
    return bp;
}

//支持首次适配和下一个适配
static void *find_fit(size_t asize) {
#ifdef NEXT_FIT
    char *oldrover = rover;

    //从rover向后找
    for(; GET_SIZE(HDRP(rover)) > 0; rover = NEXT_BLKP(rover))
        if(!GET_ALLOC(HDRP(rover)) && (asize <= GET_SIZE(HDRP(rover))))
            return rover;

    //从heap_listp(第一个块的位置)到rover之间找
    for(rover = heap_listp; rover < oldrover; rover = NEXT_BLKP(rover))
        if(!GET_ALLOC(HDRP(rover)) && (asize <= GET_SIZE(HDRP(rover))))
            return rover;

    return NULL;
#else
    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;
#endif
}

//放置新块 如果新块足够大,则将新块分割成两块
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));
    }
}

首次适配和下一次适配的实验差异

首次适配

Results for mm malloc:
trace  valid  util     ops      secs  Kops
 0       yes   99%    5694  0.009491   600
 1       yes   99%    5848  0.008619   679
 2       yes   99%    6648  0.013775   483
 3       yes  100%    5380  0.009965   540
 4       yes   66%   14400  0.000297 48518
 5       yes   92%    4800  0.009877   486
 6       yes   92%    4800  0.008335   576
 7       yes   55%   12000  0.182477    66
 8       yes   51%   24000  0.338548    71
 9       yes   27%   14401  0.101787   141
10       yes   34%   14401  0.003621  3977
Total          74%  112372  0.686791   164

Perf index = 44 (util) + 11 (thru) = 55/100

下一次适配

Results for mm malloc:
trace  valid  util     ops      secs  Kops
 0       yes   91%    5694  0.002184  2607
 1       yes   92%    5848  0.002154  2714
 2       yes   95%    6648  0.005886  1129
 3       yes   97%    5380  0.004869  1105
 4       yes   66%   14400  0.000202 71181
 5       yes   91%    4800  0.006786   707
 6       yes   89%    4800  0.005889   815
 7       yes   55%   12000  0.018857   636
 8       yes   51%   24000  0.011408  2104
 9       yes   27%   14401  0.108006   133
10       yes   45%   14401  0.003796  3794
Total          73%  112372  0.170037   661

Perf index = 44 (util) + 40 (thru) = 84/100