diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 03c60e83..ccb3076d 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -4147,6 +4147,63 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, } ctrl_c2u_push_events(&evts); + //- rjf: when a new process is loaded, for the first module, pre-emptively try + // to open all adjacent debug infos. with debug events, we learn about loaded + // modules serially, and we need to completely load debug info before continuing. + // for massive projects, this is a problem, because completely loading debug info + // isn't a trivial cost, and there are often 100s of DLLs. + // + // an imperfect but usually reasonable heuristic is to look at adjacent debug info + // files, in the same directory as the initially loaded, and pre-emptively convert + // all of them (which for us is the heaviest part of debug info loading, if native + // RDI is not used). + if(event->kind == DMN_EventKind_LoadModule) + { + CTRL_Handle process_handle = ctrl_handle_make(CTRL_MachineID_Local, event->process); + CTRL_Handle loaded_module_handle = ctrl_handle_make(CTRL_MachineID_Local, event->module); + CTRL_Entity *process = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, process_handle); + CTRL_Entity *loaded_module = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, loaded_module_handle); + B32 is_first = 1; + for(CTRL_Entity *child = process->first; child != &ctrl_entity_nil; child = child->next) + { + if(child->kind == CTRL_EntityKind_Module && child != loaded_module) + { + is_first = 0; + break; + } + } + if(is_first) + { + DI_Key loaded_di_key = ctrl_dbgi_key_from_module(loaded_module); + String8 loaded_di_name = str8_skip_last_slash(loaded_di_key.path); + String8 containing_folder_path = str8_chop_last_slash(loaded_di_key.path); + if(containing_folder_path.size < loaded_di_key.path.size) + { + String8 debug_info_ext = str8_skip_last_dot(loaded_di_key.path); + OS_FileIter *it = os_file_iter_begin(scratch.arena, containing_folder_path, OS_FileIterFlag_SkipFolders); + DI_KeyList preemptively_loaded_keys = {0}; + for(OS_FileInfo info = {0}; os_file_iter_next(scratch.arena, it, &info);) + { + if(str8_match(str8_skip_last_dot(info.name), debug_info_ext, StringMatchFlag_CaseInsensitive) && + !str8_match(loaded_di_name, info.name, StringMatchFlag_CaseInsensitive)) + { + DI_Key key = {push_str8f(scratch.arena, "%S/%S", containing_folder_path, info.name), info.props.modified}; + di_open(&key); + di_key_list_push(scratch.arena, &preemptively_loaded_keys, &key); + } + } + for(DI_KeyNode *n = preemptively_loaded_keys.first; n != 0; n = n->next) + { + DI_Scope *di_scope = di_scope_open(); + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &n->v, max_U64); + di_scope_close(di_scope); + di_close(&n->v); + } + os_file_iter_end(it); + } + } + } + //- rjf: clear process memory cache, if we've just started a lone process if(event->kind == DMN_EventKind_CreateProcess && ctrl_state->process_counter == 1) { @@ -5797,6 +5854,7 @@ ctrl_u2ms_dequeue_req(CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *o internal void ctrl_mem_stream_thread__entry_point(void *p) { + ThreadNameF("[ctrl] mem stream thread #%I64u", (U64)p); CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; for(;;) { @@ -5806,6 +5864,7 @@ ctrl_mem_stream_thread__entry_point(void *p) B32 zero_terminated = 0; ctrl_u2ms_dequeue_req(&process, &vaddr_range, &zero_terminated); U128 key = ctrl_calc_hash_store_key_from_process_vaddr_range(process, vaddr_range, zero_terminated); + ProfBegin("memory stream request"); //- rjf: unpack process memory cache key U64 process_hash = ctrl_hash_from_string(str8_struct(&process)); @@ -5956,5 +6015,6 @@ ctrl_mem_stream_thread__entry_point(void *p) //- rjf: broadcast changes os_condition_variable_broadcast(process_stripe->cv); + ProfEnd(); } } diff --git a/src/font_cache/font_cache.c b/src/font_cache/font_cache.c index ae23c3ec..14390a25 100644 --- a/src/font_cache/font_cache.c +++ b/src/font_cache/font_cache.c @@ -575,46 +575,48 @@ fnt_push_run_from_string(Arena *arena, FNT_Tag tag, F32 size, F32 base_align_px, FNT_Hash2StyleRasterCacheNode *hash2style_node = fnt_hash2style_from_tag_size_flags(tag, size, flags); //- rjf: decode string & produce run pieces - B32 first = 1; FNT_PieceChunkList piece_chunks = {0}; Vec2F32 dim = {0}; B32 font_handle_mapped_on_miss = 0; FP_Handle font_handle = {0}; U64 piece_substring_start_idx = 0; - for(U64 idx = 0; idx < string.size; first = 0) + U64 piece_substring_end_idx = 0; + for(U64 idx = 0; idx <= string.size;) { //- rjf: decode next codepoint & get piece substring, or continuation rule - String8 piece_substring; + U8 byte = (idx < string.size ? string.str[idx] : 0); B32 need_another_codepoint = 0; - switch(utf8_class[string.str[idx]>>3]) + if(byte == 0) + { + idx += 1; + } + else switch(utf8_class[byte>>3]) { case 1: { - piece_substring.str = &string.str[idx]; - piece_substring.size = 1; idx += 1; + piece_substring_end_idx += 1; + need_another_codepoint = 0; }break; default: { UnicodeDecode decode = utf8_decode(string.str+idx, string.size-idx); idx += decode.inc; - if(decode.inc == 0) { break; } - piece_substring.str = string.str + piece_substring_start_idx; - piece_substring.size = decode.inc; - // NOTE(rjf): assuming 1 codepoint per piece for now. + piece_substring_end_idx += decode.inc; + need_another_codepoint = 0; }break; } - //- rjf: need another codepoint? -> continue - if(need_another_codepoint) + //- rjf: need another codepoint, or have no substring? -> continue + if(need_another_codepoint || piece_substring_end_idx == piece_substring_start_idx) { continue; } - //- rjf: do not need another codepoint? -> bump piece start idx - { - piece_substring_start_idx = idx; - } + //- rjf: do not need another codepoint? -> grab substring, bump piece start idx + String8 piece_substring = str8_substr(string, r1u64(piece_substring_start_idx, piece_substring_end_idx)); + piece_substring_start_idx = idx; + piece_substring_end_idx = idx; //- rjf: determine if this piece is a tab - if so, use space info to draw B32 is_tab = (piece_substring.size == 1 && piece_substring.str[0] == '\t'); diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index 145e13af..1bda7c4a 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -2697,6 +2697,7 @@ rd_help_label(String8 string) internal DR_FancyStringList rd_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, Vec4F32 base_color, String8 string) { + ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); DR_FancyStringList fancy_strings = {0}; TXT_TokenArray tokens = txt_token_array_from_string__c_cpp(scratch.arena, 0, string); @@ -2857,6 +2858,7 @@ rd_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_s indirection_counter = ClampBot(0, indirection_counter); } scratch_end(scratch); + ProfEnd(); return fancy_strings; } @@ -2877,6 +2879,8 @@ rd_code_label(F32 alpha, B32 indirection_size_change, Vec4F32 base_color, String internal UI_Signal rd_line_edit(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, B32 *expanded_out, String8 pre_edit_value, String8 string) { + ProfBeginFunction(); + //- rjf: unpack visual metrics F32 expander_size_px = ui_top_font_size()*2.f; @@ -3282,6 +3286,7 @@ rd_line_edit(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx if(is_auto_focus_hot) { ui_pop_focus_hot(); } if(is_auto_focus_active) { ui_pop_focus_active(); } + ProfEnd(); return sig; } diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index 08e6af17..3830b205 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -160,7 +160,9 @@ txt_token_array_from_list(Arena *arena, TXT_TokenList *list) internal TXT_TokenArray txt_token_array_from_string__c_cpp(Arena *arena, U64 *bytes_processed_counter, String8 string) { + ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); + U64 chunk_size = Clamp(8, string.size/8, 4096); //- rjf: generate token list TXT_TokenChunkList tokens = {0}; @@ -234,7 +236,7 @@ txt_token_array_from_string__c_cpp(Arena *arena, U64 *bytes_processed_counter, S else { TXT_Token token = {TXT_TokenKind_Error, r1u64(idx, idx+1)}; - txt_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); + txt_token_chunk_list_push(scratch.arena, &tokens, chunk_size, &token); } } @@ -420,7 +422,7 @@ txt_token_array_from_string__c_cpp(Arena *arena, U64 *bytes_processed_counter, S break; } } - txt_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); + txt_token_chunk_list_push(scratch.arena, &tokens, chunk_size, &token); } // rjf: split symbols by maximum-munch-rule @@ -462,7 +464,7 @@ txt_token_array_from_string__c_cpp(Arena *arena, U64 *bytes_processed_counter, S found = 1; next_off = off + c_cpp_multichar_symbol_strings[idx].size; TXT_Token token = {TXT_TokenKind_Symbol, r1u64(active_token_start_idx+off, active_token_start_idx+next_off)}; - txt_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); + txt_token_chunk_list_push(scratch.arena, &tokens, chunk_size, &token); break; } } @@ -470,7 +472,7 @@ txt_token_array_from_string__c_cpp(Arena *arena, U64 *bytes_processed_counter, S { next_off = off+1; TXT_Token token = {TXT_TokenKind_Symbol, r1u64(active_token_start_idx+off, active_token_start_idx+next_off)}; - txt_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); + txt_token_chunk_list_push(scratch.arena, &tokens, chunk_size, &token); } } } @@ -478,7 +480,7 @@ txt_token_array_from_string__c_cpp(Arena *arena, U64 *bytes_processed_counter, S // rjf: all other tokens else { - txt_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); + txt_token_chunk_list_push(scratch.arena, &tokens, chunk_size, &token); } // rjf: increment by ender padding @@ -497,6 +499,7 @@ txt_token_array_from_string__c_cpp(Arena *arena, U64 *bytes_processed_counter, S //- rjf: token list -> token array TXT_TokenArray result = txt_token_array_from_chunk_list(arena, &tokens); scratch_end(scratch); + ProfEnd(); return result; }