Lots of small changes

This commit is contained in:
Musa Mahmood 2025-12-06 13:02:24 -05:00
parent 6970a59c35
commit 619cd76ea9
19 changed files with 293 additions and 111 deletions

View File

@ -1,7 +1,7 @@
#include "lib_main.cpp" #include "lib_main.cpp"
// Toggles: // Toggles:
#define BASE_RUN_TESTS 1 #define BASE_RUN_TESTS 0
#define BUILD_EXPLORER_APP_WIN32 1 #define BUILD_EXPLORER_APP_WIN32 1
#define BUILD_CUSTOM_GUI 0 #define BUILD_CUSTOM_GUI 0

View File

@ -180,17 +180,8 @@ s64 reserve_size (Arena_Reserve ar) {
return 0; return 0;
} }
constexpr s64 Arena_Sizes[6] = {
64LL * 1024,
2LL * 1024 * 1024,
64LL * 1024 * 1024,
2LL * 1024 * 1024 * 1024,
64LL * 1024 * 1024 * 1024,
2LL * 1024 * 1024 * 1024 * 1024,
};
Arena_Reserve next_reserve_size (s64 size) { Arena_Reserve next_reserve_size (s64 size) {
for (u8 i = 0; i < 6; i += 1) { for (u8 i = 0; i < Arena_Reserve_Count; i += 1) {
if (size <= Arena_Sizes[i]) { if (size <= Arena_Sizes[i]) {
return (Arena_Reserve)i; return (Arena_Reserve)i;
} }

View File

@ -11,6 +11,7 @@ constexpr u16 ARENA_DEFAULT_ALIGNMENT = CPU_REGISTER_WIDTH_BYTES;
#define ARENA_DEBUG BUILD_DEBUG #define ARENA_DEBUG BUILD_DEBUG
constexpr s32 Arena_Reserve_Count = 7;
enum class Arena_Reserve: u8 { enum class Arena_Reserve: u8 {
Size_64K = 0, // these are used as indices in Arena_Free_List! Size_64K = 0, // these are used as indices in Arena_Free_List!
Size_2M = 1, Size_2M = 1,
@ -21,6 +22,16 @@ enum class Arena_Reserve: u8 {
Size_64T = 6, Size_64T = 6,
}; };
constexpr s64 Arena_Sizes[Arena_Reserve_Count] = {
64LL * 1024,
2LL * 1024 * 1024,
64LL * 1024 * 1024,
2LL * 1024 * 1024 * 1024,
64LL * 1024 * 1024 * 1024,
2LL * 1024 * 1024 * 1024 * 1024,
64LL * 1024 * 1024 * 1024 * 1024,
};
enum class Arena_Flags: u8 { enum class Arena_Flags: u8 {
None = 0, None = 0,
Chained = 0x01, Chained = 0x01,
@ -61,18 +72,8 @@ 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); void* arena_allocator_proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data);
// Interface API for normal use (idk how to explain - see Arena_Free_List.cpp) // Interface API for normal use (idk how to explain - see Arena_Free_List.cpp)
struct Arena_Free_List {
Mutex mutex;
s32 in_flight_count[6];
Array<Arena*> free_table[6];
#if ARENA_DEBUG
Array<Arena*> in_flight[6];
#endif
b32 initialized;
};
void initialize_arena_table (Allocator allocator); void initialize_arena_free_list (Allocator allocator);
Arena* next_arena (Arena_Reserve reserve_size); Arena* next_arena (Arena_Reserve reserve_size);
void release_arena (Arena* arena, bool delete_extra_pages=true); void release_arena (Arena* arena, bool delete_extra_pages=true);

View File

@ -3,6 +3,17 @@
// There should be some parameters regarding what the upper limit for idle // 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 // committed pages should be and a heuristic for maximum number of arenas waiting
struct Arena_Free_List {
Mutex mutex;
s32 in_flight_count[Arena_Reserve_Count];
Array<Arena*> free_table[Arena_Reserve_Count];
#if ARENA_DEBUG
Array<Arena*> in_flight[Arena_Reserve_Count];
#endif
b32 initialized;
};
global Arena_Free_List* arena_free_list; global Arena_Free_List* arena_free_list;
// Only call once from main thread! // Only call once from main thread!
@ -12,7 +23,7 @@ void initialize_arena_free_list (Allocator allocator) {
if (arena_free_list->initialized) if (arena_free_list->initialized)
return; return;
for (s32 i = 0; i < 6; i += 1) { for (s32 i = 0; i < Arena_Reserve_Count; i += 1) {
arena_free_list->in_flight_count[i] = 0; arena_free_list->in_flight_count[i] = 0;
arena_free_list->free_table[i].allocator = allocator; arena_free_list->free_table[i].allocator = allocator;
array_reserve(arena_free_list->free_table[i], 64); array_reserve(arena_free_list->free_table[i], 64);
@ -75,5 +86,14 @@ void release_arena (Arena* arena, bool delete_extra_pages) {
// arenas_to_delete_count -= 1; // arenas_to_delete_count -= 1;
// } // }
// } // }
}
s64 committed_bytes (ArrayView<Arena*> arenas) {
s64 sum = 0;
for (s64 i = 0; i < arenas.count; i += 1) {
sum += arena_usage_committed_bytes(arenas[i]);
}
return sum;
} }

View File

@ -62,14 +62,14 @@ void arena_delete (Arena* arena) {
if (!is_valid(arena)) return; if (!is_valid(arena)) return;
bool arena_was_boostrapped = (arena->flags & Arena_Flags::Is_Bootstrapped) == Arena_Flags::Is_Bootstrapped; bool arena_was_boostrapped = (arena->flags & Arena_Flags::Is_Bootstrapped) == Arena_Flags::Is_Bootstrapped;
VirtualFree(arena->memory_base, 0, MEM_RELEASE); // s64 size_tmp = reserve_size(arena);
s64 size_tmp = reserve_size(arena);
// printf("Releasing range %p:%p (size: %llu)\n", arena->memory_base, (u8*)arena->memory_base + size_tmp, size_tmp); // printf("Releasing range %p:%p (size: %llu)\n", arena->memory_base, (u8*)arena->memory_base + size_tmp, size_tmp);
if (!arena_was_boostrapped) { if (!arena_was_boostrapped) {
arena->memory_base = nullptr; arena->memory_base = nullptr;
} }
VirtualFree(arena->memory_base, 0, MEM_RELEASE);
} }
#endif #endif

View File

@ -190,7 +190,7 @@ void array_add (Array<T>& src, T new_item) {
template <typename T> template <typename T>
s64 array_find (Array<T>& src, T item) { s64 array_find (Array<T>& src, T item) {
ForArray(i, src) { for (s64 i = 0; i < src.count; i += 1) {
if (src[i] == item) return i; if (src[i] == item) return i;
} }
return -1; return -1;

View File

@ -169,12 +169,6 @@ force_inline s64 Next_Power_Of_Two(s64 v) {
#define MSVC_RUNTIME_CHECKS_RESTORE #define MSVC_RUNTIME_CHECKS_RESTORE
#endif #endif
// ForExpansions. Not sure if this is a good idea...
// ↓TODO(Low priority): Maybe remove these. I prefer verbose and clear over this.
#define ForArray(_idx_, _array_) for (s64 _idx_ = 0; _idx_ < (_array_).count; ++_idx_)
#define ForArrayStartingAt(_it_, _array_, _start_) for (s64 _it_ = _start_; _it_ < (_array_).count; _it_ += 1)
#define ForUpTo(_it_, _end_) for (s64 _it_ = 0; _it_ < _end_; _it_ += 1)
// Scoped Macros/Functions for auto_reset and auto_release // Scoped Macros/Functions for auto_reset and auto_release
// usage `Auto_Reset guard(arena);` within a scope. // usage `Auto_Reset guard(arena);` within a scope.
#define auto_reset(x) \ #define auto_reset(x) \
@ -324,3 +318,11 @@ struct Mutex_Lock_Guard {
} }
}; };
// Helper macros for raw arrays:
#define ArrayCount(array) sizeof(array) / sizeof(array[0])
// For-loop construct macros
#define for_each_index(_idx_, _until_) for (s64 _idx_ = 0; _idx_ < _until_; ++_idx_)
// For-loops for ArrayView<> compatible types
#define for_each(_idx_, _array_) for (s64 _idx_ = 0; _idx_ < (_array_).count; ++_idx_)
// #define for_each_starting_at(_it_, _array_, _start_) for (s64 _it_ = _start_; _it_ < (_array_).count; _it_ += 1)

View File

@ -1,6 +1,30 @@
// #NOTE: This Hash Table is borrowed from Jai's implementation! (With some tweaks) // #NOTE: This Hash Table is borrowed from Jai's implementation! (With some tweaks)
// I made my own version that's arena-backed, but the mechanisms are the same. // I made my own version that's arena-backed, but the mechanisms are the same.
// s32 drive_count = 0;
// for (s64 i = 0; i < drive_table->allocated; i += 1) {
// Table_Entry<string, OS_Drive>* entry = &drive_table->entries[i]; // we should take ptr here if we want to modify?
// if (entry->hash > HASH_TABLE_FIRST_VALID_HASH) {
// // #TODO #MOVE THIS + maybe don't check this every frame!
// // entry->value.is_present = Win32_Drive_Exists(entry->value.label);
// if (entry->value.label.data == nullptr) continue;
// Text(" > [%d] drive letter: %s (is_present: %d)", drive_count + 1, entry->value.label.data, entry->value.is_present);
// drive_count += 1;
// SameLine();
// push_allocator(temp());
// if (Button(format_cstring("Read NTFS MFT Raw##%s", entry->value.label.data))) {
// push_arena(thread_context()->arena);
// // auto_release(thread_context()->arena);
// auto dfs = NTFS_MFT_read_raw(entry->value.label);
// if (dfs == nullptr) {
// log("[NTFS_MFT_read_raw] operation failed");
// }
// }
// }
// }
typedef u32 hash_result; typedef u32 hash_result;
constexpr hash_result HASH_TABLE_FIRST_VALID_HASH = 2; constexpr hash_result HASH_TABLE_FIRST_VALID_HASH = 2;

View File

@ -281,4 +281,7 @@ string to_lower_copy (string s_orig) {
} }
return s; return s;
} }
#define format_cstring(fmt, ...) \
(char*)format_string(fmt, ##__VA_ARGS__).data

View File

@ -117,7 +117,7 @@ s64 thread_group_run (Thread* thread) {
// Thread_Group API: // Thread_Group API:
void init (Thread_Group* group, s32 group_thread_count, Thread_Group_Proc group_proc, void thread_group_init (Thread_Group* group, s32 group_thread_count, Thread_Group_Proc group_proc,
bool enable_work_stealing = false) { bool enable_work_stealing = false) {
// Set allocator if not already set: // Set allocator if not already set:
if (!group->allocator.proc) { if (!group->allocator.proc) {

View File

@ -1,4 +1,4 @@
// really hacky forward declares. // really #hacky forward declares.
struct Work_Entry; struct Work_Entry;
struct Worker_Info; struct Worker_Info;
struct Work_List; struct Work_List;

View File

@ -69,7 +69,7 @@ string format_cycles (u64 ticks) {
return format_string("%1.2f %s", count_f64, units[unit_index].data); return format_string("%1.2f %s", count_f64, units[unit_index].data);
} }
string format_bytes (s64 bytes) { string format_bytes (s64 bytes, s32 trailing_width = 3) {
string units[6] = { "B", "KB", "MB", "GB", "TB", "PB" }; string units[6] = { "B", "KB", "MB", "GB", "TB", "PB" };
f64 count_f64 = (f64)bytes; f64 count_f64 = (f64)bytes;
s32 unit_index = 0; s32 unit_index = 0;
@ -79,7 +79,16 @@ string format_bytes (s64 bytes) {
unit_index += 1; unit_index += 1;
} }
return format_string("%1.3f %s", count_f64, units[unit_index].data); switch (trailing_width) {
case 0: return format_string("%.0f %s", count_f64, units[unit_index].data);
case 1: return format_string("%.1f %s", count_f64, units[unit_index].data);
case 2: return format_string("%.2f %s", count_f64, units[unit_index].data);
case 3: return format_string("%.3f %s", count_f64, units[unit_index].data);
default: break;
}
Assert(trailing_width >= 0 && trailing_width <= 3);
return "";
} }
struct timed_block_print { struct timed_block_print {

View File

@ -6,8 +6,7 @@ void run_pre_setup_tests() {
string string_literal_example = "Hello, I am a string literal."; string string_literal_example = "Hello, I am a string literal.";
void run_post_setup_tests() { void run_post_setup_tests() {
debug_break(); log_warning("Hello, I am a warning :), and I am a big number: %lld", (s64)2935088889357);
log_warning("Hello, I am a warning :), and I am a big number: %lld", (s64)293509357);
log_error("Hello, I am an error - %s", "I'm another string"); log_error("Hello, I am an error - %s", "I'm another string");
log_error("This is an error"); log_error("This is an error");
printf("Running post-setup tests...\n"); printf("Running post-setup tests...\n");
@ -40,7 +39,6 @@ void run_post_setup_tests() {
print("Hello, I am just a printed message to stdout\n\n"); print("Hello, I am just a printed message to stdout\n\n");
// Testing file writes and reads: // Testing file writes and reads:
print("Writing some nonsense to a file.\n"); print("Writing some nonsense to a file.\n");
bool success = write_entire_file("D:/TempLocal/junk.txt", to_view(result)); bool success = write_entire_file("D:/TempLocal/junk.txt", to_view(result));

View File

@ -1,7 +1,8 @@
// #TODO: #OS_Win32 // #TODO: #OS_Win32
// [ ] #Thread cleanup: in `thread_deinit` is there any requirement to cleanup child threads?
// [ ] #Exception handling code in `Win32_Exception_Filter` // [ ] #Exception handling code in `Win32_Exception_Filter`
// [ ] #cpuid - enumerate CPUs and Thread count (current implementation doesn't work) // [~] #Thread cleanup: in `thread_deinit` is there any requirement to cleanup child threads?
// - I think no? Threads should handle their own lifetimes, and the parent threads should ensure child threads are complete
// before terminating.
#if OS_WINDOWS #if OS_WINDOWS
constexpr s64 FILETIME_TO_UNIX = 116444736000000000i64; constexpr s64 FILETIME_TO_UNIX = 116444736000000000i64;
@ -26,6 +27,7 @@ s64 GetUnixTimestampNanoseconds () {
#endif #endif
struct OS_System_Info { struct OS_System_Info {
// #cpuid
s32 logical_processor_count; s32 logical_processor_count;
s32 physical_core_count; s32 physical_core_count;
s32 primary_core_count; s32 primary_core_count;
@ -40,7 +42,9 @@ struct OS_System_Info {
Array<Monitor> monitors; // Back with GPAllocator Array<Monitor> monitors; // Back with GPAllocator
// #Drives // #Drives
Table<string, Win32_Drive> drives; Table<string, OS_Drive> drives; // should we just store ptrs to OS_Drive? I think so..
// That way we can fetch the OS_Drive* and have the pointer be stable. Especially if it's b
// backed by an arena.
}; };
struct OS_Process_Info { struct OS_Process_Info {
@ -126,7 +130,7 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) {
info->process_id = GetCurrentProcessId(); info->process_id = GetCurrentProcessId();
} }
// #cpuid // #cpuid
/*{ OS_System_Info* info = &global_win32_state.system_info; { OS_System_Info* info = &global_win32_state.system_info;
// [ ] Extract input args // [ ] Extract input args
u32 length; u32 length;
GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, (PDWORD)&length); GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, (PDWORD)&length);
@ -136,7 +140,8 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) {
u32 offset = 0; u32 offset = 0;
u32 all_cpus_count = 0; u32 all_cpus_count = 0; // all logical cpus
u32 physical_cpu_count = 0;
u32 max_performance = 0; u32 max_performance = 0;
u32 performance_core_count = 0; u32 performance_core_count = 0;
// u32 efficient_core_count; // u32 efficient_core_count;
@ -159,14 +164,15 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) {
performance_core_count += count_per_group_physical; performance_core_count += count_per_group_physical;
} }
physical_cpu_count += count_per_group_physical;
all_cpus_count += count_per_group; all_cpus_count += count_per_group;
} }
info->physical_core_count = (s32)all_cpus_count; info->physical_core_count = (s32)physical_cpu_count;
info->primary_core_count = (s32)performance_core_count; info->primary_core_count = (s32)performance_core_count;
info->secondary_core_count = info->physical_core_count - info->primary_core_count;
} }
// info->secondary_core_count = ;
*/
{ OS_System_Info* info = &global_win32_state.system_info; { OS_System_Info* info = &global_win32_state.system_info;
info->monitors.allocator = GPAllocator(); info->monitors.allocator = GPAllocator();
u8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = {0}; u8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = {0};
@ -209,6 +215,8 @@ C_LINKAGE DWORD OS_Windows_Thread_Entry_Point (void* parameter) {
} }
// Individual Thread API // Individual Thread API
#define thread_task(T) (T*)thread->data;
internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name="") { internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name="") {
Assert(thread != nullptr && proc != nullptr); Assert(thread != nullptr && proc != nullptr);
@ -234,6 +242,7 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name=
thread->context->thread_name = copy_string(thread_name); thread->context->thread_name = copy_string(thread_name);
thread->context->log_builder = new_string_builder(Arena_Reserve::Size_64M); thread->context->log_builder = new_string_builder(Arena_Reserve::Size_64M);
thread->context->error_arena = next_arena(Arena_Reserve::Size_64M); thread->context->error_arena = next_arena(Arena_Reserve::Size_64M);
thread->context->logger = {default_logger_proc, &default_logger};
thread->os_thread.windows_thread = windows_thread; thread->os_thread.windows_thread = windows_thread;
thread->os_thread.windows_thread_id = windows_thread_id; thread->os_thread.windows_thread_id = windows_thread_id;
@ -244,20 +253,24 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name=
return true; return true;
} }
internal void thread_deinit (Thread* thread) { internal void thread_deinit (Thread* thread, bool zero_thread=false) {
if (thread->os_thread.windows_thread) { if (thread->os_thread.windows_thread) {
CloseHandle(thread->os_thread.windows_thread); CloseHandle(thread->os_thread.windows_thread);
} }
thread->os_thread.windows_thread = nullptr; thread->os_thread.windows_thread = nullptr;
arena_delete(thread->context->temp); // #TODO: before releasing arena, force-delete extra pages?
arena_delete(thread->context->arena); // array_reset(*thread->context->log_builder);
free_string_builder(thread->context->log_builder); free_string_builder(thread->context->log_builder);
release_arena(thread->context->error_arena);
arena_delete(thread->context->temp);
arena_delete(thread->context->arena); // must come last because thread->context is allocated with this arena!
// memset(thread, 0xCD, sizeof(Thread); if (zero_thread) memset(thread, 0, sizeof(Thread));
} }
internal void thread_start (Thread* thread) { internal void thread_start (Thread* thread, void* thread_data = nullptr) {
if (thread_data) thread->data = thread_data;
ResumeThread(thread->os_thread.windows_thread); ResumeThread(thread->os_thread.windows_thread);
} }
@ -899,6 +912,26 @@ bool os_main_window_is_minimized () {
return os_window_is_minimized(get_main_window().window); return os_window_is_minimized(get_main_window().window);
} }
s32 os_cpu_logical_core_count () {
OS_System_Info* info = &global_win32_state.system_info;
return info->logical_processor_count;
}
s32 os_cpu_physical_core_count () {
OS_System_Info* info = &global_win32_state.system_info;
return info->physical_core_count;
}
s32 os_cpu_primary_core_count () {
OS_System_Info* info = &global_win32_state.system_info;
return info->primary_core_count;
}
s32 os_cpu_secondary_core_count () {
OS_System_Info* info = &global_win32_state.system_info;
return info->secondary_core_count;
}
// #Drives // #Drives
constexpr u64 Win32_Max_Path_Length = 260; constexpr u64 Win32_Max_Path_Length = 260;
bool Win32_Discover_Drives () { bool Win32_Discover_Drives () {

View File

@ -167,6 +167,7 @@ File_System Win32_filesystem_from_string (string s) {
} }
struct Dense_FS; // #Temp forward declare! struct Dense_FS; // #Temp forward declare!
struct Win32_Drive { struct Win32_Drive {
// Arena* pool;
string label; string label;
string volume_name; string volume_name;
Win32_Drive_Type type; Win32_Drive_Type type;

View File

@ -294,14 +294,24 @@ Dense_FS* NTFS_MFT_read_raw (string drive_path) {
log("Found %lld files (bytes_accessed: %s)", mft->file_count, format_bytes(mft->bytes_accessed).data); log("Found %lld files (bytes_accessed: %s)", mft->file_count, format_bytes(mft->bytes_accessed).data);
CloseHandle(file_handle); CloseHandle(file_handle);
return nullptr; return nullptr;
} }
// Version where we transform the format so it's optimal for sorting and searching:
// bool NTFS_MFT_read_and_convert () { // pass the structure we want to read into! struct NTFS_Enumeration_Task {
// auto_release_temp(); Arena* pool; // small arena just for results
OS_Drive* drive;
string drive_path; // The drive path we want to enumerate
};
s64 ntfs_enumeration_thread_proc (Thread* thread) {
auto task = thread_task(NTFS_Enumeration_Task);
// push_allocator(temp()); log("(Thread index: %lld) Task pointer: %p", thread->index, task);
// NTFS_MFT_Internal* mft = new_ntfs_drive();
// NTFS_MFT_read_raw|#TODO:
// } Sleep(100); // #temp
return 0;
}

View File

@ -11,9 +11,16 @@ struct Explorer {
// Array<Image_Data> frame_textures; // Array<Image_Data> frame_textures;
}; };
struct Ex1_NTFS_Enumeration {
bool initialized;
ArrayView<Thread> threads;
Array<Thread*> threads_in_flight;
};
// #Ex1_global_state // #Ex1_global_state
global ExplorerUI explorer_ui; global ExplorerUI explorer_ui;
global Explorer explorer; global Explorer explorer;
global Ex1_NTFS_Enumeration ex1_ntfs;
#define HOTKEY_ID_BRING_TO_FOREGROUND 1 #define HOTKEY_ID_BRING_TO_FOREGROUND 1
#define VK_SPACE_KEY_CODE 0x20 #define VK_SPACE_KEY_CODE 0x20
@ -39,19 +46,144 @@ bool Ex1_Register_Global_Hotkeys () {
#define TRIGGER_EVERY_FRAME false #define TRIGGER_EVERY_FRAME false
#define KEY_UNUSED false #define KEY_UNUSED false
// #global_hotkeys - should rename to 'generic program hotkeys' // #program_hotkeys (Not specific to Ex1)
global Key_Combination global_exit_hotkey { ImGuiKey_W, USE_CTRL, USE_SHIFT, KEY_UNUSED, TRIGGER_ONCE }; global Key_Combination program_exit_hotkey { ImGuiKey_W, USE_CTRL, USE_SHIFT, KEY_UNUSED, TRIGGER_ONCE };
global Key_Combination global_minimize_hotkey { ImGuiKey_W, USE_CTRL, KEY_UNUSED, KEY_UNUSED, TRIGGER_ONCE }; global Key_Combination program_minimize_hotkey { ImGuiKey_W, USE_CTRL, KEY_UNUSED, KEY_UNUSED, TRIGGER_ONCE };
bool Ex1_check_key_combinations() { bool Ex1_check_key_combinations() {
update_global_keyboard_state(); update_global_keyboard_state();
// #global_hotkeys // #program_hotkeys
if (check_key_combination(&global_exit_hotkey)) { if (check_key_combination(&program_exit_hotkey)) {
return true; return true;
} }
if (check_key_combination(&global_minimize_hotkey)) { if (check_key_combination(&program_minimize_hotkey)) {
Win32_Minimize_Window_To_Tray(get_main_window_pointer()); Win32_Minimize_Window_To_Tray(get_main_window_pointer());
} }
// #Ex1_hotkeys // #Ex1_hotkeys
return false; return false;
}
// #define drive_table() &global_win32_state.system_info.drives
void Ex1_Control_Panel () { using namespace ImGui;
Table<string, OS_Drive>* drive_table = &global_win32_state.system_info.drives;
Begin("Control Panel");
if (Button("Discover drives") || !table_is_valid(drive_table)) {
Win32_Discover_Drives();
}
Text("drive_table is valid: %d", table_is_valid(drive_table));
// Basic Hash Table iterator: #hash_table_iterator
s32 drive_count = 0;
for (s64 i = 0; i < drive_table->allocated; i += 1) {
Table_Entry<string, OS_Drive>* entry = &drive_table->entries[i]; // we should take ptr here if we want to modify?
if (entry->hash > HASH_TABLE_FIRST_VALID_HASH) {
// #TODO #MOVE THIS + maybe don't check this every frame!
// entry->value.is_present = Win32_Drive_Exists(entry->value.label);
if (entry->value.label.data == nullptr) continue;
Text(" > [%d] drive letter: %s (is_present: %d)", drive_count + 1, entry->value.label.data, entry->value.is_present);
drive_count += 1;
SameLine();
push_allocator(temp());
if (Button(format_cstring("Read NTFS MFT Raw##%s", entry->value.label.data))) {
push_arena(thread_context()->arena);
// auto_release(thread_context()->arena);
auto dfs = NTFS_MFT_read_raw(entry->value.label);
if (dfs == nullptr) {
log("[NTFS_MFT_read_raw] operation failed");
}
}
}
}
if (drive_count > 0) {
if (!ex1_ntfs.initialized) { Timed_Block_Print("Thread initialization (ntfs)");
push_allocator(GPAllocator());
ex1_ntfs.initialized = true;
s32 cpu_core_count = os_cpu_physical_core_count();
ex1_ntfs.threads = ArrayView<Thread>(cpu_core_count);
ex1_ntfs.threads_in_flight.allocator = GPAllocator();
for_each(t, ex1_ntfs.threads) {
string thread_name = format_string("ntfs_enumeration_thread#%d", t);
bool success = thread_init(&ex1_ntfs.threads[t], ntfs_enumeration_thread_proc, thread_name);
Assert(success);
}
}
}
if (drive_count > 0 && ex1_ntfs.initialized && Button("Enumerate all NTFS drives")) {
// if drive count exceeds the number of threads, we need to group them so each thread
// can enumerate multiple drives.
// We need to distribute the drives across our available threads:
// see: #hash_table_iterator (what part of this can we macro out?):
if (drive_count > ex1_ntfs.threads.count) {
debug_break(); // #TODO: Fix this!
}
for (s32 t = 0; t < drive_count; t += 1) {
Thread* thread = &ex1_ntfs.threads[t];
Arena* thread_arena = next_arena(Arena_Reserve::Size_64K);
push_arena(thread_arena);
auto thread_data = New<NTFS_Enumeration_Task>();
thread_data->pool = thread_arena;
// #TODO: fill out
thread_start(thread, thread_data);
array_add(ex1_ntfs.threads_in_flight, thread);
}
}
if (ex1_ntfs.threads_in_flight.count) {
Text("Threads in flight: %d", ex1_ntfs.threads_in_flight.count);
// keep track of which indices to remove!
for_each(t, ex1_ntfs.threads_in_flight) {
if (thread_is_done(ex1_ntfs.threads_in_flight[t])) {
Thread* thread = ex1_ntfs.threads_in_flight[t];
auto task = thread_task(NTFS_Enumeration_Task);
release_arena(task->pool);
thread_deinit(ex1_ntfs.threads_in_flight[t], true);
array_unordered_remove_by_index(ex1_ntfs.threads_in_flight, t);
t -= 1; // check this element index again!
}
}
}
End();
}
void ImGui_Debug_Panel () { using namespace ImGui;
push_allocator(temp());
Begin("Debug Panel");
SeparatorText("ex1_ntfs");
Text("Threads in flight count: %d", ex1_ntfs.threads_in_flight.count);
for_each(i, ex1_ntfs.threads) {
Text(" [%d] initialized: %d, has_context: %d, has_data: %d",
i, ex1_ntfs.threads[i].proc != nullptr, ex1_ntfs.threads[i].context != nullptr, ex1_ntfs.threads[i].data != nullptr);
}
// #cpuid
// Text("[cpus] physical: %d, logical: %d, primary: %d, secondary: %d", os_cpu_physical_core_count(), os_cpu_logical_core_count(), os_cpu_primary_core_count(), os_cpu_secondary_core_count());
SeparatorText("Arena In-Use List");
for (u8 i = 0; i < Arena_Reserve_Count; i += 1) {
auto t = format_cstring(
" [%s] in_use: %d, committed_bytes: %s",
format_bytes(Arena_Sizes[i], 0).data,
arena_free_list->in_flight_count[i],
format_bytes(committed_bytes(arena_free_list->in_flight[i])).data
);
Text(t);
}
SeparatorText("Arena Free List");
for (u8 i = 0; i < Arena_Reserve_Count; i += 1) {
auto t = format_cstring(
" [%s] free: %d, committed_bytes: %s",
format_bytes(Arena_Sizes[i], 0).data,
(s32)arena_free_list->free_table[i].count,
format_bytes(committed_bytes(arena_free_list->free_table[i])).data
);
Text(t);
}
SeparatorText("Child Threads");
End();
} }

View File

@ -339,49 +339,6 @@ struct ImGui_Font_Size {
} }
}; };
void ImGui_Debug_Panel () {
ImGui::Begin("Debug Panel");
Table<string, Win32_Drive>* drive_table = &global_win32_state.system_info.drives;
if (ImGui::Button("Debug_Break()")) {
debug_break();
}
if (ImGui::Button("Discover drives") || !table_is_valid(drive_table)) {
Win32_Discover_Drives();
}
ImGui::Text("drive_table is valid: %d", table_is_valid(drive_table));
// Most basic Table iterator
s32 current_index = 0;
for (s64 i = 0; i < drive_table->allocated; i += 1) {
Table_Entry<string, Win32_Drive>* entry = &drive_table->entries[i]; // we should take ptr here if we want to modify?
if (entry->hash > HASH_TABLE_FIRST_VALID_HASH) {
// #TODO #MOVE THIS + maybe don't check this every frame!
// entry->value.is_present = Win32_Drive_Exists(entry->value.label);
if (entry->value.label.data == nullptr) continue;
ImGui::Text(" > [%d] drive letter: %s (is_present: %d)", current_index, entry->value.label.data, entry->value.is_present);
current_index += 1;
ImGui::SameLine();
push_allocator(temp());
char* button_label = (char*)format_string("Read NTFS MFT Raw##%s", entry->value.label.data).data;
if (ImGui::Button(button_label)) {
push_arena(thread_context()->arena);
// auto_release(thread_context()->arena);
auto dfs = NTFS_MFT_read_raw(entry->value.label);
if (dfs == nullptr) {
log("[NTFS_MFT_read_raw] operation failed");
}
}
}
}
ImGui::End();
}
void ImGui_Show_Font_Info () { void ImGui_Show_Font_Info () {
ImGui::Begin("Font Settings"); // imgui_push_default_font_index(0); ImGui::Begin("Font Settings"); // imgui_push_default_font_index(0);
if (!ImGui_Default_Font_Loaded()){ if (!ImGui_Default_Font_Loaded()){

View File

@ -86,7 +86,7 @@ void Explorer_ImGui_Application_Win32 () {
imgui_default_font.sizes.allocator = GPAllocator(); imgui_default_font.sizes.allocator = GPAllocator();
imgui_default_font.font_name = font_file_name; imgui_default_font.font_name = font_file_name;
for (s64 i = 0; i < 6; i += 1) { for (s64 i = 0; i < ArrayCount(imgui_font_sizes); i += 1) {
f32 font_size = imgui_font_sizes[i]; f32 font_size = imgui_font_sizes[i];
ImFont* new_font = io.Fonts->AddFontFromFileTTF((char*)font_file_name.data, font_size); ImFont* new_font = io.Fonts->AddFontFromFileTTF((char*)font_file_name.data, font_size);
if (new_font) { if (new_font) {
@ -150,6 +150,7 @@ void Explorer_ImGui_Application_Win32 () {
ImGui::DockSpaceOverViewport(); ImGui::DockSpaceOverViewport();
ImGui_Debug_Panel(); ImGui_Debug_Panel();
Ex1_Control_Panel();
ImGui_Show_Font_Info(); ImGui_Show_Font_Info();
ImGui_Pop_Default_Font(); ImGui_Pop_Default_Font();