From 382ca331be07e3b71acbd93ea645eacb8d339e36 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Thu, 26 Mar 2026 19:38:49 +0100 Subject: [PATCH 1/3] runtime align_forward procs as source of truth --- .../runtime/default_temp_allocator_arena.odin | 9 --- base/runtime/internal.odin | 72 ++++++++----------- bench.odin | 69 ++++++++++++++++++ core/mem/mem.odin | 24 ++----- 4 files changed, 101 insertions(+), 73 deletions(-) create mode 100644 bench.odin diff --git a/base/runtime/default_temp_allocator_arena.odin b/base/runtime/default_temp_allocator_arena.odin index eafaf9fbe..f1d09792a 100644 --- a/base/runtime/default_temp_allocator_arena.odin +++ b/base/runtime/default_temp_allocator_arena.odin @@ -97,15 +97,6 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) @(require_results) arena_alloc :: proc(arena: ^Arena, size, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { - align_forward_uint :: proc "contextless" (ptr, align: uint) -> uint { - p := ptr - modulo := p & (align-1) - if modulo != 0 { - p += align - modulo - } - return p - } - assert(alignment & (alignment-1) == 0, "non-power of two alignment", loc) size := size diff --git a/base/runtime/internal.odin b/base/runtime/internal.odin index 12f0dceca..db17cb033 100644 --- a/base/runtime/internal.odin +++ b/base/runtime/internal.odin @@ -29,6 +29,30 @@ byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byt return ([^]byte)(data)[:max(len, 0)] } +@(require_results) +align_forward_uint :: #force_inline proc "odin" (ptr, align: uint) -> uint { + assert(is_power_of_two_uint(align)) + return (ptr + align-1) & ~(align-1) +} + +@(require_results) +align_forward_int :: #force_inline proc "odin" (ptr, align: int) -> int { + assert(is_power_of_two_int(align)) + return int(align_forward_uint(uint(ptr), uint(align))) +} + +@(require_results) +align_forward_uintptr :: #force_inline proc "odin" (ptr, align: uintptr) -> uintptr { + return uintptr(align_forward_uint(uint(ptr), uint(align))) +} + +align_forward :: proc { + align_forward_int, + align_forward_uint, + align_forward_uintptr, +} + +@(require_results) is_power_of_two_int :: #force_inline proc "contextless" (x: int) -> bool { if x <= 0 { return false @@ -36,51 +60,17 @@ is_power_of_two_int :: #force_inline proc "contextless" (x: int) -> bool { return (x & (x-1)) == 0 } -align_forward_int :: #force_inline proc "odin" (ptr, align: int) -> int { - assert(is_power_of_two_int(align)) - - p := ptr - modulo := p & (align-1) - if modulo != 0 { - p += align - modulo - } - return p -} - +@(require_results) is_power_of_two_uint :: #force_inline proc "contextless" (x: uint) -> bool { - if x <= 0 { + if x == 0 { return false } return (x & (x-1)) == 0 } -align_forward_uint :: #force_inline proc "odin" (ptr, align: uint) -> uint { - assert(is_power_of_two_uint(align)) - - p := ptr - modulo := p & (align-1) - if modulo != 0 { - p += align - modulo - } - return p -} - +@(require_results) is_power_of_two_uintptr :: #force_inline proc "contextless" (x: uintptr) -> bool { - if x <= 0 { - return false - } - return (x & (x-1)) == 0 -} - -align_forward_uintptr :: #force_inline proc "odin" (ptr, align: uintptr) -> uintptr { - assert(is_power_of_two_uintptr(align)) - - p := ptr - modulo := p & (align-1) - if modulo != 0 { - p += align - modulo - } - return p + return is_power_of_two_uint(uint(x)) } is_power_of_two :: proc { @@ -89,12 +79,6 @@ is_power_of_two :: proc { is_power_of_two_uintptr, } -align_forward :: proc { - align_forward_int, - align_forward_uint, - align_forward_uintptr, -} - mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr { if data == nil { return nil diff --git a/bench.odin b/bench.odin new file mode 100644 index 000000000..aab09bbfe --- /dev/null +++ b/bench.odin @@ -0,0 +1,69 @@ +package bench + +import "core:slice" +import "core:math/rand" +import "core:time" +import "core:fmt" + +T :: u64 + +benchmark_sort :: proc(num: int) -> f64 { + data := make([]T, num) + defer delete(data) + for &x in data { + x = T(rand.uint64()) + } + + start := time.tick_now() + + slice.sort(data) + + return time.duration_milliseconds(time.tick_since(start)) +} + +benchmark_sort_with_indices :: proc(num: int) -> f64 { + data := make([]T, num) + defer delete(data) + for &x in data { + x = T(rand.uint64()) + } + + start := time.tick_now() + + // Important: includes 'sort_from_permutation_indices' + indices := slice.sort_with_indices(data) + + return time.duration_milliseconds(time.tick_since(start)) +} + +benchmark_proc :: proc(num: int, bench: proc(int) -> f64, expr := #caller_expression(bench)) { + + ITERS :: 10 + min_dur := max(f64) + max_dur := min(f64) + sum_dur: f64 + for i in 0.. bool { - if x <= 0 { - return false - } - return (x & (x-1)) == 0 -} +is_power_of_two :: runtime.is_power_of_two_uintptr /* Check if a pointer is aligned. @@ -497,11 +491,7 @@ bytes, `ptr` is returned. The specified alignment must be a power of 2. */ -@(require_results) -align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr { - assert(is_power_of_two(align)) - return (ptr + align-1) & ~(align-1) -} +align_forward_uintptr :: runtime.align_forward_uintptr /* Align pointer forward. @@ -526,10 +516,7 @@ bytes, `ptr` is returned. The specified alignment must be a power of 2. */ -@(require_results) -align_forward_int :: proc(ptr, align: int) -> int { - return int(align_forward_uintptr(uintptr(ptr), uintptr(align))) -} +align_forward_int :: runtime.align_forward_int /* Align uint forward. @@ -540,10 +527,7 @@ bytes, `ptr` is returned. The specified alignment must be a power of 2. */ -@(require_results) -align_forward_uint :: proc(ptr, align: uint) -> uint { - return uint(align_forward_uintptr(uintptr(ptr), uintptr(align))) -} +align_forward_uint :: runtime.align_forward_uint /* Align uintptr backwards. From e7c29e21eedc82bf272b64804c1b20da40ce29a7 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Thu, 26 Mar 2026 19:40:14 +0100 Subject: [PATCH 2/3] remove Fixed_Byte_Buffer --- core/mem/mem.odin | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/core/mem/mem.odin b/core/mem/mem.odin index 912d62dbc..66da0f2d9 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -610,32 +610,6 @@ reinterpret_copy :: proc "contextless" ($T: typeid, ptr: rawptr) -> (value: T) { return } -/* -Dynamic array with a fixed capacity buffer. - -This type represents dynamic arrays with a fixed-size backing buffer. Upon -allocating memory beyond reaching the maximum capacity, allocations from fixed -byte buffers return `nil` and no error. -*/ -Fixed_Byte_Buffer :: distinct [dynamic]byte - -/* -Create a fixed byte buffer from a slice. -*/ -@(require_results) -make_fixed_byte_buffer :: proc "contextless" (backing: []byte) -> Fixed_Byte_Buffer { - s := transmute(Raw_Slice)backing - d: Raw_Dynamic_Array - d.data = s.data - d.len = 0 - d.cap = s.len - d.allocator = Allocator{ - procedure = nil_allocator_proc, - data = nil, - } - return transmute(Fixed_Byte_Buffer)d -} - /* General-purpose align formula. From 2dd9c703376032160cf323464cdd86dcc9d57063 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Thu, 26 Mar 2026 19:51:51 +0100 Subject: [PATCH 3/3] remove bench.odin - unrelated to this PR --- bench.odin | 69 ------------------------------------------------------ 1 file changed, 69 deletions(-) delete mode 100644 bench.odin diff --git a/bench.odin b/bench.odin deleted file mode 100644 index aab09bbfe..000000000 --- a/bench.odin +++ /dev/null @@ -1,69 +0,0 @@ -package bench - -import "core:slice" -import "core:math/rand" -import "core:time" -import "core:fmt" - -T :: u64 - -benchmark_sort :: proc(num: int) -> f64 { - data := make([]T, num) - defer delete(data) - for &x in data { - x = T(rand.uint64()) - } - - start := time.tick_now() - - slice.sort(data) - - return time.duration_milliseconds(time.tick_since(start)) -} - -benchmark_sort_with_indices :: proc(num: int) -> f64 { - data := make([]T, num) - defer delete(data) - for &x in data { - x = T(rand.uint64()) - } - - start := time.tick_now() - - // Important: includes 'sort_from_permutation_indices' - indices := slice.sort_with_indices(data) - - return time.duration_milliseconds(time.tick_since(start)) -} - -benchmark_proc :: proc(num: int, bench: proc(int) -> f64, expr := #caller_expression(bench)) { - - ITERS :: 10 - min_dur := max(f64) - max_dur := min(f64) - sum_dur: f64 - for i in 0..