Browse Source

[mem]: Split alloc and alloc_non_zeroed for buddy allocator

flysand7 1 year ago
parent
commit
c0e17808d4
1 changed files with 21 additions and 38 deletions
  1. 21 38
      core/mem/allocators.odin

+ 21 - 38
core/mem/allocators.odin

@@ -1133,7 +1133,6 @@ buddy_block_coalescence :: proc(head, tail: ^Buddy_Block) {
 		// Keep looping until there are no more buddies to coalesce
 		block := head
 		buddy := buddy_block_next(block)
-
 		no_coalescence := true
 		for block < tail && buddy < tail { // make sure the buddies are within the range
 			if block.is_free && buddy.is_free && block.size == buddy.size {
@@ -1156,7 +1155,6 @@ buddy_block_coalescence :: proc(head, tail: ^Buddy_Block) {
 				}
 			}
 		}
-
 		if no_coalescence {
 			return
 		}
@@ -1166,17 +1164,14 @@ buddy_block_coalescence :: proc(head, tail: ^Buddy_Block) {
 @(require_results)
 buddy_block_find_best :: proc(head, tail: ^Buddy_Block, size: uint) -> ^Buddy_Block {
 	assert(size != 0)
-
 	best_block: ^Buddy_Block
 	block := head                    // left
 	buddy := buddy_block_next(block) // right
-
 	// The entire memory section between head and tail is free,
 	// just call 'buddy_block_split' to get the allocation
 	if buddy == tail && block.is_free {
 		return buddy_block_split(block, size)
 	}
-
 	// Find the block which is the 'best_block' to requested allocation sized
 	for block < tail && buddy < tail { // make sure the buddies are within the range
 		// If both buddies are free, coalesce them together
@@ -1187,7 +1182,6 @@ buddy_block_find_best :: proc(head, tail: ^Buddy_Block, size: uint) -> ^Buddy_Bl
 			if size <= block.size && (best_block == nil || block.size <= best_block.size) {
 				best_block = block
 			}
-
 			block = buddy_block_next(buddy)
 			if block < tail {
 				// Delay the buddy block for the next iteration
@@ -1195,20 +1189,16 @@ buddy_block_find_best :: proc(head, tail: ^Buddy_Block, size: uint) -> ^Buddy_Bl
 			}
 			continue
 		}
-
-
 		if block.is_free && size <= block.size &&
 		   (best_block == nil || block.size <= best_block.size) {
 			best_block = block
 		}
-
 		if buddy.is_free && size <= buddy.size &&
 		   (best_block == nil || buddy.size < best_block.size) {
 			// If each buddy are the same size, then it makes more sense
 			// to pick the buddy as it "bounces around" less
 			best_block = buddy
 		}
-
 		if (block.size <= buddy.size) {
 			block = buddy_block_next(buddy)
 			if (block < tail) {
@@ -1221,12 +1211,10 @@ buddy_block_find_best :: proc(head, tail: ^Buddy_Block, size: uint) -> ^Buddy_Bl
 			buddy = buddy_block_next(buddy)
 		}
 	}
-
 	if best_block != nil {
 		// This will handle the case if the 'best_block' is also the perfect fit
 		return buddy_block_split(best_block, size)
 	}
-
 	// Maybe out of memory
 	return nil
 }
@@ -1245,26 +1233,20 @@ buddy_allocator :: proc(b: ^Buddy_Allocator) -> Allocator {
 	}
 }
 
-buddy_allocator_init :: proc(b: ^Buddy_Allocator, data: []byte, alignment: uint) {
+buddy_allocator_init :: proc(b: ^Buddy_Allocator, data: []byte, alignment: uint, loc := #caller_location) {
 	assert(data != nil)
-	assert(is_power_of_two(uintptr(len(data))))
-	assert(is_power_of_two(uintptr(alignment)))
-
+	assert(is_power_of_two(uintptr(len(data))), "Size of the backing buffer must be power of two", loc)
+	assert(is_power_of_two(uintptr(alignment)), "Alignment must be a power of two", loc)
 	alignment := alignment
 	if alignment < size_of(Buddy_Block) {
 		alignment = size_of(Buddy_Block)
 	}
-
 	ptr := raw_data(data)
-	assert(uintptr(ptr) % uintptr(alignment) == 0, "data is not aligned to minimum alignment")
-
+	assert(uintptr(ptr) % uintptr(alignment) == 0, "data is not aligned to minimum alignment", loc)
 	b.head = (^Buddy_Block)(ptr)
-
 	b.head.size = len(data)
 	b.head.is_free = true
-
 	b.tail = buddy_block_next(b.head)
-
 	b.alignment = alignment
 }
 
@@ -1274,19 +1256,25 @@ buddy_block_size_required :: proc(b: ^Buddy_Allocator, size: uint) -> uint {
 	actual_size := b.alignment
 	size += size_of(Buddy_Block)
 	size = align_forward_uint(size, b.alignment)
-
 	for size > actual_size {
 		actual_size <<= 1
 	}
-
 	return actual_size
 }
 
 @(require_results)
-buddy_allocator_alloc :: proc(b: ^Buddy_Allocator, size: uint, zeroed: bool) -> ([]byte, Allocator_Error) {
+buddy_allocator_alloc :: proc(b: ^Buddy_Allocator, size: uint) -> ([]byte, Allocator_Error) {
+	bytes, err := buddy_allocator_alloc_non_zeroed(b, size)
+	if bytes != nil {
+		zero_slice(bytes)
+	}
+	return bytes, err
+}
+
+@(require_results)
+buddy_allocator_alloc_non_zeroed :: proc(b: ^Buddy_Allocator, size: uint) -> ([]byte, Allocator_Error) {
 	if size != 0 {
 		actual_size := buddy_block_size_required(b, size)
-
 		found := buddy_block_find_best(b.head, b.tail, actual_size)
 		if found != nil {
 			// Try to coalesce all the free buddy blocks and then search again
@@ -1297,32 +1285,28 @@ buddy_allocator_alloc :: proc(b: ^Buddy_Allocator, size: uint, zeroed: bool) ->
 			return nil, .Out_Of_Memory
 		}
 		found.is_free = false
-
 		data := ([^]byte)(found)[b.alignment:][:size]
-		if zeroed {
-			zero_slice(data)
-		}
 		return data, nil
 	}
 	return nil, nil
 }
 
+@(require_results)
 buddy_allocator_free :: proc(b: ^Buddy_Allocator, ptr: rawptr) -> Allocator_Error {
 	if ptr != nil {
 		if !(b.head <= ptr && ptr <= b.tail) {
 			return .Invalid_Pointer
 		}
-
 		block := (^Buddy_Block)(([^]byte)(ptr)[-b.alignment:])
 		block.is_free = true
-
 		buddy_block_coalescence(b.head, b.tail)
 	}
 	return nil
 }
 
 buddy_allocator_proc :: proc(
-	allocator_data: rawptr, mode: Allocator_Mode,
+	allocator_data: rawptr,
+	mode: Allocator_Mode,
 	size, alignment: int,
 	old_memory: rawptr,
 	old_size: int,
@@ -1330,10 +1314,11 @@ buddy_allocator_proc :: proc(
 ) -> ([]byte, Allocator_Error) {
 
 	b := (^Buddy_Allocator)(allocator_data)
-
 	switch mode {
-	case .Alloc, .Alloc_Non_Zeroed:
-		return buddy_allocator_alloc(b, uint(size), mode == .Alloc)
+	case .Alloc:
+		return buddy_allocator_alloc(b, uint(size))
+	case .Alloc_Non_Zeroed:
+		return buddy_allocator_alloc_non_zeroed(b, uint(size))
 	case .Resize:
 		return default_resize_bytes_align(byte_slice(old_memory, old_size), size, alignment, buddy_allocator(b))
 	case .Resize_Non_Zeroed:
@@ -1341,13 +1326,11 @@ buddy_allocator_proc :: proc(
 	case .Free:
 		return nil, buddy_allocator_free(b, old_memory)
 	case .Free_All:
-
 		alignment := b.alignment
 		head := ([^]byte)(b.head)
 		tail := ([^]byte)(b.tail)
 		data := head[:ptr_sub(tail, head)]
 		buddy_allocator_init(b, data, alignment)
-
 	case .Query_Features:
 		set := (^Allocator_Mode_Set)(old_memory)
 		if set != nil {