diff --git a/exe_main.cpp b/exe_main.cpp index ce5e9f0..46540d1 100644 --- a/exe_main.cpp +++ b/exe_main.cpp @@ -1,7 +1,7 @@ #include "lib_main.cpp" // Toggles: -#define BASE_RUN_TESTS 1 +#define BASE_RUN_TESTS 0 #define BUILD_EXPLORER_APP_WIN32 1 #define BUILD_CUSTOM_GUI 0 diff --git a/lib/Base/Arena.cpp b/lib/Base/Arena.cpp index 4299f6f..302cd93 100644 --- a/lib/Base/Arena.cpp +++ b/lib/Base/Arena.cpp @@ -180,17 +180,8 @@ s64 reserve_size (Arena_Reserve ar) { 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) { - for (u8 i = 0; i < 6; i += 1) { + for (u8 i = 0; i < Arena_Reserve_Count; i += 1) { if (size <= Arena_Sizes[i]) { return (Arena_Reserve)i; } diff --git a/lib/Base/Arena.h b/lib/Base/Arena.h index c3eb7d3..7eca7e0 100644 --- a/lib/Base/Arena.h +++ b/lib/Base/Arena.h @@ -11,6 +11,7 @@ constexpr u16 ARENA_DEFAULT_ALIGNMENT = CPU_REGISTER_WIDTH_BYTES; #define ARENA_DEBUG BUILD_DEBUG +constexpr s32 Arena_Reserve_Count = 7; enum class Arena_Reserve: u8 { Size_64K = 0, // these are used as indices in Arena_Free_List! Size_2M = 1, @@ -21,6 +22,16 @@ enum class Arena_Reserve: u8 { 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 { None = 0, 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); // 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 free_table[6]; - -#if ARENA_DEBUG - Array 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); void release_arena (Arena* arena, bool delete_extra_pages=true); diff --git a/lib/Base/Arena_Free_List.cpp b/lib/Base/Arena_Free_List.cpp index 6cb6767..bce6e8a 100644 --- a/lib/Base/Arena_Free_List.cpp +++ b/lib/Base/Arena_Free_List.cpp @@ -3,6 +3,17 @@ // 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 +struct Arena_Free_List { + Mutex mutex; + s32 in_flight_count[Arena_Reserve_Count]; + Array free_table[Arena_Reserve_Count]; + +#if ARENA_DEBUG + Array in_flight[Arena_Reserve_Count]; +#endif + b32 initialized; +}; + global Arena_Free_List* arena_free_list; // Only call once from main thread! @@ -12,7 +23,7 @@ void initialize_arena_free_list (Allocator allocator) { if (arena_free_list->initialized) 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->free_table[i].allocator = allocator; 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; // } // } - +} + +s64 committed_bytes (ArrayView arenas) { + s64 sum = 0; + + for (s64 i = 0; i < arenas.count; i += 1) { + sum += arena_usage_committed_bytes(arenas[i]); + } + + return sum; } diff --git a/lib/Base/Arena_Windows.cpp b/lib/Base/Arena_Windows.cpp index 002312c..e0e5bbd 100644 --- a/lib/Base/Arena_Windows.cpp +++ b/lib/Base/Arena_Windows.cpp @@ -62,14 +62,14 @@ void arena_delete (Arena* arena) { if (!is_valid(arena)) return; 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); if (!arena_was_boostrapped) { arena->memory_base = nullptr; } + + VirtualFree(arena->memory_base, 0, MEM_RELEASE); } #endif diff --git a/lib/Base/Array.h b/lib/Base/Array.h index be9ea18..b9632eb 100644 --- a/lib/Base/Array.h +++ b/lib/Base/Array.h @@ -190,7 +190,7 @@ void array_add (Array& src, T new_item) { template s64 array_find (Array& src, T item) { - ForArray(i, src) { + for (s64 i = 0; i < src.count; i += 1) { if (src[i] == item) return i; } return -1; diff --git a/lib/Base/Base.h b/lib/Base/Base.h index dd7c1aa..4220045 100644 --- a/lib/Base/Base.h +++ b/lib/Base/Base.h @@ -169,12 +169,6 @@ force_inline s64 Next_Power_Of_Two(s64 v) { #define MSVC_RUNTIME_CHECKS_RESTORE #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 // usage `Auto_Reset guard(arena);` within a scope. #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) + diff --git a/lib/Base/Hash_Table.h b/lib/Base/Hash_Table.h index b3df3c0..5a8d8b2 100644 --- a/lib/Base/Hash_Table.h +++ b/lib/Base/Hash_Table.h @@ -1,6 +1,30 @@ // #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. +// s32 drive_count = 0; +// for (s64 i = 0; i < drive_table->allocated; i += 1) { +// Table_Entry* 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; constexpr hash_result HASH_TABLE_FIRST_VALID_HASH = 2; diff --git a/lib/Base/String.cpp b/lib/Base/String.cpp index 7a2ab6d..71ba236 100644 --- a/lib/Base/String.cpp +++ b/lib/Base/String.cpp @@ -281,4 +281,7 @@ string to_lower_copy (string s_orig) { } return s; -} \ No newline at end of file +} + +#define format_cstring(fmt, ...) \ + (char*)format_string(fmt, ##__VA_ARGS__).data \ No newline at end of file diff --git a/lib/Base/Thread_Group.cpp b/lib/Base/Thread_Group.cpp index 2709dc8..8859188 100644 --- a/lib/Base/Thread_Group.cpp +++ b/lib/Base/Thread_Group.cpp @@ -117,7 +117,7 @@ s64 thread_group_run (Thread* thread) { // 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) { // Set allocator if not already set: if (!group->allocator.proc) { diff --git a/lib/Base/Threads.cpp b/lib/Base/Threads.cpp index d061a6b..4689147 100644 --- a/lib/Base/Threads.cpp +++ b/lib/Base/Threads.cpp @@ -1,4 +1,4 @@ -// really hacky forward declares. +// really #hacky forward declares. struct Work_Entry; struct Worker_Info; struct Work_List; diff --git a/lib/Base/Timing.h b/lib/Base/Timing.h index 5ea9fd0..43d44a6 100644 --- a/lib/Base/Timing.h +++ b/lib/Base/Timing.h @@ -69,7 +69,7 @@ string format_cycles (u64 ticks) { 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" }; f64 count_f64 = (f64)bytes; s32 unit_index = 0; @@ -79,7 +79,16 @@ string format_bytes (s64 bytes) { 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 { diff --git a/lib/Base/run_tests.cpp b/lib/Base/run_tests.cpp index a51972f..cb0124c 100644 --- a/lib/Base/run_tests.cpp +++ b/lib/Base/run_tests.cpp @@ -6,8 +6,7 @@ void run_pre_setup_tests() { string string_literal_example = "Hello, I am a string literal."; void run_post_setup_tests() { - debug_break(); - log_warning("Hello, I am a warning :), and I am a big number: %lld", (s64)293509357); + log_warning("Hello, I am a warning :), and I am a big number: %lld", (s64)2935088889357); log_error("Hello, I am an error - %s", "I'm another string"); log_error("This is an error"); 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"); - // Testing file writes and reads: print("Writing some nonsense to a file.\n"); bool success = write_entire_file("D:/TempLocal/junk.txt", to_view(result)); diff --git a/lib/OS/OS_Win32.cpp b/lib/OS/OS_Win32.cpp index 1558b0c..e9635d7 100644 --- a/lib/OS/OS_Win32.cpp +++ b/lib/OS/OS_Win32.cpp @@ -1,7 +1,8 @@ // #TODO: #OS_Win32 -// [ ] #Thread cleanup: in `thread_deinit` is there any requirement to cleanup child threads? // [ ] #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 constexpr s64 FILETIME_TO_UNIX = 116444736000000000i64; @@ -26,6 +27,7 @@ s64 GetUnixTimestampNanoseconds () { #endif struct OS_System_Info { + // #cpuid s32 logical_processor_count; s32 physical_core_count; s32 primary_core_count; @@ -40,7 +42,9 @@ struct OS_System_Info { Array monitors; // Back with GPAllocator // #Drives - Table drives; + Table 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 { @@ -126,7 +130,7 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) { info->process_id = GetCurrentProcessId(); } // #cpuid - /*{ OS_System_Info* info = &global_win32_state.system_info; + { OS_System_Info* info = &global_win32_state.system_info; // [ ] Extract input args u32 length; GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, (PDWORD)&length); @@ -136,7 +140,8 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) { 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 performance_core_count = 0; // u32 efficient_core_count; @@ -159,14 +164,15 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) { performance_core_count += count_per_group_physical; } + physical_cpu_count += count_per_group_physical; 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->secondary_core_count = info->physical_core_count - info->primary_core_count; } - // info->secondary_core_count = ; - */ + { OS_System_Info* info = &global_win32_state.system_info; info->monitors.allocator = GPAllocator(); u8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = {0}; @@ -209,6 +215,8 @@ C_LINKAGE DWORD OS_Windows_Thread_Entry_Point (void* parameter) { } // Individual Thread API +#define thread_task(T) (T*)thread->data; + internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name="") { 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->log_builder = new_string_builder(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_id = windows_thread_id; @@ -244,20 +253,24 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name= return true; } -internal void thread_deinit (Thread* thread) { +internal void thread_deinit (Thread* thread, bool zero_thread=false) { if (thread->os_thread.windows_thread) { CloseHandle(thread->os_thread.windows_thread); } thread->os_thread.windows_thread = nullptr; - arena_delete(thread->context->temp); - arena_delete(thread->context->arena); + // #TODO: before releasing arena, force-delete extra pages? + // array_reset(*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); } @@ -899,6 +912,26 @@ bool os_main_window_is_minimized () { 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 constexpr u64 Win32_Max_Path_Length = 260; bool Win32_Discover_Drives () { diff --git a/lib/OS/OS_Win32.h b/lib/OS/OS_Win32.h index e3ddc30..5af2c0b 100644 --- a/lib/OS/OS_Win32.h +++ b/lib/OS/OS_Win32.h @@ -167,6 +167,7 @@ File_System Win32_filesystem_from_string (string s) { } struct Dense_FS; // #Temp forward declare! struct Win32_Drive { + // Arena* pool; string label; string volume_name; Win32_Drive_Type type; diff --git a/lib/OS/OS_Win32_NTFS.cpp b/lib/OS/OS_Win32_NTFS.cpp index b05aa65..c4f3e78 100644 --- a/lib/OS/OS_Win32_NTFS.cpp +++ b/lib/OS/OS_Win32_NTFS.cpp @@ -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); CloseHandle(file_handle); + 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! -// auto_release_temp(); + +struct NTFS_Enumeration_Task { + 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()); -// NTFS_MFT_Internal* mft = new_ntfs_drive(); + log("(Thread index: %lld) Task pointer: %p", thread->index, task); + // NTFS_MFT_read_raw|#TODO: -// } \ No newline at end of file + Sleep(100); // #temp + + return 0; +} \ No newline at end of file diff --git a/src/Ex1.cpp b/src/Ex1.cpp index 5455702..08481a0 100644 --- a/src/Ex1.cpp +++ b/src/Ex1.cpp @@ -11,9 +11,16 @@ struct Explorer { // Array frame_textures; }; +struct Ex1_NTFS_Enumeration { + bool initialized; + ArrayView threads; + Array threads_in_flight; +}; + // #Ex1_global_state global ExplorerUI explorer_ui; global Explorer explorer; +global Ex1_NTFS_Enumeration ex1_ntfs; #define HOTKEY_ID_BRING_TO_FOREGROUND 1 #define VK_SPACE_KEY_CODE 0x20 @@ -39,19 +46,144 @@ bool Ex1_Register_Global_Hotkeys () { #define TRIGGER_EVERY_FRAME false #define KEY_UNUSED false -// #global_hotkeys - should rename to 'generic program hotkeys' -global Key_Combination global_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 }; +// #program_hotkeys (Not specific to Ex1) +global Key_Combination program_exit_hotkey { ImGuiKey_W, USE_CTRL, USE_SHIFT, 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() { update_global_keyboard_state(); - // #global_hotkeys - if (check_key_combination(&global_exit_hotkey)) { + // #program_hotkeys + if (check_key_combination(&program_exit_hotkey)) { 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()); } // #Ex1_hotkeys return false; +} + +// #define drive_table() &global_win32_state.system_info.drives +void Ex1_Control_Panel () { using namespace ImGui; + Table* 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* 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(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(); + 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(); } \ No newline at end of file diff --git a/src/ImGui_Supplementary.cpp b/src/ImGui_Supplementary.cpp index de9c136..23e429c 100644 --- a/src/ImGui_Supplementary.cpp +++ b/src/ImGui_Supplementary.cpp @@ -339,49 +339,6 @@ struct ImGui_Font_Size { } }; -void ImGui_Debug_Panel () { - ImGui::Begin("Debug Panel"); - - Table* 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* 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 () { ImGui::Begin("Font Settings"); // imgui_push_default_font_index(0); if (!ImGui_Default_Font_Loaded()){ diff --git a/src/explorer_main.cpp b/src/explorer_main.cpp index 77530bd..a844810 100644 --- a/src/explorer_main.cpp +++ b/src/explorer_main.cpp @@ -86,7 +86,7 @@ void Explorer_ImGui_Application_Win32 () { imgui_default_font.sizes.allocator = GPAllocator(); 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]; ImFont* new_font = io.Fonts->AddFontFromFileTTF((char*)font_file_name.data, font_size); if (new_font) { @@ -150,6 +150,7 @@ void Explorer_ImGui_Application_Win32 () { ImGui::DockSpaceOverViewport(); ImGui_Debug_Panel(); + Ex1_Control_Panel(); ImGui_Show_Font_Info(); ImGui_Pop_Default_Font();