first pass at call stack cache, need a lot of clean up before this is working...

This commit is contained in:
Ryan Fleury
2025-05-14 21:44:09 -07:00
parent a84739e1c4
commit e5d6a49055
7 changed files with 132 additions and 69 deletions
+72 -26
View File
@@ -1443,7 +1443,7 @@ ctrl_scope_close(CTRL_Scope *scope)
internal void
ctrl_scope_touch_call_stack_node__stripe_r_guarded(CTRL_Scope *scope, CTRL_CallStackCacheNode *node)
{
ins_atomic_u64_eval(&node->scope_touch_count);
ins_atomic_u64_inc_eval(&node->scope_touch_count);
CTRL_ScopeCallStackTouch *touch = ctrl_tctx->free_call_stack_touch;
if(touch != 0)
{
@@ -3299,13 +3299,21 @@ ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *bas
}
//- rjf: package
result.count = frame_count;
result.frames = push_array(arena, CTRL_CallStackFrame, result.count);
result.frames_count = frame_count;
result.frames = push_array(arena, CTRL_CallStackFrame, result.frames_count);
result.concrete_frames_count = base_unwind->frames.count;
result.concrete_frames = push_array(arena, CTRL_CallStackFrame *, result.concrete_frames_count);
{
U64 idx = 0;
U64 concrete_idx = 0;
for(FrameNode *n = first_frame; n != 0; n = n->next, idx += 1)
{
MemoryCopyStruct(&result.frames[idx], &n->v);
if(n->v.inline_depth == 0 && concrete_idx < result.concrete_frames_count)
{
result.concrete_frames[concrete_idx] = &result.frames[idx];
concrete_idx += 1;
}
}
}
}
@@ -3320,7 +3328,7 @@ ctrl_call_stack_frame_from_unwind_and_inline_depth(CTRL_CallStack *call_stack, U
CTRL_CallStackFrame *f = 0;
{
U64 base_frame_idx = 0;
for(U64 idx = 0; idx < call_stack->count; idx += 1)
for(U64 idx = 0; idx < call_stack->frames_count; idx += 1)
{
if(call_stack->frames[idx].inline_depth == 0)
{
@@ -3361,7 +3369,7 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_Entity *thread, U64 endt_us)
//- rjf: loop: try to grab cached call stack; request; wait
U64 reg_gen = ctrl_reg_gen();
U64 mem_gen = ctrl_mem_gen();
OS_MutexScopeW(stripe->rw_mutex) for(;;)
OS_MutexScopeR(stripe->rw_mutex) for(;;)
{
//- rjf: try to grab cached
B32 is_good = 0;
@@ -3385,20 +3393,31 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_Entity *thread, U64 endt_us)
}
//- rjf: create node if needed
if(!is_good)
if(!is_good) OS_MutexScopeRWPromote(stripe->rw_mutex)
{
node = push_array(stripe->arena, CTRL_CallStackCacheNode, 1);
DLLPushBack(slot->first, slot->last, node);
node->thread = thread->handle;
for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next)
{
if(ctrl_handle_match(n->thread, handle))
{
node = n;
break;
}
}
if(node == 0)
{
node = push_array(stripe->arena, CTRL_CallStackCacheNode, 1);
DLLPushBack(slot->first, slot->last, node);
node->thread = thread->handle;
}
}
//- rjf: request if needed
if(!is_working && (!is_good || !is_stale))
if(!is_working && (!is_good || is_stale))
{
if(ctrl_u2csb_enqueue_req(thread->handle, endt_us) &&
async_push_work(ctrl_call_stack_build_work))
{
node->working_count += 1;
ins_atomic_u64_inc_eval(&node->working_count);
}
}
@@ -3409,7 +3428,7 @@ ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_Entity *thread, U64 endt_us)
}
//- rjf: time to wait for new result? -> wait
os_condition_variable_wait_rw_w(stripe->cv, stripe->rw_mutex, endt_us);
os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us);
}
}
return call_stack;
@@ -6784,30 +6803,47 @@ ASYNC_WORK_DEF(ctrl_call_stack_build_work)
U64 pre_reg_gen = ctrl_reg_gen();
U64 pre_mem_gen = ctrl_mem_gen();
Arena *arena = arena_alloc();
CTRL_Unwind unwind = ctrl_unwind_from_thread(arena, ctx, thread_handle, os_now_microseconds()+1000000);
CTRL_Unwind unwind = ctrl_unwind_from_thread(arena, ctx, thread_handle, 0);
CTRL_CallStack call_stack = ctrl_call_stack_from_unwind(arena, process, &unwind);
U64 post_reg_gen = ctrl_reg_gen();
U64 post_mem_gen = ctrl_mem_gen();
//- rjf: store in cache
//- rjf: store new results in cache
Arena *last_arena = arena;
OS_MutexScopeW(stripe->rw_mutex)
if(pre_reg_gen == post_reg_gen &&
pre_mem_gen == post_mem_gen)
{
for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next)
for(B32 done = 0; !done;)
{
if(ctrl_handle_match(n->thread, thread_handle))
B32 found = 0;
OS_MutexScopeW(stripe->rw_mutex)
{
if(pre_reg_gen == post_reg_gen &&
pre_mem_gen == post_mem_gen)
for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next)
{
last_arena = n->arena;
n->arena = arena;
n->reg_gen = pre_reg_gen;
n->mem_gen = pre_mem_gen;
n->unwind = unwind;
n->call_stack = call_stack;
if(ctrl_handle_match(n->thread, thread_handle))
{
found = 1;
if(n->scope_touch_count == 0)
{
done = 1;
if(unwind.flags == 0 || call_stack.frames_count >= n->call_stack.frames_count)
{
last_arena = n->arena;
n->arena = arena;
n->call_stack = call_stack;
}
if(unwind.flags == 0)
{
n->reg_gen = pre_reg_gen;
n->mem_gen = pre_mem_gen;
}
}
break;
}
}
n->working_count -= 1;
}
if(!found)
{
break;
}
}
@@ -6819,6 +6855,16 @@ ASYNC_WORK_DEF(ctrl_call_stack_build_work)
arena_release(last_arena);
}
//- rjf: mark work as done
OS_MutexScopeW(stripe->rw_mutex) for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next)
{
if(ctrl_handle_match(n->thread, thread_handle))
{
ins_atomic_u64_dec_eval(&n->working_count);
break;
}
}
scratch_end(scratch);
}
+12 -5
View File
@@ -266,7 +266,9 @@ typedef struct CTRL_CallStack CTRL_CallStack;
struct CTRL_CallStack
{
CTRL_CallStackFrame *frames;
U64 count;
U64 frames_count;
CTRL_CallStackFrame **concrete_frames;
U64 concrete_frames_count;
};
////////////////////////////////
@@ -609,13 +611,18 @@ struct CTRL_CallStackCacheNode
{
CTRL_CallStackCacheNode *next;
CTRL_CallStackCacheNode *prev;
// rjf: key
CTRL_Handle thread;
U64 scope_touch_count;
U64 working_count;
Arena *arena;
U64 reg_gen;
U64 mem_gen;
CTRL_Unwind unwind;
// rjf: refcounts
U64 scope_touch_count;
U64 working_count;
// rjf: value
Arena *arena;
CTRL_CallStack call_stack;
};
+24 -18
View File
@@ -1815,11 +1815,12 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range)
}break;
case CTRL_EntityKind_Thread:
{
CTRL_Unwind unwind = d_query_cached_unwind_from_thread(entity);
U64 frame_idx = e_interpret_ctx->reg_unwind_count;
if(frame_idx < unwind.frames.count)
CTRL_Scope *ctrl_scope = ctrl_scope_open();
CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, entity, 0);
U64 concrete_frame_idx = e_interpret_ctx->reg_unwind_count;
if(concrete_frame_idx < call_stack.concrete_frames_count)
{
CTRL_UnwindFrame *f = &unwind.frames.v[frame_idx];
CTRL_CallStackFrame *f = call_stack.concrete_frames[concrete_frame_idx];
U64 regs_size = regs_block_size_from_arch(e_interpret_ctx->reg_arch);
Rng1U64 legal_range = r1u64(0, regs_size);
Rng1U64 read_range = intersect_1u64(legal_range, range);
@@ -1827,6 +1828,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range)
MemoryCopy(out, (U8 *)f->regs + read_range.min, read_size);
result = (read_size == dim_1u64(range));
}
ctrl_scope_close(ctrl_scope);
}break;
}
}break;
@@ -6393,12 +6395,12 @@ rd_window_frame(void)
// rjf: unwind
if(ctrl_entity->kind == CTRL_EntityKind_Thread) RD_Font(RD_FontSlot_Code)
{
CTRL_Scope *ctrl_scope = ctrl_scope_open();
Vec4F32 code_color = ui_color_from_name(str8_lit("code_default"));
Vec4F32 symbol_color = ui_color_from_name(str8_lit("code_symbol"));
CTRL_Entity *process = ctrl_entity_ancestor_from_kind(ctrl_entity, CTRL_EntityKind_Process);
CTRL_Unwind base_unwind = d_query_cached_unwind_from_thread(ctrl_entity);
CTRL_CallStack call_stack = ctrl_call_stack_from_unwind(scratch.arena, process, &base_unwind);
if(call_stack.count != 0)
CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, ctrl_entity, 0);
if(call_stack.frames_count != 0)
{
ui_spacer(ui_em(1.5f, 1.f));
}
@@ -6414,6 +6416,7 @@ rd_window_frame(void)
String8 rip_value_string = rd_value_string_from_eval(scratch.arena, str8_zero(), &string_params, ui_top_font(), ui_top_font_size(), ui_top_font_size()*40.f, rip_eval);
rd_code_label(1, 0, code_color, rip_value_string);
}
ctrl_scope_close(ctrl_scope);
}
}break;
@@ -11238,10 +11241,12 @@ rd_frame(void)
}
//////////////////////////////
//- rjf: open frame debug info scope
//- rjf: open frame scopes
//
if(rd_state->frame_depth == 0)
{
rd_state->frame_di_scope = di_scope_open();
rd_state->frame_ctrl_scope = ctrl_scope_open();
}
//////////////////////////////
@@ -11283,7 +11288,7 @@ rd_frame(void)
U64 candidate_frame_time_us = 1000000/(U64)candidate;
S64 frame_time_us_diff = (S64)frame_time_history_avg_us - (S64)candidate_frame_time_us;
if(abs_s64(frame_time_us_diff) < best_target_hz_frame_time_us_diff &&
frame_time_history_avg_us < candidate_frame_time_us + 1000)
frame_time_history_avg_us < candidate_frame_time_us + candidate_frame_time_us/4)
{
best_target_hz = candidate;
best_target_hz_frame_time_us_diff = frame_time_us_diff;
@@ -11613,7 +11618,6 @@ rd_frame(void)
Arch arch = thread->arch;
U64 unwind_count = rd_regs()->unwind_count;
U64 rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_count);
CTRL_Unwind unwind = d_query_cached_unwind_from_thread(thread);
CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr);
U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr);
U64 tls_root_vaddr = ctrl_tls_root_vaddr_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle);
@@ -15634,10 +15638,9 @@ rd_frame(void)
}break;
case RD_CmdKind_SelectUnwind:
{
CTRL_Scope *ctrl_scope = ctrl_scope_open();
CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_base_regs()->thread);
CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process);
CTRL_Unwind base_unwind = d_query_cached_unwind_from_thread(thread);
CTRL_CallStack call_stack = ctrl_call_stack_from_unwind(scratch.arena, process, &base_unwind);
CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, thread, os_now_microseconds()+10000);
CTRL_CallStackFrame *frame = ctrl_call_stack_frame_from_unwind_and_inline_depth(&call_stack, rd_regs()->unwind_count, rd_regs()->inline_depth);
if(frame == 0)
{
@@ -15649,14 +15652,14 @@ rd_frame(void)
rd_state->base_regs.v.inline_depth = rd_regs()->inline_depth;
}
rd_cmd(RD_CmdKind_FindThread, .thread = thread->handle, .unwind_count = rd_state->base_regs.v.unwind_count, .inline_depth = rd_state->base_regs.v.inline_depth);
ctrl_scope_close(ctrl_scope);
}break;
case RD_CmdKind_UpOneFrame:
case RD_CmdKind_DownOneFrame:
{
CTRL_Scope *ctrl_scope = ctrl_scope_open();
CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_base_regs()->thread);
CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process);
CTRL_Unwind base_unwind = d_query_cached_unwind_from_thread(thread);
CTRL_CallStack call_stack = ctrl_call_stack_from_unwind(scratch.arena, process, &base_unwind);
CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, thread, os_now_microseconds()+10000);
CTRL_CallStackFrame *current_frame = ctrl_call_stack_frame_from_unwind_and_inline_depth(&call_stack, rd_regs()->unwind_count, rd_regs()->inline_depth);
CTRL_CallStackFrame *next_frame = current_frame;
if(current_frame != 0) switch(kind)
@@ -15668,7 +15671,7 @@ rd_frame(void)
next_frame = current_frame-1;
}break;
case RD_CmdKind_DownOneFrame:
if(current_frame+1 < call_stack.frames + call_stack.count)
if(current_frame+1 < call_stack.frames + call_stack.frames_count)
{
next_frame = current_frame+1;
}break;
@@ -15680,6 +15683,7 @@ rd_frame(void)
.unwind_count = next_frame->unwind_count,
.inline_depth = next_frame->inline_depth);
}
ctrl_scope_close(ctrl_scope);
}break;
//- rjf: meta controls
@@ -16700,10 +16704,12 @@ rd_frame(void)
}
//////////////////////////////
//- rjf: close frame debug info scope
//- rjf: close frame scopes
//
if(rd_state->frame_depth == 0)
{
di_scope_close(rd_state->frame_di_scope);
ctrl_scope_close(rd_state->frame_ctrl_scope);
}
//////////////////////////////
+1
View File
@@ -599,6 +599,7 @@ struct RD_State
// rjf: frame parameters
F32 frame_dt;
DI_Scope *frame_di_scope;
CTRL_Scope *frame_ctrl_scope;
// rjf: dbgi match store
DI_MatchStore *match_store;
+4 -6
View File
@@ -955,11 +955,9 @@ E_TYPE_IREXT_FUNCTION_DEF(call_stack)
CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(interp.space);
if(entity->kind == CTRL_EntityKind_Thread)
{
CTRL_Entity *process = ctrl_process_from_entity(entity);
CTRL_Unwind base_unwind = d_query_cached_unwind_from_thread(entity);
accel->arch = entity->arch;
accel->process = process->handle;
accel->call_stack = ctrl_call_stack_from_unwind(arena, process, &base_unwind);
accel->process = ctrl_process_from_entity(entity)->handle;
accel->call_stack = ctrl_call_stack_from_thread(rd_state->frame_ctrl_scope, entity, 0);
}
scratch_end(scratch);
}
@@ -975,7 +973,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(call_stack)
RD_CallStackAccel *accel = (RD_CallStackAccel *)lhs_irtree->user_data;
E_Value rhs_value = e_value_from_expr(expr->first->next);
CTRL_CallStack *call_stack = &accel->call_stack;
if(0 <= rhs_value.u64 && rhs_value.u64 < call_stack->count)
if(0 <= rhs_value.u64 && rhs_value.u64 < call_stack->frames_count)
{
CTRL_Entity *process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, accel->process);
CTRL_CallStackFrame *f = &call_stack->frames[rhs_value.u64];
@@ -992,7 +990,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack)
RD_CallStackAccel *accel = (RD_CallStackAccel *)eval.irtree.user_data;
E_TypeExpandInfo result = {0};
result.user_data = accel;
result.expr_count = accel->call_stack.count;
result.expr_count = accel->call_stack.frames_count;
return result;
}
+13 -10
View File
@@ -1008,17 +1008,18 @@ rd_watch_row_info_from_row(Arena *arena, EV_Row *row)
CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(block_eval.space);
if(entity->kind == CTRL_EntityKind_Thread)
{
CTRL_Scope *ctrl_scope = ctrl_scope_open();
info.callstack_thread = entity;
U64 frame_num = ev_block_num_from_id(block, key.child_id);
CTRL_Unwind unwind = d_query_cached_unwind_from_thread(entity);
CTRL_CallStack call_stack = ctrl_call_stack_from_unwind(scratch.arena, ctrl_process_from_entity(entity), &unwind);
if(1 <= frame_num && frame_num <= call_stack.count)
CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, entity, 0);
if(1 <= frame_num && frame_num <= call_stack.frames_count)
{
CTRL_CallStackFrame *f = &call_stack.frames[frame_num-1];
info.callstack_unwind_index = f->unwind_count;
info.callstack_inline_depth = f->inline_depth;
info.callstack_vaddr = regs_rip_from_arch_block(entity->arch, f->regs);
}
ctrl_scope_close(ctrl_scope);
}
}
@@ -2837,17 +2838,18 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
};
AnnotationList *visible_memory_annotations = push_array(scratch.arena, AnnotationList, visible_memory_size);
{
CTRL_Scope *ctrl_scope = ctrl_scope_open();
CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread);
CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process);
CTRL_Unwind unwind = d_query_cached_unwind_from_thread(thread);
CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, thread, 0);
//- rjf: fill unwind frame annotations
if(unwind.frames.count != 0) UI_Tag(str8_lit("weak"))
if(call_stack.concrete_frames_count != 0) UI_Tag(str8_lit("weak"))
{
U64 last_stack_top = regs_rsp_from_arch_block(thread->arch, unwind.frames.v[0].regs);
for(U64 idx = 1; idx < unwind.frames.count; idx += 1)
U64 last_stack_top = regs_rsp_from_arch_block(thread->arch, call_stack.concrete_frames[0]->regs);
for(U64 idx = 1; idx < call_stack.concrete_frames_count; idx += 1)
{
CTRL_UnwindFrame *f = &unwind.frames.v[idx];
CTRL_CallStackFrame *f = call_stack.concrete_frames[idx];
U64 f_stack_top = regs_rsp_from_arch_block(thread->arch, f->regs);
Rng1U64 frame_vaddr_range = r1u64(last_stack_top, f_stack_top);
Rng1U64 frame_vaddr_range_in_viz = intersect_1u64(frame_vaddr_range, viz_range_bytes);
@@ -2896,10 +2898,10 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
}
//- rjf: fill selected thread stack range annotation
if(unwind.frames.count > 0)
if(call_stack.concrete_frames_count > 0)
{
U64 stack_base_vaddr = thread->stack_base;
U64 stack_top_vaddr = regs_rsp_from_arch_block(thread->arch, unwind.frames.v[0].regs);
U64 stack_top_vaddr = regs_rsp_from_arch_block(thread->arch, call_stack.concrete_frames[0]->regs);
Rng1U64 stack_vaddr_range = r1u64(stack_base_vaddr, stack_top_vaddr);
Rng1U64 stack_vaddr_range_in_viz = intersect_1u64(stack_vaddr_range, viz_range_bytes);
if(dim_1u64(stack_vaddr_range_in_viz) != 0)
@@ -2954,6 +2956,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
}
di_scope_close(scope);
}
ctrl_scope_close(ctrl_scope);
}
//////////////////////////////
+6 -4
View File
@@ -521,13 +521,14 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e
{
Vec4F32 symbol_color = ui_color_from_name(str8_lit("code_symbol"));
dr_fstrs_push_new(arena, &result, &params, str8_lit(" "));
CTRL_Scope *ctrl_scope = ctrl_scope_open();
DI_Scope *di_scope = di_scope_open();
CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process);
Arch arch = entity->arch;
CTRL_Unwind unwind = d_query_cached_unwind_from_thread(entity);
for(U64 idx = 0, limit = 6; idx < unwind.frames.count && idx < limit; idx += 1)
CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, entity, 0);
for(U64 idx = 0, limit = 6; idx < call_stack.frames_count && idx < limit; idx += 1)
{
CTRL_UnwindFrame *f = &unwind.frames.v[unwind.frames.count - 1 - idx];
CTRL_CallStackFrame *f = &call_stack.frames[call_stack.frames_count - 1 - idx];
U64 rip_vaddr = regs_rip_from_arch_block(arch, f->regs);
CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr);
U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr);
@@ -542,7 +543,7 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e
if(name.size != 0)
{
dr_fstrs_push_new(arena, &result, &params, name, .size = extras_size, .color = symbol_color);
if(idx+1 < unwind.frames.count)
if(idx+1 < call_stack.frames_count)
{
dr_fstrs_push_new(arena, &result, &params, str8_lit(" > "), .color = secondary_color, .size = extras_size);
if(idx+1 == limit)
@@ -554,6 +555,7 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e
}
}
di_scope_close(di_scope);
ctrl_scope_close(ctrl_scope);
}
//- rjf: modules get debug info status extras