rd: prioritize fastpath for non-unwound register reads; d2r2: prepass to find all top-level tag trees, subdivide unit work on a root-level tag tree basis

This commit is contained in:
Ryan Fleury
2026-05-01 12:34:35 -07:00
parent 0b26b1c83e
commit 0b5e827f6c
4 changed files with 1271 additions and 1002 deletions
+1 -1
View File
@@ -49,7 +49,7 @@ commands =
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg meta telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f1 = { .win = "build radbin telemetry release", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f1 = { .win = "build radbin release telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [raddbg wsl]
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
+13 -1
View File
@@ -769,16 +769,28 @@ rd_eval_space_read(E_Space space, void *out, Rng1U64 range)
case D_EntityKind_Thread:
{
Access *access = access_open();
void *regs_block = 0;
if(e_interpret_ctx->reg_unwind_count == 0)
{
regs_block = d_reg_block_from_thread(scratch.arena, &d_user_state->ctrl_entity_store->ctx, entity->handle);
}
else
{
D_CallStack call_stack = d_call_stack_from_thread(access, entity->handle, 1, rd_state->frame_eval_memread_endt_us);
U64 concrete_frame_idx = e_interpret_ctx->reg_unwind_count;
if(concrete_frame_idx < call_stack.concrete_frames_count)
{
D_CallStackFrame *f = call_stack.concrete_frames[concrete_frame_idx];
regs_block = f->regs;
}
}
if(regs_block != 0)
{
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);
U64 read_size = dim_1u64(read_range);
MemoryCopy(out, (U8 *)f->regs + read_range.min, read_size);
MemoryCopy(out, (U8 *)regs_block + read_range.min, read_size);
result = (read_size == dim_1u64(range));
}
access_close(access);
+2 -2
View File
@@ -537,7 +537,7 @@ lane_sync(); if(flags & (1ull<<(kind))) ProfScope(rdi_name_title_from_dump_subse
{
if(lane_idx() == 0)
{
dumpf("\n // %-16s %-16s %-12s %-12s %-12s %s\n", "name", "flags", "voff_first", "voff_opl", "foff_first", "foff_opl");
dumpf("\n // %-32s %-16s %-12s %-12s %-12s %s\n", "name", "flags", "voff_first", "voff_opl", "foff_first", "foff_opl");
}
U64 count = 0;
RDI_BinarySection *v = rdi_table_from_name(rdi, BinarySections, &count);
@@ -548,7 +548,7 @@ lane_sync(); if(flags & (1ull<<(kind))) ProfScope(rdi_name_title_from_dump_subse
RDI_BinarySection *bin_section = &v[idx];
String8 name = str8_from_rdi_string_idx(rdi, bin_section->name_string_idx);
String8 flags = rdi_string_from_binary_section_flags(scratch.arena, bin_section->flags);
dumpf(" { %-16S %-16S 0x%-10I64x 0x%-10I64x 0x%-10I64x 0x%-10I64x } // binary_section[%I64u]\n",
dumpf(" { %-32S %-16S 0x%-10I64x 0x%-10I64x 0x%-10I64x 0x%-10I64x } // binary_section[%I64u]\n",
push_str8f(scratch.arena, "'%S'", name),
push_str8f(scratch.arena, "`%S`", flags),
bin_section->voff_first,
+269 -12
View File
@@ -1226,6 +1226,170 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
}
lane_sync_u64(&all_line_tables, 0);
////////////////////////////
//- rjf: find all offsets of top-level tag trees across all units
//
U64Array *unit_info_root_tag_offs = 0;
U64 total_root_tag_count = 0;
U64 *total_root_tag_count_ptr = &total_root_tag_count;
lane_sync_u64(&total_root_tag_count_ptr, 0);
ProfScope("find all offsets of top-level tag trees across all units")
{
if(lane_idx() == 0)
{
unit_info_root_tag_offs = push_array(scratch.arena, U64Array, unit_count);
}
lane_sync_u64(&unit_info_root_tag_offs, 0);
typedef struct D2R2_UnitTagTreeOffChunkNode D2R2_UnitTagTreeOffChunkNode;
struct D2R2_UnitTagTreeOffChunkNode
{
D2R2_UnitTagTreeOffChunkNode *next;
U64 *v;
U64 count;
U64 cap;
};
typedef struct D2R2_UnitTagTreeOffChunkList D2R2_UnitTagTreeOffChunkList;
struct D2R2_UnitTagTreeOffChunkList
{
D2R2_UnitTagTreeOffChunkNode *first;
D2R2_UnitTagTreeOffChunkNode *last;
U64 chunk_count;
U64 total_count;
};
U64 unit_take_idx_ = 0;
U64 *unit_take_idx_ptr = &unit_take_idx_;
lane_sync_u64(&unit_take_idx_ptr, 0);
for(;;)
{
//- rjf: take the next unit
U64 unit_idx = ins_atomic_u64_inc_eval(unit_take_idx_ptr)-1;
if(unit_idx >= unit_count)
{
break;
}
Temp scratch2 = scratch_begin(&scratch.arena, 1);
//- rjf: unpack this unit
Rng1U64 unit_info_tag_range = unit_info_tag_ranges[unit_idx];
DW2_ParseCtx *unit_parse_ctx = &unit_parse_ctxs[unit_idx];
//- rjf: gather all offsets of root-level trees
D2R2_UnitTagTreeOffChunkList tree_offs = {0};
S64 depth = 0;
for(U64 off = unit_info_tag_range.min; contains_1u64(unit_info_tag_range, off);)
{
U64 start_off = off;
Temp scratch3 = scratch_begin(&scratch2.arena, 1);
//- rjf: if this next tag is root-level, gather
if(depth == 1)
{
D2R2_UnitTagTreeOffChunkNode *chunk = tree_offs.last;
if(chunk == 0 || chunk->count >= chunk->cap)
{
chunk = push_array(scratch2.arena, D2R2_UnitTagTreeOffChunkNode, 1);
chunk->cap = 512;
chunk->v = push_array(scratch2.arena, U64, chunk->cap);
SLLQueuePush(tree_offs.first, tree_offs.last, chunk);
tree_offs.chunk_count += 1;
}
chunk->v[chunk->count] = off;
chunk->count += 1;
tree_offs.total_count += 1;
}
//- rjf: reading the next tag
DW2_Tag tag = {0};
off += dw2_read_tag(scratch3.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, off, &tag);
//- rjf: do tree navigations
if(tag.has_children)
{
depth += 1;
}
if(tag.kind == DW_TagKind_Null)
{
depth -= 1;
}
scratch_end(scratch3);
if(off == start_off)
{
break;
}
}
//- rjf: flatten & store
{
U64Array tree_offs_array = {0};
tree_offs_array.count = tree_offs.total_count;
tree_offs_array.v = push_array(scratch.arena, U64, tree_offs_array.count);
{
U64 idx = 0;
for EachNode(n, D2R2_UnitTagTreeOffChunkNode, tree_offs.first)
{
MemoryCopy(tree_offs_array.v + idx, n->v, sizeof(n->v[0])*n->count);
idx += n->count;
}
}
unit_info_root_tag_offs[unit_idx] = tree_offs_array;
ins_atomic_u64_add_eval(total_root_tag_count_ptr, tree_offs_array.count);
}
scratch_end(scratch2);
}
lane_sync();
total_root_tag_count = *total_root_tag_count_ptr;
}
////////////////////////////
//- rjf: produce list of (unit * range(root_tag_idx)), so that we can easily
// subdivide work from all units across all lanes
//
typedef struct D2R2_SubUnitWork D2R2_SubUnitWork;
struct D2R2_SubUnitWork
{
U64 unit_idx;
Rng1U64 root_tag_idx_range;
};
U64 sub_unit_works_count = 0;
D2R2_SubUnitWork *sub_unit_works = 0;
ProfScope("produce sub-unit work division") if(lane_idx() == 0)
{
U64 root_tags_per_work = 1024;
for(B32 build = 0; build <= 1; build += 1)
{
U64 sub_unit_work_idx = 0;
for EachIndex(unit_idx, unit_count)
{
U64 root_tags_in_this_unit = unit_info_root_tag_offs[unit_idx].count;
U64 works_per_this_unit = (root_tags_in_this_unit+root_tags_per_work-1) / root_tags_per_work;
if(build)
{
D2R2_SubUnitWork *works = sub_unit_works + sub_unit_work_idx;
U64 works_count = works_per_this_unit;
U64 root_tag_idx = 0;
for EachIndex(work_idx, works_count)
{
U64 root_tag_idx_opl = root_tag_idx + root_tags_per_work;
root_tag_idx_opl = ClampTop(root_tag_idx_opl, root_tags_in_this_unit);
works[work_idx].unit_idx = unit_idx;
works[work_idx].root_tag_idx_range = r1u64(root_tag_idx, root_tag_idx_opl);
root_tag_idx = root_tag_idx_opl;
}
}
sub_unit_work_idx += works_per_this_unit;
}
if(!build)
{
sub_unit_works_count = sub_unit_work_idx;
sub_unit_works = push_array(scratch.arena, D2R2_SubUnitWork, sub_unit_works_count);
}
}
}
lane_sync_u64(&sub_unit_works_count, 0);
lane_sync_u64(&sub_unit_works, 0);
////////////////////////////
//- rjf: build built-in types
//
@@ -2614,11 +2778,11 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
}
////////////////////////////
//- rjf: convert all units / symbols
//- rjf: convert all units
//
RDIM_UnitChunkList *all_units = 0;
RDIM_Unit **unit_from_idx_map = 0;
ProfScope("convert all units / symbols")
ProfScope("convert all units")
{
if(lane_idx() == 0)
{
@@ -2760,8 +2924,51 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
dst_unit->line_table = unit_line_tables[unit_idx];
dst_unit->voff_ranges = unit_voff_ranges;
}
}
}
//- rjf: produce all unit symbols
////////////////////////////
//- rjf: convert all symbols
//
typedef struct D2R2_SubUnitWorkArtifacts D2R2_SubUnitWorkArtifacts;
struct D2R2_SubUnitWorkArtifacts
{
RDIM_SymbolChunkList global_variables;
RDIM_SymbolChunkList thread_variables;
RDIM_SymbolChunkList constants;
RDIM_SymbolChunkList procedures;
RDIM_ScopeChunkList scopes;
RDIM_InlineSiteChunkList inline_sites;
};
D2R2_SubUnitWorkArtifacts *sub_unit_work_artifacts = 0;
ProfScope("convert all symbols")
{
if(lane_idx() == 0)
{
sub_unit_work_artifacts = push_array(scratch.arena, D2R2_SubUnitWorkArtifacts, sub_unit_works_count);
}
lane_sync_u64(&sub_unit_work_artifacts, 0);
U64 work_take_idx_ = 0;
U64 *work_take_idx_ptr = &work_take_idx_;
lane_sync_u64(&work_take_idx_ptr, 0);
for(;;)
{
U64 work_idx = ins_atomic_u64_inc_eval(work_take_idx_ptr) - 1;
if(work_idx >= sub_unit_works_count)
{
break;
}
//- rjf: unpack work
U64 unit_idx = sub_unit_works[work_idx].unit_idx;
Rng1U64 root_tag_idx_range = sub_unit_works[work_idx].root_tag_idx_range;
D2R2_SubUnitWorkArtifacts *dst_artifacts = &sub_unit_work_artifacts[work_idx];
//- rjf: unpack unit info
DW2_ParseCtx *unit_parse_ctx = &unit_parse_ctxs[unit_idx];
Rng1U64 unit_info_tag_range = unit_info_tag_ranges[unit_idx];
//- rjf: produce all unit symbols in this work
typedef struct D2R2_ScopeNode D2R2_ScopeNode;
struct D2R2_ScopeNode
{
@@ -2771,8 +2978,12 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
};
D2R2_ScopeNode *top_scope = 0;
D2R2_ScopeNode *free_scope = 0;
U64 chunk_count = 512;
for(U64 off = unit_info_tag_range.min; off < unit_info_tag_range.max;)
U64 chunk_count = 256;
for(U64 root_tag_idx = root_tag_idx_range.min; root_tag_idx < root_tag_idx_range.max; root_tag_idx += 1)
{
U64 root_tag_start_off = unit_info_root_tag_offs[unit_idx].v[root_tag_idx];
S64 depth = 1;
for(U64 off = root_tag_start_off; off < unit_info_tag_range.max && (depth > 1 || off == root_tag_start_off);)
{
Temp scratch2 = scratch_begin(&scratch.arena, 1);
U64 start_off = off;
@@ -3689,8 +3900,8 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
//- rjf: subprograms (procedures)
case DW_TagKind_SubProgram:
{
RDIM_Scope *root_scope = rdim_scope_chunk_list_push(arena, &dst_unit->scopes, chunk_count);
RDIM_Symbol *procedure = rdim_symbol_chunk_list_push(arena, &dst_unit->procedures, chunk_count);
RDIM_Scope *root_scope = rdim_scope_chunk_list_push(arena, &dst_artifacts->scopes, chunk_count);
RDIM_Symbol *procedure = rdim_symbol_chunk_list_push(arena, &dst_artifacts->procedures, chunk_count);
procedure->name = name;
procedure->link_name = link_name;
procedure->type = type;
@@ -3698,7 +3909,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
procedure->location_cases = framebase_location_cases;
root_scope->symbol = procedure;
root_scope->voff_ranges = ranges;
dst_unit->scopes.scope_voff_count += 2*ranges.count;
dst_artifacts->scopes.scope_voff_count += 2*ranges.count;
new_scope_open = root_scope;
}break;
@@ -3714,10 +3925,10 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
if(name.size != 0)
{
U64 var_chunk_count = chunk_count;
RDIM_SymbolChunkList *dst_symbols = &dst_unit->global_variables;
RDIM_SymbolChunkList *dst_symbols = &dst_artifacts->global_variables;
if(location_is_tls_dependent)
{
dst_symbols = &dst_unit->thread_variables;
dst_symbols = &dst_artifacts->thread_variables;
}
else if(top_scope != 0)
{
@@ -3740,9 +3951,9 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
//- rjf: lexical blocks (scopes)
case DW_TagKind_LexicalBlock:
{
RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, &dst_unit->scopes, chunk_count);
RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, &dst_artifacts->scopes, chunk_count);
scope->voff_ranges = ranges;
dst_unit->scopes.scope_voff_count += 2*ranges.count;
dst_artifacts->scopes.scope_voff_count += 2*ranges.count;
new_scope_open = scope;
}break;
}
@@ -3796,6 +4007,18 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
SLLStackPush(free_scope, n);
}
////////////////////////
//- rjf: tree nav
//
if(tag.has_children)
{
depth += 1;
}
if(tag.kind == DW_TagKind_Null)
{
depth -= 1;
}
scratch_end(scratch2);
if(off == start_off)
{
@@ -3804,6 +4027,40 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
}
}
}
lane_sync();
}
////////////////////////////
//- rjf: join all symbols from all sub-unit works into their units
//
ProfScope("join all symbols from all sub-unit works into their units")
{
U64 unit_take_idx_ = 0;
U64 *unit_take_idx_ptr = &unit_take_idx_;
lane_sync_u64(&unit_take_idx_ptr, 0);
for(;;)
{
U64 unit_idx = ins_atomic_u64_inc_eval(unit_take_idx_ptr)-1;
if(unit_idx >= unit_count)
{
break;
}
RDIM_Unit *dst_unit = unit_from_idx_map[unit_idx];
for EachIndex(work_idx, sub_unit_works_count)
{
if(sub_unit_works[work_idx].unit_idx == unit_idx)
{
rdim_symbol_chunk_list_concat_in_place(&dst_unit->global_variables, &sub_unit_work_artifacts[work_idx].global_variables);
rdim_symbol_chunk_list_concat_in_place(&dst_unit->thread_variables, &sub_unit_work_artifacts[work_idx].thread_variables);
rdim_symbol_chunk_list_concat_in_place(&dst_unit->constants, &sub_unit_work_artifacts[work_idx].constants);
rdim_symbol_chunk_list_concat_in_place(&dst_unit->procedures, &sub_unit_work_artifacts[work_idx].procedures);
rdim_scope_chunk_list_concat_in_place(&dst_unit->scopes, &sub_unit_work_artifacts[work_idx].scopes);
rdim_inline_site_chunk_list_concat_in_place(&dst_unit->inline_sites, &sub_unit_work_artifacts[work_idx].inline_sites);
}
}
}
lane_sync();
}
////////////////////////////
//- rjf: fill result