mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
rewrite frontend unwind cache to always preserve stale results until a new unwind successfully completes
This commit is contained in:
+63
-68
@@ -3607,14 +3607,14 @@ df_set_thread_rip(DF_Entity *thread, U64 vaddr)
|
||||
// rjf: early mutation of unwind cache for immediate frontend effect
|
||||
if(result)
|
||||
{
|
||||
DF_RunUnwindCache *unwind_cache = &df_state->unwind_caches[df_state->unwind_cache_gen%ArrayCount(df_state->unwind_caches)];
|
||||
if(unwind_cache->slots_count != 0)
|
||||
DF_UnwindCache *cache = &df_state->unwind_cache;
|
||||
if(cache->slots_count != 0)
|
||||
{
|
||||
DF_Handle thread_handle = df_handle_from_entity(thread);
|
||||
U64 hash = df_hash_from_string(str8_struct(&thread_handle));
|
||||
U64 slot_idx = hash % unwind_cache->slots_count;
|
||||
DF_RunUnwindCacheSlot *slot = &unwind_cache->slots[slot_idx];
|
||||
for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next)
|
||||
U64 slot_idx = hash%cache->slots_count;
|
||||
DF_UnwindCacheSlot *slot = &cache->slots[slot_idx];
|
||||
for(DF_UnwindCacheNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(df_handle_match(n->thread, thread_handle) && n->unwind.frames.count != 0)
|
||||
{
|
||||
@@ -6139,57 +6139,52 @@ df_query_cached_unwind_from_thread(DF_Entity *thread)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
CTRL_Unwind result = {0};
|
||||
if(thread->kind == DF_EntityKind_Thread)
|
||||
{
|
||||
U64 reg_gen = ctrl_reg_gen();
|
||||
U64 mem_gen = ctrl_mem_gen();
|
||||
DF_UnwindCache *cache = &df_state->unwind_cache;
|
||||
DF_Handle handle = df_handle_from_entity(thread);
|
||||
U64 hash = df_hash_from_string(str8_struct(&handle));
|
||||
for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->unwind_caches); cache_idx += 1)
|
||||
U64 slot_idx = hash%cache->slots_count;
|
||||
DF_UnwindCacheSlot *slot = &cache->slots[slot_idx];
|
||||
DF_UnwindCacheNode *node = 0;
|
||||
for(DF_UnwindCacheNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
//- rjf: grab next recent cache
|
||||
DF_RunUnwindCache *cache = &df_state->unwind_caches[(df_state->unwind_cache_gen+cache_idx)%ArrayCount(df_state->unwind_caches)];
|
||||
if(cache_idx == 0 && cache->slots_count == 0)
|
||||
if(df_handle_match(handle, n->thread))
|
||||
{
|
||||
cache->slots_count = 1024;
|
||||
cache->slots = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->slots_count);
|
||||
}
|
||||
else if(cache->slots_count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//- rjf: thread/hash -> node
|
||||
U64 slot_idx = hash%cache->slots_count;
|
||||
DF_RunUnwindCacheSlot *slot = &cache->slots[slot_idx];
|
||||
DF_RunUnwindCacheNode *node = 0;
|
||||
for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next)
|
||||
{
|
||||
if(df_handle_match(n->thread, handle))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: no node? -> calculate unwind if needed - store if good & return
|
||||
if(node == 0)
|
||||
{
|
||||
CTRL_Unwind current_unwind = ctrl_unwind_from_thread(scratch.arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, os_now_microseconds()+200);
|
||||
if(!(current_unwind.flags & (CTRL_UnwindFlag_Error|CTRL_UnwindFlag_Stale)))
|
||||
{
|
||||
Architecture arch = df_architecture_from_entity(thread);
|
||||
node = push_array(cache->arena, DF_RunUnwindCacheNode, 1);
|
||||
SLLQueuePush_N(slot->first, slot->last, node, hash_next);
|
||||
node->thread = handle;
|
||||
node->unwind = ctrl_unwind_deep_copy(cache->arena, arch, ¤t_unwind);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: cached node -> grab result & return
|
||||
if(node != 0)
|
||||
{
|
||||
result = node->unwind;
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node == 0)
|
||||
{
|
||||
node = cache->free_node;
|
||||
if(node != 0)
|
||||
{
|
||||
SLLStackPop(cache->free_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = push_array_no_zero(df_state->arena, DF_UnwindCacheNode, 1);
|
||||
}
|
||||
DLLPushBack(slot->first, slot->last, node);
|
||||
MemoryZeroStruct(node);
|
||||
node->arena = arena_alloc();
|
||||
node->thread = handle;
|
||||
}
|
||||
if(node->reggen != reg_gen ||
|
||||
node->memgen != mem_gen)
|
||||
{
|
||||
CTRL_Unwind new_unwind = ctrl_unwind_from_thread(scratch.arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, os_now_microseconds()+100);
|
||||
if(!(new_unwind.flags & (CTRL_UnwindFlag_Error|CTRL_UnwindFlag_Stale)))
|
||||
{
|
||||
node->unwind = ctrl_unwind_deep_copy(node->arena, thread->arch, &new_unwind);
|
||||
node->reggen = reg_gen;
|
||||
node->memgen = mem_gen;
|
||||
}
|
||||
}
|
||||
result = node->unwind;
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
@@ -6498,11 +6493,9 @@ df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist)
|
||||
df_register_core_view_rule_specs(array);
|
||||
}
|
||||
|
||||
// rjf: set up per-run caches
|
||||
for(U64 idx = 0; idx < ArrayCount(df_state->unwind_caches); idx += 1)
|
||||
{
|
||||
df_state->unwind_caches[idx].arena = arena_alloc();
|
||||
}
|
||||
// rjf: set up caches
|
||||
df_state->unwind_cache.slots_count = 1024;
|
||||
df_state->unwind_cache.slots = push_array(arena, DF_UnwindCacheSlot, df_state->unwind_cache.slots_count);
|
||||
for(U64 idx = 0; idx < ArrayCount(df_state->tls_base_caches); idx += 1)
|
||||
{
|
||||
df_state->tls_base_caches[idx].arena = arena_alloc();
|
||||
@@ -6661,7 +6654,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
|
||||
}
|
||||
|
||||
// rjf: select & snap to thread causing stop
|
||||
if(!df_entity_is_nil(stop_thread))
|
||||
if(stop_thread->kind == DF_EntityKind_Thread)
|
||||
{
|
||||
DF_CmdParams params = df_cmd_params_zero();
|
||||
params.entity = df_handle_from_entity(stop_thread);
|
||||
@@ -6987,20 +6980,6 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: clear unwind cache
|
||||
if((df_state->unwind_cache_memgen_idx != new_mem_gen ||
|
||||
df_state->unwind_cache_reggen_idx != new_reg_gen) &&
|
||||
!df_ctrl_targets_running()) ProfScope("per-thread unwind gather")
|
||||
{
|
||||
df_state->unwind_cache_gen += 1;
|
||||
DF_RunUnwindCache *cache = &df_state->unwind_caches[df_state->unwind_cache_gen%ArrayCount(df_state->unwind_caches)];
|
||||
arena_clear(cache->arena);
|
||||
cache->slots_count = 0;
|
||||
cache->slots = 0;
|
||||
df_state->unwind_cache_memgen_idx = new_mem_gen;
|
||||
df_state->unwind_cache_reggen_idx = new_reg_gen;
|
||||
}
|
||||
|
||||
//- rjf: clear tls base cache
|
||||
if((df_state->tls_base_cache_reggen_idx != new_reg_gen ||
|
||||
df_state->tls_base_cache_memgen_idx != new_mem_gen) &&
|
||||
@@ -8784,6 +8763,22 @@ df_core_end_frame(void)
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: garbage collect eliminated thread unwinds
|
||||
for(U64 slot_idx = 0; slot_idx < df_state->unwind_cache.slots_count; slot_idx += 1)
|
||||
{
|
||||
DF_UnwindCacheSlot *slot = &df_state->unwind_cache.slots[slot_idx];
|
||||
for(DF_UnwindCacheNode *n = slot->first, *next = 0; n != 0; n = next)
|
||||
{
|
||||
next = n->next;
|
||||
if(df_entity_is_nil(df_entity_from_handle(n->thread)))
|
||||
{
|
||||
DLLRemove(slot->first, slot->last, n);
|
||||
arena_release(n->arena);
|
||||
SLLStackPush(df_state->unwind_cache.free_node, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: write config changes
|
||||
ProfScope("write config changes")
|
||||
{
|
||||
|
||||
+17
-16
@@ -946,29 +946,33 @@ struct DF_AutoViewRuleMapCache
|
||||
DF_AutoViewRuleSlot *slots;
|
||||
};
|
||||
|
||||
//- rjf: per-run unwind cache
|
||||
//- rjf: per-thread unwind cache
|
||||
|
||||
typedef struct DF_RunUnwindCacheNode DF_RunUnwindCacheNode;
|
||||
struct DF_RunUnwindCacheNode
|
||||
typedef struct DF_UnwindCacheNode DF_UnwindCacheNode;
|
||||
struct DF_UnwindCacheNode
|
||||
{
|
||||
DF_RunUnwindCacheNode *hash_next;
|
||||
DF_UnwindCacheNode *next;
|
||||
DF_UnwindCacheNode *prev;
|
||||
U64 reggen;
|
||||
U64 memgen;
|
||||
Arena *arena;
|
||||
DF_Handle thread;
|
||||
CTRL_Unwind unwind;
|
||||
};
|
||||
|
||||
typedef struct DF_RunUnwindCacheSlot DF_RunUnwindCacheSlot;
|
||||
struct DF_RunUnwindCacheSlot
|
||||
typedef struct DF_UnwindCacheSlot DF_UnwindCacheSlot;
|
||||
struct DF_UnwindCacheSlot
|
||||
{
|
||||
DF_RunUnwindCacheNode *first;
|
||||
DF_RunUnwindCacheNode *last;
|
||||
DF_UnwindCacheNode *first;
|
||||
DF_UnwindCacheNode *last;
|
||||
};
|
||||
|
||||
typedef struct DF_RunUnwindCache DF_RunUnwindCache;
|
||||
struct DF_RunUnwindCache
|
||||
typedef struct DF_UnwindCache DF_UnwindCache;
|
||||
struct DF_UnwindCache
|
||||
{
|
||||
Arena *arena;
|
||||
U64 slots_count;
|
||||
DF_RunUnwindCacheSlot *slots;
|
||||
DF_UnwindCacheSlot *slots;
|
||||
DF_UnwindCacheNode *free_node;
|
||||
};
|
||||
|
||||
//- rjf: per-run tls-base-vaddr cache
|
||||
@@ -1146,10 +1150,7 @@ struct DF_State
|
||||
DF_AutoViewRuleMapCache auto_view_rule_cache;
|
||||
|
||||
// rjf: per-run caches
|
||||
U64 unwind_cache_reggen_idx;
|
||||
U64 unwind_cache_memgen_idx;
|
||||
DF_RunUnwindCache unwind_caches[2];
|
||||
U64 unwind_cache_gen;
|
||||
DF_UnwindCache unwind_cache;
|
||||
U64 tls_base_cache_reggen_idx;
|
||||
U64 tls_base_cache_memgen_idx;
|
||||
DF_RunTLSBaseCache tls_base_caches[2];
|
||||
|
||||
@@ -3494,7 +3494,6 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds)
|
||||
avg_ui_hash_chain_length = chain_length_sum / chain_count;
|
||||
}
|
||||
ui_labelf("Target Hz: %.2f", 1.f/df_dt());
|
||||
ui_labelf("Unwind Cache Gen: %I64u", df_state->unwind_cache_gen);
|
||||
ui_labelf("Ctrl Run Index: %I64u", ctrl_run_gen());
|
||||
ui_labelf("Ctrl Mem Gen Index: %I64u", ctrl_mem_gen());
|
||||
ui_labelf("Window %p", window);
|
||||
|
||||
Reference in New Issue
Block a user