77 lines
2.1 KiB
V
77 lines
2.1 KiB
V
// Copyright (c) 2026 Alexander Medvednikov. All rights reserved.
|
|
// Use of this source code is governed by an MIT license
|
|
// that can be found in the LICENSE file.
|
|
module profiler
|
|
|
|
import context
|
|
|
|
// Allocator interface - can be swapped at runtime
|
|
// Similar to Jai's context.allocator design
|
|
pub struct Allocator {
|
|
pub:
|
|
alloc_fn fn (size int, ctx voidptr) voidptr = default_alloc
|
|
free_fn fn (ptr voidptr, ctx voidptr) = default_free
|
|
realloc_fn fn (ptr voidptr, new_size int, ctx voidptr) voidptr = default_realloc
|
|
ctx voidptr // User data for allocator implementation
|
|
}
|
|
|
|
// Thread-local context (implicit parameter)
|
|
// This allows all allocations in a scope to be tracked without explicit annotations
|
|
|
|
@[thread_local]
|
|
__global context = Context{}
|
|
|
|
pub struct Context {
|
|
pub mut:
|
|
allocator Allocator = default_allocator
|
|
}
|
|
|
|
// Default allocator - just wraps malloc/free/realloc
|
|
pub const default_allocator = Allocator{
|
|
alloc_fn: default_alloc
|
|
free_fn: default_free
|
|
realloc_fn: default_realloc
|
|
ctx: unsafe { nil }
|
|
}
|
|
|
|
fn default_alloc(size int, ctx voidptr) voidptr {
|
|
return unsafe { C.malloc(size) }
|
|
}
|
|
|
|
fn default_free(ptr voidptr, ctx voidptr) {
|
|
unsafe { C.free(ptr) }
|
|
}
|
|
|
|
fn default_realloc(ptr voidptr, new_size int, ctx voidptr) voidptr {
|
|
return unsafe { C.realloc(ptr, new_size) }
|
|
}
|
|
|
|
// User code calls these - they use context.allocator implicitly
|
|
// This provides the Jai-like implicit allocation tracking
|
|
pub fn alloc(size int) voidptr {
|
|
return context.allocator.alloc_fn(size, context.allocator.ctx)
|
|
}
|
|
|
|
pub fn free(ptr voidptr) {
|
|
context.allocator.free_fn(ptr, context.allocator.ctx)
|
|
}
|
|
|
|
pub fn realloc(ptr voidptr, new_size int) voidptr {
|
|
return context.allocator.realloc_fn(ptr, new_size, context.allocator.ctx)
|
|
}
|
|
|
|
// Scoped allocator helper - saves and restores the allocator
|
|
// Usage:
|
|
// old := profiler.push_allocator(my_allocator)
|
|
// defer { profiler.pop_allocator(old) }
|
|
// // ... all allocations here use my_allocator
|
|
pub fn push_allocator(a Allocator) Allocator {
|
|
old := context.allocator
|
|
context.allocator = a
|
|
return old
|
|
}
|
|
|
|
pub fn pop_allocator(old Allocator) {
|
|
context.allocator = old
|
|
}
|