/********************************************************** * find_fit * Traverse the heap searching for a block to fit asize * Return NULL if no free blocks can handle that size * Assumed that asize is aligned * Uses fit bit option * If we find a block that is close to the request size (4*sizethreshold) * we will use that block * If we can't find a block close to request size then we return the closest * size and split the block before using it **********************************************************/ void * find_fit(size_t asize, int *list_broken) { if(asize>maxBlockSize1) return NULL; size_t bestfit = mem_heapsize(); size_t curfit; void *bestfitptr = NULL; void *free_bp; int sizethreshold = 2*DSIZE; for (free_bp = free_listp; free_bp != NULL; free_bp = *((void **)free_bp)) { if (asize <= GET_SIZE(HDRP(free_bp))) { curfit = GET_SIZE(HDRP(free_bp)) - asize; if (curfit < 4*sizethreshold) { bestfitptr = free_bp; break; } if (curfit < bestfit) { bestfit = curfit; bestfitptr = free_bp; } } } if ((bestfitptr != NULL) && (GET_SIZE(HDRP(bestfitptr)) - asize >= sizethreshold)) { bestfitptr = split_block (bestfitptr, asize); *list_broken = 1; } return bestfitptr; }
// Return a pointer to the memory malloc should return static inline uint32_t* block_mem(uint32_t* const block) { REQUIRES(block != NULL); REQUIRES(in_heap(block)); REQUIRES(aligned(block + 1)); if (VERBOSE) printf("Heap size = %d bytes \n", (int)mem_heapsize()); return block + 1; }
/* * 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(int incr) { char *old_brk = __sync_fetch_and_add(&mem_brk, incr); if ((incr < 0) || (mem_brk > mem_max_addr)) { errno = ENOMEM; fprintf(stderr, "ERROR: mem_sbrk failed. Ran out of memory... (%ld)\n", mem_heapsize()); __sync_fetch_and_add(&mem_brk, -incr); return (void *)-1; } return (void *)old_brk; }
/* check_heap - Check the heap for consistency etc. Convenient to manually call while running GDB but is not called otherwise */ void check_heap() { listBlock* ptr; int *footer; listBlock* heapStart = (listBlock*)mem_heap_lo(); listBlock* heapEnd = (listBlock*)mem_heap_hi(); printf("Address Block size Allocated\n"); ptr = heapStart; while (ptr < heapEnd) { footer = (int *)(((char *)ptr) + (ptr->header&~0x1) - WORD_SIZE); printf("%5p%14d%12d%10s\n", ptr, (int)(ptr->header & ~0x1), ptr->header & 0x1, ptr->header == *footer?"OK":"corrupt"); ptr = (listBlock*)((char*)ptr + (ptr->header & ~0x1)); } printf("Heap Size Total: %5d\n", (int)mem_heapsize()); }
static void *extend_heap(size_t words) //extend heap { char *bp; size_t size; size = (words % 2) ? (words + 1)*WSIZE : words * WSIZE; #ifdef __DEBUG__ fprintf(stderr, "Extending heap by %u...\n",size); printf("Heap size now : %u\n",mem_heapsize()); #endif if((long)(bp = mem_sbrk(size)) == -1) return NULL; //sbrk : gathering moar spaces set(getBlockHeader(bp), setMask(size, 0)); set(getBlockFooter(bp), setMask(size, 0)); set(getBlockHeader(getNextBlock(bp)), setMask(0, 1)); push_back(size, bp); //empty block to the list void* result = coalesce(bp); //coalesces! // push_back(getSize(getBlockHeader(result)), result); return result; }
/* * findFit * findFit finds a free block that has size at least asize bytes. * It uses an algorithm that is a slight combination of best fit * and first fit. The function traverses the list from the free_listp * and once it hits a free block of large enough size we traverse a * CONSTANT number of times. I used trial and error to find a constant * that would give me the most throughput. */ static void *findFit(size_t asize) { void *bp = NULL; void *temp = free_listp; size_t minSize = mem_heapsize(); // maximum size /* First fit search */ size_t size; int counter = 0; /* counter for CONSTANT number of traversals */ int flag = 0; /* flag is set if we come across a fit. */ while(!GET_ALLOC(HDRP(temp))) /* While we are pointing to a free block */ { if(asize <= (size = (size_t)GET_SIZE(HDRP(temp))) && size < minSize) { /* If we have a block that fits perfectly, * then there is no point in searching for * a smaller block because we have found the smallest possible one */ if(asize == size) return temp; bp = temp; minSize = size; flag = 1; } if(flag == 1) counter++; /* We have traversed enough. */ if(counter == CONSTANT) return bp; temp = NEXT_FREE(temp); } return bp; }
/* * eval_mm_util - Evaluate the space utilization of the student's package * The idea is to remember the high water mark "hwm" of the heap for * an optimal allocator, i.e., no gaps and no internal fragmentation. * Utilization is the ratio hwm/heapsize, where heapsize is the * size of the heap in bytes after running the student's malloc * package on the trace. Note that our implementation of mem_sbrk() * doesn't allow the students to decrement the brk pointer, so brk * is always the high water mark of the heap. * */ static double eval_mm_util(trace_t *trace, int tracenum, range_t **ranges) { assert((int)tracenum || 1); assert((int)ranges || 1); int i; int index; int size, newsize, oldsize; int max_total_size = 0; int total_size = 0; char *p; char *newp, *oldp; /* initialize the heap and the mm malloc package */ mem_reset_brk(); if (mm_init() < 0) app_error("mm_init failed in eval_mm_util"); for (i = 0; i < trace->num_ops; i++) { switch (trace->ops[i].type) { case ALLOC: /* mm_alloc */ index = trace->ops[i].index; size = trace->ops[i].size; if ((p = mm_malloc(size)) == NULL) app_error("mm_malloc failed in eval_mm_util"); /* Remember region and size */ trace->blocks[index] = p; trace->block_sizes[index] = size; /* Keep track of current total size * of all allocated blocks */ total_size += size; /* Update statistics */ max_total_size = (total_size > max_total_size) ? total_size : max_total_size; break; case REALLOC: /* mm_realloc */ index = trace->ops[i].index; newsize = trace->ops[i].size; oldsize = trace->block_sizes[index]; oldp = trace->blocks[index]; if ((newp = mm_realloc(oldp,newsize)) == NULL) app_error("mm_realloc failed in eval_mm_util"); /* Remember region and size */ trace->blocks[index] = newp; trace->block_sizes[index] = newsize; /* Keep track of current total size * of all allocated blocks */ total_size += (newsize - oldsize); /* Update statistics */ max_total_size = (total_size > max_total_size) ? total_size : max_total_size; break; case FREE: /* mm_free */ index = trace->ops[i].index; size = trace->block_sizes[index]; p = trace->blocks[index]; mm_free(p); /* Keep track of current total size * of all allocated blocks */ total_size -= size; break; default: app_error("Nonexistent request type in eval_mm_util"); } } return ((double)max_total_size / (double)mem_heapsize()); }
/* * mm_checkheap * * @param verbose mask: * val func desc * 0x1 Check Prologue and Epilogue * 0x2 Check heap boundaries * 0x4 Check each block's address alignment * 0x8 Check each block’s header and footer * 0x10(16) Check coalescing: no two consecutive free blocks in the heap. * 0x20(32) Check next/previous pointers are consistent */ void mm_checkheap(int verbose) { if (!verbose) { return; } verbose = verbose; char *bp = heap_listp; int i = 1; int hd_size, hd_alloc, ft_size, ft_alloc; /*char *blkp = root;*/ if (heap_listp == NULL) { dbg_printf("Heap Uninitialized!\n"); } /* check prologue and epilogue blocks */ if (verbose & 0x1) { dbg_printf("Prologue Header size = %d, alloc = %d\n", (int)GET_SIZE(GET_HEADER(heap_listp)), (int)GET_ALLOC(GET_HEADER(heap_listp))); dbg_printf("Prologue Footer size = %d, alloc = %d\n", (int)GET_SIZE(GET_FOOTER(heap_listp)), (int)GET_ALLOC(GET_FOOTER(heap_listp))); bp = heap_listp; while (GET_SIZE(GET_HEADER(NEXT_BLKP(bp))) > 0) bp = NEXT_BLKP(bp); bp = NEXT_BLKP(bp); dbg_printf("Epilogue Header size = %d, alloc = %d\n", (int)GET_SIZE(GET_HEADER(bp)), (int)GET_ALLOC(GET_HEADER(bp))); } /* Check heap size and boundary */ if (verbose & 0x2) { dbg_printf("Heap Information:\n"); dbg_printf("Heap size(long) = %ld\n Heap first address = 0x%lx\n Heap last address = 0x%lx\n", mem_heapsize(), (unsigned long)mem_heap_lo(), (unsigned long)mem_heap_hi()); } /* Check each block's information */ if (verbose & 0xc) { i = 1; bp = heap_listp; while (GET_SIZE(GET_HEADER(NEXT_BLKP(bp))) > 0) { bp = NEXT_BLKP(bp); hd_size = (int)GET_SIZE(GET_HEADER(bp)); hd_alloc = (int)GET_ALLOC(GET_HEADER(bp)); ft_size = (int)GET_SIZE(GET_FOOTER(bp)); ft_alloc = (int)GET_ALLOC(GET_FOOTER(bp)); if (verbose & 0x8) { if (!hd_alloc) { if (hd_size - ft_size) { dbg_printf("SIZE NOT MATCH!!! Block (%d), addr = 0x%lx, header_size = %d footer_size = %d \n", i, (unsigned long)bp , hd_size, ft_size); exit(1); } if (hd_alloc - ft_alloc) { dbg_printf("ALLOC NOT MATCH!!! Block (%d), addr = 0x%lx, header_alloc = %d footer_alloc = %d \n", i, (unsigned long)bp, hd_alloc, ft_alloc); exit(1); } } } if (verbose & 0x4) { dbg_printf("Block %d, addr = 0x%lx, size = %d, alloc = %d \n", i, (unsigned long)bp, hd_size, hd_alloc); } ++i; } } /* Check coalescing */ if (verbose & 0x10) { bp = heap_listp; while (GET_SIZE(GET_HEADER(NEXT_BLKP(bp))) > 0) { bp = NEXT_BLKP(bp); if ((GET_ALLOC(GET_HEADER(bp)) == 0) && (GET_ALLOC(GET_HEADER(NEXT_BLKP(bp))) == 0)) { dbg_printf("Not coalesced: (%lx) and (%lx)\n", (unsigned long)bp, (unsigned long)NEXT_BLKP(bp)); } } } /* Check pred, succ pointers */ if (verbose & 0x20) { for (i = 0; i < CLASS_NUM; i++) { dbg_printf("CLASS No. %d, class_address = 0x%lx ,root block address = 0x%lx\n", i, (size_t)GET_CLASS(i), (size_t)GET_CLASS_ROOT_BLK(GET_CLASS(i))); } /*i = 1; blkp = root; if (root != NULL) { dbg_printf("root address = 0x%lx\n", (size_t)root); do { dbg_printf("Check Free Block %d\n",i); check_bp_pred_succ(blkp); i++; if (i > 100) { exit(1); } } while ((blkp = GET_SUCC_BLK(blkp)) != NULL); }*/ } /* Check each block’s address alignment */ dbg_printf("******************\n"); }
/* * eval_mm_util - Evaluate the space utilization of the student's package * The idea is to remember the high water mark "hwm" of the heap for * an optimal allocator, i.e., no gaps and no internal fragmentation. * Utilization is the ratio hwm/heapsize, where heapsize is the * size of the heap in bytes after running the student's malloc * package on the trace. * */ static double eval_mm_util(trace_t *trace, int tracenum) { int i; int index; int size, newsize, oldsize; int max_total_size = 0; int total_size = 0; size_t heap_size = 0 ; char *p; char *newp, *oldp; /* initialize the heap and the mm malloc package */ mem_reset_brk(); if (my_impl.init() < 0) { app_error("init failed in eval_mm_util"); } for (i = 0; i < trace->num_ops; i++) { switch (trace->ops[i].type) { case ALLOC: /* alloc */ index = trace->ops[i].index; size = trace->ops[i].size; if ((p = (char *) my_impl.malloc(size)) == NULL) { app_error("malloc failed in eval_mm_util"); } /* Remember region and size */ trace->blocks[index] = p; trace->block_sizes[index] = size; /* Keep track of current total size * of all allocated blocks */ total_size += size; /* Update statistics */ max_total_size = (total_size > max_total_size) ? total_size : max_total_size; break; case REALLOC: /* realloc */ index = trace->ops[i].index; newsize = trace->ops[i].size; oldsize = trace->block_sizes[index]; oldp = trace->blocks[index]; if ((newp = (char *) my_impl.realloc(oldp,newsize)) == NULL) app_error("realloc failed in eval_mm_util"); /* Remember region and size */ trace->blocks[index] = newp; trace->block_sizes[index] = newsize; /* Keep track of current total size * of all allocated blocks */ total_size += (newsize - oldsize); /* Update statistics */ max_total_size = (total_size > max_total_size) ? total_size : max_total_size; break; case FREE: /* free */ index = trace->ops[i].index; size = trace->block_sizes[index]; p = trace->blocks[index]; my_impl.free(p); /* Keep track of current total size * of all allocated blocks */ total_size -= size; break; default: app_error("Nonexistent request type in eval_mm_util"); } } max_total_size = (max_total_size > MEM_ALLOWANCE) ? max_total_size : MEM_ALLOWANCE ; heap_size = mem_heapsize() ; heap_size = (heap_size > MEM_ALLOWANCE) ? heap_size : MEM_ALLOWANCE ; return ((double)max_total_size / (double)heap_size); }
/********************************************************** * mm_check * Check the consistency of the memory heap * Return nonzero if the heap is consistant. *********************************************************/ int mm_check(void) { #ifdef DEBUG_BUILD int i; dlist *current; void *bp; //To point at the start of the heap size_t size = 0; //To measure the total size of blocks on the heap // Check if every block in free list is actually marked free. // If a allocated block is in the free list then it may result in segmentation faults // while accessing the prev and next pointers. It will also result in the allocater manipulating // memory allocated to user which will be nasty! for(i = 0; i < NUM_SEG_LIST; i++) { current = sep_list_head[i]; while (current != NULL) { // Check if block is in heap if (is_in_heap((void*)current) == 0) return 0; if (GET_ALLOC(HDRP((void*)current))) { PRINTDBG (("block (%p) in free list is allocated!\n", current)); return 0; } current = current->next; } } // Check if there exist any free blocks that may have escaped coalescing. // If found, these cases result in internal fragmentation. for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)) { // Check if the current block is free and the next block is also free // Since this is done in a sequential manner, we don't need to check the previous blk if (!GET_ALLOC(HDRP(bp)) && (!GET_ALLOC(HDRP(NEXT_BLKP(bp))))) { PRINTDBG (("Consecutive blocks (%p, %p) have escaped coalescing!\n", bp, NEXT_BLKP(bp))); return 0; } } for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)) { if (bp < mem_heap_lo() || bp > mem_heap_hi()) { PRINTDBG (("Block is outside the heap.\n")); return 0; } else { size += GET_SIZE(HDRP(bp)); //Add the size of the current block to the total size of the calculated blocks on the heap so far } } if (size == mem_heapsize()) PRINTDBG (("The total size of all blocks on the heap match the heap size.\n")); if (mem_heapsize() > mem_pagesize()) //Check if heap size exceeded systems page size PRINTDBG (("Heap size is more than page size. TLB misses might occur\n")); char c; scanf("%c\n", &c); #endif return 1; }