Skip to content

Commit

Permalink
Add location tracking for memory allocations.
Browse files Browse the repository at this point in the history
  • Loading branch information
lerno committed Nov 9, 2023
1 parent e31f2a0 commit f39aa1a
Show file tree
Hide file tree
Showing 16 changed files with 185 additions and 338 deletions.
4 changes: 2 additions & 2 deletions lib/std/collections/bitset.c3
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ struct GrowableBitSet
* @param initial_capacity
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
**/
fn GrowableBitSet* GrowableBitSet.init_new(&self, usz initial_capacity = 1, Allocator* allocator = mem::heap())
fn GrowableBitSet* GrowableBitSet.init_new(&self, usz initial_capacity = 1, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
{
self.data.init_new(initial_capacity, allocator);
self.data.init_new(initial_capacity, allocator, env);
return self;
}

Expand Down
4 changes: 2 additions & 2 deletions lib/std/collections/list.c3
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ struct List (Printable)
* @param initial_capacity "The initial capacity to reserve"
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
**/
fn List* List.init_new(&self, usz initial_capacity = 16, Allocator* allocator = mem::heap())
fn List* List.init_new(&self, usz initial_capacity = 16, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
{
self.allocator = allocator;
self.size = 0;
if (initial_capacity > 0)
{
initial_capacity = math::next_power_of_2(initial_capacity);
self.entries = allocator.alloc_aligned(Type.sizeof * initial_capacity, .alignment = Type[1].alignof)!!;
self.entries = allocator.alloc_aligned(Type.sizeof * initial_capacity, .alignment = Type[1].alignof, .env = env)!!;
}
else
{
Expand Down
8 changes: 4 additions & 4 deletions lib/std/collections/map.c3
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ struct HashMap
* @require !map.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn HashMap* HashMap.init_new(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = mem::heap())
fn HashMap* HashMap.init_new(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
{
capacity = math::next_power_of_2(capacity);
map.allocator = allocator;
map.load_factor = load_factor;
map.threshold = (uint)(capacity * load_factor);
map.table = allocator.new_zero_array(Entry*, capacity);
map.table = allocator.new_zero_array(Entry*, capacity, .env = env);
return map;
}

Expand Down Expand Up @@ -62,9 +62,9 @@ fn bool HashMap.is_initialized(&map)
* @param [&inout] allocator "The allocator to use"
* @param [&in] other_map "The map to copy from."
**/
fn HashMap* HashMap.init_new_from_map(&self, HashMap* other_map, Allocator* allocator = mem::heap())
fn HashMap* HashMap.init_new_from_map(&self, HashMap* other_map, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
{
self.init_new(other_map.table.len, other_map.load_factor, allocator);
self.init_new(other_map.table.len, other_map.load_factor, allocator, env);
self.put_all_for_create(other_map);
return self;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/std/collections/object.c3
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ fn usz! Object.to_format(&self, Formatter* formatter) @dynamic
}
}

fn Object* new_obj(Allocator* allocator)
fn Object* new_obj(Allocator* allocator, TrackingEnv* env = mem::get_tracking_env())
{
Object* o = allocator.new(Object);
Object* o = allocator.new(Object, .env = env);
*o = { .allocator = allocator, .type = void.typeid };
return o;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/std/collections/priorityqueue.c3
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ struct PrivatePriorityQueue (Printable)
Heap heap;
}

fn void PrivatePriorityQueue.init_new(&self, usz initial_capacity = 16, Allocator* allocator = mem::heap()) @inline
fn void PrivatePriorityQueue.init_new(&self, usz initial_capacity = 16, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env()) @inline
{
self.heap.init_new(initial_capacity, allocator);
self.heap.init_new(initial_capacity, allocator, .env = env);
}

fn void PrivatePriorityQueue.init_temp(&self, usz initial_capacity = 16) @inline
Expand Down
46 changes: 23 additions & 23 deletions lib/std/core/dstring.c3
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ const usz MIN_CAPACITY @private = 16;
/**
* @require !self.data() "String already initialized"
**/
fn DString DString.init_new(&self, usz capacity = MIN_CAPACITY, Allocator* allocator = mem::heap())
fn DString DString.init_new(&self, usz capacity = MIN_CAPACITY, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
{
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY;
StringData* data = allocator.new(StringData, .end_padding = capacity);
StringData* data = allocator.new(StringData, .end_padding = capacity, .env = env);
data.allocator = allocator;
data.len = 0;
data.capacity = capacity;
Expand All @@ -27,17 +27,17 @@ fn DString DString.init_temp(&self, usz capacity = MIN_CAPACITY)
return *self;
}

fn DString new_with_capacity(usz capacity, Allocator* allocator = mem::heap())
fn DString new_with_capacity(usz capacity, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
{
return DString{}.init_new(capacity, allocator);
return DString{}.init_new(capacity, allocator, .env = env);
}

fn DString temp_with_capacity(usz capacity) => new_with_capacity(capacity, mem::temp()) @inline;

fn DString new(String c = "", Allocator* allocator = mem::heap())
fn DString new(String c = "", Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
{
usz len = c.len;
StringData* data = (StringData*)new_with_capacity(len, allocator);
StringData* data = (StringData*)new_with_capacity(len, allocator, env);
if (len)
{
data.len = len;
Expand All @@ -48,10 +48,10 @@ fn DString new(String c = "", Allocator* allocator = mem::heap())

fn DString temp_new(String s = "") => new(s, mem::temp()) @inline;

fn DString DString.new_concat(self, DString b, Allocator* allocator = mem::heap())
fn DString DString.new_concat(self, DString b, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
{
DString string;
string.init_new(self.len() + b.len(), allocator);
string.init_new(self.len() + b.len(), allocator, env);
string.append(self);
string.append(b);
return string;
Expand Down Expand Up @@ -148,37 +148,37 @@ fn void DString.append_char32(&self, Char32 c)

fn DString DString.tcopy(&self) => self.copy(mem::temp());

fn DString DString.copy(self, Allocator* allocator = null)
fn DString DString.copy(self, Allocator* allocator = null, TrackingEnv* env = mem::get_tracking_env())
{
if (!self)
{
if (allocator) return new_with_capacity(0, allocator);
if (allocator) return new_with_capacity(0, allocator, env);
return (DString)null;
}
StringData* data = self.data();
if (!allocator) allocator = mem::heap();
DString new_string = new_with_capacity(data.capacity, allocator);
DString new_string = new_with_capacity(data.capacity, allocator, env);
mem::copy((char*)new_string.data(), (char*)data, StringData.sizeof + data.len);
return new_string;
}

fn ZString DString.copy_zstr(self, Allocator* allocator = mem::heap())
fn ZString DString.copy_zstr(self, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
{
usz str_len = self.len();
if (!str_len)
{
return (ZString)allocator.calloc(1);
return (ZString)allocator.calloc(1, env);
}
char* zstr = allocator.alloc(str_len + 1);
char* zstr = allocator.alloc(str_len + 1, env);
StringData* data = self.data();
mem::copy(zstr, &data.chars, str_len);
zstr[str_len] = 0;
return (ZString)zstr;
}

fn String DString.copy_str(self, Allocator* allocator = mem::heap())
fn String DString.copy_str(self, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
{
return (String)self.copy_zstr(allocator)[:self.len()];
return (String)self.copy_zstr(allocator, env)[:self.len()];
}

fn String DString.tcopy_str(self) => self.copy_str(mem::temp()) @inline;
Expand Down Expand Up @@ -240,9 +240,9 @@ fn void DString.append_chars(&self, String str)
data.len += other_len;
}

fn Char32[] DString.copy_utf32(&self, Allocator* allocator = mem::heap())
fn Char32[] DString.copy_utf32(&self, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
{
return self.str_view().to_new_utf32(allocator) @inline!!;
return self.str_view().to_new_utf32(allocator, env) @inline!!;
}

fn void DString.append_string(&self, DString str)
Expand Down Expand Up @@ -354,15 +354,15 @@ fn usz! DString.appendfn(&self, String format, args...) @maydiscard
return len + 1;
}

fn DString new_join(String[] s, String joiner, Allocator* allocator = mem::heap())
fn DString new_join(String[] s, String joiner, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
{
if (!s.len) return (DString)null;
usz total_size = joiner.len * s.len;
foreach (String* &str : s)
{
total_size += str.len;
}
DString res = new_with_capacity(total_size, allocator);
DString res = new_with_capacity(total_size, allocator, env);
res.append(s[0]);
foreach (String* &str : s[1..])
{
Expand All @@ -384,12 +384,12 @@ fn StringData* DString.data(self) @inline @private
return (StringData*)self;
}

fn void DString.reserve(&self, usz addition)
fn void DString.reserve(&self, usz addition, TrackingEnv* env = mem::get_tracking_env())
{
StringData* data = self.data();
if (!data)
{
*self = dstring::new_with_capacity(addition);
*self = dstring::new_with_capacity(addition, .env = env);
return;
}
usz len = data.len + addition;
Expand All @@ -398,7 +398,7 @@ fn void DString.reserve(&self, usz addition)
if (new_capacity < MIN_CAPACITY) new_capacity = MIN_CAPACITY;
while (new_capacity < len) new_capacity *= 2;
data.capacity = new_capacity;
*self = (DString)data.allocator.realloc(data, StringData.sizeof + new_capacity);
*self = (DString)data.allocator.realloc(data, StringData.sizeof + new_capacity, env);
}

fn usz! DString.read_from_stream(&self, InStream* reader)
Expand Down
66 changes: 45 additions & 21 deletions lib/std/core/mem.c3
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,20 @@ macro void @scoped(Allocator* allocator; @body())
@body();
}

macro void @report_heap_allocs_in_scope(;@body())
{
TrackingAllocator tracker;
tracker.init(thread_allocator);
Allocator* old_allocator = thread_allocator;
thread_allocator = &tracker;
defer
{
thread_allocator = old_allocator;
tracker.print_report();
tracker.free();
}
@body();
}

macro void @stack_mem(usz $size; @body(Allocator* mem)) @builtin
{
Expand Down Expand Up @@ -494,36 +508,46 @@ fn void initialize_wasm_mem() @init(1) @private
thread_allocator = &wasm_allocator;
}

module std::core::mem @if(!env::TRACK_MEMORY);
module std::core::mem;

macro @clone(value) @builtin

macro TrackingEnv* get_tracking_env()
{
return mem::heap().clone(value);
$if env::TRACK_MEMORY:
return &&TrackingEnv { $$FILE, $$FUNC, $$LINE };
$else
return null;
$endif
}

macro @clone(value, TrackingEnv* env = mem::get_tracking_env()) @builtin
{
return mem::heap().clone(value, env);
}

macro @tclone(value) @builtin
{
return mem::temp().clone(value);
}

fn void* malloc(usz size) @builtin @inline
fn void* malloc(usz size, TrackingEnv* env = mem::get_tracking_env()) @builtin @inline
{
return mem::heap().alloc(size);
return mem::heap().alloc(size, env);
}

fn void* tmalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline
fn void* tmalloc(usz size, usz alignment = 0, usz offset = 0, TrackingEnv* env = mem::get_tracking_env()) @builtin @inline
{
return temp().acquire(size, false, alignment, offset, null)!!;
return temp().acquire(size, false, alignment, offset, env)!!;
}

macro new($Type)
macro new($Type, TrackingEnv* env = mem::get_tracking_env())
{
return heap().new($Type);
return heap().new($Type, .env = env);
}

macro new_clear($Type)
macro new_clear($Type, TrackingEnv* env = mem::get_tracking_env())
{
return heap().new_clear($Type);
return heap().new_clear($Type, env);
}

macro new_temp($Type)
Expand All @@ -536,44 +560,44 @@ macro new_temp_clear($Type)
return tcalloc($Type.sizeof);
}

macro new_array($Type, usz elements)
macro new_array($Type, usz elements, TrackingEnv* env = mem::get_tracking_env())
{
return heap().new_array($Type, elements);
return heap().new_array($Type, elements, .env = env);
}

macro temp_array($Type, usz elements)
{
return (($Type*)tmalloc($Type.sizeof * elements, $Type.alignof))[:elements];
}

macro new_zero_array($Type, usz elements)
macro new_zero_array($Type, usz elements, TrackingEnv* env = mem::get_tracking_env())
{
return heap().new_zero_array($Type, elements);
return heap().new_zero_array($Type, elements, env);
}

macro temp_zero_array($Type, usz elements)
{
return (($Type*)tcalloc($Type.sizeof * elements, $Type.alignof))[:elements];
}

fn void* calloc(usz size) @builtin @inline
fn void* calloc(usz size, TrackingEnv* env = mem::get_tracking_env()) @builtin @inline
{
return heap().calloc(size);
return heap().calloc(size, env);
}

fn void* tcalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline
{
return temp().acquire(size, false, alignment, offset, null)!!;
}

fn void* realloc(void *ptr, usz new_size) @builtin @inline
fn void* realloc(void *ptr, usz new_size, TrackingEnv* env = mem::get_tracking_env()) @builtin @inline
{
return heap().realloc(ptr, new_size);
return heap().realloc(ptr, new_size, env);
}

fn void free(void* ptr) @builtin @inline
fn void free(void* ptr, TrackingEnv* env = mem::get_tracking_env()) @builtin @inline
{
heap().free(ptr);
heap().free(ptr, env);
}

fn void* trealloc(void* ptr, usz size, usz alignment = mem::DEFAULT_MEM_ALIGNMENT) @builtin @inline
Expand Down
Loading

0 comments on commit f39aa1a

Please sign in to comment.