Finish string module, add timing module
This commit is contained in:
parent
6d8a580724
commit
efdb057361
@ -3,8 +3,6 @@
|
||||
// There should be some parameters regarding what the upper limit for idle
|
||||
// committed pages should be and a heuristic for maximum number of arenas waiting
|
||||
|
||||
// API in Arena.h
|
||||
|
||||
global Arena_Table* arena_table;
|
||||
|
||||
// Only call once from main thread!
|
||||
@ -65,15 +63,13 @@ void release_arena (Arena* arena, bool delete_extra_pages) {
|
||||
array_add(arena_table->free_table[reserve_index], arena);
|
||||
|
||||
arena_table->in_flight_count[reserve_index] -= 1;
|
||||
/*
|
||||
// #TODO #garbage_collection
|
||||
if (arena_free_table[reserve_index].count > 64) {
|
||||
// s64 arenas_to_delete_count = arena_free_table[reserve_index].count - 64.
|
||||
// while (arenas_to_delete_count > 0) {
|
||||
// arena_delete(arena_free_table[arena_free_table.count-1]);
|
||||
// array_unordered_remove_by_index(..);
|
||||
// arenas_to_delete_count -= 1;
|
||||
// }
|
||||
}
|
||||
*/
|
||||
// if (arena_free_table[reserve_index].count > 64) {
|
||||
// s64 arenas_to_delete_count = arena_free_table[reserve_index].count - 64;
|
||||
// while (arenas_to_delete_count > 0) {
|
||||
// arena_delete(arena_free_table[arena_free_table.count-1]);
|
||||
// array_unordered_remove_by_index(..);
|
||||
// arenas_to_delete_count -= 1;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// See Context_Base in jai, and TCTX in raddebugger:
|
||||
|
||||
internal void Bootstrap_Main_Thread_Context () {
|
||||
// Timed_Block_Print_No_Context("Bootstrap_Main_Thread_Context");
|
||||
// 0. Setup general allocator
|
||||
GPAllocator_Initialize_Allocation_Tracker();
|
||||
|
||||
@ -10,6 +11,7 @@ internal void Bootstrap_Main_Thread_Context () {
|
||||
initialize_arena_table(GPAllocator());
|
||||
|
||||
// 2. Setup thread local context
|
||||
// #NewContext
|
||||
ExpandableArena* arena_ex = expandable_arena_new(Arena_Reserve::Size_64M, 16);
|
||||
|
||||
thread_local_context = New<Thread_Context>(get_allocator(arena_ex));
|
||||
@ -75,7 +77,7 @@ void temp_reset_keeping_memory() {
|
||||
arena_reset(context->temp, false);
|
||||
}
|
||||
|
||||
void temp_reset() {
|
||||
void temp_reset() { // alias: reset_temporary_storage.
|
||||
Thread_Context* context = get_thread_context();
|
||||
arena_reset(context->temp, true);
|
||||
}
|
||||
@ -23,6 +23,8 @@ thread_static Thread_Context* thread_local_context;
|
||||
|
||||
Thread_Context* get_thread_context ();
|
||||
|
||||
// #TODO #NewContext void create_thread_context (Thread_Context** context, string thread_name, bool is_main_thread);
|
||||
|
||||
internal void Bootstrap_Main_Thread_Context ();
|
||||
|
||||
struct Push_Allocator {
|
||||
|
||||
@ -35,7 +35,7 @@ string copy_string (string s) {
|
||||
}
|
||||
|
||||
string copy_string (char* c_string) {
|
||||
string str = {0};
|
||||
string str = {};
|
||||
s64 string_length = strlen(c_string);
|
||||
if (string_length == 0)
|
||||
return "";
|
||||
@ -72,11 +72,6 @@ force_inline string string_view (string s, s64 start_index, s64 view_count) {
|
||||
return { new_count, s.data + start_index };
|
||||
}
|
||||
|
||||
string copy_string_view (string s, s64 start_index, s64 view_count) {
|
||||
// maybe redundant...
|
||||
return copy_string(string_view(s, start_index, view_count));
|
||||
}
|
||||
|
||||
bool strings_match (string first_string, string second_string) {
|
||||
return (first_string == second_string);
|
||||
}
|
||||
@ -109,10 +104,33 @@ string wide_to_utf8 (u16* source, s32 length) {
|
||||
return utf8_string;
|
||||
}
|
||||
|
||||
wstring utf8_to_wide (string source) {
|
||||
if (!source) return {};
|
||||
s32 query_num_chars = MultiByteToWideChar(CP_UTF8, 0,
|
||||
(LPCCH)source.data, (s32)source.count, // @Robustness: Silent failure if too long. @Cleanup.
|
||||
nullptr, 0);
|
||||
if (query_num_chars <= 0) return {};
|
||||
|
||||
wstring name_u16s = wstring(query_num_chars);
|
||||
s32 result_num_chars = MultiByteToWideChar(CP_UTF8, 0,
|
||||
(LPCCH)source.data, (s32)source.count, // @Robustness: Silent failure if too long. @Cleanup.
|
||||
(LPWSTR)name_u16s.data, query_num_chars);
|
||||
|
||||
if (!result_num_chars) {
|
||||
internal_free(name_u16s.data);
|
||||
return {};
|
||||
}
|
||||
|
||||
Assert(result_num_chars <= query_num_chars);
|
||||
name_u16s.data[result_num_chars] = 0; // null terminate
|
||||
|
||||
return name_u16s;
|
||||
}
|
||||
|
||||
string format_string (char* format, ...) {
|
||||
constexpr s64 BUFFER_SIZE = 4096;
|
||||
|
||||
string str = {0};
|
||||
string str = {};
|
||||
|
||||
str.data = NewArray<u8>(BUFFER_SIZE);
|
||||
|
||||
@ -125,6 +143,23 @@ string format_string (char* format, ...) {
|
||||
return str;
|
||||
}
|
||||
|
||||
// #MemoryLeak #NoContext - memory will leak from this operation.
|
||||
string format_string_no_context (char* format, ...) {
|
||||
constexpr s64 BUFFER_SIZE = 4096;
|
||||
|
||||
string str = {};
|
||||
|
||||
str.data = (u8*)GPAllocator_New(BUFFER_SIZE);
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
// Note that this *is* null-terminated for compatibility.
|
||||
str.count = (s64)vsnprintf((char*)str.data, (size_t)BUFFER_SIZE, format, args);
|
||||
va_end(args);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
force_inline String_Builder* new_string_builder (Arena_Reserve new_reserve) {
|
||||
return arena_array_new<u8>(1, new_reserve);
|
||||
}
|
||||
|
||||
@ -40,6 +40,11 @@ struct string {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator ! () {
|
||||
Assert(count >= 0);
|
||||
return (data == nullptr || count == 0);
|
||||
}
|
||||
};
|
||||
|
||||
struct wstring {
|
||||
@ -50,6 +55,17 @@ struct wstring {
|
||||
count = 0;
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
wstring (s32 length) {
|
||||
data = NewArray<u16>(length + 1);
|
||||
s32 length_bytes = (length + 1) * sizeof(u16);
|
||||
count = length_bytes;
|
||||
}
|
||||
|
||||
bool operator ! () {
|
||||
Assert(count >= 0);
|
||||
return (data == nullptr || count == 0);
|
||||
}
|
||||
};
|
||||
|
||||
// ~Keep these API
|
||||
@ -63,23 +79,28 @@ void free(string& s);
|
||||
|
||||
// String manipulation & comparison
|
||||
force_inline string string_view (string s, s64 start_index, s64 view_count);
|
||||
string copy_string_view (string s, s64 start_index, s64 view_count);
|
||||
bool strings_match (string first_string, string second_string);
|
||||
|
||||
// #Unicode
|
||||
// #TODO: Make a raw version that returns the raw pointer?
|
||||
string wide_to_utf8 (u16* source, s32 length);
|
||||
// wstring utf8_to_wide (string source); TODO.
|
||||
wstring utf8_to_wide (string source);
|
||||
|
||||
string format_string (char* format, ...);
|
||||
string format_string_no_context (char* format, ...);
|
||||
|
||||
// Parsing stuff:
|
||||
// #TODO #Parsing stuff:
|
||||
// is_white_space(char: u8)
|
||||
// advance
|
||||
// eat_spaces
|
||||
|
||||
// Print stuff
|
||||
// string to type or type to string conversions
|
||||
// s64 string_to_int (string v, s32 base = 10, s64* remainder=nullptr);
|
||||
//
|
||||
// f64 string_to_f64
|
||||
// f32 string_to_f32
|
||||
|
||||
// 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
|
||||
|
||||
130
lib/Base/Timing.h
Normal file
130
lib/Base/Timing.h
Normal file
@ -0,0 +1,130 @@
|
||||
// #Timing API:
|
||||
#define System_Timed_Block_Print(name) \
|
||||
system_timed_block_print Concat(_sys_timed_block_print_guard, __LINE__)(name)
|
||||
#define Timed_Block_Print(name) \
|
||||
timed_block_print Concat(_timed_block_print_guard, __LINE__)(name)
|
||||
// This is for timing stuff that happens where context is not available.
|
||||
// memory will leak from this operation. #MemoryLeak #NoContext
|
||||
#define Timed_Block_Print_No_Context(name) \
|
||||
timed_block_print_no_context Concat(_timed_block_print_guard, __LINE__)(name)
|
||||
|
||||
|
||||
force_inline u64 rdtsc();
|
||||
|
||||
#if OS_WINDOWS
|
||||
#include <intrin.h>
|
||||
|
||||
#pragma intrinsic(__rdtsc)
|
||||
|
||||
force_inline u64 rdtsc() {
|
||||
return __rdtsc();
|
||||
}
|
||||
#endif
|
||||
|
||||
global u32 g_cpu_base_frequency_megahertz;
|
||||
|
||||
void set_cpu_base_frequency (u32 frequency_megahertz) {
|
||||
g_cpu_base_frequency_megahertz = frequency_megahertz;
|
||||
}
|
||||
|
||||
string format_time_seconds_no_context (f64 time) { // #MemoryLeak #NoContext
|
||||
if (time < 1.0e-6) { return format_string_no_context("%1.2f ns", time * 1.0e9); }
|
||||
if (time < 1.0e-3) { return format_string_no_context("%1.3f us", time * 1.0e6); }
|
||||
if (time < 1) { return format_string_no_context("%1.3f ms", time * 1.0e3); }
|
||||
|
||||
return format_string_no_context("%1.3f s", time);
|
||||
}
|
||||
|
||||
string format_cycles_no_context (u64 ticks) { // #MemoryLeak #NoContext
|
||||
string units[5] = { "cycles", "K cycles", "M cycles", "B cycles", "T cycles" };
|
||||
|
||||
f64 count_f64 = (f64)ticks;
|
||||
s64 unit_index = 0;
|
||||
while (count_f64 >= 1000 && unit_index < 4) { // 4 is from (units.count-1)
|
||||
count_f64 /= 1000.0;
|
||||
unit_index += 1;
|
||||
}
|
||||
|
||||
return format_string_no_context("%1.2f %s", count_f64, units[unit_index].data);
|
||||
}
|
||||
|
||||
string format_time_seconds (f64 time) {
|
||||
if (time < 1.0e-6) { return format_string("%1.2f ns", time * 1.0e9); }
|
||||
if (time < 1.0e-3) { return format_string("%1.3f us", time * 1.0e6); }
|
||||
if (time < 1) { return format_string("%1.3f ms", time * 1.0e3); }
|
||||
|
||||
return format_string("%1.3f s", time);
|
||||
}
|
||||
|
||||
string format_cycles (u64 ticks) {
|
||||
string units[5] = { "cycles", "K cycles", "M cycles", "B cycles", "T cycles" };
|
||||
|
||||
f64 count_f64 = (f64)ticks;
|
||||
s64 unit_index = 0;
|
||||
while (count_f64 >= 1000 && unit_index < 4) { // 4 is from (units.count-1)
|
||||
count_f64 /= 1000.0;
|
||||
unit_index += 1;
|
||||
}
|
||||
|
||||
return format_string("%1.2f %s", count_f64, units[unit_index].data);
|
||||
}
|
||||
|
||||
struct timed_block_print {
|
||||
string block_name;
|
||||
u64 start_tick;
|
||||
|
||||
timed_block_print(string _block_name) {
|
||||
Assert(g_cpu_base_frequency_megahertz != 0);
|
||||
Assert(thread_local_context != nullptr); // we need temp allocator initialized!
|
||||
block_name = _block_name;
|
||||
start_tick = rdtsc();
|
||||
}
|
||||
|
||||
~timed_block_print() {
|
||||
u64 end_tick = rdtsc();
|
||||
u64 tick_difference = end_tick - start_tick;
|
||||
f64 ticks_f64 = (f64)tick_difference;
|
||||
f64 elapsed_time_seconds = ticks_f64 / (f64)((s64)g_cpu_base_frequency_megahertz * 1000000);
|
||||
push_allocator(get_temp_allocator());
|
||||
log("[Timed_Block %s]: %s (%s)", block_name.data, format_time_seconds(elapsed_time_seconds).data, format_cycles(tick_difference).data);
|
||||
}
|
||||
};
|
||||
|
||||
struct timed_block_print_no_context {
|
||||
string block_name;
|
||||
u64 start_tick;
|
||||
|
||||
timed_block_print_no_context(string _block_name) {
|
||||
Assert(g_cpu_base_frequency_megahertz != 0);
|
||||
block_name = _block_name;
|
||||
start_tick = rdtsc();
|
||||
}
|
||||
|
||||
~timed_block_print_no_context() {
|
||||
u64 end_tick = rdtsc();
|
||||
u64 tick_difference = end_tick - start_tick;
|
||||
f64 ticks_f64 = (f64)tick_difference;
|
||||
f64 elapsed_time_seconds = ticks_f64 / (f64)((s64)g_cpu_base_frequency_megahertz * 1000000);
|
||||
printf("[Timed_Block(No Context) %s]: %s (%s)\n",
|
||||
block_name.data,
|
||||
format_time_seconds_no_context(elapsed_time_seconds).data,
|
||||
format_cycles_no_context(tick_difference).data);
|
||||
}
|
||||
};
|
||||
|
||||
struct system_timed_block_print {
|
||||
string block_name;
|
||||
f64 start_time;
|
||||
|
||||
system_timed_block_print(string _block_name) {
|
||||
block_name = _block_name;
|
||||
start_time = GetUnixTimestamp();
|
||||
}
|
||||
|
||||
~system_timed_block_print() {
|
||||
f64 end_time = GetUnixTimestamp();
|
||||
f64 elapsed_time_seconds = end_time - start_time;
|
||||
push_allocator(get_temp_allocator());
|
||||
log("[Timed_Block %s]: %s", block_name.data, format_time_seconds(elapsed_time_seconds).data);
|
||||
}
|
||||
};
|
||||
@ -74,6 +74,7 @@ internal LONG WINAPI Win32_Exception_Filter (EXCEPTION_POINTERS* exception_ptrs)
|
||||
|
||||
// internal void Main_Entry_Point (int argc, WCHAR **argv);
|
||||
internal void Win32_Entry_Point (int argc, WCHAR **argv) {
|
||||
// Timed_Block_Print("Win32_Entry_Point");
|
||||
// See: w32_entry_point_caller(); (raddebugger)
|
||||
SetUnhandledExceptionFilter(&Win32_Exception_Filter);
|
||||
|
||||
@ -173,7 +174,7 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) {
|
||||
|
||||
// [ ] Get Working directory (info->working_path)
|
||||
// [ ] GetEnvironmentStringsW
|
||||
// temp_reset();
|
||||
temp_reset();
|
||||
printf("Hello there!\n\n");
|
||||
}
|
||||
|
||||
@ -201,7 +202,7 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name=
|
||||
}
|
||||
|
||||
s64 this_thread_index = InterlockedIncrement(&next_thread_index);
|
||||
|
||||
// #NewContext
|
||||
ExpandableArena* arena_ex = expandable_arena_new(Arena_Reserve::Size_64M, 16);
|
||||
|
||||
thread->context = New<Thread_Context>(get_allocator(arena_ex));
|
||||
@ -209,8 +210,8 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name=
|
||||
thread->context->arena = arena_ex;
|
||||
thread->context->allocator = get_allocator(arena_ex);
|
||||
thread->context->thread_idx = (s32)this_thread_index;
|
||||
push_arena(arena_ex);
|
||||
thread->context->thread_name = copy_string(thread_name);
|
||||
thread->context->log_builder = new_string_builder(Arena_Reserve::Size_64M);
|
||||
|
||||
thread->os_thread.windows_thread = windows_thread;
|
||||
thread->os_thread.windows_thread_id = windows_thread_id;
|
||||
@ -229,6 +230,9 @@ internal void thread_deinit (Thread* thread) {
|
||||
|
||||
arena_delete(thread->context->temp);
|
||||
arena_delete(thread->context->arena);
|
||||
free_string_builder(thread->context->log_builder);
|
||||
|
||||
// memset(thread, 0xCD, sizeof(Thread);
|
||||
}
|
||||
|
||||
internal void thread_start (Thread* thread) {
|
||||
|
||||
@ -23,8 +23,9 @@
|
||||
#include "lib/Base/String.cpp"
|
||||
|
||||
#include "lib/Base/ErrorType.cpp"
|
||||
#include "lib/Base/Arena_Table.cpp"
|
||||
#include "lib/Base/Base_Thread_Context.h"
|
||||
#include "lib/Base/Timing.h"
|
||||
#include "lib/Base/Arena_Table.cpp"
|
||||
#include "lib/Base/Expandable_Arena.h"
|
||||
|
||||
#include "lib/Base/Arena.cpp"
|
||||
|
||||
@ -184,40 +184,52 @@ void ImGui_Application () {
|
||||
string string_literal_example = "Hello, I am a string literal.";
|
||||
|
||||
internal void Main_Entry_Point (int argc, WCHAR **argv) {
|
||||
set_cpu_base_frequency(3200); // REQUIRED FOR TIMING MODULE!
|
||||
// #NOTE: Be careful using a timing or auto-release macros
|
||||
// before setting up the thread context!
|
||||
Bootstrap_Main_Thread_Context();
|
||||
#if OS_WINDOWS
|
||||
Win32_Entry_Point(argc, argv); // This might be the problem.
|
||||
#endif
|
||||
#if OS_LINUX
|
||||
// Linux_Entry_Point(argc, argv);
|
||||
#endif
|
||||
// See: main_thread_base_entry_point
|
||||
temp_reset();
|
||||
push_allocator(get_temp_allocator());
|
||||
// tip: use auto_reset or auto_release with `get_thread_context()->arena`
|
||||
|
||||
{ Timed_Block_Print("string_builder_testing");
|
||||
temp_reset();
|
||||
push_allocator(get_temp_allocator());
|
||||
// tip: use auto_reset or auto_release with `get_thread_context()->arena`
|
||||
|
||||
// String builder example:
|
||||
// OK. I can work with this.
|
||||
|
||||
auto sb = new_string_builder(Arena_Reserve::Size_64K);
|
||||
append(sb, "string_literal_example");
|
||||
append(sb, " ");
|
||||
print_to_builder(sb, "There are %d cats in the %s", 64, "house.\n");
|
||||
append(sb, " > ");
|
||||
print_to_builder(sb, "some size_t: %u", (u64)3982739867);
|
||||
append(sb, "\n");
|
||||
print_to_builder(sb, "the literal: %s", string_literal_example.data);
|
||||
|
||||
// string result = string_view(sb);
|
||||
string result = builder_to_string(sb); // also frees
|
||||
// print((char*)result.data);
|
||||
log("Hello.");
|
||||
log("log() should automatically append newlines to these prints.");
|
||||
log("If it doesn't, I will be very upset.");
|
||||
log(result);
|
||||
log("Hello. There are %s things here\n", string_literal_example.data);
|
||||
|
||||
print("Hello, I am just a printed message to stdout\n\n");
|
||||
}
|
||||
{ string s = "hello I am cool";
|
||||
wstring sw = utf8_to_wide(s);
|
||||
printf("testing operator overload: %d\n", !s);
|
||||
printf("testing utf8_to_wide: %ls\n", sw.data);
|
||||
}
|
||||
// debug_break();
|
||||
|
||||
// String builder example:
|
||||
// OK. I can work with this.
|
||||
|
||||
auto sb = new_string_builder(Arena_Reserve::Size_64K);
|
||||
append(sb, "string_literal_example");
|
||||
append(sb, " ");
|
||||
print_to_builder(sb, "There are %d cats in the %s", 64, "house.\n");
|
||||
append(sb, " > ");
|
||||
print_to_builder(sb, "some size_t: %u", (u64)3982739867);
|
||||
append(sb, "\n");
|
||||
print_to_builder(sb, "the literal: %s", string_literal_example.data);
|
||||
|
||||
// string result = string_view(sb);
|
||||
string result = builder_to_string(sb); // also frees
|
||||
// print((char*)result.data);
|
||||
log("Hello.");
|
||||
log("log() should automatically append newlines to these prints.");
|
||||
log("If it doesn't, I will be very upset.");
|
||||
log(result);
|
||||
log("Hello. There are %s things here\n", string_literal_example.data);
|
||||
|
||||
print("Hello, I am just a printed message to stdout\n\n");
|
||||
|
||||
// free_string_builder(sb);
|
||||
|
||||
// ImGui_Application();
|
||||
|
||||
// #TODO: #Main - `Main_Entry_Point`
|
||||
|
||||
Loading…
Reference in New Issue
Block a user