diff --git a/.gitignore b/.gitignore index 6f91747..e362568 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ autom4te.cache .vscode include/config.h* missing -stamp-h1 \ No newline at end of file +stamp-h1 +tests/test_bitmapalloc \ No newline at end of file diff --git a/include/libmalloc/bitmap_alloc.h b/include/libmalloc/bitmap_alloc.h index 06d57c9..b5d4ae9 100644 --- a/include/libmalloc/bitmap_alloc.h +++ b/include/libmalloc/bitmap_alloc.h @@ -8,7 +8,7 @@ * @brief * */ -typedef struct +typedef struct bitmap_heap_descriptor_t { /** * @brief The underlying bitmap representing the availability of chunks of @@ -60,6 +60,42 @@ typedef struct */ unsigned long free_block_count; + /** + * @brief Bitmask used to isolate only those bits which indicate the + * availability of a block. Useful when several bits are used to represent + * the state of a single block. See `block_bits`. + * + */ + unsigned long mask; + + /** + * @brief The number of bits required to represent the state of each block. + * + * If the value is greater than 1, the most significant bit describing each + * block shall indicate its availability. Less significant bits shall + * represent other aspects of the block's state. The number of trailing + * zeroes in `mask` shall be used to calculate this quantity. + * + * This qualtity is assumed to be a power of 2, and less than or equal to + * the number of bits in an unsigned long. Therefore, acceptable values for + * this quantity are as follows: 1, 2, 4, 8, 16, 32[, 64]. + * + */ + unsigned long block_bits; + + /** + * @brief The number of blocks described by a single unsigned long contained + * in `bitmap`. Equal to (8 * sizeof(unsigned long)) / block_bits. + * + */ + unsigned long blocks_in_word; + + /** + * @brief Memory will be allocated relative to this location. + * + */ + unsigned long offset; + } bitmap_heap_descriptor_t; /** @@ -73,7 +109,8 @@ typedef struct * @param size * @return unsigned long */ -unsigned long reserve_region(bitmap_heap_descriptor_t *heap, unsigned long size); +unsigned long reserve_region(bitmap_heap_descriptor_t *heap, + unsigned long size); /** * @brief Marks the region of memory indicated by `location` and `size` as @@ -97,13 +134,12 @@ void free_region(bitmap_heap_descriptor_t *heap, unsigned long location, * @param block_size The minimum unit of allocation * @return unsigned long */ -unsigned long bitmap_size(const memory_map_t *map, unsigned long block_size); +unsigned long bitmap_size(const memory_map_t *map, unsigned long block_size, unsigned long block_bits); /** * @brief Builds the heap's internal structures according to the memory - * layout provided in `map`. Assumes that the layout in `map` refers to the - * caller's virtual address space, and utilizes some of the memory marked as - * 'available' to store the heap's internal structures. + * layout provided in `map`. All locations in `map` are relative to the `offset` + * field in `heap`. * * A callback function `mmap` may be provided, which will be used to map the * space required by the heap to store its internal bitmaps. If `mmap` is NULL, @@ -111,43 +147,34 @@ unsigned long bitmap_size(const memory_map_t *map, unsigned long block_size); * * There are several requirements for the initial state of the `heap` structure: * - * - The `cache` field must be defined, and point to an array of unsigned longs - * of sufficient size. + * - The `bitmap` field may point to a pre-allocated region of memory which will + * be used to store the heap's internal bitmap. If this field is NULL, part of + * the heap will be used to store the bitmap, and `mmap`, if not NULL, will be + * called to map that region of memory. * - * - The `block_size` field must be set to the desired smallest unit of allocation. - * - * @param heap A pointer to the structure describing the heap - * @param map A pointer to the structure providing an initial memory layout - * @param mmap A callback function used to map memory in the virtual address space - * @return int - */ -int initialize_virtual_heap(bitmap_heap_descriptor_t *heap, const memory_map_t *map, - int (*mmap)(void *location, unsigned long size)); - -/** - * @brief Builds the heap's internal structures according to the memory - * layout provided in `map`. Assumes that physical memory space is being alocated, - * and therefore does not make assumptions about the caller's address space or - * attempt to utilize the memory inside the heap. The caller is responsible for - * providing space to store the heap's internal structures. - * - * There are several requirements for the initial state of the `heap` structure: - * - * - The `bitmap` field must be defined, and sufficient memory reserved at that - * location to contain the heap's bitmap. - * - * - The `cache` field must be defined, and point to an array of unsigned longs - * of sufficient size. + * - The `cache` field may point to an array of unsigned longs of sufficient + * size, which will be used to speed up memory allocation. If this field is + * NULL, caching will not be performed. * * - The `cache_capacity` field must be set to the size of the array pointed to - * by `cache` + * by `cache`. * - * - The `block_size` field must be set to the desired smallest unit of allocation. + * - The `block_size` field must be set to the desired smallest unit of + * allocation. + * + * - The `block_bits` field must be set to the number of bits required to store + * a block's metadata. + * + * - The `offset` field must be set to the first location to allocate memory + * from. Locations in `map` will be interpreted as relative to `offset`. * * @param heap A pointer to the structure describing the heap * @param map A pointer to the structure providing an initial memory layout - * @return int 0 upon success; nonzero upon failure + * @param mmap A callback function used to map memory in the virtual address + * space + * @return int 0 upon success, nonzero upon failure. */ -int initialize_physical_heap(bitmap_heap_descriptor_t *heap, const memory_map_t *map); +int initialize_heap(bitmap_heap_descriptor_t *heap, memory_map_t *map, + int (*mmap)(void *location, unsigned long size)); #endif \ No newline at end of file diff --git a/include/libmalloc/common.h b/include/libmalloc/common.h index 231599f..aead99e 100644 --- a/include/libmalloc/common.h +++ b/include/libmalloc/common.h @@ -8,6 +8,6 @@ * NOMEM shall be returned by any malloc-like function upon failure, rather than * NULL. */ -#define NOMEM ~0 +#define NOMEM ((unsigned long)~0) #endif \ No newline at end of file diff --git a/src/bitmap_alloc.c b/src/bitmap_alloc.c index ceb28a8..85df42d 100644 --- a/src/bitmap_alloc.c +++ b/src/bitmap_alloc.c @@ -2,17 +2,19 @@ #include "libmalloc/common.h" #include "util.h" -/* - * The number of bits contained in a single integer inside the heap's bitmap. - * Should be either 32 or 64 depending on the host machine. - */ -static const int bitmap_word_size = 8 * sizeof(unsigned long); +static const int BIT_AVAIL = 0; +static const int BIT_USED = 1; /* * Sets all elements in the cache's underlying array to 0. */ static inline void clear_cache(bitmap_heap_descriptor_t *heap) { + if(heap->cache == (unsigned long*)0) + { + return; + } + for(int i = 0; i < heap->cache_capacity; i++) { heap->cache[i] = 0; @@ -34,22 +36,48 @@ static inline void clear_bitmap(bitmap_heap_descriptor_t *heap) * Sets bit `index` in the heap's bitmap, marking the underlying block as * available. */ -static inline void set_bit(bitmap_heap_descriptor_t *heap, int index) +static inline void set_bit(bitmap_heap_descriptor_t *heap, int index, int bit) { - int bitmap_index = index / bitmap_word_size; - int bitmap_offset = index % bitmap_word_size; - heap->bitmap[bitmap_index] |= (unsigned long)1 << bitmap_offset; + if(bit < heap->block_bits) + { + int bitmap_index = index / heap->blocks_in_word; + int bitmap_offset = index % heap->blocks_in_word; + unsigned long mask = (unsigned long)1 << (heap->block_bits * (bitmap_offset + 1) - 1 - bit); + heap->bitmap[bitmap_index] |= mask; + } } /* * Clears bit `index` in the heap's bitmap, marking the underlying block as * reserved. */ -static inline void clear_bit(bitmap_heap_descriptor_t *heap, int index) +static inline void clear_bit(bitmap_heap_descriptor_t *heap, int index, int bit) { - int bitmap_index = index / bitmap_word_size; - int bitmap_offset = index % bitmap_word_size; - heap->bitmap[bitmap_index] &= ~((unsigned long)1 << bitmap_offset); + if(bit < heap->block_bits) + { + int bitmap_index = index / heap->blocks_in_word; + int bitmap_offset = index % heap->blocks_in_word; + unsigned long mask = ~((unsigned long)1 + << (heap->block_bits * (bitmap_offset + 1) - 1 - bit)); + heap->bitmap[bitmap_index] &= mask; + } +} + +/* + * Tests whether the block at bit `index` is available. If so, returns nonzero, + * else returns 0. + */ +static inline int test_bit(bitmap_heap_descriptor_t *heap, int index, int bit) +{ + if(bit > (heap->block_bits - 1)) + { + return 1; + } + unsigned long mask = ((unsigned long)1 + << (heap->block_bits * ((index % heap->blocks_in_word) + 1) + - 1 + - bit)); + return (heap->bitmap[index / heap->blocks_in_word] & mask) != 0; } /* @@ -57,33 +85,57 @@ static inline void clear_bit(bitmap_heap_descriptor_t *heap, int index) * blocks as available. Operation is used while spltting a block to reserve one * of its child blocks. */ -static inline void set_pair(bitmap_heap_descriptor_t *heap, int index) +static inline void set_pair(bitmap_heap_descriptor_t *heap, int index, int bit) { - int bitmap_index = index / bitmap_word_size; - int bitmap_offset = index % bitmap_word_size; - heap->bitmap[bitmap_index] |= (unsigned long)1 << bitmap_offset; - heap->bitmap[bitmap_index] |= (unsigned long)1 << (bitmap_offset ^ 1); + if(bit < heap->block_bits) + { + int bitmap_index = index / heap->blocks_in_word; + int bitmap_offset = index % heap->blocks_in_word; + + unsigned long mask_a = (unsigned long)1 << (heap->block_bits * (bitmap_offset + 1) - 1 - bit); + unsigned long mask_b = (unsigned long)1 << (heap->block_bits * ((bitmap_offset ^ 1) + 1) - 1 - bit); + + heap->bitmap[bitmap_index] |= mask_a; + heap->bitmap[bitmap_index] |= mask_b; + } } /* * Clears bit `index` and its buddy in the heap's bitmap, marking the underlying - * blocks as reserved. Used when merging two child blocks into a single parent block. + * blocks as reserved. Used when merging two child blocks into a single parent + * block. */ -static inline void clear_pair(bitmap_heap_descriptor_t *heap, int index) +static inline void clear_pair(bitmap_heap_descriptor_t *heap, int index, int bit) { - int bitmap_index = index / bitmap_word_size; - int bitmap_offset = index % bitmap_word_size; - heap->bitmap[bitmap_index] &= ~((unsigned long)1 << bitmap_offset); - heap->bitmap[bitmap_index] &= ~((unsigned long)1 << (bitmap_offset ^ 1)); + if(bit < heap->block_bits) + { + int bitmap_index = index / heap->blocks_in_word; + int bitmap_offset = index % heap->blocks_in_word; + + unsigned long mask_a = ~((unsigned long)1 << (heap->block_bits * (bitmap_offset + 1) - 1 - bit)); + unsigned long mask_b = ~((unsigned long)1 << (heap->block_bits * ((bitmap_offset ^ 1) + 1) - 1 - bit)); + + heap->bitmap[bitmap_index] &= mask_a; + heap->bitmap[bitmap_index] &= mask_b; + } } /* * Computes the location in the cache that `index` would be stored at, if it * were cached. */ -static inline int cache_location_from_index(int index) +static inline int cache_location_from_index(bitmap_heap_descriptor_t *heap, int index) { - return llog2(index + 1) - llog2(bitmap_word_size) - 1; + return llog2(index + 1) - llog2(heap->blocks_in_word) - 1; +} + +/* + * Computes the location in the cache that blocks at the indicated height are + * cached at. + */ +static inline int cache_location_from_height(bitmap_heap_descriptor_t *heap, int height) +{ + return heap->height - height - llog2(heap->blocks_in_word); } /* @@ -92,9 +144,17 @@ static inline int cache_location_from_index(int index) */ static inline int check_cache(bitmap_heap_descriptor_t *heap, int height) { - unsigned long n = heap->cache[heap->height - height - llog2(bitmap_word_size)]; - heap->cache[heap->height - height - llog2(bitmap_word_size)] = 0; - return n; + if(heap->cache != (unsigned long*)0) + { + int loc = cache_location_from_height(heap, height); + unsigned long n = heap->cache[loc]; + heap->cache[loc] = 0; + return n; + } + else + { + return 0; + } } /* @@ -103,10 +163,17 @@ static inline int check_cache(bitmap_heap_descriptor_t *heap, int height) */ static inline void store_cache(bitmap_heap_descriptor_t *heap, int index) { - int level = cache_location_from_index(index); - if(level >= 0 && heap->cache[level] == 0) + if(heap->cache != (unsigned long*)0) { - heap->cache[level] = index; + int level = cache_location_from_index(heap, index); + if(level >= 0 && heap->cache[level] == 0) + { + heap->cache[level] = index; + } + } + else + { + return 0; } } @@ -116,10 +183,17 @@ static inline void store_cache(bitmap_heap_descriptor_t *heap, int index) */ static inline void uncache(bitmap_heap_descriptor_t *heap, int index) { - int level = cache_location_from_index(index); - if(level >= 0 && heap->cache[level] == index) + if(heap->cache != (unsigned long*)0) { - heap->cache[level] = 0; + int level = cache_location_from_index(heap, index); + if(level >= 0 && heap->cache[level] == index) + { + heap->cache[level] = 0; + } + } + else + { + return 0; } } @@ -133,9 +207,9 @@ static inline int split_block(bitmap_heap_descriptor_t *heap, int index) { if(index) { - clear_bit(heap, index); + clear_bit(heap, index, BIT_AVAIL); index *= 2; - set_pair(heap, index); + set_pair(heap, index, BIT_AVAIL); store_cache(heap, index + 1); } return index; @@ -152,12 +226,12 @@ static inline int split_block(bitmap_heap_descriptor_t *heap, int index) */ static int merge_block(bitmap_heap_descriptor_t *heap, int index) { - while(index > 1 && (heap->bitmap[index / bitmap_word_size] & ((unsigned long)1 << ((index % bitmap_word_size) ^ 1)))) + while(index > 1 && test_bit(heap, index ^ 1, BIT_AVAIL)) { uncache(heap, index ^ 1); - clear_pair(heap, index); + clear_pair(heap, index, BIT_AVAIL); index /= 2; - set_bit(heap, index); + set_bit(heap, index, BIT_AVAIL); } return index; } @@ -174,20 +248,21 @@ static int find_free_region(bitmap_heap_descriptor_t *heap, int height) { return 0; } - else if (height <= heap->height - ilog2(bitmap_word_size)) + else if (height <= heap->height - ilog2(heap->blocks_in_word)) { unsigned long cached_index = check_cache(heap, height); if(cached_index) { return cached_index; } - unsigned long start = (1 << (heap->height - height)) / bitmap_word_size; - unsigned long end = ((1 << (heap->height - height + 1)) / bitmap_word_size); + unsigned long start = (1 << (heap->height - height)) / heap->blocks_in_word; + unsigned long end = ((1 << (heap->height - height + 1)) / heap->blocks_in_word); for (int index = start; index < end; index++) { - if (heap->bitmap[index] != 0) + unsigned long avail_mask = heap->bitmap[index] & heap->mask; + if (avail_mask != 0) { - return bitmap_word_size * index + __builtin_ctzl(heap->bitmap[index]); + return heap->blocks_in_word * index + (__builtin_ctzl(avail_mask) / heap->block_bits); } } } @@ -198,25 +273,144 @@ static int find_free_region(bitmap_heap_descriptor_t *heap, int height) #else static const unsigned long bitmasks[] = {0x00000002, 0x0000000C, 0x000000F0, 0x0000FF00, 0xFFFF0000}; #endif - int depth = heap->height - height; - if (heap->bitmap[0] & bitmasks[depth]) + int bitmask_index = heap->height - height + llog2(heap->block_bits); + if (heap->bitmap[0] & bitmasks[bitmask_index] & heap->mask) { - return __builtin_ctzl(heap->bitmap[0] & bitmasks[depth]); + return __builtin_ctzl(heap->bitmap[0] & bitmasks[bitmask_index] & heap->mask) / heap->block_bits; } } return split_block(heap, find_free_region(heap, height + 1)); } +static unsigned long compute_memory_size(const memory_map_t *map) +{ + // Find the last available region in the memory map. + int map_index = map->size - 1; + while(map->array[map_index].type != M_AVAILABLE) + { + map_index--; + } + + return map->array[map_index].location + map->array[map_index].size; +} + +static unsigned long generate_mask(unsigned long block_bits) +{ + unsigned long blocks_in_word = 8 * sizeof(unsigned long) / block_bits; + unsigned long mask = 0; + for(unsigned long i = 1; i <= blocks_in_word; i++) + { + mask |= 1UL << (i * block_bits - 1UL); + } + return mask; +} + +static int construct_heap_desc(bitmap_heap_descriptor_t *heap, const memory_map_t *map) +{ + if(heap->block_bits == 0 || heap->block_bits > (8 * sizeof(*heap->bitmap))) + { + return -1; + } + else if(heap->block_size == 0) + { + return -1; + } + else if((1 << llog2(heap->block_bits)) != heap->block_bits) + { + return -1; + } + + unsigned long memory_size = compute_memory_size(map); + heap->blocks_in_word = 8 * sizeof(*heap->bitmap) / heap->block_bits; + heap->bitmap_size = heap->block_bits * (memory_size / heap->block_size) / 4; + heap->bitmap_size = 1 << llog2(heap->bitmap_size); + heap->height = llog2(memory_size / heap->block_size); + heap->free_block_count = 0; + heap->mask = generate_mask(heap->block_bits); + + if(heap->bitmap_size <= sizeof(*heap->bitmap)) + { + return -1; + } + else if(heap->bitmap_size >= memory_size && heap->bitmap == (unsigned long*)0) + { + return -1; + } + return 0; +} + +static void initialize_bitmap(bitmap_heap_descriptor_t *heap, const memory_map_t *map) +{ + clear_bitmap(heap); + for(int i = 0; i < map->size; i++) + { + if(map->array[i].type != M_AVAILABLE) + { + continue; + } + + unsigned long location = (map->array[i].location + heap->block_size - 1);// & ~(heap->block_size - 1); + location -= location % heap->block_size; + unsigned long region_end = map->array[i].location + map->array[i].size; + + while(location + heap->block_size <= region_end) + { + int bit_offset = (location / heap->block_size) % heap->blocks_in_word; + int bitmap_index = ((1UL << (heap->height - 0)) / heap->blocks_in_word) + (location / heap->block_size) / heap->blocks_in_word; + unsigned long chunk_size = (heap->blocks_in_word - bit_offset) * heap->block_size; + if(bit_offset == 0 && (region_end - location) >= chunk_size) + { + // Set all bits in the word + heap->bitmap[bitmap_index] = heap->mask & ~0; + heap->free_block_count += heap->blocks_in_word; + } + else if(bit_offset == 0) + { + // Set the first 'count' bits + int count = (region_end - location) / heap->block_size; + heap->bitmap[bitmap_index] |= heap->mask & ((1UL << (heap->block_bits * count)) - 1); + heap->free_block_count += count; + } + else if((region_end - location) >= chunk_size) + { + // Set all bits starting at 'bit_offset' + heap->bitmap[bitmap_index] |= heap->mask & ~((1UL << (heap->block_bits * bit_offset)) - 1); + heap->free_block_count += heap->blocks_in_word - bit_offset; + } + else + { + // Set all bits starting at 'bit_offset' up to 'count' + int count = (region_end - location) / heap->block_size; + heap->bitmap[bitmap_index] |= heap->mask & ((1UL << (heap->block_bits * count)) - 1) & ~((1UL << (heap->block_bits * bit_offset)) - 1); + heap->free_block_count += count - bit_offset; + } + + // Merge 'buddies' when both available + unsigned long mask = ((1UL << (2 * heap->block_bits)) - 1) & heap->mask; + for(int j = 0; j < heap->blocks_in_word / 2; j++) + { + if((heap->bitmap[bitmap_index] & mask) == mask) + { + merge_block(heap, bitmap_index * heap->blocks_in_word + j * 2); + } + mask <<= 2 * heap->block_bits; + } + + location += chunk_size; + } + } +} unsigned long reserve_region(bitmap_heap_descriptor_t *heap, unsigned long size) { - int height = llog2(size / heap->block_size); + int height = llog2((size - 1) / heap->block_size + 1); int index = find_free_region(heap, height); if(index) { - clear_bit(heap, index); + clear_bit(heap, index, BIT_AVAIL); + set_bit(heap, index, BIT_USED); heap->free_block_count -= 1 << height; - return (heap->block_size << height) * (index - ((unsigned long)1 << (heap->height - height))); + return heap->offset + (heap->block_size << height) * (index - ((unsigned long)1 << (heap->height - height))); } else { @@ -226,107 +420,54 @@ unsigned long reserve_region(bitmap_heap_descriptor_t *heap, unsigned long size) void free_region(bitmap_heap_descriptor_t *heap, unsigned long location, unsigned long size) { + location -= heap->offset; int height = llog2(size / heap->block_size); int index = (location / (heap->block_size * ((unsigned long)1 << height))) + (1 << (heap->height - height)); - set_bit(heap, index); + while(!test_bit(heap, index, BIT_USED)) + { + height++; + index /= 2; + } + set_bit(heap, index, BIT_AVAIL); + clear_bit(heap, index, BIT_USED); index = merge_block(heap, index); store_cache(heap, index); heap->free_block_count += 1 << height; } -unsigned long bitmap_size(const memory_map_t *map, unsigned long block_size) +unsigned long bitmap_size(const memory_map_t *map, unsigned long block_size, unsigned long block_bits) { - // Find the last available region in the memory map. - int map_index = map->size - 1; - while(map->array[map_index].type != M_AVAILABLE) - { - map_index--; - } - - // Take memory_size to be the last available location in the memory map. - // Round memory_size up to nearest power of 2 - unsigned long memory_size = 1 << llog2(map->array[map_index].location + map->array[map_index].size); - return (memory_size / block_size) / 4; + return 1UL << llog2((block_bits * compute_memory_size(map) / block_size) / 4); } -int initialize_virtual_heap(bitmap_heap_descriptor_t *heap, const memory_map_t *map, int (*mmap)(void *location, unsigned long size)) +int initialize_heap(bitmap_heap_descriptor_t *heap, memory_map_t *map, int (*mmap)(void *location, unsigned long size)) { - /* Not yet implemented */ - return -1; -} - -int initialize_physical_heap(bitmap_heap_descriptor_t *heap, const memory_map_t *map) -{ - // Find the last available region in the memory map. - int map_index = map->size - 1; - while(map->array[map_index].type != M_AVAILABLE) + if(construct_heap_desc(heap, map)) { - map_index--; + return -1; } - // Take memory_size to be the last available location in the memory map. - // Round memory_size up to nearest power of 2 - unsigned long memory_size = 1 << llog2(map->array[map_index].location + map->array[map_index].size); - heap->bitmap_size = (memory_size / heap->block_size) / 4; - heap->height = llog2(memory_size / heap->block_size); - heap->free_block_count = 0; - clear_bitmap(heap); - for(int i = 0; i < map->size; i++) + if(heap->bitmap == (unsigned long*)0) { - if(map->array[i].type != M_AVAILABLE) + int map_index = 0; + while(map->array[map_index].size < heap->bitmap_size) { - continue; + map_index++; + if(map_index >= map->size) + { + return -1; + } } - unsigned long location = (map->array[i].location + heap->block_size - 1) & ~(heap->block_size - 1); - unsigned long region_end = map->array[i].location + map->array[i].size; - - while(location + heap->block_size <= region_end) + heap->bitmap = (unsigned long*)(heap->offset + map->array[map_index].location); + memmap_insert_region(map, map->array[map_index].location, heap->bitmap_size, M_UNAVAILABLE); + if(mmap && mmap(heap->bitmap, heap->bitmap_size)) { - int bit_offset = (location / heap->block_size) % bitmap_word_size; - int bitmap_index = ((1 << (heap->height - 0)) / bitmap_word_size) + (location / heap->block_size) / bitmap_word_size; - unsigned long chunk_size = (bitmap_word_size - bit_offset) * heap->block_size; - if(bit_offset == 0 && (region_end - location) >= chunk_size) - { - // Set all bits in the word - heap->bitmap[bitmap_index] = ~0; - heap->free_block_count += bitmap_word_size; - } - else if(bit_offset == 0) - { - // Set the first 'count' bits - int count = (region_end - location) / heap->block_size; - heap->bitmap[bitmap_index] |= (1 << count) - 1; - heap->free_block_count += count; - } - else if((region_end - location) >= chunk_size) - { - // Set all bits starting at 'bit_offset' - heap->bitmap[bitmap_index] |= ~((1 << bit_offset) - 1); - heap->free_block_count += bitmap_word_size - bit_offset; - } - else - { - // Set all bits starting at 'bit_offset' up to 'count' - int count = (region_end - location) / heap->block_size; - heap->bitmap[bitmap_index] |= ((1 << count) - 1) & ~((1 << bit_offset) - 1); - heap->free_block_count += count - bit_offset; - } - - // Merge 'buddies' when both available - unsigned long mask = 3; - for(int j = 0; j < bitmap_word_size / 2; j++) - { - if((heap->bitmap[bitmap_index] & mask) == mask) - { - merge_block(heap, bitmap_index * bitmap_word_size + j * 2); - } - mask <<= 2; - } - - location += chunk_size; + return -1; } } + + initialize_bitmap(heap, map); clear_cache(heap); return 0; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 1e03683..fe2ee89 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ if BUILD_TESTS - noinst_PROGRAMS = test_buddyalloc + noinst_PROGRAMS = test_bitmapalloc - test_buddyalloc_SOURCES = test_buddyalloc.c - test_buddyalloc_LDADD = ../src/libmalloc.a + test_bitmapalloc_SOURCES = test_bitmapalloc.c + test_bitmapalloc_LDADD = ../src/libmalloc.a endif \ No newline at end of file diff --git a/tests/test_bitmapalloc.c b/tests/test_bitmapalloc.c new file mode 100644 index 0000000..a0abbaa --- /dev/null +++ b/tests/test_bitmapalloc.c @@ -0,0 +1,160 @@ +#include "libmalloc/bitmap_alloc.h" +#include "util.h" +#include +#include +#include +#include + +typedef struct memblock_t +{ + unsigned long size; + unsigned long location; +} memblock_t; + +void print_heap_desc(bitmap_heap_descriptor_t *heap) +{ + printf("heap = {\n" + "\t.bitmap = %p\n" + "\t.bitmap_size = %i\n" + "\t.cache = %p\n" + "\t.cache_capacity = %i\n" + "\t.block_size = %i\n" + "\t.height = %i\n" + "\t.free_block_count = %i\n" + "\t.mask = %lX\n" + "\t.block_bits = %i\n" + "\t.blocks_in_word = %i\n" + "\t.offset = %p\n" + "}\n", + heap->bitmap, + heap->bitmap_size, + heap->cache, + heap->cache_capacity, + heap->block_size, + heap->height, + heap->free_block_count, + heap->mask, + heap->block_bits, + heap->blocks_in_word, + heap->offset); +} + +void print_memory_map(memory_map_t *map) +{ + printf("map = {\n" + "\t.size = %i\n" + "\t.capacity = %i\n" + "\t.array = {", + map->size, + map->capacity); + for(int i = 0; i < map->size; i++) + { + printf("{.type = %i, .location = %lX, .size = %i} ", \ + map->array[i].type, + map->array[i].location, + map->array[i].size); + } + printf("}\n}\n"); +} + +void test_heap(unsigned long size, unsigned long block_size, unsigned long bits, int result) +{ + printf("[TEST] Bitmap allocator: memory=%lX, block_size=%lu, block_bits=%lu\n", size, block_size, bits); + const int memory_map_capacity = 32; + const int cache_capacity = 20; + memory_region_t arr[memory_map_capacity]; + unsigned long heap_cache[cache_capacity]; + void *heap_data = malloc(size); + + memory_map_t memory_map = { + .array = arr, + .capacity = memory_map_capacity, + .size = 0 + }; + + bitmap_heap_descriptor_t heap = { + .bitmap = NULL, + .block_size = block_size, + .cache = heap_cache, + .cache_capacity = cache_capacity, + .block_bits = bits, + .offset = (unsigned long)heap_data + }; + + memmap_insert_region(&memory_map, 0, size, M_AVAILABLE); + int status = initialize_heap(&heap, &memory_map, NULL); + assert(!(!status != !result)); + if(status) + { + return; + } + + print_heap_desc(&heap); + print_memory_map(&memory_map); + + unsigned long total_blocks = heap.free_block_count; + + memblock_t *reserved_blocks = malloc(sizeof(memblock_t) * size / heap.block_size); + unsigned long count = 0; + while(1) + { + memblock_t next_block; + next_block.size = heap.block_size * (rand() % 8 + 1); + next_block.location = reserve_region(&heap, next_block.size); + if(next_block.location != NOMEM) + { + char *s = (char*)next_block.location; + for(int i = 0; i < next_block.size; i++) + { + s[i] = (char)rand(); + } + reserved_blocks[count] = next_block; + count++; + } + else + { + printf("\tOut of memory: %i free blocks left, %i total blocks, %i allocations. Tried to allocate %i bytes.\n", heap.free_block_count, total_blocks, count, next_block.size); + break; + } + } + + for(int i = 0; i < count; i++) + { + assert(reserved_blocks[i].location >= heap.offset); + assert(reserved_blocks[i].location + reserved_blocks[i].size <= heap.offset + size); + for(int j = i + 1; j < count; j++) + { + assert((reserved_blocks[j].location + reserved_blocks[j].size) <= reserved_blocks[i].location + || reserved_blocks[j].location >= (reserved_blocks[i].location + reserved_blocks[i].size)); + } + } + + for(int i = 0; i < count; i++) + { + free_region(&heap, reserved_blocks[i].location, bits < 2 ? reserved_blocks[i].size : 0); + } + + assert(heap.free_block_count == total_blocks); + free(reserved_blocks); + free(heap_data); +} + +int main(int argc, char **args) +{ + srand(time(0)); + test_heap(32, 1, 1, 1); + test_heap(256, 0, 1, 1); + test_heap(256, 1, 0, 1); + test_heap(256, 1, 3, 1); + test_heap(256, 1, 128, 1); + test_heap(256, 1, 4, 1); + + for(int bs = 1; bs <= 32; bs++) + { + unsigned long n = (8 * sizeof(unsigned long)) - 1 - __builtin_clzl((unsigned long) bs); + for(int bits = 1; bits <= (8 * sizeof(unsigned long)) && (2 * bits) < (8 * (1 << n)); bits <<= 1) + { + test_heap(1024, bs, bits, 0); + } + } +} \ No newline at end of file diff --git a/tests/test_buddyalloc.c b/tests/test_buddyalloc.c deleted file mode 100644 index 358e56e..0000000 --- a/tests/test_buddyalloc.c +++ /dev/null @@ -1,51 +0,0 @@ -#include "libmalloc/bitmap_alloc.h" -#include "util.h" -#include -#include -#include - -int main(int argc, char **args) -{ - const int memory_map_capacity = 32; - const int heap_size = 1 << 20; - const int cache_capacity = 20; - memory_region_t arr[memory_map_capacity]; - unsigned long heap_cache[cache_capacity]; - - memory_map_t memory_map = { - .array = arr, - .capacity = memory_map_capacity, - .size = 0 - }; - - bitmap_heap_descriptor_t heap = { - .bitmap = malloc(heap_size / 4), - .block_size = 1, - .cache = heap_cache, - .cache_capacity = cache_capacity - }; - - memmap_insert_region(&memory_map, 0, heap_size, M_AVAILABLE); - initialize_physical_heap(&heap, &memory_map); - - unsigned long *reserved_blocks = malloc(sizeof(unsigned long) * heap_size); - for(int i = 0; i < heap_size; i++) - { - reserved_blocks[i] = reserve_region(&heap, 1); - } - - /*for(int i = 0; i < heap_size; i++) - { - for(int j = i + 1; j < heap_size; j++) - { - assert(reserved_blocks[i] != reserved_blocks[j]); - } - }*/ - - for(int i = 0; i < heap_size; i++) - { - free_region(&heap, reserved_blocks[i], 1); - } - - assert(heap.free_block_count == heap_size); -} \ No newline at end of file