From ad995374bb4f46e0f2df5d38433b479d1a0c9634 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 20 Jun 2025 07:57:16 -0700 Subject: [PATCH] cache module requirement disqualifications; reuse within scope of same run (& thus same user bps) --- src/ctrl/ctrl_core.c | 208 ++++++++++++++++++++++++------------------- src/ctrl/ctrl_core.h | 16 ++++ 2 files changed, 132 insertions(+), 92 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 8a3c2c71..af4a9fdd 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1552,6 +1552,7 @@ ctrl_init(void) ctrl_state->ctrl_thread_entity_ctx_rw_mutex = os_rw_mutex_alloc(); ctrl_state->ctrl_thread_entity_store = ctrl_entity_ctx_rw_store_alloc(); ctrl_state->ctrl_thread_eval_cache = e_cache_alloc(); + ctrl_state->ctrl_thread_msg_process_arena = arena_alloc(); ctrl_state->dmn_event_arena = arena_alloc(); ctrl_state->user_entry_point_arena = arena_alloc(); ctrl_state->dbg_dir_arena = arena_alloc(); @@ -3708,9 +3709,75 @@ ctrl_thread__entry_point(void *p) log_infof("user2ctrl_msg:{kind:\"%S\"}\n", ctrl_string_from_msg_kind(msg->kind)); } - //- rjf: unpack per-message parameterizations & store + //- rjf: reset per-message state + arena_clear(ctrl_state->ctrl_thread_msg_process_arena); + ctrl_state->module_req_cache_slots_count = 1024; + ctrl_state->module_req_cache_slots = push_array(ctrl_state->ctrl_thread_msg_process_arena, CTRL_ModuleReqCacheNode *, ctrl_state->module_req_cache_slots_count); + MemoryZeroStruct(&ctrl_state->msg_user_bp_touched_files); + MemoryZeroStruct(&ctrl_state->msg_user_bp_touched_symbols); + MemoryCopyArray(ctrl_state->exception_code_filters, msg->exception_code_filters); + + //- rjf: gather all touched symbols by user breakpoints { - MemoryCopyArray(ctrl_state->exception_code_filters, msg->exception_code_filters); + Temp scratch = scratch_begin(0, 0); + for(CTRL_UserBreakpointNode *n = msg->user_bps.first; n != 0; n = n->next) + { + if(n->v.kind != CTRL_UserBreakpointKind_Expression) + { + continue; + } + E_Parse addr_parse = e_parse_from_string(n->v.string); + E_Parse cnd_parse = e_parse_from_string(n->v.condition); + E_Expr *exprs[] = {addr_parse.expr, cnd_parse.expr}; + for EachElement(idx, exprs) + { + typedef struct ExprWalkTask ExprWalkTask; + struct ExprWalkTask + { + ExprWalkTask *next; + E_Expr *expr; + }; + ExprWalkTask start_task = {0, exprs[idx]}; + ExprWalkTask *first_task = &start_task; + for(ExprWalkTask *t = first_task; t != 0; t = t->next) + { + E_Expr *expr = t->expr; + if(expr->ref != &e_expr_nil) + { + expr = expr->ref; + } + if(expr->kind == E_ExprKind_LeafIdentifier) + { + str8_list_push(ctrl_state->ctrl_thread_msg_process_arena, &ctrl_state->msg_user_bp_touched_symbols, expr->string); + } + if(expr->next != &e_expr_nil) + { + ExprWalkTask *task = push_array(scratch.arena, ExprWalkTask, 1); + task->expr = expr->next; + task->next = t->next; + t->next = task; + } + if(expr->first != &e_expr_nil) + { + ExprWalkTask *task = push_array(scratch.arena, ExprWalkTask, 1); + task->expr = expr->first; + task->next = t->next; + t->next = task; + } + } + } + } + scratch_end(scratch); + } + + //- rjf: gather all touched files by user breakpoints + for(CTRL_UserBreakpointNode *n = msg->user_bps.first; n != 0; n = n->next) + { + if(n->v.kind != CTRL_UserBreakpointKind_FileNameAndLineColNumber) + { + continue; + } + str8_list_push(ctrl_state->ctrl_thread_msg_process_arena, &ctrl_state->msg_user_bp_touched_files, n->v.string); } //- rjf: process message @@ -5018,117 +5085,74 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C B32 rdi_is_necessary = 1; if(rdi == &rdi_parsed_nil) ProfScope("determine if RDI is necessary") { - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, dbgi_key.path); + // rjf: find cached result + U64 hash = ctrl_hash_from_handle(mod->handle); + U64 slot_idx = hash%ctrl_state->module_req_cache_slots_count; + CTRL_ModuleReqCacheNode *slot = ctrl_state->module_req_cache_slots[slot_idx]; + CTRL_ModuleReqCacheNode *node = 0; + for(CTRL_ModuleReqCacheNode *n = slot; slot != 0; slot = slot->next) { - //- rjf: determine if file is PDB - B32 file_is_pdb = 0; - if(!file_is_pdb) + if(ctrl_handle_match(n->module, mod->handle)) { - U8 msf70_magic_maybe[sizeof(msf_msf70_magic)] = {0}; - os_file_read(file, r1u64(0, sizeof(msf70_magic_maybe)), msf70_magic_maybe); - if(MemoryMatch(msf70_magic_maybe, msf_msf70_magic, sizeof(msf70_magic_maybe))) - { - file_is_pdb = 1; - } + node = n; + break; } - if(!file_is_pdb) + } + + // rjf: cached? -> take cached result + if(node != 0) + { + rdi_is_necessary = node->required; + } + + // rjf: not cached -> compute & store + else ProfScope("cache miss") + { + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, dbgi_key.path); { - U8 msf20_magic_maybe[sizeof(msf_msf20_magic)] = {0}; - os_file_read(file, r1u64(0, sizeof(msf20_magic_maybe)), msf20_magic_maybe); - if(MemoryMatch(msf20_magic_maybe, msf_msf20_magic, sizeof(msf20_magic_maybe))) + //- rjf: determine if file is PDB + B32 file_is_pdb = 0; + if(!file_is_pdb) { - file_is_pdb = 1; - } - } - - //- rjf: file is PDB -> do thin parse & lookup of all breakpoint files/symbols. - // if any are found in the PDB, then this RDI is necessary. - if(file_is_pdb) - { - Temp scratch = scratch_begin(&arena, 1); - - // rjf: gather breakpoint-referenced symbols - String8List symbols = {0}; - { - for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) + U8 msf70_magic_maybe[sizeof(msf_msf70_magic)] = {0}; + os_file_read(file, r1u64(0, sizeof(msf70_magic_maybe)), msf70_magic_maybe); + if(MemoryMatch(msf70_magic_maybe, msf_msf70_magic, sizeof(msf70_magic_maybe))) { - if(n->v.kind != CTRL_UserBreakpointKind_Expression) - { - continue; - } - E_Parse addr_parse = e_parse_from_string(n->v.string); - E_Parse cnd_parse = e_parse_from_string(n->v.condition); - E_Expr *exprs[] = {addr_parse.expr, cnd_parse.expr}; - for EachElement(idx, exprs) - { - typedef struct ExprWalkTask ExprWalkTask; - struct ExprWalkTask - { - ExprWalkTask *next; - E_Expr *expr; - }; - ExprWalkTask start_task = {0, exprs[idx]}; - ExprWalkTask *first_task = &start_task; - for(ExprWalkTask *t = first_task; t != 0; t = t->next) - { - E_Expr *expr = t->expr; - if(expr->ref != &e_expr_nil) - { - expr = expr->ref; - } - if(expr->kind == E_ExprKind_LeafIdentifier) - { - str8_list_push(scratch.arena, &symbols, expr->string); - } - if(expr->next != &e_expr_nil) - { - ExprWalkTask *task = push_array(scratch.arena, ExprWalkTask, 1); - task->expr = expr->next; - task->next = t->next; - t->next = task; - } - if(expr->first != &e_expr_nil) - { - ExprWalkTask *task = push_array(scratch.arena, ExprWalkTask, 1); - task->expr = expr->first; - task->next = t->next; - t->next = task; - } - } - } + file_is_pdb = 1; + } + } + if(!file_is_pdb) + { + U8 msf20_magic_maybe[sizeof(msf_msf20_magic)] = {0}; + os_file_read(file, r1u64(0, sizeof(msf20_magic_maybe)), msf20_magic_maybe); + if(MemoryMatch(msf20_magic_maybe, msf_msf20_magic, sizeof(msf20_magic_maybe))) + { + file_is_pdb = 1; } } - // rjf: gather breakpoint-referenced file paths - String8List files = {0}; - { - for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) - { - if(n->v.kind != CTRL_UserBreakpointKind_FileNameAndLineColNumber) - { - continue; - } - str8_list_push(scratch.arena, &files, n->v.string); - } - } - - // rjf: check file + //- rjf: file is PDB -> do thin parse & lookup of all breakpoint files/symbols. + // if any are found in the PDB, then this RDI is necessary. + if(file_is_pdb) { FileProperties props = os_properties_from_file(file); OS_Handle map = os_file_map_open(OS_AccessFlag_Read, file); void *file_base = os_file_map_view_open(map, OS_AccessFlag_Read, r1u64(0, props.size)); String8 file_data = str8(file_base, props.size); { - rdi_is_necessary = pdb_has_symbol_or_file_ref(file_data, symbols, files); + rdi_is_necessary = pdb_has_symbol_or_file_ref(file_data, ctrl_state->msg_user_bp_touched_symbols, ctrl_state->msg_user_bp_touched_files); } os_file_map_view_close(map, file_base, r1u64(0, props.size)); os_file_map_close(map); } - - scratch_end(scratch); } + os_file_close(file); + node = push_array(ctrl_state->ctrl_thread_msg_process_arena, CTRL_ModuleReqCacheNode, 1); + node->next = slot; + ctrl_state->module_req_cache_slots[slot_idx] = node; + node->module = mod->handle; + node->required = rdi_is_necessary; } - os_file_close(file); } //- rjf: if this RDI is necessary, but we do not have it => wait for it forever diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 651726ac..f7d5b1af 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -756,6 +756,17 @@ struct CTRL_TCTX CTRL_ScopeCallStackTouch *free_call_stack_touch; }; +//////////////////////////////// +//~ rjf: Module Requirement Cache Types + +typedef struct CTRL_ModuleReqCacheNode CTRL_ModuleReqCacheNode; +struct CTRL_ModuleReqCacheNode +{ + CTRL_ModuleReqCacheNode *next; + CTRL_Handle module; + B32 required; +}; + //////////////////////////////// //~ rjf: Wakeup Hook Function Types @@ -806,6 +817,7 @@ struct CTRL_State OS_Handle ctrl_thread_entity_ctx_rw_mutex; CTRL_EntityCtxRWStore *ctrl_thread_entity_store; E_Cache *ctrl_thread_eval_cache; + Arena *ctrl_thread_msg_process_arena; Arena *dmn_event_arena; DMN_EventNode *first_dmn_event_node; DMN_EventNode *last_dmn_event_node; @@ -816,6 +828,10 @@ struct CTRL_State U64 process_counter; Arena *dbg_dir_arena; CTRL_DbgDirNode *dbg_dir_root; + U64 module_req_cache_slots_count; + CTRL_ModuleReqCacheNode **module_req_cache_slots; + String8List msg_user_bp_touched_files; + String8List msg_user_bp_touched_symbols; // rjf: user -> memstream ring buffer U64 u2ms_ring_size;