mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-19 10:32:23 -07:00
pass over hash store layer / all users, to switch to explicit 64-bit root alloc/dealloc, and 128-bit ids, for a full 192-bit hs key
This commit is contained in:
@@ -61,6 +61,7 @@ async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params
|
||||
work.output = params->output;
|
||||
work.semaphore = params->semaphore;
|
||||
work.completion_counter = params->completion_counter;
|
||||
work.working_counter = params->working_counter;
|
||||
|
||||
// rjf: loop; try to write into user -> writer ring buffer. if we're on a
|
||||
// worker thread, determine if we need to execute this task locally on this
|
||||
@@ -227,6 +228,12 @@ async_execute_work(ASYNC_Work work)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(work.completion_counter);
|
||||
}
|
||||
|
||||
//- rjf: decrement working counter
|
||||
if(work.working_counter != 0)
|
||||
{
|
||||
ins_atomic_u64_dec_eval(work.working_counter);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -29,6 +29,7 @@ struct ASYNC_WorkParams
|
||||
void **output;
|
||||
OS_Handle semaphore;
|
||||
U64 *completion_counter;
|
||||
U64 *working_counter;
|
||||
U64 endt_us;
|
||||
ASYNC_Priority priority;
|
||||
};
|
||||
@@ -41,6 +42,7 @@ struct ASYNC_Work
|
||||
void **output;
|
||||
OS_Handle semaphore;
|
||||
U64 *completion_counter;
|
||||
U64 *working_counter;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
+206
-45
@@ -1577,8 +1577,188 @@ ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook)
|
||||
////////////////////////////////
|
||||
//~ rjf: Process Memory Functions
|
||||
|
||||
//- rjf: process memory cache key reading
|
||||
|
||||
internal HS_Key
|
||||
ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale)
|
||||
{
|
||||
CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache;
|
||||
|
||||
//- rjf: unpack process key
|
||||
U64 process_hash = ctrl_hash_from_handle(process);
|
||||
U64 process_slot_idx = process_hash%cache->slots_count;
|
||||
U64 process_stripe_idx = process_slot_idx%cache->stripes_count;
|
||||
CTRL_ProcessMemoryCacheSlot *process_slot = &cache->slots[process_slot_idx];
|
||||
CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx];
|
||||
|
||||
//- rjf: get the hash store root for this process; construct process node if it
|
||||
// doesn't exist
|
||||
HS_Root root = {0};
|
||||
{
|
||||
B32 node_found = 0;
|
||||
OS_MutexScopeR(process_stripe->rw_mutex)
|
||||
{
|
||||
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(ctrl_handle_match(n->handle, process))
|
||||
{
|
||||
node_found = 1;
|
||||
root = n->root;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!node_found) OS_MutexScopeW(process_stripe->rw_mutex)
|
||||
{
|
||||
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(ctrl_handle_match(n->handle, process))
|
||||
{
|
||||
node_found = 1;
|
||||
root = n->root;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!node_found)
|
||||
{
|
||||
Arena *node_arena = arena_alloc();
|
||||
CTRL_ProcessMemoryCacheNode *node = push_array(node_arena, CTRL_ProcessMemoryCacheNode, 1);
|
||||
DLLPushBack(process_slot->first, process_slot->last, node);
|
||||
node->arena = node_arena;
|
||||
node->handle = process;
|
||||
node->root = hs_root_alloc();
|
||||
node->range_hash_slots_count = 1024;
|
||||
node->range_hash_slots = push_array(node_arena, CTRL_ProcessMemoryRangeHashSlot, node->range_hash_slots_count);
|
||||
root = node->root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: form ID for this process memory query
|
||||
HS_ID id = {0};
|
||||
{
|
||||
id.u128[0].u64[0] = vaddr_range.min & 0x00ffffffffffffffull;
|
||||
id.u128[0].u64[1] = vaddr_range.max & 0x00ffffffffffffffull;
|
||||
if(zero_terminated)
|
||||
{
|
||||
id.u128[0].u64[0] |= (1ull << 63);
|
||||
}
|
||||
}
|
||||
U64 range_hash = hs_little_hash_from_data(str8_struct(&id));
|
||||
|
||||
//- rjf: form full key
|
||||
HS_Key key = hs_key_make(root, id);
|
||||
|
||||
//- rjf: loop: try to look for current results, request if not there, wait if we can, repeat until we can't
|
||||
U64 mem_gen = ctrl_mem_gen();
|
||||
B32 key_is_stale = 0;
|
||||
for(;;)
|
||||
{
|
||||
//- rjf: step 1: [read-only] try to look for current results for key's ID
|
||||
B32 id_exists = 0;
|
||||
B32 id_stale = 0;
|
||||
OS_MutexScopeR(process_stripe->rw_mutex)
|
||||
{
|
||||
for(CTRL_ProcessMemoryCacheNode *process_n = process_slot->first; process_n != 0; process_n = process_n->next)
|
||||
{
|
||||
if(ctrl_handle_match(process_n->handle, process))
|
||||
{
|
||||
U64 range_slot_idx = range_hash%process_n->range_hash_slots_count;
|
||||
CTRL_ProcessMemoryRangeHashSlot *range_slot = &process_n->range_hash_slots[range_slot_idx];
|
||||
for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(hs_id_match(n->id, id))
|
||||
{
|
||||
id_exists = 1;
|
||||
id_stale = (n->mem_gen < mem_gen);
|
||||
goto end_fast_lookup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end_fast_lookup:;
|
||||
}
|
||||
key_is_stale = id_stale;
|
||||
|
||||
//- rjf: step 2: if the ID exists and is not stale, then we're done;
|
||||
// the hash store contains the most up-to-date representation of the
|
||||
// process memory for this key.
|
||||
if(id_exists && !id_stale)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//- rjf: step 3: if the ID does not exist in the process' cache, then we
|
||||
// need to build a node for it. if that, or if the ID is stale, then also
|
||||
// request that that range is streamed.
|
||||
if(!id_exists || (id_exists && id_stale))
|
||||
{
|
||||
B32 node_needs_stream = 0;
|
||||
U64 *node_working_count = 0;
|
||||
OS_MutexScopeW(process_stripe->rw_mutex)
|
||||
{
|
||||
for(CTRL_ProcessMemoryCacheNode *process_n = process_slot->first; process_n != 0; process_n = process_n->next)
|
||||
{
|
||||
if(ctrl_handle_match(process_n->handle, process))
|
||||
{
|
||||
U64 range_slot_idx = range_hash%process_n->range_hash_slots_count;
|
||||
CTRL_ProcessMemoryRangeHashSlot *range_slot = &process_n->range_hash_slots[range_slot_idx];
|
||||
CTRL_ProcessMemoryRangeHashNode *range_n = 0;
|
||||
for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(hs_id_match(n->id, id))
|
||||
{
|
||||
range_n = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(range_n == 0)
|
||||
{
|
||||
range_n = push_array(process_n->arena, CTRL_ProcessMemoryRangeHashNode, 1);
|
||||
SLLQueuePush(range_slot->first, range_slot->last, range_n);
|
||||
range_n->vaddr_range = vaddr_range;
|
||||
range_n->zero_terminated = zero_terminated;
|
||||
range_n->id = id;
|
||||
range_n->working_count += 1;
|
||||
node_needs_stream = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
node_needs_stream = (range_n->mem_gen < mem_gen);
|
||||
}
|
||||
node_working_count = &range_n->working_count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(node_needs_stream)
|
||||
{
|
||||
ctrl_u2ms_enqueue_req(key, process, vaddr_range, zero_terminated, max_U64);
|
||||
async_push_work(ctrl_mem_stream_work, .working_counter = node_working_count);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: step 4: if we have no time to wait, then abort; otherwise,
|
||||
// wait on this process' stripe
|
||||
if(os_now_microseconds() >= endt_us)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else OS_MutexScopeR(process_stripe->rw_mutex)
|
||||
{
|
||||
os_condition_variable_wait_rw_r(process_stripe->cv, process_stripe->rw_mutex, endt_us);
|
||||
}
|
||||
}
|
||||
if(out_is_stale)
|
||||
{
|
||||
*out_is_stale = key_is_stale;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
//- rjf: process memory cache interaction
|
||||
|
||||
#if 0 // TODO(rjf): @hs
|
||||
internal U128
|
||||
ctrl_calc_hash_store_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B32 zero_terminated)
|
||||
{
|
||||
@@ -1758,9 +1938,11 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B3
|
||||
ProfEnd();
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
//- rjf: bundled key/stream helper
|
||||
|
||||
#if 0 // TODO(rjf): @hs
|
||||
internal U128
|
||||
ctrl_hash_store_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B32 zero_terminated)
|
||||
{
|
||||
@@ -1768,6 +1950,7 @@ ctrl_hash_store_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range,
|
||||
ctrl_stored_hash_from_process_vaddr_range(process, range, zero_terminated, 0, 0);
|
||||
return key;
|
||||
}
|
||||
#endif
|
||||
|
||||
//- rjf: process memory cache reading helpers
|
||||
|
||||
@@ -1798,9 +1981,9 @@ ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rn
|
||||
for(U64 page_idx = 0; page_idx < page_count; page_idx += 1)
|
||||
{
|
||||
U64 page_base_vaddr = page_range.min + page_idx*page_size;
|
||||
U128 page_key = ctrl_calc_hash_store_key_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0);
|
||||
B32 page_is_stale = 0;
|
||||
U128 page_hash = ctrl_stored_hash_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, &page_is_stale, endt_us);
|
||||
HS_Key page_key = ctrl_key_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, endt_us, &page_is_stale);
|
||||
U128 page_hash = hs_hash_from_key(page_key, 0);
|
||||
U128 page_last_hash = hs_hash_from_key(page_key, 1);
|
||||
result.stale = (result.stale || page_is_stale);
|
||||
page_hashes[page_idx] = page_hash;
|
||||
@@ -6542,16 +6725,17 @@ ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
//- rjf: user -> memory stream communication
|
||||
|
||||
internal B32
|
||||
ctrl_u2ms_enqueue_req(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us)
|
||||
ctrl_u2ms_enqueue_req(HS_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us)
|
||||
{
|
||||
B32 good = 0;
|
||||
OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;)
|
||||
{
|
||||
U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos;
|
||||
U64 available_size = ctrl_state->u2ms_ring_size-unconsumed_size;
|
||||
if(available_size >= sizeof(process)+sizeof(vaddr_range)+sizeof(zero_terminated))
|
||||
if(available_size >= sizeof(key)+sizeof(process)+sizeof(vaddr_range)+sizeof(zero_terminated))
|
||||
{
|
||||
good = 1;
|
||||
ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &key);
|
||||
ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &process);
|
||||
ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &vaddr_range);
|
||||
ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &zero_terminated);
|
||||
@@ -6565,13 +6749,14 @@ ctrl_u2ms_enqueue_req(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_termina
|
||||
}
|
||||
|
||||
internal void
|
||||
ctrl_u2ms_dequeue_req(CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated)
|
||||
ctrl_u2ms_dequeue_req(HS_Key *out_key, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated)
|
||||
{
|
||||
OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;)
|
||||
{
|
||||
U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos;
|
||||
if(unconsumed_size >= sizeof(*out_process)+sizeof(*out_vaddr_range)+sizeof(*out_zero_terminated))
|
||||
if(unconsumed_size >= sizeof(*out_key)+sizeof(*out_process)+sizeof(*out_vaddr_range)+sizeof(*out_zero_terminated))
|
||||
{
|
||||
ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_key);
|
||||
ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_process);
|
||||
ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_vaddr_range);
|
||||
ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_zero_terminated);
|
||||
@@ -6590,50 +6775,29 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work)
|
||||
CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache;
|
||||
|
||||
//- rjf: unpack next request
|
||||
HS_Key key = {0};
|
||||
CTRL_Handle process = {0};
|
||||
Rng1U64 vaddr_range = {0};
|
||||
B32 zero_terminated = 0;
|
||||
ctrl_u2ms_dequeue_req(&process, &vaddr_range, &zero_terminated);
|
||||
U128 key = ctrl_calc_hash_store_key_from_process_vaddr_range(process, vaddr_range, zero_terminated);
|
||||
ctrl_u2ms_dequeue_req(&key, &process, &vaddr_range, &zero_terminated);
|
||||
ProfBegin("memory stream request");
|
||||
|
||||
//- rjf: unpack process memory cache key
|
||||
U64 process_hash = ctrl_hash_from_string(str8_struct(&process));
|
||||
//- rjf: unpack process key
|
||||
U64 process_hash = ctrl_hash_from_handle(process);
|
||||
U64 process_slot_idx = process_hash%cache->slots_count;
|
||||
U64 process_stripe_idx = process_slot_idx%cache->stripes_count;
|
||||
CTRL_ProcessMemoryCacheSlot *process_slot = &cache->slots[process_slot_idx];
|
||||
CTRL_ProcessMemoryCacheStripe *process_stripe = &cache->stripes[process_stripe_idx];
|
||||
|
||||
//- rjf: unpack address range hash cache key
|
||||
U64 range_hash = ctrl_hash_from_string(str8_struct(&vaddr_range));
|
||||
U64 range_hash = hs_little_hash_from_data(str8_struct(&key.id));
|
||||
|
||||
//- rjf: take task
|
||||
B32 got_task = 0;
|
||||
U64 preexisting_mem_gen = 0;
|
||||
U128 preexisting_hash = {0};
|
||||
Rng1U64 vaddr_range_clamped = {0};
|
||||
OS_MutexScopeW(process_stripe->rw_mutex)
|
||||
//- rjf: clamp vaddr range
|
||||
Rng1U64 vaddr_range_clamped = vaddr_range;
|
||||
{
|
||||
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(ctrl_handle_match(n->handle, process))
|
||||
{
|
||||
U64 range_slot_idx = range_hash%n->range_hash_slots_count;
|
||||
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
|
||||
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
|
||||
{
|
||||
if(MemoryMatchStruct(&range_n->vaddr_range, &vaddr_range) && range_n->zero_terminated == zero_terminated)
|
||||
{
|
||||
got_task = !ins_atomic_u32_eval_cond_assign(&range_n->is_taken, 1, 0);
|
||||
preexisting_mem_gen = range_n->mem_gen;
|
||||
preexisting_hash = range_n->hash;
|
||||
vaddr_range_clamped = range_n->vaddr_range_clamped;
|
||||
goto take_task__break_all;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
take_task__break_all:;
|
||||
vaddr_range_clamped.max = Max(vaddr_range_clamped.max, vaddr_range_clamped.min);
|
||||
U64 max_size_cap = Min(max_U64-vaddr_range_clamped.min, GB(1));
|
||||
vaddr_range_clamped.max = Min(vaddr_range_clamped.max, vaddr_range_clamped.min+max_size_cap);
|
||||
}
|
||||
|
||||
//- rjf: task was taken -> read memory
|
||||
@@ -6641,9 +6805,8 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work)
|
||||
Arena *range_arena = 0;
|
||||
void *range_base = 0;
|
||||
U64 zero_terminated_size = 0;
|
||||
U64 pre_read_mem_gen = dmn_mem_gen();
|
||||
U64 pre_read_mem_gen = ctrl_mem_gen();
|
||||
U64 post_read_mem_gen = 0;
|
||||
if(got_task && pre_read_mem_gen != preexisting_mem_gen)
|
||||
{
|
||||
range_size = dim_1u64(vaddr_range_clamped);
|
||||
U64 page_size = os_get_system_info()->page_size;
|
||||
@@ -6708,7 +6871,7 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work)
|
||||
|
||||
//- rjf: read successful -> submit to hash store
|
||||
U128 hash = {0};
|
||||
if(got_task && range_base != 0 && pre_read_mem_gen == post_read_mem_gen)
|
||||
if(range_base != 0 && pre_read_mem_gen == post_read_mem_gen)
|
||||
{
|
||||
hash = hs_submit_data(key, &range_arena, str8((U8*)range_base, zero_terminated_size));
|
||||
}
|
||||
@@ -6717,8 +6880,8 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work)
|
||||
arena_release(range_arena);
|
||||
}
|
||||
|
||||
//- rjf: commit hash to cache
|
||||
if(got_task) OS_MutexScopeW(process_stripe->rw_mutex)
|
||||
//- rjf: commit new info to cache
|
||||
OS_MutexScopeW(process_stripe->rw_mutex)
|
||||
{
|
||||
for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
@@ -6728,14 +6891,12 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work)
|
||||
CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx];
|
||||
for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next)
|
||||
{
|
||||
if(MemoryMatchStruct(&range_n->vaddr_range, &vaddr_range) && range_n->zero_terminated == zero_terminated)
|
||||
if(hs_id_match(range_n->id, key.id))
|
||||
{
|
||||
if(!u128_match(u128_zero(), hash))
|
||||
{
|
||||
range_n->hash = hash;
|
||||
range_n->mem_gen = post_read_mem_gen;
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&range_n->is_taken, 0);
|
||||
goto commit__break_all;
|
||||
}
|
||||
}
|
||||
|
||||
+19
-5
@@ -505,13 +505,19 @@ typedef struct CTRL_ProcessMemoryRangeHashNode CTRL_ProcessMemoryRangeHashNode;
|
||||
struct CTRL_ProcessMemoryRangeHashNode
|
||||
{
|
||||
CTRL_ProcessMemoryRangeHashNode *next;
|
||||
|
||||
// rjf: key
|
||||
Rng1U64 vaddr_range;
|
||||
B32 zero_terminated;
|
||||
Rng1U64 vaddr_range_clamped;
|
||||
U128 hash;
|
||||
HS_ID id;
|
||||
|
||||
// rjf: staleness info
|
||||
U64 mem_gen;
|
||||
|
||||
// rjf: metadata
|
||||
U64 working_count;
|
||||
U64 last_time_requested_us;
|
||||
B32 is_taken;
|
||||
U64 last_user_clock_idx_touched;
|
||||
};
|
||||
|
||||
typedef struct CTRL_ProcessMemoryRangeHashSlot CTRL_ProcessMemoryRangeHashSlot;
|
||||
@@ -528,6 +534,7 @@ struct CTRL_ProcessMemoryCacheNode
|
||||
CTRL_ProcessMemoryCacheNode *prev;
|
||||
Arena *arena;
|
||||
CTRL_Handle handle;
|
||||
HS_Root root;
|
||||
U64 range_hash_slots_count;
|
||||
CTRL_ProcessMemoryRangeHashSlot *range_hash_slots;
|
||||
};
|
||||
@@ -983,12 +990,19 @@ internal void ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook);
|
||||
////////////////////////////////
|
||||
//~ rjf: Process Memory Functions
|
||||
|
||||
//- rjf: process memory cache key reading
|
||||
internal HS_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale);
|
||||
|
||||
//- rjf: process memory cache interaction
|
||||
#if 0 // TODO(rjf): @hs
|
||||
internal U128 ctrl_calc_hash_store_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B32 zero_terminated);
|
||||
internal U128 ctrl_stored_hash_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B32 zero_terminated, B32 *out_is_stale, U64 endt_us);
|
||||
#endif
|
||||
|
||||
//- rjf: bundled key/stream helper
|
||||
#if 0 // TODO(rjf): @hs
|
||||
internal U128 ctrl_hash_store_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B32 zero_terminated);
|
||||
#endif
|
||||
|
||||
//- rjf: process memory cache reading helpers
|
||||
internal CTRL_ProcessMemorySlice ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us);
|
||||
@@ -1114,8 +1128,8 @@ internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
//~ rjf: Asynchronous Memory Streaming Functions
|
||||
|
||||
//- rjf: user -> memory stream communication
|
||||
internal B32 ctrl_u2ms_enqueue_req(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us);
|
||||
internal void ctrl_u2ms_dequeue_req(CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated);
|
||||
internal B32 ctrl_u2ms_enqueue_req(HS_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us);
|
||||
internal void ctrl_u2ms_dequeue_req(HS_Key *out_key, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated);
|
||||
|
||||
//- rjf: entry point
|
||||
ASYNC_WORK_DEF(ctrl_mem_stream_work);
|
||||
|
||||
+38
-67
@@ -345,10 +345,13 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params)
|
||||
DASM_Info info = {0};
|
||||
if(!u128_match(hash, u128_zero()))
|
||||
{
|
||||
//- rjf: unpack hash
|
||||
U64 slot_idx = hash.u64[1]%dasm_shared->slots_count;
|
||||
U64 stripe_idx = slot_idx%dasm_shared->stripes_count;
|
||||
DASM_Slot *slot = &dasm_shared->slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx];
|
||||
|
||||
//- rjf: try to get existing results
|
||||
B32 found = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
@@ -363,9 +366,13 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params)
|
||||
}
|
||||
}
|
||||
}
|
||||
B32 node_is_new = 0;
|
||||
|
||||
//- rjf: miss -> kick off work to fill cache
|
||||
if(!found)
|
||||
{
|
||||
B32 node_is_new = 0;
|
||||
U64 *node_working_count = 0;
|
||||
HS_Root root = {0};
|
||||
OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
DASM_Node *node = 0;
|
||||
@@ -379,16 +386,7 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params)
|
||||
}
|
||||
if(node == 0)
|
||||
{
|
||||
LogInfoNamedBlockF("dasm_new_node")
|
||||
{
|
||||
log_infof("hash: [0x%I64x 0x%I64x]\n", hash.u64[0], hash.u64[1]);
|
||||
log_infof("vaddr: 0x%I64x\n", params->vaddr);
|
||||
log_infof("arch: %S\n", string_from_arch(params->arch));
|
||||
log_infof("style_flags: 0x%x\n", params->style_flags);
|
||||
log_infof("syntax: %i\n", params->syntax);
|
||||
log_infof("base_vaddr: 0x%I64x\n", params->base_vaddr);
|
||||
log_infof("dbgi_key: [%S 0x%I64x]\n", params->dbgi_key.path, params->dbgi_key.min_timestamp);
|
||||
}
|
||||
// rjf: allocate node
|
||||
node = stripe->free_node;
|
||||
if(node)
|
||||
{
|
||||
@@ -399,26 +397,34 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params)
|
||||
node = push_array_no_zero(stripe->arena, DASM_Node, 1);
|
||||
}
|
||||
MemoryZeroStruct(node);
|
||||
|
||||
// rjf: fill node
|
||||
DLLPushBack(slot->first, slot->last, node);
|
||||
node->hash = hash;
|
||||
MemoryCopyStruct(&node->params, params);
|
||||
node->root = hs_root_alloc();
|
||||
// TODO(rjf): need to make this releasable - currently all exe_paths just leak
|
||||
node->params.dbgi_key = di_key_copy(stripe->arena, &node->params.dbgi_key);
|
||||
|
||||
// rjf: gather work kickoff params
|
||||
node_is_new = 1;
|
||||
ins_atomic_u64_inc_eval(&node->working_count);
|
||||
node_working_count = &node->working_count;
|
||||
root = node->root;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(node_is_new)
|
||||
{
|
||||
dasm_u2p_enqueue_req(hash, params, max_U64);
|
||||
async_push_work(dasm_parse_work);
|
||||
if(node_is_new)
|
||||
{
|
||||
dasm_u2p_enqueue_req(root, hash, params, max_U64);
|
||||
async_push_work(dasm_parse_work, .working_counter = node_working_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
internal DASM_Info
|
||||
dasm_info_from_key_params(DASM_Scope *scope, U128 key, DASM_Params *params, U128 *hash_out)
|
||||
dasm_info_from_key_params(DASM_Scope *scope, HS_Key key, DASM_Params *params, U128 *hash_out)
|
||||
{
|
||||
DASM_Info result = {0};
|
||||
for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1)
|
||||
@@ -441,16 +447,17 @@ dasm_info_from_key_params(DASM_Scope *scope, U128 key, DASM_Params *params, U128
|
||||
//~ rjf: Parse Threads
|
||||
|
||||
internal B32
|
||||
dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us)
|
||||
dasm_u2p_enqueue_req(HS_Root root, U128 hash, DASM_Params *params, U64 endt_us)
|
||||
{
|
||||
B32 good = 0;
|
||||
OS_MutexScope(dasm_shared->u2p_ring_mutex) for(;;)
|
||||
{
|
||||
U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos;
|
||||
U64 available_size = dasm_shared->u2p_ring_size - unconsumed_size;
|
||||
if(available_size >= sizeof(hash)+sizeof(U64)+sizeof(Arch)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+params->dbgi_key.path.size+sizeof(U64))
|
||||
if(available_size >= sizeof(root)+sizeof(hash)+sizeof(U64)+sizeof(Arch)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+params->dbgi_key.path.size+sizeof(U64))
|
||||
{
|
||||
good = 1;
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, &root);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, &hash);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->vaddr);
|
||||
dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->arch);
|
||||
@@ -476,13 +483,14 @@ dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us)
|
||||
}
|
||||
|
||||
internal void
|
||||
dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out)
|
||||
dasm_u2p_dequeue_req(Arena *arena, HS_Root *root_out, U128 *hash_out, DASM_Params *params_out)
|
||||
{
|
||||
OS_MutexScope(dasm_shared->u2p_ring_mutex) for(;;)
|
||||
{
|
||||
U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos;
|
||||
if(unconsumed_size >= sizeof(*hash_out)+sizeof(U64)+sizeof(Arch)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+sizeof(U64))
|
||||
{
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, root_out);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, hash_out);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->vaddr);
|
||||
dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->arch);
|
||||
@@ -509,9 +517,10 @@ ASYNC_WORK_DEF(dasm_parse_work)
|
||||
TXT_Scope *txt_scope = txt_scope_open();
|
||||
|
||||
//- rjf: get next request
|
||||
HS_Root root = {0};
|
||||
U128 hash = {0};
|
||||
DASM_Params params = {0};
|
||||
dasm_u2p_dequeue_req(scratch.arena, &hash, ¶ms);
|
||||
dasm_u2p_dequeue_req(scratch.arena, &root, &hash, ¶ms);
|
||||
U64 change_gen = fs_change_gen();
|
||||
|
||||
//- rjf: unpack hash
|
||||
@@ -520,38 +529,19 @@ ASYNC_WORK_DEF(dasm_parse_work)
|
||||
DASM_Slot *slot = &dasm_shared->slots[slot_idx];
|
||||
DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx];
|
||||
|
||||
//- rjf: take task
|
||||
B32 got_task = 0;
|
||||
OS_MutexScopeR(stripe->rw_mutex)
|
||||
{
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash) && dasm_params_match(&n->params, ¶ms))
|
||||
{
|
||||
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: get dbg info
|
||||
RDI_Parsed *rdi = &rdi_parsed_nil;
|
||||
if(got_task && params.dbgi_key.path.size != 0)
|
||||
if(params.dbgi_key.path.size != 0)
|
||||
{
|
||||
rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, max_U64);
|
||||
}
|
||||
|
||||
//- rjf: hash -> data
|
||||
String8 data = {0};
|
||||
if(got_task)
|
||||
{
|
||||
data = hs_data_from_hash(hs_scope, hash);
|
||||
}
|
||||
String8 data = hs_data_from_hash(hs_scope, hash);
|
||||
|
||||
//- rjf: data * arch * addr * dbg -> decode artifacts
|
||||
DASM_LineChunkList line_list = {0};
|
||||
String8List inst_strings = {0};
|
||||
if(got_task)
|
||||
{
|
||||
switch(params.arch)
|
||||
{
|
||||
@@ -621,7 +611,7 @@ ASYNC_WORK_DEF(dasm_parse_work)
|
||||
{
|
||||
// TODO(rjf): need redirection path - this may map to a different path on the local machine,
|
||||
// need frontend to communicate path remapping info to this layer
|
||||
U128 key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64));
|
||||
HS_Key key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64), 0);
|
||||
TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path);
|
||||
U64 endt_us = max_U64;
|
||||
U128 hash = {0};
|
||||
@@ -712,7 +702,6 @@ ASYNC_WORK_DEF(dasm_parse_work)
|
||||
//- rjf: artifacts -> value bundle
|
||||
Arena *info_arena = 0;
|
||||
DASM_Info info = {0};
|
||||
if(got_task)
|
||||
{
|
||||
//- rjf: produce joined text
|
||||
Arena *text_arena = arena_alloc();
|
||||
@@ -721,21 +710,7 @@ ASYNC_WORK_DEF(dasm_parse_work)
|
||||
String8 text = str8_list_join(text_arena, &inst_strings, &text_join);
|
||||
|
||||
//- rjf: produce unique key for this disassembly's text
|
||||
U128 text_key = {0};
|
||||
{
|
||||
U64 hash_data[] =
|
||||
{
|
||||
hash.u64[0],
|
||||
hash.u64[1],
|
||||
params.vaddr,
|
||||
(U64)params.arch,
|
||||
(U64)params.style_flags,
|
||||
(U64)params.syntax,
|
||||
(U64)rdi,
|
||||
0x4d534144,
|
||||
};
|
||||
text_key = hs_hash_from_data(str8((U8 *)hash_data, sizeof(hash_data)));
|
||||
}
|
||||
HS_Key text_key = hs_key_make(root, hs_id_make(0, 0));
|
||||
|
||||
//- rjf: submit text data to hash store
|
||||
U128 text_hash = hs_submit_data(text_key, &text_arena, text);
|
||||
@@ -747,7 +722,7 @@ ASYNC_WORK_DEF(dasm_parse_work)
|
||||
}
|
||||
|
||||
//- rjf: commit results to cache
|
||||
if(got_task) OS_MutexScopeW(stripe->rw_mutex)
|
||||
OS_MutexScopeW(stripe->rw_mutex)
|
||||
{
|
||||
for(DASM_Node *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
@@ -763,8 +738,6 @@ ASYNC_WORK_DEF(dasm_parse_work)
|
||||
{
|
||||
n->change_gen = 0;
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&n->is_working, 0);
|
||||
ins_atomic_u64_inc_eval(&n->load_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -807,8 +780,7 @@ dasm_evictor_detector_thread__entry_point(void *p)
|
||||
if(n->scope_ref_count == 0 &&
|
||||
n->last_time_touched_us+evict_threshold_us <= check_time_us &&
|
||||
n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks &&
|
||||
n->load_count != 0 &&
|
||||
n->is_working == 0)
|
||||
ins_atomic_u64_eval(&n->working_count) == 0)
|
||||
{
|
||||
slot_has_work = 1;
|
||||
break;
|
||||
@@ -830,8 +802,7 @@ dasm_evictor_detector_thread__entry_point(void *p)
|
||||
if(n->scope_ref_count == 0 &&
|
||||
n->last_time_touched_us+evict_threshold_us <= check_time_us &&
|
||||
n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks &&
|
||||
n->load_count != 0 &&
|
||||
n->is_working == 0)
|
||||
ins_atomic_u64_eval(&n->working_count) == 0)
|
||||
{
|
||||
DLLRemove(slot->first, slot->last, n);
|
||||
if(n->info_arena != 0)
|
||||
@@ -844,7 +815,7 @@ dasm_evictor_detector_thread__entry_point(void *p)
|
||||
n->last_time_requested_us+retry_threshold_us <= check_time_us &&
|
||||
n->last_user_clock_idx_requested+retry_threshold_user_clocks <= check_time_user_clocks)
|
||||
{
|
||||
if(dasm_u2p_enqueue_req(n->hash, &n->params, max_U64))
|
||||
if(dasm_u2p_enqueue_req(n->root, n->hash, &n->params, max_U64))
|
||||
{
|
||||
async_push_work(dasm_parse_work);
|
||||
n->last_time_requested_us = os_now_microseconds();
|
||||
|
||||
@@ -159,7 +159,7 @@ struct DASM_Result
|
||||
typedef struct DASM_Info DASM_Info;
|
||||
struct DASM_Info
|
||||
{
|
||||
U128 text_key;
|
||||
HS_Key text_key;
|
||||
DASM_LineArray lines;
|
||||
};
|
||||
|
||||
@@ -177,6 +177,9 @@ struct DASM_Node
|
||||
U128 hash;
|
||||
DASM_Params params;
|
||||
|
||||
// rjf: root
|
||||
HS_Root root;
|
||||
|
||||
// rjf: generations
|
||||
U64 change_gen;
|
||||
|
||||
@@ -185,11 +188,10 @@ struct DASM_Node
|
||||
DASM_Info info;
|
||||
|
||||
// rjf: metadata
|
||||
B32 is_working;
|
||||
U64 working_count;
|
||||
U64 scope_ref_count;
|
||||
U64 last_time_touched_us;
|
||||
U64 last_user_clock_idx_touched;
|
||||
U64 load_count;
|
||||
U64 last_time_requested_us;
|
||||
U64 last_user_clock_idx_requested;
|
||||
};
|
||||
@@ -309,13 +311,13 @@ internal void dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_No
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal DASM_Info dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params);
|
||||
internal DASM_Info dasm_info_from_key_params(DASM_Scope *scope, U128 key, DASM_Params *params, U128 *hash_out);
|
||||
internal DASM_Info dasm_info_from_key_params(DASM_Scope *scope, HS_Key key, DASM_Params *params, U128 *hash_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Threads
|
||||
|
||||
internal B32 dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us);
|
||||
internal void dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out);
|
||||
internal B32 dasm_u2p_enqueue_req(HS_Root root, U128 hash, DASM_Params *params, U64 endt_us);
|
||||
internal void dasm_u2p_dequeue_req(Arena *arena, HS_Root *root_out, U128 *hash_out, DASM_Params *params_out);
|
||||
ASYNC_WORK_DEF(dasm_parse_work);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -1443,7 +1443,7 @@ d_init(void)
|
||||
d_state = push_array(arena, D_State, 1);
|
||||
d_state->arena = arena;
|
||||
d_state->cmds_arena = arena_alloc();
|
||||
d_state->output_log_key = hs_hash_from_data(str8_lit("output_log_key"));
|
||||
d_state->output_log_key = hs_key_make(hs_root_alloc(), hs_id_make(0, 0));
|
||||
hs_submit_data(d_state->output_log_key, 0, str8_zero());
|
||||
d_state->ctrl_entity_store = ctrl_entity_ctx_rw_store_alloc();
|
||||
d_state->ctrl_stop_arena = arena_alloc();
|
||||
|
||||
@@ -312,7 +312,7 @@ struct D_State
|
||||
D_CmdList cmds;
|
||||
|
||||
// rjf: output log key
|
||||
U128 output_log_key;
|
||||
HS_Key output_log_key;
|
||||
|
||||
// rjf: per-run caches
|
||||
D_UnwindCache unwind_cache;
|
||||
|
||||
+137
-109
@@ -71,125 +71,151 @@ fs_change_gen(void)
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Interaction
|
||||
|
||||
internal U128
|
||||
fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
|
||||
internal HS_Key
|
||||
fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//- rjf: unpack args
|
||||
path = path_normalized_from_string(scratch.arena, path);
|
||||
U128 key = fs_big_hash_from_string_range(path, range);
|
||||
U64 path_little_hash = fs_little_hash_from_string(path);
|
||||
U64 path_slot_idx = path_little_hash%fs_shared->slots_count;
|
||||
U64 path_stripe_idx = path_slot_idx%fs_shared->stripes_count;
|
||||
FS_Slot *path_slot = &fs_shared->slots[path_slot_idx];
|
||||
FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx];
|
||||
|
||||
//- rjf: loop through key -> hash history; obtain most recent hash for this key
|
||||
U128 result = {0};
|
||||
for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1)
|
||||
//- rjf: get root for this path
|
||||
HS_Root root = {0};
|
||||
OS_MutexScopeR(path_stripe->rw_mutex)
|
||||
{
|
||||
result = hs_hash_from_key(key, rewind_idx);
|
||||
|
||||
//- rjf: nonzero hash -> got valid results, return
|
||||
if(!u128_match(result, u128_zero()))
|
||||
B32 node_found = 0;
|
||||
for(FS_Node *n = path_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//- rjf: zero hash, not rewound? -> send new stream request if needed
|
||||
else if(u128_match(result, u128_zero()) && rewind_idx == 0)
|
||||
{
|
||||
// rjf: unpack path cache info
|
||||
U64 path_little_hash = fs_little_hash_from_string(path);
|
||||
U64 path_slot_idx = path_little_hash%fs_shared->slots_count;
|
||||
U64 path_stripe_idx = path_slot_idx%fs_shared->stripes_count;
|
||||
FS_Slot *path_slot = &fs_shared->slots[path_slot_idx];
|
||||
FS_Stripe *path_stripe = &fs_shared->stripes[path_stripe_idx];
|
||||
|
||||
// rjf: loop: request, check for results, return until we can't
|
||||
OS_MutexScopeW(path_stripe->rw_mutex) for(;;)
|
||||
if(str8_match(n->path, path, 0))
|
||||
{
|
||||
// rjf: path -> node
|
||||
FS_Node *node = 0;
|
||||
for(FS_Node *n = path_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(path, n->path, 0))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: node does not exist? -> create & store
|
||||
if(node == 0)
|
||||
{
|
||||
node = push_array(path_stripe->arena, FS_Node, 1);
|
||||
SLLQueuePush(path_slot->first, path_slot->last, node);
|
||||
node->path = push_str8_copy(path_stripe->arena, path);
|
||||
node->slots_count = 64;
|
||||
node->slots = push_array(path_stripe->arena, FS_RangeSlot, node->slots_count);
|
||||
}
|
||||
|
||||
// rjf: range -> node
|
||||
U64 range_hash = fs_little_hash_from_string(str8_struct(&range));
|
||||
U64 range_slot_idx = range_hash%node->slots_count;
|
||||
FS_RangeSlot *range_slot = &node->slots[range_slot_idx];
|
||||
FS_RangeNode *range_node = 0;
|
||||
for(FS_RangeNode *n = range_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(MemoryMatchStruct(&n->range, &range))
|
||||
{
|
||||
range_node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: range node does not exist? create & store
|
||||
if(range_node == 0)
|
||||
{
|
||||
range_node = push_array(path_stripe->arena, FS_RangeNode, 1);
|
||||
SLLQueuePush(range_slot->first, range_slot->last, range_node);
|
||||
range_node->range = range;
|
||||
}
|
||||
|
||||
// rjf: try to send stream request
|
||||
if((ins_atomic_u64_eval(&range_node->request_count) == ins_atomic_u64_eval(&range_node->completion_count) ||
|
||||
ins_atomic_u64_eval(&range_node->last_time_requested_us)+100000 < os_now_microseconds()) &&
|
||||
fs_u2s_enqueue_req(range, path, endt_us))
|
||||
{
|
||||
ins_atomic_u64_eval_assign(&range_node->last_time_requested_us, os_now_microseconds());
|
||||
ins_atomic_u64_inc_eval(&range_node->request_count);
|
||||
DeferLoop(os_rw_mutex_drop_w(path_stripe->rw_mutex), os_rw_mutex_take_w(path_stripe->rw_mutex))
|
||||
{
|
||||
async_push_work(fs_stream_work, .completion_counter = &range_node->completion_count);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: try to reobtain results
|
||||
result = hs_hash_from_key(key, 0);
|
||||
|
||||
// rjf: have time to wait? -> wait on this stripe; otherwise exit
|
||||
if(u128_match(result, u128_zero()) && os_now_microseconds() <= endt_us)
|
||||
{
|
||||
os_condition_variable_wait_rw_w(path_stripe->cv, path_stripe->rw_mutex, endt_us);
|
||||
}
|
||||
else
|
||||
node_found = 1;
|
||||
root = n->root;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!node_found) OS_MutexScopeRWPromote(path_stripe->rw_mutex)
|
||||
{
|
||||
B32 node_found = 0;
|
||||
for(FS_Node *n = path_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->path, path, 0))
|
||||
{
|
||||
node_found = 1;
|
||||
root = n->root;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!node_found)
|
||||
{
|
||||
FS_Node *node = push_array(path_stripe->arena, FS_Node, 1);
|
||||
SLLQueuePush(path_slot->first, path_slot->last, node);
|
||||
node->path = push_str8_copy(path_stripe->arena, path);
|
||||
node->root = hs_root_alloc();
|
||||
node->slots_count = 64;
|
||||
node->slots = push_array(path_stripe->arena, FS_RangeSlot, node->slots_count);
|
||||
root = node->root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: build a key for this path/range combo
|
||||
HS_Key key = hs_key_make(root, hs_id_make(range.min, range.max));
|
||||
|
||||
//- rjf: if the most recent hash for this key is zero, then try to submit a new
|
||||
// request to pull it in.
|
||||
if(u128_match(hs_hash_from_key(key, 0), u128_zero()))
|
||||
{
|
||||
// rjf: loop: request, check for results, return until we can't
|
||||
OS_MutexScopeW(path_stripe->rw_mutex) for(;;)
|
||||
{
|
||||
// rjf: path -> node
|
||||
FS_Node *node = 0;
|
||||
for(FS_Node *n = path_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(path, n->path, 0))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: no node? -> weird case, node should've been made at this point.
|
||||
if(node == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: range -> node
|
||||
U64 range_hash = fs_little_hash_from_string(str8_struct(&key.id));
|
||||
U64 range_slot_idx = range_hash%node->slots_count;
|
||||
FS_RangeSlot *range_slot = &node->slots[range_slot_idx];
|
||||
FS_RangeNode *range_node = 0;
|
||||
for(FS_RangeNode *n = range_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(hs_id_match(n->id, key.id))
|
||||
{
|
||||
range_node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: range node does not exist? create & store
|
||||
if(range_node == 0)
|
||||
{
|
||||
range_node = push_array(path_stripe->arena, FS_RangeNode, 1);
|
||||
SLLQueuePush(range_slot->first, range_slot->last, range_node);
|
||||
range_node->id = key.id;
|
||||
}
|
||||
|
||||
// rjf: try to send stream request
|
||||
if(ins_atomic_u64_eval(&range_node->working_count) == 0 &&
|
||||
fs_u2s_enqueue_req(key, range, path, endt_us))
|
||||
{
|
||||
ins_atomic_u64_inc_eval(&range_node->working_count);
|
||||
DeferLoop(os_rw_mutex_drop_w(path_stripe->rw_mutex), os_rw_mutex_take_w(path_stripe->rw_mutex))
|
||||
{
|
||||
async_push_work(fs_stream_work, .working_counter = &range_node->working_count);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: have time to wait? -> wait on this stripe; otherwise exit
|
||||
B32 have_results = !u128_match(hs_hash_from_key(key, 0), u128_zero());
|
||||
if(!have_results && os_now_microseconds() < endt_us)
|
||||
{
|
||||
os_condition_variable_wait_rw_w(path_stripe->cv, path_stripe->rw_mutex, endt_us);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
return key;
|
||||
}
|
||||
|
||||
internal U128
|
||||
fs_key_from_path_range(String8 path, Rng1U64 range)
|
||||
fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
String8 path_normalized = path_normalized_from_string(scratch.arena, path);
|
||||
U128 key = fs_big_hash_from_string_range(path_normalized, range);
|
||||
fs_hash_from_path_range(path_normalized, range, 0);
|
||||
scratch_end(scratch);
|
||||
return key;
|
||||
U128 hash = {0};
|
||||
{
|
||||
HS_Key key = fs_key_from_path_range(path, range, endt_us);
|
||||
for EachIndex(rewind_idx, HS_KEY_HASH_HISTORY_COUNT)
|
||||
{
|
||||
hash = hs_hash_from_key(key, rewind_idx);
|
||||
if(!u128_match(hash, u128_zero()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
internal FileProperties
|
||||
@@ -222,7 +248,7 @@ fs_properties_from_path(String8 path)
|
||||
//~ rjf: Streamer Threads
|
||||
|
||||
internal B32
|
||||
fs_u2s_enqueue_req(Rng1U64 range, String8 path, U64 endt_us)
|
||||
fs_u2s_enqueue_req(HS_Key key, Rng1U64 range, String8 path, U64 endt_us)
|
||||
{
|
||||
B32 result = 0;
|
||||
path.size = Min(path.size, fs_shared->u2s_ring_size);
|
||||
@@ -230,10 +256,11 @@ fs_u2s_enqueue_req(Rng1U64 range, String8 path, U64 endt_us)
|
||||
{
|
||||
U64 unconsumed_size = fs_shared->u2s_ring_write_pos - fs_shared->u2s_ring_read_pos;
|
||||
U64 available_size = fs_shared->u2s_ring_size - unconsumed_size;
|
||||
U64 needed_size = sizeof(range.min) + sizeof(range.max) + sizeof(path.size) + path.size;
|
||||
U64 needed_size = sizeof(key) + sizeof(range.min) + sizeof(range.max) + sizeof(path.size) + path.size;
|
||||
if(available_size >= needed_size)
|
||||
{
|
||||
result = 1;
|
||||
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &key);
|
||||
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &range.min);
|
||||
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &range.max);
|
||||
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &path.size);
|
||||
@@ -250,13 +277,14 @@ fs_u2s_enqueue_req(Rng1U64 range, String8 path, U64 endt_us)
|
||||
}
|
||||
|
||||
internal void
|
||||
fs_u2s_dequeue_req(Arena *arena, Rng1U64 *range_out, String8 *path_out)
|
||||
fs_u2s_dequeue_req(Arena *arena, HS_Key *key_out, Rng1U64 *range_out, String8 *path_out)
|
||||
{
|
||||
OS_MutexScope(fs_shared->u2s_ring_mutex) for(;;)
|
||||
{
|
||||
U64 unconsumed_size = fs_shared->u2s_ring_write_pos - fs_shared->u2s_ring_read_pos;
|
||||
if(unconsumed_size >= sizeof(U64))
|
||||
if(unconsumed_size >= sizeof(*key_out) + sizeof(U64)*2 + sizeof(U64))
|
||||
{
|
||||
fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, key_out);
|
||||
fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, &range_out->min);
|
||||
fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, &range_out->max);
|
||||
fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, &path_out->size);
|
||||
@@ -275,12 +303,12 @@ ASYNC_WORK_DEF(fs_stream_work)
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//- rjf: get next request
|
||||
HS_Key key = {0};
|
||||
Rng1U64 range = {0};
|
||||
String8 path = {0};
|
||||
fs_u2s_dequeue_req(scratch.arena, &range, &path);
|
||||
fs_u2s_dequeue_req(scratch.arena, &key, &range, &path);
|
||||
|
||||
//- rjf: unpack request
|
||||
U128 key = fs_big_hash_from_string_range(path, range);
|
||||
U64 path_hash = fs_little_hash_from_string(path);
|
||||
U64 path_slot_idx = path_hash%fs_shared->slots_count;
|
||||
U64 path_stripe_idx = path_slot_idx%fs_shared->stripes_count;
|
||||
@@ -387,12 +415,12 @@ fs_detector_thread__entry_point(void *p)
|
||||
range_n != 0;
|
||||
range_n = range_n->next)
|
||||
{
|
||||
if(ins_atomic_u64_eval(&range_n->request_count) == ins_atomic_u64_eval(&range_n->completion_count) &&
|
||||
fs_u2s_enqueue_req(range_n->range, n->path, os_now_microseconds()+100000))
|
||||
HS_Key key = hs_key_make(n->root, range_n->id);
|
||||
if(ins_atomic_u64_eval(&range_n->working_count) == 0 &&
|
||||
fs_u2s_enqueue_req(key, r1u64(key.id.u128[0].u64[0], key.id.u128[0].u64[1]), n->path, os_now_microseconds()+100000))
|
||||
{
|
||||
ins_atomic_u64_eval_assign(&range_n->last_time_requested_us, os_now_microseconds());
|
||||
ins_atomic_u64_inc_eval(&range_n->request_count);
|
||||
async_push_work(fs_stream_work, .completion_counter = &range_n->completion_count);
|
||||
ins_atomic_u64_inc_eval(&range_n->working_count);
|
||||
async_push_work(fs_stream_work, .working_counter = &range_n->working_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,8 @@ typedef struct FS_RangeNode FS_RangeNode;
|
||||
struct FS_RangeNode
|
||||
{
|
||||
FS_RangeNode *next;
|
||||
Rng1U64 range;
|
||||
U64 request_count;
|
||||
U64 completion_count;
|
||||
U64 last_time_requested_us;
|
||||
HS_ID id;
|
||||
U64 working_count;
|
||||
};
|
||||
|
||||
typedef struct FS_RangeSlot FS_RangeSlot;
|
||||
@@ -33,6 +31,9 @@ struct FS_Node
|
||||
String8 path;
|
||||
FileProperties props;
|
||||
|
||||
// rjf: hash store root
|
||||
HS_Root root;
|
||||
|
||||
// rjf: sub-table of per-requested-file-range info
|
||||
U64 slots_count;
|
||||
FS_RangeSlot *slots;
|
||||
@@ -104,16 +105,15 @@ internal U64 fs_change_gen(void);
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Interaction
|
||||
|
||||
internal HS_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us);
|
||||
internal U128 fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us);
|
||||
internal U128 fs_key_from_path_range(String8 path, Rng1U64 range);
|
||||
|
||||
internal FileProperties fs_properties_from_path(String8 path);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Streaming Work
|
||||
|
||||
internal B32 fs_u2s_enqueue_req(Rng1U64 range, String8 path, U64 endt_us);
|
||||
internal void fs_u2s_dequeue_req(Arena *arena, Rng1U64 *range_out, String8 *path_out);
|
||||
internal B32 fs_u2s_enqueue_req(HS_Key key, Rng1U64 range, String8 path, U64 endt_us);
|
||||
internal void fs_u2s_dequeue_req(Arena *arena, HS_Key *key_out, Rng1U64 *range_out, String8 *path_out);
|
||||
ASYNC_WORK_DEF(fs_stream_work);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -181,7 +181,7 @@ geo_buffer_from_hash(GEO_Scope *scope, U128 hash)
|
||||
}
|
||||
|
||||
internal R_Handle
|
||||
geo_buffer_from_key(GEO_Scope *scope, U128 key)
|
||||
geo_buffer_from_key(GEO_Scope *scope, HS_Key key)
|
||||
{
|
||||
R_Handle handle = {0};
|
||||
for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1)
|
||||
|
||||
@@ -118,7 +118,7 @@ internal void geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal R_Handle geo_buffer_from_hash(GEO_Scope *scope, U128 hash);
|
||||
internal R_Handle geo_buffer_from_key(GEO_Scope *scope, U128 key);
|
||||
internal R_Handle geo_buffer_from_key(GEO_Scope *scope, HS_Key key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Transfer Threads
|
||||
|
||||
+53
-14
@@ -13,6 +13,13 @@
|
||||
# include "third_party/xxHash/xxhash.h"
|
||||
#endif
|
||||
|
||||
internal U64
|
||||
hs_little_hash_from_data(String8 data)
|
||||
{
|
||||
U64 result = XXH3_64bits(data.str, data.size);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U128
|
||||
hs_hash_from_data(String8 data)
|
||||
{
|
||||
@@ -22,6 +29,35 @@ hs_hash_from_data(String8 data)
|
||||
return u128;
|
||||
}
|
||||
|
||||
internal HS_ID
|
||||
hs_id_make(U64 u64_0, U64 u64_1)
|
||||
{
|
||||
HS_ID id;
|
||||
id.u128[0].u64[0] = u64_0;
|
||||
id.u128[0].u64[1] = u64_1;
|
||||
return id;
|
||||
}
|
||||
|
||||
internal B32
|
||||
hs_id_match(HS_ID a, HS_ID b)
|
||||
{
|
||||
B32 result = MemoryMatchStruct(&a, &b);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal HS_Key
|
||||
hs_key_make(HS_Root root, HS_ID id)
|
||||
{
|
||||
HS_Key key = {root, 0, id};
|
||||
return key;
|
||||
}
|
||||
|
||||
internal B32
|
||||
hs_key_match(HS_Key a, HS_Key b)
|
||||
{
|
||||
return (MemoryMatchStruct(&a.root, &b.root) && hs_id_match(a.id, b.id));
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
@@ -73,11 +109,11 @@ hs_init(void)
|
||||
////////////////////////////////
|
||||
//~ rjf: Root Allocation/Deallocation
|
||||
|
||||
internal U128
|
||||
internal HS_Root
|
||||
hs_root_alloc(void)
|
||||
{
|
||||
U128 root = {0};
|
||||
root.u64[1] = ins_atomic_u64_inc_eval(&hs_shared->root_id_gen);
|
||||
HS_Root root = {0};
|
||||
root.u64[0] = ins_atomic_u64_inc_eval(&hs_shared->root_id_gen);
|
||||
U64 slot_idx = root.u64[1]%hs_shared->root_slots_count;
|
||||
U64 stripe_idx = slot_idx%hs_shared->root_stripes_count;
|
||||
HS_RootSlot *slot = &hs_shared->root_slots[slot_idx];
|
||||
@@ -101,7 +137,7 @@ hs_root_alloc(void)
|
||||
}
|
||||
|
||||
internal void
|
||||
hs_root_release(U128 root)
|
||||
hs_root_release(HS_Root root)
|
||||
{
|
||||
U64 slot_idx = root.u64[1]%hs_shared->root_slots_count;
|
||||
U64 stripe_idx = slot_idx%hs_shared->root_stripes_count;
|
||||
@@ -111,7 +147,7 @@ hs_root_release(U128 root)
|
||||
{
|
||||
for(HS_RootNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->root, root))
|
||||
if(MemoryMatchStruct(&root, &n->root))
|
||||
{
|
||||
DLLRemove(slot->first, slot->last, n);
|
||||
arena_release(n->arena);
|
||||
@@ -126,9 +162,10 @@ hs_root_release(U128 root)
|
||||
//~ rjf: Cache Submission
|
||||
|
||||
internal U128
|
||||
hs_submit_data(U128 key, Arena **data_arena, String8 data)
|
||||
hs_submit_data(HS_Key key, Arena **data_arena, String8 data)
|
||||
{
|
||||
U64 key_slot_idx = key.u64[1]%hs_shared->key_slots_count;
|
||||
U64 key_hash = hs_little_hash_from_data(str8_struct(&key));
|
||||
U64 key_slot_idx = key_hash%hs_shared->key_slots_count;
|
||||
U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count;
|
||||
HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx];
|
||||
HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx];
|
||||
@@ -192,7 +229,7 @@ hs_submit_data(U128 key, Arena **data_arena, String8 data)
|
||||
HS_KeyNode *key_node = 0;
|
||||
for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->key, key))
|
||||
if(hs_key_match(n->key, key))
|
||||
{
|
||||
key_node = n;
|
||||
break;
|
||||
@@ -321,9 +358,10 @@ hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *node)
|
||||
//~ rjf: Key Closing
|
||||
|
||||
internal void
|
||||
hs_key_close(U128 key)
|
||||
hs_key_close(HS_Key key)
|
||||
{
|
||||
U64 key_slot_idx = key.u64[1]%hs_shared->key_slots_count;
|
||||
U64 key_hash = hs_little_hash_from_data(str8_struct(&key));
|
||||
U64 key_slot_idx = key_hash%hs_shared->key_slots_count;
|
||||
U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count;
|
||||
HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx];
|
||||
HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx];
|
||||
@@ -331,7 +369,7 @@ hs_key_close(U128 key)
|
||||
{
|
||||
for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->key, key))
|
||||
if(hs_key_match(n->key, key))
|
||||
{
|
||||
for(U64 history_idx = 0; history_idx < HS_KEY_HASH_HISTORY_STRONG_REF_COUNT && history_idx < n->hash_history_gen; history_idx += 1)
|
||||
{
|
||||
@@ -407,10 +445,11 @@ hs_hash_downstream_dec(U128 hash)
|
||||
//~ rjf: Cache Lookup
|
||||
|
||||
internal U128
|
||||
hs_hash_from_key(U128 key, U64 rewind_count)
|
||||
hs_hash_from_key(HS_Key key, U64 rewind_count)
|
||||
{
|
||||
U128 result = {0};
|
||||
U64 key_slot_idx = key.u64[1]%hs_shared->key_slots_count;
|
||||
U64 key_hash = hs_little_hash_from_data(str8_struct(&key));
|
||||
U64 key_slot_idx = key_hash%hs_shared->key_slots_count;
|
||||
U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count;
|
||||
HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx];
|
||||
HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx];
|
||||
@@ -418,7 +457,7 @@ hs_hash_from_key(U128 key, U64 rewind_count)
|
||||
{
|
||||
for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->key, key) && n->hash_history_gen > 0 && n->hash_history_gen-1 >= rewind_count)
|
||||
if(hs_key_match(n->key, key) && n->hash_history_gen > 0 && n->hash_history_gen-1 >= rewind_count)
|
||||
{
|
||||
result = n->hash_history[(n->hash_history_gen-1-rewind_count)%ArrayCount(n->hash_history)];
|
||||
break;
|
||||
|
||||
+43
-15
@@ -40,23 +40,46 @@
|
||||
// submit that data to the hash store, correllating with the root and key
|
||||
// combo.
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Key Types
|
||||
|
||||
typedef struct HS_Root HS_Root;
|
||||
struct HS_Root
|
||||
{
|
||||
U64 u64[1];
|
||||
};
|
||||
|
||||
typedef struct HS_ID HS_ID;
|
||||
struct HS_ID
|
||||
{
|
||||
U128 u128[1];
|
||||
};
|
||||
|
||||
typedef struct HS_Key HS_Key;
|
||||
struct HS_Key
|
||||
{
|
||||
HS_Root root;
|
||||
U64 _padding_;
|
||||
HS_ID id;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Types
|
||||
|
||||
typedef struct HS_RootKeyChunkNode HS_RootKeyChunkNode;
|
||||
struct HS_RootKeyChunkNode
|
||||
typedef struct HS_RootIDChunkNode HS_RootIDChunkNode;
|
||||
struct HS_RootIDChunkNode
|
||||
{
|
||||
HS_RootKeyChunkNode *next;
|
||||
HS_RootIDChunkNode *next;
|
||||
U128 *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct HS_RootKeyChunkList HS_RootKeyChunkList;
|
||||
struct HS_RootKeyChunkList
|
||||
typedef struct HS_RootIDChunkList HS_RootIDChunkList;
|
||||
struct HS_RootIDChunkList
|
||||
{
|
||||
HS_RootKeyChunkNode *first;
|
||||
HS_RootKeyChunkNode *last;
|
||||
HS_RootIDChunkNode *first;
|
||||
HS_RootIDChunkNode *last;
|
||||
U64 chunk_count;
|
||||
U64 total_count;
|
||||
};
|
||||
@@ -67,8 +90,8 @@ struct HS_RootNode
|
||||
HS_RootNode *next;
|
||||
HS_RootNode *prev;
|
||||
Arena *arena;
|
||||
U128 root;
|
||||
HS_RootKeyChunkList keys;
|
||||
HS_Root root;
|
||||
HS_RootIDChunkList ids;
|
||||
};
|
||||
|
||||
typedef struct HS_RootSlot HS_RootSlot;
|
||||
@@ -86,7 +109,7 @@ struct HS_KeyNode
|
||||
{
|
||||
HS_KeyNode *next;
|
||||
HS_KeyNode *prev;
|
||||
U128 key;
|
||||
HS_Key key;
|
||||
U128 hash_history[HS_KEY_HASH_HISTORY_COUNT];
|
||||
U64 hash_history_gen;
|
||||
};
|
||||
@@ -197,7 +220,12 @@ global HS_Shared *hs_shared = 0;
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U64 hs_little_hash_from_data(String8 data);
|
||||
internal U128 hs_hash_from_data(String8 data);
|
||||
internal HS_ID hs_id_make(U64 u64_0, U64 u64_1);
|
||||
internal B32 hs_id_match(HS_ID a, HS_ID b);
|
||||
internal HS_Key hs_key_make(HS_Root root, HS_ID id);
|
||||
internal B32 hs_key_match(HS_Key a, HS_Key b);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
@@ -207,13 +235,13 @@ internal void hs_init(void);
|
||||
////////////////////////////////
|
||||
//~ rjf: Root Allocation/Deallocation
|
||||
|
||||
internal U128 hs_root_alloc(void);
|
||||
internal void hs_root_release(U128 root);
|
||||
internal HS_Root hs_root_alloc(void);
|
||||
internal void hs_root_release(HS_Root root);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Submission
|
||||
|
||||
internal U128 hs_submit_data(U128 key, Arena **data_arena, String8 data);
|
||||
internal U128 hs_submit_data(HS_Key key, Arena **data_arena, String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access
|
||||
@@ -225,7 +253,7 @@ internal void hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *no
|
||||
////////////////////////////////
|
||||
//~ rjf: Key Closing
|
||||
|
||||
internal void hs_key_close(U128 key);
|
||||
internal void hs_key_close(HS_Key key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Downstream Accesses
|
||||
@@ -236,7 +264,7 @@ internal void hs_hash_downstream_dec(U128 hash);
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal U128 hs_hash_from_key(U128 key, U64 rewind_count);
|
||||
internal U128 hs_hash_from_key(HS_Key key, U64 rewind_count);
|
||||
internal String8 hs_data_from_hash(HS_Scope *scope, U128 hash);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -38,9 +38,10 @@ mtx_init(void)
|
||||
//~ rjf: Buffer Operations
|
||||
|
||||
internal void
|
||||
mtx_push_op(U128 buffer_key, MTX_Op op)
|
||||
mtx_push_op(HS_Key buffer_key, MTX_Op op)
|
||||
{
|
||||
MTX_MutThread *thread = &mtx_shared->mut_threads[buffer_key.u64[1]%mtx_shared->mut_threads_count];
|
||||
U64 hash = hs_little_hash_from_data(str8_struct(&buffer_key));
|
||||
MTX_MutThread *thread = &mtx_shared->mut_threads[hash%mtx_shared->mut_threads_count];
|
||||
mtx_enqueue_op(thread, buffer_key, op);
|
||||
}
|
||||
|
||||
@@ -48,7 +49,7 @@ mtx_push_op(U128 buffer_key, MTX_Op op)
|
||||
//~ rjf: Mutation Threads
|
||||
|
||||
internal void
|
||||
mtx_enqueue_op(MTX_MutThread *thread, U128 buffer_key, MTX_Op op)
|
||||
mtx_enqueue_op(MTX_MutThread *thread, HS_Key buffer_key, MTX_Op op)
|
||||
{
|
||||
// TODO(rjf): if op.replace is too big, need to split into multiple edits
|
||||
OS_MutexScope(thread->mutex) for(;;)
|
||||
@@ -70,7 +71,7 @@ mtx_enqueue_op(MTX_MutThread *thread, U128 buffer_key, MTX_Op op)
|
||||
}
|
||||
|
||||
internal void
|
||||
mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, U128 *buffer_key_out, MTX_Op *op_out)
|
||||
mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, HS_Key *buffer_key_out, MTX_Op *op_out)
|
||||
{
|
||||
OS_MutexScope(thread->mutex) for(;;)
|
||||
{
|
||||
@@ -100,7 +101,7 @@ mtx_mut_thread__entry_point(void *p)
|
||||
HS_Scope *hs_scope = hs_scope_open();
|
||||
|
||||
//- rjf: get next op
|
||||
U128 buffer_key = {0};
|
||||
HS_Key buffer_key = {0};
|
||||
MTX_Op op = {0};
|
||||
mtx_dequeue_op(scratch.arena, mut_thread, &buffer_key, &op);
|
||||
|
||||
|
||||
@@ -84,13 +84,13 @@ internal void mtx_init(void);
|
||||
////////////////////////////////
|
||||
//~ rjf: Buffer Operations
|
||||
|
||||
internal void mtx_push_op(U128 buffer_key, MTX_Op op);
|
||||
internal void mtx_push_op(HS_Key buffer_key, MTX_Op op);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Mutation Threads
|
||||
|
||||
internal void mtx_enqueue_op(MTX_MutThread *thread, U128 buffer_key, MTX_Op op);
|
||||
internal void mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, U128 *buffer_key_out, MTX_Op *op_out);
|
||||
internal void mtx_enqueue_op(MTX_MutThread *thread, HS_Key buffer_key, MTX_Op op);
|
||||
internal void mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, HS_Key *buffer_key_out, MTX_Op *op_out);
|
||||
internal void mtx_mut_thread__entry_point(void *p);
|
||||
|
||||
#endif // MUTABLE_TEXT_H
|
||||
|
||||
@@ -456,7 +456,7 @@ Rng1U64 rd_reg_slot_range_table[44] =
|
||||
{OffsetOf(RD_Regs, file_path), OffsetOf(RD_Regs, file_path) + sizeof(String8)},
|
||||
{OffsetOf(RD_Regs, cursor), OffsetOf(RD_Regs, cursor) + sizeof(TxtPt)},
|
||||
{OffsetOf(RD_Regs, mark), OffsetOf(RD_Regs, mark) + sizeof(TxtPt)},
|
||||
{OffsetOf(RD_Regs, text_key), OffsetOf(RD_Regs, text_key) + sizeof(U128)},
|
||||
{OffsetOf(RD_Regs, text_key), OffsetOf(RD_Regs, text_key) + sizeof(HS_Key)},
|
||||
{OffsetOf(RD_Regs, lang_kind), OffsetOf(RD_Regs, lang_kind) + sizeof(TXT_LangKind)},
|
||||
{OffsetOf(RD_Regs, lines), OffsetOf(RD_Regs, lines) + sizeof(D_LineList)},
|
||||
{OffsetOf(RD_Regs, dbgi_key), OffsetOf(RD_Regs, dbgi_key) + sizeof(DI_Key)},
|
||||
|
||||
@@ -450,7 +450,7 @@ U64 inline_depth;
|
||||
String8 file_path;
|
||||
TxtPt cursor;
|
||||
TxtPt mark;
|
||||
U128 text_key;
|
||||
HS_Key text_key;
|
||||
TXT_LangKind lang_kind;
|
||||
D_LineList lines;
|
||||
DI_Key dbgi_key;
|
||||
|
||||
@@ -712,7 +712,7 @@ RD_RegTable:
|
||||
{String8 file_path FilePath }
|
||||
{TxtPt cursor Cursor }
|
||||
{TxtPt mark Mark }
|
||||
{U128 text_key TextKey }
|
||||
{HS_Key text_key TextKey }
|
||||
{TXT_LangKind lang_kind LangKind }
|
||||
{D_LineList lines Lines }
|
||||
{DI_Key dbgi_key DbgiKey }
|
||||
|
||||
+21
-14
@@ -1747,7 +1747,9 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range)
|
||||
//- rjf: reads from hash store key
|
||||
case E_SpaceKind_HashStoreKey:
|
||||
{
|
||||
U128 key = space.u128;
|
||||
HS_Root root = {space.u64_0};
|
||||
HS_ID id = {space.u128};
|
||||
HS_Key key = hs_key_make(root, id);
|
||||
U128 hash = hs_hash_from_key(key, 0);
|
||||
HS_Scope *scope = hs_scope_open();
|
||||
{
|
||||
@@ -1778,7 +1780,7 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range)
|
||||
containing_range.max -= containing_range.max%chunk_size;
|
||||
|
||||
// rjf: map to hash
|
||||
U128 key = fs_key_from_path_range(file_path, containing_range);
|
||||
HS_Key key = fs_key_from_path_range(file_path, containing_range, 0);
|
||||
U128 hash = hs_hash_from_key(key, 0);
|
||||
|
||||
// rjf: look up from hash store
|
||||
@@ -2136,28 +2138,30 @@ rd_eval_space_write(void *u, E_Space space, void *in, Rng1U64 range)
|
||||
|
||||
//- rjf: asynchronous streamed reads -> hashes from spaces
|
||||
|
||||
internal U128
|
||||
internal HS_Key
|
||||
rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated)
|
||||
{
|
||||
U128 result = {0};
|
||||
HS_Key result = {0};
|
||||
switch(space.kind)
|
||||
{
|
||||
case E_SpaceKind_HashStoreKey:
|
||||
{
|
||||
result = space.u128;
|
||||
HS_Root root = {space.u64_0};
|
||||
HS_ID id = {space.u128};
|
||||
result = hs_key_make(root, id);
|
||||
}break;
|
||||
case E_SpaceKind_File:
|
||||
{
|
||||
U64 file_path_string_id = space.u64_0;
|
||||
String8 file_path = e_string_from_id(file_path_string_id);
|
||||
result = fs_key_from_path_range(file_path, range);
|
||||
result = fs_key_from_path_range(file_path, range, 0);
|
||||
}break;
|
||||
case RD_EvalSpaceKind_CtrlEntity:
|
||||
{
|
||||
CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(space);
|
||||
if(entity->kind == CTRL_EntityKind_Process)
|
||||
{
|
||||
result = ctrl_hash_store_key_from_process_vaddr_range(entity->handle, range, zero_terminated);
|
||||
result = ctrl_key_from_process_vaddr_range(entity->handle, range, zero_terminated, 0, 0);
|
||||
}
|
||||
}break;
|
||||
}
|
||||
@@ -2174,7 +2178,9 @@ rd_whole_range_from_eval_space(E_Space space)
|
||||
{
|
||||
case E_SpaceKind_HashStoreKey:
|
||||
{
|
||||
U128 key = space.u128;
|
||||
HS_Root root = {space.u64_0};
|
||||
HS_ID id = {space.u128};
|
||||
HS_Key key = hs_key_make(root, id);
|
||||
U128 hash = hs_hash_from_key(key, 0);
|
||||
HS_Scope *hs_scope = hs_scope_open();
|
||||
{
|
||||
@@ -2867,7 +2873,7 @@ rd_view_ui(Rng2F32 rect)
|
||||
// rjf: unpack view's target expression & hash
|
||||
E_Eval eval = e_eval_from_string(expr_string);
|
||||
Rng1U64 range = r1u64(0, 1024);
|
||||
U128 key = rd_key_from_eval_space_range(eval.space, range, 0);
|
||||
HS_Key key = rd_key_from_eval_space_range(eval.space, range, 0);
|
||||
U128 hash = hs_hash_from_key(key, 0);
|
||||
|
||||
// rjf: determine if hash's blob is ready, and which viewer to use
|
||||
@@ -6519,7 +6525,7 @@ rd_window_frame(void)
|
||||
if(ws->dev_menu_is_open) RD_Font(RD_FontSlot_Code)
|
||||
{
|
||||
ui_set_next_flags(UI_BoxFlag_ViewScrollY|UI_BoxFlag_AllowOverflowY|UI_BoxFlag_ViewClamp);
|
||||
UI_PaneF(r2f32p(30, 30, 30+ui_top_font_size()*100, ui_top_font_size()*150), "###dev_ctx_menu")
|
||||
UI_PaneF(r2f32p(30, 30, 30+ui_top_font_size()*100, ui_top_font_size()*60), "###dev_ctx_menu")
|
||||
{
|
||||
//- rjf: capture
|
||||
if(!ProfIsCapturing() && ui_clicked(ui_buttonf("Begin Profiler Capture###prof_cap")))
|
||||
@@ -6580,7 +6586,7 @@ rd_window_frame(void)
|
||||
ui_labelf("mark: (L:%I64d, C:%I64d)", regs->mark.line, regs->mark.column);
|
||||
ui_labelf("unwind_count: %I64u", regs->unwind_count);
|
||||
ui_labelf("inline_depth: %I64u", regs->inline_depth);
|
||||
ui_labelf("text_key: [0x%I64x, 0x%I64x]", regs->text_key.u64[0], regs->text_key.u64[1]);
|
||||
ui_labelf("text_key: [0x%I64x / 0x%I64x:0x%I64x]", regs->text_key.root.u64[0], regs->text_key.id.u128[0].u64[0], regs->text_key.id.u128[0].u64[1]);
|
||||
ui_labelf("lang_kind: '%S'", txt_extension_from_lang_kind(regs->lang_kind));
|
||||
ui_labelf("vaddr_range: [0x%I64x, 0x%I64x)", regs->vaddr_range.min, regs->vaddr_range.max);
|
||||
ui_labelf("voff_range: [0x%I64x, 0x%I64x)", regs->voff_range.min, regs->voff_range.max);
|
||||
@@ -12174,12 +12180,13 @@ rd_frame(void)
|
||||
//- rjf: add macro for output log
|
||||
{
|
||||
HS_Scope *hs_scope = hs_scope_open();
|
||||
U128 key = d_state->output_log_key;
|
||||
HS_Key key = d_state->output_log_key;
|
||||
U128 hash = hs_hash_from_key(key, 0);
|
||||
String8 data = hs_data_from_hash(hs_scope, hash);
|
||||
E_Space space = e_space_make(E_SpaceKind_HashStoreKey);
|
||||
space.u64_0 = key.root.u64[0];
|
||||
space.u128 = key.id.u128[0];
|
||||
E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0));
|
||||
space.u128 = key;
|
||||
expr->space = space;
|
||||
expr->mode = E_Mode_Offset;
|
||||
expr->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), data.size, 0);
|
||||
@@ -15479,7 +15486,7 @@ rd_frame(void)
|
||||
HS_Scope *hs_scope = hs_scope_open();
|
||||
TXT_Scope *txt_scope = txt_scope_open();
|
||||
RD_Regs *regs = rd_regs();
|
||||
U128 text_key = regs->text_key;
|
||||
HS_Key text_key = regs->text_key;
|
||||
TXT_LangKind lang_kind = regs->lang_kind;
|
||||
TxtRng range = txt_rng(regs->cursor, regs->mark);
|
||||
U128 hash = {0};
|
||||
|
||||
@@ -890,7 +890,7 @@ internal B32 rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range
|
||||
internal B32 rd_eval_space_write(void *u, E_Space space, void *in, Rng1U64 range);
|
||||
|
||||
//- rjf: asynchronous streamed reads -> hashes from spaces
|
||||
internal U128 rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated);
|
||||
internal HS_Key rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated);
|
||||
|
||||
//- rjf: space -> entire range
|
||||
internal Rng1U64 rd_whole_range_from_eval_space(E_Space space);
|
||||
|
||||
@@ -2381,7 +2381,7 @@ RD_VIEW_UI_FUNCTION_DEF(disasm)
|
||||
syntax = DASM_Syntax_ATT;
|
||||
}
|
||||
}
|
||||
U128 dasm_key = rd_key_from_eval_space_range(space, range, 0);
|
||||
HS_Key dasm_key = rd_key_from_eval_space_range(space, range, 0);
|
||||
U128 dasm_data_hash = {0};
|
||||
DASM_Params dasm_params = {0};
|
||||
{
|
||||
@@ -3572,7 +3572,7 @@ RD_VIEW_UI_FUNCTION_DEF(bitmap)
|
||||
//////////////////////////////
|
||||
//- rjf: map expression artifacts -> texture
|
||||
//
|
||||
U128 texture_key = rd_key_from_eval_space_range(eval.space, offset_range, 0);
|
||||
HS_Key texture_key = rd_key_from_eval_space_range(eval.space, offset_range, 0);
|
||||
TEX_Topology topology = tex_topology_make(dim, fmt);
|
||||
U128 data_hash = {0};
|
||||
R_Handle texture = tex_texture_from_key_topology(tex_scope, texture_key, topology, &data_hash);
|
||||
@@ -4058,8 +4058,8 @@ RD_VIEW_UI_FUNCTION_DEF(geo3d)
|
||||
U64 base_offset = e_base_offset_from_eval(eval);
|
||||
Rng1U64 idxs_range = r1u64(base_offset, base_offset+count*sizeof(U32));
|
||||
Rng1U64 vtxs_range = r1u64(vtx_base_off, vtx_base_off+vtx_size);
|
||||
U128 idxs_key = rd_key_from_eval_space_range(eval.space, idxs_range, 0);
|
||||
U128 vtxs_key = rd_key_from_eval_space_range(eval.space, vtxs_range, 0);
|
||||
HS_Key idxs_key = rd_key_from_eval_space_range(eval.space, idxs_range, 0);
|
||||
HS_Key vtxs_key = rd_key_from_eval_space_range(eval.space, vtxs_range, 0);
|
||||
R_Handle idxs_buffer = geo_buffer_from_key(geo_scope, idxs_key);
|
||||
R_Handle vtxs_buffer = geo_buffer_from_key(geo_scope, vtxs_key);
|
||||
|
||||
|
||||
@@ -1771,7 +1771,7 @@ txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang)
|
||||
}
|
||||
|
||||
internal TXT_TextInfo
|
||||
txt_text_info_from_key_lang(TXT_Scope *scope, U128 key, TXT_LangKind lang, U128 *hash_out)
|
||||
txt_text_info_from_key_lang(TXT_Scope *scope, HS_Key key, TXT_LangKind lang, U128 *hash_out)
|
||||
{
|
||||
TXT_TextInfo result = {0};
|
||||
for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1)
|
||||
|
||||
@@ -274,7 +274,7 @@ internal void txt_scope_touch_node__stripe_r_guarded(TXT_Scope *scope, TXT_Node
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal TXT_TextInfo txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang);
|
||||
internal TXT_TextInfo txt_text_info_from_key_lang(TXT_Scope *scope, U128 key, TXT_LangKind lang, U128 *hash_out);
|
||||
internal TXT_TextInfo txt_text_info_from_key_lang(TXT_Scope *scope, HS_Key key, TXT_LangKind lang, U128 *hash_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text Info Extractor Helpers
|
||||
|
||||
@@ -196,7 +196,7 @@ tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topolog
|
||||
}
|
||||
|
||||
internal R_Handle
|
||||
tex_texture_from_key_topology(TEX_Scope *scope, U128 key, TEX_Topology topology, U128 *hash_out)
|
||||
tex_texture_from_key_topology(TEX_Scope *scope, HS_Key key, TEX_Topology topology, U128 *hash_out)
|
||||
{
|
||||
R_Handle handle = {0};
|
||||
for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1)
|
||||
|
||||
@@ -135,7 +135,7 @@ internal void tex_scope_touch_node__stripe_r_guarded(TEX_Scope *scope, TEX_Node
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
internal R_Handle tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topology);
|
||||
internal R_Handle tex_texture_from_key_topology(TEX_Scope *scope, U128 key, TEX_Topology topology, U128 *hash_out);
|
||||
internal R_Handle tex_texture_from_key_topology(TEX_Scope *scope, HS_Key key, TEX_Topology topology, U128 *hash_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Transfer Threads
|
||||
|
||||
Reference in New Issue
Block a user