first pass at call stack tree evaluation

This commit is contained in:
Ryan Fleury
2025-08-11 16:08:04 -07:00
parent 056604fb94
commit 36dcd65a83
6 changed files with 143 additions and 2 deletions
+27
View File
@@ -188,6 +188,22 @@ ctrl_handle_list_copy(Arena *arena, CTRL_HandleList *src)
return dst;
}
internal CTRL_HandleArray
ctrl_handle_array_from_list(Arena *arena, CTRL_HandleList *src)
{
CTRL_HandleArray array = {0};
array.count = src->count;
array.v = push_array_no_zero(arena, CTRL_Handle, array.count);
{
U64 idx = 0;
for(CTRL_HandleNode *n = src->first; n != 0; n = n->next, idx += 1)
{
array.v[idx] = n->v;
}
}
return array;
}
internal String8
ctrl_string_from_handle(Arena *arena, CTRL_Handle handle)
{
@@ -1543,6 +1559,9 @@ ctrl_init(void)
ctrl_state->module_image_info_cache.stripes[idx].arena = arena_alloc();
ctrl_state->module_image_info_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc();
}
ctrl_state->call_stack_tree_cache.tree.root = &ctrl_call_stack_tree_node_nil;
ctrl_state->call_stack_tree_cache.cv = os_condition_variable_alloc();
ctrl_state->call_stack_tree_cache.rw_mutex = os_rw_mutex_alloc();
ctrl_state->u2c_ring_size = KB(64);
ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size);
ctrl_state->u2c_ring_mutex = os_mutex_alloc();
@@ -7358,9 +7377,14 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work)
if(pre_mem_gen == post_mem_gen &&
pre_reg_gen == post_reg_gen)
{
U64 id_gen = 0;
arena = arena_alloc();
tree.root = push_array(arena, CTRL_CallStackTreeNode, 1);
MemoryCopyStruct(tree.root, &ctrl_call_stack_tree_node_nil);
tree.root->id = id_gen;
tree.slots_count = Max(1, threads_count);
tree.slots = push_array(arena, CTRL_CallStackTreeNode *, tree.slots_count);
id_gen += 1;
for EachIndex(thread_idx, threads_count)
{
CTRL_Handle thread = threads[thread_idx];
@@ -7385,6 +7409,9 @@ ASYNC_WORK_DEF(ctrl_call_stack_tree_build_work)
{
next_node = push_array(arena, CTRL_CallStackTreeNode, 1);
MemoryCopyStruct(next_node, &ctrl_call_stack_tree_node_nil);
next_node->id = id_gen;
SLLStackPush_N(tree.slots[next_node->id%tree.slots_count], next_node, hash_next);
id_gen += 1;
SLLQueuePush_NZ(&ctrl_call_stack_tree_node_nil, thread_node->first, thread_node->last, next_node, next);
next_node->parent = thread_node;
thread_node->child_count += 1;
+13
View File
@@ -84,6 +84,13 @@ struct CTRL_HandleList
U64 count;
};
typedef struct CTRL_HandleArray CTRL_HandleArray;
struct CTRL_HandleArray
{
CTRL_Handle *v;
U64 count;
};
////////////////////////////////
//~ rjf: Generated Code
@@ -277,11 +284,13 @@ struct CTRL_CallStack
typedef struct CTRL_CallStackTreeNode CTRL_CallStackTreeNode;
struct CTRL_CallStackTreeNode
{
CTRL_CallStackTreeNode *hash_next;
CTRL_CallStackTreeNode *first;
CTRL_CallStackTreeNode *last;
CTRL_CallStackTreeNode *next;
CTRL_CallStackTreeNode *parent;
U64 child_count;
U64 id;
CTRL_Handle process;
U64 vaddr;
U64 depth;
@@ -293,6 +302,8 @@ typedef struct CTRL_CallStackTree CTRL_CallStackTree;
struct CTRL_CallStackTree
{
CTRL_CallStackTreeNode *root;
U64 slots_count;
CTRL_CallStackTreeNode **slots;
};
////////////////////////////////
@@ -911,6 +922,7 @@ read_only global CTRL_Entity ctrl_entity_nil =
};
read_only global CTRL_CallStackTreeNode ctrl_call_stack_tree_node_nil =
{
0,
&ctrl_call_stack_tree_node_nil,
&ctrl_call_stack_tree_node_nil,
&ctrl_call_stack_tree_node_nil,
@@ -945,6 +957,7 @@ internal CTRL_Handle ctrl_handle_make(CTRL_MachineID machine_id, DMN_Handle dmn_
internal B32 ctrl_handle_match(CTRL_Handle a, CTRL_Handle b);
internal void ctrl_handle_list_push(Arena *arena, CTRL_HandleList *list, CTRL_Handle *pair);
internal CTRL_HandleList ctrl_handle_list_copy(Arena *arena, CTRL_HandleList *src);
internal CTRL_HandleArray ctrl_handle_array_from_list(Arena *arena, CTRL_HandleList *src);
internal String8 ctrl_string_from_handle(Arena *arena, CTRL_Handle handle);
internal CTRL_Handle ctrl_handle_from_string(String8 string);
+21
View File
@@ -11499,6 +11499,7 @@ rd_frame(void)
CTRL_Scope *frame_ctrl_scope_restore = rd_state->frame_ctrl_scope;
rd_state->frame_di_scope = di_scope_open();
rd_state->frame_ctrl_scope = ctrl_scope_open();
rd_state->got_frame_call_stack_tree = 0;
//////////////////////////////
//- rjf: calculate avg length in us of last many frames
@@ -12296,6 +12297,26 @@ rd_frame(void)
e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, collection_name, collection_type_key);
}
//- rjf: add macro for call stack tree
{
String8 collection_name = str8_lit("call_stack_tree");
E_TypeKey collection_type_key = e_type_key_cons(.kind = E_TypeKind_Set,
.name = collection_name,
.flags = E_TypeFlag_StubSingleLineExpansion,
.access = E_TYPE_ACCESS_FUNCTION_NAME(call_stack_tree),
.expand =
{
.info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(call_stack_tree),
.range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(call_stack_tree)
});
E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafValue, r1u64(0, 0));
expr->value.u64 = 1;
expr->type_key = collection_type_key;
expr->space = e_space_make(RD_EvalSpaceKind_MetaCallStackTree);
e_string2expr_map_insert(scratch.arena, macro_map, collection_name, expr);
e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, collection_name, collection_type_key);
}
//- rjf: add macro / lookup rules for unattached processes
{
String8 collection_name = str8_lit("unattached_processes");
+3
View File
@@ -88,6 +88,7 @@ enum
RD_EvalSpaceKind_MetaTheme,
RD_EvalSpaceKind_MetaCtrlEntity,
RD_EvalSpaceKind_MetaUnattachedProcess,
RD_EvalSpaceKind_MetaCallStackTree,
};
////////////////////////////////
@@ -600,6 +601,8 @@ struct RD_State
F32 frame_dt;
DI_Scope *frame_di_scope;
CTRL_Scope *frame_ctrl_scope;
CTRL_CallStackTree frame_call_stack_tree;
B32 got_frame_call_stack_tree;
// rjf: dbgi match store
DI_MatchStore *match_store;
+78 -2
View File
@@ -1541,14 +1541,90 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(ctrl_entities)
////////////////////////////////
//~ rjf: Call Stack Tree Type Hooks
E_TYPE_ACCESS_FUNCTION_DEF(call_stack_tree)
{
E_IRTreeAndType result = {&e_irnode_nil};
if(expr->kind == E_ExprKind_MemberAccess)
{
String8 id_string = expr->first->next->string;
U64 id = u64_from_str8(str8_skip(id_string, 1), 16);
if(id != 0)
{
result.type_key = lhs_irtree->type_key;
result.mode = E_Mode_Value;
result.root = e_irtree_set_space(arena, e_space_make(RD_EvalSpaceKind_MetaCallStackTree), e_irtree_const_u(arena, id));
}
}
return result;
}
typedef struct RD_CallStackTreeExpandAccel RD_CallStackTreeExpandAccel;
struct RD_CallStackTreeExpandAccel
{
CTRL_CallStackTreeNode *node;
CTRL_CallStackTreeNode **children;
CTRL_HandleArray threads;
};
E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack_tree)
{
if(!rd_state->got_frame_call_stack_tree)
{
rd_state->got_frame_call_stack_tree = 1;
rd_state->frame_call_stack_tree = ctrl_call_stack_tree(rd_state->frame_ctrl_scope, 0);
}
RD_CallStackTreeExpandAccel *accel = push_array(arena, RD_CallStackTreeExpandAccel, 1);
accel->node = &ctrl_call_stack_tree_node_nil;
U64 id = e_value_eval_from_eval(eval).value.u64;
if(rd_state->frame_call_stack_tree.slots_count != 0)
{
for(CTRL_CallStackTreeNode *n = rd_state->frame_call_stack_tree.slots[id%rd_state->frame_call_stack_tree.slots_count];
n != 0;
n = n->hash_next)
{
if(n->id == id)
{
accel->node = n;
break;
}
}
}
accel->children = push_array(arena, CTRL_CallStackTreeNode *, accel->node->child_count);
{
U64 idx = 0;
for(CTRL_CallStackTreeNode *n = accel->node->first;
n != &ctrl_call_stack_tree_node_nil;
n = n->next, idx += 1)
{
accel->children[idx] = n;
}
}
accel->threads = ctrl_handle_array_from_list(arena, &accel->node->threads);
E_TypeExpandInfo result = {accel};
result.expr_count = accel->node->child_count + accel->threads.count;
return result;
}
E_TYPE_EXPAND_RANGE_FUNCTION_DEF(call_stack_tree)
{
Temp scratch = scratch_begin(&arena, 1);
RD_CallStackTreeExpandAccel *accel = (RD_CallStackTreeExpandAccel *)user_data;
CTRL_CallStackTreeNode *node = accel->node;
U64 needed_row_count = dim_1u64(idx_range);
for EachIndex(idx, needed_row_count)
{
E_Eval eval = e_eval_nil;
if(idx < node->child_count)
{
eval = e_eval_from_stringf("query:call_stack_tree.$%I64x", accel->children[idx]->id);
}
else if(node->child_count <= idx && idx < node->child_count + accel->threads.count)
{
eval = e_eval_from_stringf("query:control.%S", ctrl_string_from_handle(scratch.arena, accel->threads.v[idx - node->child_count]));
}
evals_out[idx] = eval;
}
scratch_end(scratch);
}
////////////////////////////////
+1
View File
@@ -103,6 +103,7 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(ctrl_entities);
////////////////////////////////
//~ rjf: Call Stack Tree Type Hooks
E_TYPE_ACCESS_FUNCTION_DEF(call_stack_tree);
E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack_tree);
E_TYPE_EXPAND_RANGE_FUNCTION_DEF(call_stack_tree);