[WIP] Add debug tools for Arenas
This commit is contained in:
parent
6e1928aa03
commit
493efe4d74
@ -82,7 +82,12 @@ bool arena_commit_first_pages (Arena* arena, s64 commit_size, s64 start_offset)
|
||||
return true;
|
||||
}
|
||||
|
||||
Arena* bootstrap_arena (Arena_Reserve new_reserve, s32 default_commit_page_count) {
|
||||
// Arena* bootstrap_arena (Arena_Reserve new_reserve, s32 default_commit_page_count) {
|
||||
Arena* bootstrap_arena_internal (Arena_Reserve new_reserve, s32 default_commit_page_count, string file_path,
|
||||
string function_name, s32 line_number) {
|
||||
// #TODO: Store info in debug mode:
|
||||
// + Save thread ID/name MAKE A COPY OBVIOUSLY! + PUSH default_allocator!
|
||||
// WE USE default_allocator because this arena may be used to back an array!
|
||||
s64 commit_size = default_commit_page_count * PLATFORM_MEMORY_PAGE_SIZE;
|
||||
Assert(commit_size <= reserve_size(new_reserve));
|
||||
|
||||
@ -93,11 +98,18 @@ Arena* bootstrap_arena (Arena_Reserve new_reserve, s32 default_commit_page_count
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memcpy(arena_ptr, &new_arena, sizeof(Arena));
|
||||
memcpy(arena_ptr, &new_arena, sizeof(Arena));
|
||||
arena_ptr->current_point = arena_start(arena_ptr);
|
||||
|
||||
arena_set_bootstrap_flag(arena_ptr);
|
||||
|
||||
// #if BUILD_DEBUG
|
||||
// { push_allocator(default_allocator());
|
||||
// arena_ptr->file_path = copy_string(file_path);
|
||||
// arena_ptr->function_name =
|
||||
// }
|
||||
// #endif
|
||||
|
||||
return arena_ptr;
|
||||
}
|
||||
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
struct ExpandableArena; // fwd declare #temp
|
||||
|
||||
#if OS_WINDOWS
|
||||
constexpr u32 ARENA_DEFAULT_COMMIT_PAGE_COUNT = 16; // 16 * 4k page = 64kB
|
||||
constexpr s64 ARENA_DEFAULT_COMMIT_SIZE_BYTES = 65536;
|
||||
const u32 ARENA_DEFAULT_COMMIT_PAGE_COUNT = 16; // 16 * 4k page = 64kB
|
||||
const s64 ARENA_DEFAULT_COMMIT_SIZE_BYTES = 65536;
|
||||
#endif
|
||||
|
||||
constexpr u16 ARENA_DEFAULT_ALIGNMENT = CPU_REGISTER_WIDTH_BYTES;
|
||||
@ -65,6 +65,11 @@ struct Arena {
|
||||
Arena_Reserve reserve_size = Arena_Reserve::Size_64K;
|
||||
Arena_Flags flags = Arena_Flags::None;
|
||||
u32 initial_commit_page_count = ARENA_DEFAULT_COMMIT_PAGE_COUNT;
|
||||
#if BUILD_DEBUG
|
||||
string file_path;
|
||||
string function_name;
|
||||
s32 line_number;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef void* (*Memory_Wipe_Function)(void* memory, u64 byte_count);
|
||||
@ -72,9 +77,18 @@ typedef void* (*Memory_Wipe_Function)(void* memory, u64 byte_count);
|
||||
void* arena_allocator_proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data);
|
||||
|
||||
// Main API
|
||||
Arena* bootstrap_arena (Arena_Reserve new_reserve, s32 default_commit_page_count=ARENA_DEFAULT_COMMIT_PAGE_COUNT);
|
||||
#if BUILD_DEBUG
|
||||
#define bootstrap_arena(_reserve_) \
|
||||
bootstrap_arena_internal((_reserve_), (s32)ARENA_DEFAULT_COMMIT_PAGE_COUNT, __FILE__, __FUNCTION__, __LINE__)
|
||||
#else
|
||||
#define bootstrap_arena(_reserve_) \
|
||||
bootstrap_arena_internal((_reserve_), (s32)ARENA_DEFAULT_COMMIT_PAGE_COUNT)
|
||||
#endif
|
||||
|
||||
void arena_init (Arena* arena, Arena_Reserve new_reserve, s32 default_commit_page_count=16); // For when we're *not* bootstrapping arenas: (I'm debating if we should keep this..)
|
||||
Arena* bootstrap_arena_internal (Arena_Reserve new_reserve, s32 commit_page_count=ARENA_DEFAULT_COMMIT_PAGE_COUNT,
|
||||
string file_path="", string function_name="", s32 line_number=0);
|
||||
|
||||
void arena_init (Arena* arena, Arena_Reserve new_reserve, s32 commit_page_count=16); // For when we're *not* bootstrapping arenas: (I'm debating if we should keep this..)
|
||||
bool arena_commit_first_pages (Arena* arena, s64 commit_size, s64 start_offset=0); // This is useful for initializing arenas (arena_init), and for starting Arena-backed arrays.
|
||||
|
||||
void arena_clear_flags (Arena* arena);
|
||||
@ -146,7 +160,7 @@ struct FixedArena {
|
||||
void* fixed_arena_allocator_proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data);
|
||||
|
||||
// #FixedArena API
|
||||
FixedArena* bootstrap_fixed_arena (s64 size, Allocator backing_allocator);
|
||||
FixedArena* bootstrap_fixed_arena (s64 size, Allocator backing_allocator = { default_allocator_proc, nullptr });
|
||||
force_inline void destroy_arena (FixedArena* arena);
|
||||
Allocator allocator (FixedArena* arena);
|
||||
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#if BUILD_DEBUG
|
||||
constexpr s64 ARRAY_ARENA_START_OFFSET = 2 * 64; // sizeof(Arena)+sizeof(array)
|
||||
#else
|
||||
constexpr s64 ARRAY_ARENA_START_OFFSET = 64;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
struct ArenaArray { // #downcasts to an ArrayView.
|
||||
@ -41,13 +45,22 @@ ArenaArray<T>* arena_array_new (s64 preallocate_count, Arena_Reserve reserve_siz
|
||||
|
||||
array->count = 0;
|
||||
array->arena = arena;
|
||||
// #TODO: Should align to next cache line!
|
||||
array->data = array_start<T>(*array);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
template <typename T> T* array_start (ArenaArray<T>& array) {
|
||||
return (T*)(array.arena->memory_base + ARRAY_ARENA_START_OFFSET);
|
||||
T* memory = (T*)(array.arena->memory_base + ARRAY_ARENA_START_OFFSET);
|
||||
Assert((u8*)memory >= (u8*)array.arena->current_point);
|
||||
return memory;
|
||||
}
|
||||
|
||||
s64 max_array_size (ArenaArray<u8>& array) {
|
||||
u8* address_limit = array.arena->memory_base + reserve_size(array.arena);
|
||||
u8* address_start = array_start(array);
|
||||
return (s64)(address_limit - address_start);
|
||||
}
|
||||
|
||||
template <typename T> bool is_valid (ArenaArray<T>* array) {
|
||||
@ -160,10 +173,6 @@ template <typename T> void array_resize (ArenaArray<T>& array, s64 desired_item_
|
||||
}
|
||||
}
|
||||
|
||||
s64 max_array_size (ArenaArray<u8>& array) {
|
||||
return reserve_size(array.arena) - sizeof(Arena) - sizeof(ArenaArray<u8>);
|
||||
}
|
||||
|
||||
void array_arena_realloc (ArenaArray<u8>& array, s64 new_size, s64 old_size) {
|
||||
Assert(new_size <= max_array_size(array));
|
||||
|
||||
|
||||
@ -16,10 +16,10 @@ internal void Bootstrap_Main_Thread_Context () {
|
||||
// initialize_arena_free_list(default_allocator());
|
||||
|
||||
// 2. #NewContext Setup thread local context
|
||||
ExpandableArena* arena_ex = expandable_arena_new(Arena_Reserve::Size_64M, 16);
|
||||
ExpandableArena* arena_ex = bootstrap_expandable_arena(Arena_Reserve::Size_64M);
|
||||
|
||||
thread_local_context = New<Thread_Context>(allocator(arena_ex));
|
||||
thread_local_context->temp = expandable_arena_new(Arena_Reserve::Size_2M, 16);
|
||||
thread_local_context->temp = bootstrap_expandable_arena(Arena_Reserve::Size_2M);
|
||||
thread_local_context->arena = arena_ex;
|
||||
thread_local_context->allocator = allocator(arena_ex);
|
||||
thread_local_context->thread_idx = 0;
|
||||
|
||||
@ -54,19 +54,19 @@ string to_string (Error* error) {
|
||||
}
|
||||
|
||||
#define log_todo(fmt, ...) \
|
||||
Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::TODO, fmt, ##__VA_ARGS__)
|
||||
log_error_internal(__FILE__, __FUNCTION__, __LINE__, ErrorClass::TODO, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define log_fatal_error(fmt, ...) \
|
||||
Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::FATAL, fmt, ##__VA_ARGS__)
|
||||
log_error_internal(__FILE__, __FUNCTION__, __LINE__, ErrorClass::FATAL, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define log_error(fmt, ...) \
|
||||
Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::ERROR, fmt, ##__VA_ARGS__)
|
||||
log_error_internal(__FILE__, __FUNCTION__, __LINE__, ErrorClass::ERROR, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define log_warning(fmt, ...) \
|
||||
Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::WARNING, fmt, ##__VA_ARGS__)
|
||||
log_error_internal(__FILE__, __FUNCTION__, __LINE__, ErrorClass::WARNING, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define log_none(fmt, ...) \
|
||||
Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::NONE, fmt, ##__VA_ARGS__)
|
||||
log_error_internal(__FILE__, __FUNCTION__, __LINE__, ErrorClass::NONE, fmt, ##__VA_ARGS__)
|
||||
|
||||
Error* new_error (ErrorClass severity, string error_string) {
|
||||
Error* error = New<Error>();
|
||||
@ -77,7 +77,7 @@ Error* new_error (ErrorClass severity, string error_string) {
|
||||
return error;
|
||||
}
|
||||
|
||||
void Log_Error_2 (string file_path, string function_name, s32 line_number, ErrorClass severity, string fmt, ...) {
|
||||
void log_error_internal (string file_path, string function_name, s32 line_number, ErrorClass severity, string fmt, ...) {
|
||||
auto tctx = thread_context();
|
||||
Assert(tctx != nullptr);
|
||||
push_arena(tctx->error_arena);
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
ExpandableArena* expandable_arena_new (Arena_Reserve starting_reserve, s32 commit_page_count) {
|
||||
ExpandableArena* new_arena = (ExpandableArena*)bootstrap_arena(starting_reserve, commit_page_count);
|
||||
ExpandableArena* bootstrap_expandable_arena_internal (Arena_Reserve new_reserve, s32 commit_page_count,
|
||||
string file_path, string function_name, s32 line_number) {
|
||||
ExpandableArena* new_arena = (ExpandableArena*)bootstrap_arena_internal(
|
||||
new_reserve,
|
||||
commit_page_count,
|
||||
file_path,
|
||||
function_name,
|
||||
line_number);
|
||||
// Note: beyond first 32 bytes (sizeof(Arena)) ExpandableArena will not be initialized,
|
||||
// so we do it here:
|
||||
new_arena->current = (Arena*)new_arena;
|
||||
@ -15,6 +21,10 @@ ExpandableArena* expandable_arena_new (Arena_Reserve starting_reserve, s32 commi
|
||||
return new_arena;
|
||||
}
|
||||
|
||||
// force_inline ExpandableArena* bootstrap_expandable_arena (Arena_Reserve new_reserve, s32 commit_page_count) {
|
||||
// return bootstrap_expandable_arena_internal(new_reserve, commit_page_count, __FILE__, __FUNCTION__, __LINE__);
|
||||
// }
|
||||
|
||||
void* expandable_arena_allocator_proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data) {
|
||||
ExpandableArena* arena = (ExpandableArena*)allocator_data;
|
||||
Assert(arena != nullptr);
|
||||
|
||||
@ -16,9 +16,26 @@ struct ExpandableArena {
|
||||
// Note that this downcasts to Arena*, so can be initialized in the same way.
|
||||
Arena* current;
|
||||
Array<Arena*> next_arenas;
|
||||
#if BUILD_DEBUG
|
||||
string info;
|
||||
string file_path;
|
||||
string function_name;
|
||||
s32 line_number;
|
||||
#endif
|
||||
};
|
||||
|
||||
ExpandableArena* expandable_arena_new (Arena_Reserve starting_reserve=Arena_Reserve::Size_64K, s32 commit_page_count=8);
|
||||
#if BUILD_DEBUG
|
||||
#define bootstrap_expandable_arena(_reserve_) \
|
||||
bootstrap_expandable_arena_internal((_reserve_), (s32)ARENA_DEFAULT_COMMIT_PAGE_COUNT, __FILE__, __FUNCTION__, __LINE__)
|
||||
#else
|
||||
#define bootstrap_expandable_arena(_reserve_) \
|
||||
bootstrap_expandable_arena_internal((_reserve_), (s32)ARENA_DEFAULT_COMMIT_PAGE_COUNT)
|
||||
#endif
|
||||
|
||||
ExpandableArena* bootstrap_expandable_arena_internal (Arena_Reserve new_reserve=Arena_Reserve::Size_64K, s32 commit_page_count=ARENA_DEFAULT_COMMIT_PAGE_COUNT,
|
||||
string file_path="", string function_name="", s32 line_number=0);
|
||||
|
||||
// ExpandableArena* bootstrap_expandable_arena_internal (Arena_Reserve starting_reserve=Arena_Reserve::Size_64K, s32 commit_page_count=8);
|
||||
void* expandable_arena_allocator_proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data);
|
||||
bool is_valid (ExpandableArena* arena);
|
||||
void* expandable_arena_alloc (ExpandableArena* arena_ex, s64 byte_count);
|
||||
|
||||
@ -29,4 +29,4 @@ void print (string message) {
|
||||
void print_error (string error_message) {
|
||||
Logger* logger = context_logger();
|
||||
logger->proc(error_message, Log_Level::Error, logger->data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,23 +112,3 @@ string trim_right (string s, string chars=DEFAULT_SPACES, bool replace_with_zero
|
||||
// Need an API for inserting various types (ints, floats, etc.) into a String_Builder, and advancing
|
||||
// the count.
|
||||
|
||||
// #string_builder
|
||||
// #limitations This won't be as fast as Jon's String_Builder in jai because we're backing it with an
|
||||
// Arena, which requires a variable number of cycles depending on if our process has
|
||||
// memory available already. It also has a max capacity depending on what Arena_Reserve we choose.
|
||||
// That being said, the implementation is much simpler.
|
||||
typedef ArenaArray<u8> String_Builder; // struct String_Builder
|
||||
|
||||
force_inline String_Builder* new_string_builder (Arena_Reserve new_reserve=Arena_Reserve::Size_64K);
|
||||
force_inline void append (String_Builder* sb, string s);
|
||||
void append (String_Builder* sb, ArrayView<string> strings);
|
||||
// This should probably be called append_but_do_not_increment_count
|
||||
internal force_inline void append_no_add (String_Builder* sb, string s); // for appending null terminators, does not increment count.
|
||||
void print_to_builder (String_Builder* sb, string format, ...);
|
||||
void print_to_builder_internal (String_Builder* sb, string format, va_list args);
|
||||
string string_view (String_Builder* sb);
|
||||
internal force_inline void reset_string_builder (String_Builder* sb, bool keep_memory=false);
|
||||
|
||||
// #rename copy_string_and_free_builder
|
||||
force_inline string builder_to_string (String_Builder* sb); // returns copy and frees string_builder
|
||||
internal force_inline void free_string_builder (String_Builder* sb);
|
||||
|
||||
20
lib/Base/String_Builder.h
Normal file
20
lib/Base/String_Builder.h
Normal file
@ -0,0 +1,20 @@
|
||||
// #string_builder
|
||||
// #limitations This won't be as fast as Jon's String_Builder in jai because we're backing it with an
|
||||
// Arena, which requires a variable number of cycles depending on if our process has
|
||||
// memory available already. It also has a max capacity depending on what Arena_Reserve we choose.
|
||||
// That being said, the implementation is much simpler.
|
||||
typedef ArenaArray<u8> String_Builder; // struct String_Builder
|
||||
|
||||
force_inline String_Builder* new_string_builder (Arena_Reserve new_reserve=Arena_Reserve::Size_64K);
|
||||
force_inline void append (String_Builder* sb, string s);
|
||||
void append (String_Builder* sb, ArrayView<string> strings);
|
||||
// This should probably be called append_but_do_not_increment_count
|
||||
internal force_inline void append_no_add (String_Builder* sb, string s); // for appending null terminators, does not increment count.
|
||||
void print_to_builder (String_Builder* sb, string format, ...);
|
||||
void print_to_builder_internal (String_Builder* sb, string format, va_list args);
|
||||
string string_view (String_Builder* sb);
|
||||
internal force_inline void reset_string_builder (String_Builder* sb, bool keep_memory=false);
|
||||
|
||||
// #rename copy_string_and_free_builder
|
||||
force_inline string builder_to_string (String_Builder* sb); // returns copy and frees string_builder
|
||||
internal force_inline void free_string_builder (String_Builder* sb);
|
||||
@ -282,12 +282,12 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name)
|
||||
|
||||
s64 this_thread_index = InterlockedIncrement(&next_thread_index);
|
||||
// 2. #NewContext Setup NEW thread local context
|
||||
ExpandableArena* arena_ex = expandable_arena_new(Arena_Reserve::Size_64M, 16);
|
||||
ExpandableArena* arena_ex = bootstrap_expandable_arena(Arena_Reserve::Size_64M);
|
||||
push_arena(arena_ex);
|
||||
|
||||
// #NOTE: we don't assign thread_local_context until we hit the #thread_entry_point
|
||||
thread->context = New<Thread_Context>();
|
||||
thread->context->temp = expandable_arena_new(Arena_Reserve::Size_2M, 16);
|
||||
thread->context->temp = bootstrap_expandable_arena(Arena_Reserve::Size_2M);
|
||||
thread->context->arena = arena_ex;
|
||||
thread->context->allocator = allocator(arena_ex);
|
||||
thread->context->thread_idx = (s32)this_thread_index;
|
||||
|
||||
@ -15,9 +15,10 @@
|
||||
#include "lib/Base/Allocator.h"
|
||||
#include "lib/Base/Array.h"
|
||||
#include "lib/Base/General_Purpose_Allocator.h"
|
||||
#include "lib/Base/String.h"
|
||||
#include "lib/Base/Arena.h"
|
||||
#include "lib/Base/Arena_Array.h"
|
||||
#include "lib/Base/String.h"
|
||||
#include "lib/Base/String_Builder.h"
|
||||
#include "lib/Base/Hash_Functions.h"
|
||||
#include "lib/Base/Hash_Table.h"
|
||||
#include "lib/Base/Arena_Hash_Table.h"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user