mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-31 20:00:09 +00:00
Refactor core:mem/tlsf, add free_all support.
TODO: Allow the TLSF allocator to add additional pools when it would ordinarily OOM
by calling its backing allocator.
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
package test_core_mem
|
||||
|
||||
import "core:mem"
|
||||
import "core:mem/tlsf"
|
||||
import "core:mem/virtual"
|
||||
import "core:testing"
|
||||
import "core:slice"
|
||||
|
||||
@test
|
||||
test_tlsf_bitscan :: proc(t: ^testing.T) {
|
||||
@@ -54,3 +56,103 @@ test_align_bumping_block_limit :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, err, nil)
|
||||
testing.expect(t, len(data) == 896)
|
||||
}
|
||||
|
||||
@(test)
|
||||
tlsf_test_overlap_and_zero :: proc(t: ^testing.T) {
|
||||
default_allocator := context.allocator
|
||||
alloc: tlsf.Allocator
|
||||
defer tlsf.destroy(&alloc)
|
||||
|
||||
NUM_ALLOCATIONS :: 1_000
|
||||
BACKING_SIZE :: NUM_ALLOCATIONS * (1_000 + size_of(uintptr))
|
||||
|
||||
if err := tlsf.init_from_allocator(&alloc, default_allocator, BACKING_SIZE); err != .None {
|
||||
testing.fail_now(t, "TLSF init error")
|
||||
}
|
||||
context.allocator = tlsf.allocator(&alloc)
|
||||
|
||||
allocations := make([dynamic][]byte, 0, NUM_ALLOCATIONS, default_allocator)
|
||||
defer delete(allocations)
|
||||
|
||||
err: mem.Allocator_Error
|
||||
s: []byte
|
||||
|
||||
for size := 1; err == .None && size <= NUM_ALLOCATIONS; size += 1 {
|
||||
s, err = make([]byte, size)
|
||||
append(&allocations, s)
|
||||
}
|
||||
|
||||
slice.sort_by(allocations[:len(allocations)], proc(a, b: []byte) -> bool {
|
||||
return uintptr(raw_data(a)) < uintptr(raw_data((b)))
|
||||
})
|
||||
|
||||
for i in 0..<len(allocations) - 1 {
|
||||
fail_if_allocations_overlap(t, allocations[i], allocations[i + 1])
|
||||
fail_if_not_zeroed(t, allocations[i])
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
tlsf_test_free_all :: proc(t: ^testing.T) {
|
||||
default_allocator := context.allocator
|
||||
alloc: tlsf.Allocator
|
||||
defer tlsf.destroy(&alloc)
|
||||
|
||||
NUM_ALLOCATIONS :: 10
|
||||
ALLOCATION_SIZE :: mem.Megabyte
|
||||
BACKING_SIZE :: NUM_ALLOCATIONS * (ALLOCATION_SIZE + size_of(uintptr))
|
||||
|
||||
if init_err := tlsf.init_from_allocator(&alloc, default_allocator, BACKING_SIZE); init_err != .None {
|
||||
testing.fail_now(t, "TLSF init error")
|
||||
}
|
||||
context.allocator = tlsf.allocator(&alloc)
|
||||
|
||||
allocations: [2][dynamic][]byte
|
||||
allocations[0] = make([dynamic][]byte, 0, NUM_ALLOCATIONS, default_allocator) // After `init`
|
||||
allocations[1] = make([dynamic][]byte, 0, NUM_ALLOCATIONS, default_allocator) // After `free_all`
|
||||
defer {
|
||||
delete(allocations[0])
|
||||
delete(allocations[1])
|
||||
}
|
||||
|
||||
for {
|
||||
s := make([]byte, ALLOCATION_SIZE) or_break
|
||||
append(&allocations[0], s)
|
||||
}
|
||||
testing.expect(t, len(allocations[0]) >= 10)
|
||||
|
||||
free_all(tlsf.allocator(&alloc))
|
||||
|
||||
for {
|
||||
s := make([]byte, ALLOCATION_SIZE) or_break
|
||||
append(&allocations[1], s)
|
||||
}
|
||||
testing.expect(t, len(allocations[1]) >= 10)
|
||||
|
||||
for i in 0..<len(allocations[0]) {
|
||||
s0, s1 := allocations[0][i], allocations[1][i]
|
||||
assert(raw_data(s0) == raw_data((s1)))
|
||||
assert(len(s0) == len((s1)))
|
||||
}
|
||||
}
|
||||
|
||||
fail_if_not_zeroed :: proc(t: ^testing.T, a: []byte) {
|
||||
for b in a {
|
||||
if b != 0 {
|
||||
testing.fail_now(t, "Allocation wasn't zeroed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail_if_allocations_overlap :: proc(t: ^testing.T, a, b: []byte) {
|
||||
a, b := a, b
|
||||
|
||||
a_start := uintptr(raw_data(a))
|
||||
a_end := a_start + uintptr(len(a))
|
||||
b_start := uintptr(raw_data(b))
|
||||
b_end := b_start + uintptr(len(b))
|
||||
|
||||
if a_end >= b_end && b_end >= a_start {
|
||||
testing.fail_now(t, "Allocations overlapped")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user