mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-18 20:02:22 -07:00
[mem]: Split alloc and alloc_non_zeroed for buddy allocator
This commit is contained in:
+21
-38
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user