mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
checkpoint in new debug info layer: 16-byte key (set up to use GUIDs or otherwise unique keys at the base), better control over oversubscribing cores for conversion, better prioritization of conversions
This commit is contained in:
@@ -71,6 +71,9 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
|
||||
#if defined(DBG_INFO_H) && !defined(DI_INIT_MANUAL)
|
||||
di_init();
|
||||
#endif
|
||||
#if defined(DBG_INFO2_H) && !defined(DI_INIT_MANUAL)
|
||||
di2_init();
|
||||
#endif
|
||||
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
|
||||
dmn_init();
|
||||
#endif
|
||||
@@ -205,6 +208,9 @@ async_thread_entry_point(void *params)
|
||||
#endif
|
||||
#if defined(FILE_STREAM_H)
|
||||
fs_async_tick();
|
||||
#endif
|
||||
#if defined(DBG_INFO2_H)
|
||||
di2_async_tick();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1040,7 +1040,7 @@ ASYNC_WORK_DEF(di_parse_work)
|
||||
U64 start_wait_t = os_now_microseconds();
|
||||
for(;;)
|
||||
{
|
||||
B32 wait_done = os_process_join(process, os_now_microseconds()+1000);
|
||||
B32 wait_done = os_process_join(process, os_now_microseconds()+1000, 0);
|
||||
if(wait_done)
|
||||
{
|
||||
rdi_file_is_up_to_date = 1;
|
||||
|
||||
@@ -0,0 +1,528 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal DI2_Key
|
||||
di2_key_zero(void)
|
||||
{
|
||||
DI2_Key key = {0};
|
||||
return key;
|
||||
}
|
||||
|
||||
internal B32
|
||||
di2_key_match(DI2_Key a, DI2_Key b)
|
||||
{
|
||||
B32 result = MemoryMatchStruct(&a, &b);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void
|
||||
di2_init(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
di2_shared = push_array(arena, DI2_Shared, 1);
|
||||
di2_shared->arena = arena;
|
||||
di2_shared->key_slots_count = 4096;
|
||||
di2_shared->key_slots = push_array(arena, DI2_KeySlot, di2_shared->key_slots_count);
|
||||
di2_shared->key_stripes = stripe_array_alloc(arena);
|
||||
di2_shared->key_path_slots_count = 4096;
|
||||
di2_shared->key_path_slots = push_array(arena, DI2_KeySlot, di2_shared->key_path_slots_count);
|
||||
di2_shared->key_path_stripes = stripe_array_alloc(arena);
|
||||
di2_shared->slots_count = 4096;
|
||||
di2_shared->slots = push_array(arena, DI2_Slot, di2_shared->slots_count);
|
||||
di2_shared->stripes = stripe_array_alloc(arena);
|
||||
for EachElement(idx, di2_shared->req_batches)
|
||||
{
|
||||
di2_shared->req_batches[idx].mutex = mutex_alloc();
|
||||
di2_shared->req_batches[idx].arena = arena_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Path * Timestamp Cache Submission & Lookup
|
||||
|
||||
internal DI2_Key
|
||||
di2_key_from_path_timestamp(String8 path, U64 min_timestamp)
|
||||
{
|
||||
//- rjf: unpack key
|
||||
U64 hash = u64_hash_from_str8(path);
|
||||
U64 slot_idx = hash%di2_shared->key_slots_count;
|
||||
DI2_KeySlot *slot = &di2_shared->key_slots[slot_idx];
|
||||
Stripe *stripe = stripe_from_slot_idx(&di2_shared->key_stripes, slot_idx);
|
||||
|
||||
//- rjf: look up key, create if needed
|
||||
DI2_Key key = {0};
|
||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
||||
{
|
||||
// rjf: look up node, with this write mode, to find existing key computation
|
||||
B32 found = 0;
|
||||
RWMutexScope(stripe->rw_mutex, write_mode)
|
||||
{
|
||||
DI2_KeyNode *node = 0;
|
||||
for(DI2_KeyNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->path, path, 0) && min_timestamp <= n->min_timestamp)
|
||||
{
|
||||
found = 1;
|
||||
node = n;
|
||||
key = node->key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found && write_mode)
|
||||
{
|
||||
node = stripe->free;
|
||||
if(node)
|
||||
{
|
||||
stripe->free = node->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = push_array(stripe->arena, DI2_KeyNode, 1);
|
||||
}
|
||||
node->path = str8_copy(stripe->arena, path);
|
||||
node->min_timestamp = min_timestamp;
|
||||
node->key = key;
|
||||
DLLPushBack(slot->first, slot->last, node);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: found the key? abort
|
||||
if(found)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: didn't find the key on our read lookup? compute the key before entering
|
||||
// write mode
|
||||
if(!found && !write_mode)
|
||||
{
|
||||
B32 made_key = 0;
|
||||
|
||||
//- rjf: try to make key from file's contents
|
||||
if(!made_key)
|
||||
{
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path);
|
||||
FileProperties props = os_properties_from_file(file);
|
||||
if(min_timestamp <= props.modified)
|
||||
{
|
||||
//- rjf: PDB magic => use GUID for key
|
||||
if(!made_key)
|
||||
{
|
||||
B32 is_pdb = 0;
|
||||
if(!is_pdb)
|
||||
{
|
||||
U8 msf20_magic_maybe[sizeof(msf_msf20_magic)] = {0};
|
||||
os_file_read(file, r1u64(0, sizeof(msf20_magic_maybe)), msf20_magic_maybe);
|
||||
if(MemoryMatch(msf20_magic_maybe, msf_msf20_magic, sizeof(msf20_magic_maybe)))
|
||||
{
|
||||
is_pdb = 1;
|
||||
}
|
||||
}
|
||||
if(!is_pdb)
|
||||
{
|
||||
U8 msf70_magic_maybe[sizeof(msf_msf70_magic)] = {0};
|
||||
os_file_read(file, r1u64(0, sizeof(msf70_magic_maybe)), msf70_magic_maybe);
|
||||
if(MemoryMatch(msf70_magic_maybe, msf_msf70_magic, sizeof(msf70_magic_maybe)))
|
||||
{
|
||||
is_pdb = 1;
|
||||
}
|
||||
}
|
||||
if(is_pdb)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
}
|
||||
}
|
||||
os_file_close(file);
|
||||
}
|
||||
|
||||
//- rjf: fallback: hash from path/timestamp
|
||||
if(!made_key)
|
||||
{
|
||||
made_key = 1;
|
||||
U128 hash = u128_hash_from_seed_str8(min_timestamp, path);
|
||||
MemoryCopy(&key, &hash, Min(sizeof(hash), sizeof(key)));
|
||||
}
|
||||
|
||||
//- rjf: made key -> store in (key -> path/timestamp) table
|
||||
if(made_key)
|
||||
{
|
||||
U64 key_hash = u64_hash_from_str8(str8_struct(&key));
|
||||
U64 key_slot_idx = key_hash%di2_shared->key_path_slots_count;
|
||||
DI2_KeySlot *key_slot = &di2_shared->key_path_slots[key_slot_idx];
|
||||
Stripe *key_stripe = stripe_from_slot_idx(&di2_shared->key_path_stripes, key_slot_idx);
|
||||
RWMutexScope(key_stripe->rw_mutex, 1)
|
||||
{
|
||||
DI2_KeyNode *node = 0;
|
||||
for EachNode(n, DI2_KeyNode, key_slot->first)
|
||||
{
|
||||
if(di2_key_match(n->key, key))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node == 0)
|
||||
{
|
||||
node = key_stripe->free;
|
||||
if(node != 0)
|
||||
{
|
||||
key_stripe->free = node->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = push_array(key_stripe->arena, DI2_KeyNode, 1);
|
||||
}
|
||||
DLLPushBack(key_slot->first, key_slot->last, node);
|
||||
node->path = str8_copy(key_stripe->arena, path);
|
||||
node->min_timestamp = min_timestamp;
|
||||
node->key = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Opening / Closing
|
||||
|
||||
internal void
|
||||
di2_open(DI2_Key key)
|
||||
{
|
||||
DI2_RequestBatch *batch = &di2_shared->req_batches[1];
|
||||
MutexScope(batch->mutex)
|
||||
{
|
||||
DI2_RequestNode *n = push_array(batch->arena, DI2_RequestNode, 1);
|
||||
SLLQueuePush(batch->first, batch->last, n);
|
||||
n->v.key = key;
|
||||
batch->count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
di2_close(DI2_Key key)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Lookups
|
||||
|
||||
internal RDI_Parsed *
|
||||
di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us)
|
||||
{
|
||||
RDI_Parsed *rdi = &rdi_parsed_nil;
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
return rdi;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Asynchronous Tick
|
||||
|
||||
internal void
|
||||
di2_async_tick(void)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: do single-lane update: pop requests, update tasks, gather RDI paths to parse wide
|
||||
//
|
||||
typedef struct ParseTask ParseTask;
|
||||
struct ParseTask
|
||||
{
|
||||
DI2_Key key;
|
||||
String8 rdi_path;
|
||||
};
|
||||
ParseTask *parse_tasks = 0;
|
||||
U64 parse_tasks_count = 0;
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
typedef struct ParseTaskNode ParseTaskNode;
|
||||
struct ParseTaskNode
|
||||
{
|
||||
ParseTaskNode *next;
|
||||
ParseTask v;
|
||||
};
|
||||
ParseTaskNode *first_parse_task = 0;
|
||||
ParseTaskNode *last_parse_task = 0;
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: pop requests, high priority first, and generate conversion tasks for them
|
||||
//
|
||||
for EachElement(idx, di2_shared->req_batches)
|
||||
{
|
||||
DI2_RequestBatch *b = &di2_shared->req_batches[idx];
|
||||
MutexScope(b->mutex)
|
||||
{
|
||||
for EachNode(n, DI2_RequestNode, b->first)
|
||||
{
|
||||
DI2_LoadTask *t = di2_shared->free_load_task;
|
||||
if(t)
|
||||
{
|
||||
SLLStackPop(di2_shared->free_load_task);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = push_array_no_zero(di2_shared->arena, DI2_LoadTask, 1);
|
||||
}
|
||||
MemoryZeroStruct(t);
|
||||
DLLPushBack(di2_shared->first_load_task, di2_shared->last_load_task, t);
|
||||
t->key = n->v.key;
|
||||
}
|
||||
arena_clear(b->arena);
|
||||
b->first = b->last = 0;
|
||||
b->count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: update tasks: configure, launch if we can, & retire if we can
|
||||
//
|
||||
for(DI2_LoadTask *t = di2_shared->first_load_task, *next = 0; t != 0; t = next)
|
||||
{
|
||||
next = t->next;
|
||||
|
||||
//- rjf: unpack key
|
||||
DI2_Key key = t->key;
|
||||
U64 key_hash = u64_hash_from_str8(str8_struct(&key));
|
||||
U64 key_slot_idx = key_hash%di2_shared->key_slots_count;
|
||||
DI2_KeySlot *key_slot = &di2_shared->key_slots[key_slot_idx];
|
||||
Stripe *key_stripe = stripe_from_slot_idx(&di2_shared->key_stripes, key_slot_idx);
|
||||
|
||||
//- rjf: get key's O.G. path
|
||||
String8 og_path = {0};
|
||||
U64 og_min_timestamp = 0;
|
||||
RWMutexScope(key_stripe->rw_mutex, 0)
|
||||
{
|
||||
for(DI2_KeyNode *n = key_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(di2_key_match(n->key, key))
|
||||
{
|
||||
og_path = str8_copy(scratch.arena, n->path);
|
||||
og_min_timestamp = n->min_timestamp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: analyze O.G. debug info
|
||||
if(!t->og_analyzed)
|
||||
{
|
||||
t->og_analyzed = 1;
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, og_path);
|
||||
FileProperties props = os_properties_from_file(file);
|
||||
t->og_size = props.size;
|
||||
U64 rdi_magic_maybe = 0;
|
||||
if(os_file_read_struct(file, 0, &rdi_magic_maybe) == 8 &&
|
||||
rdi_magic_maybe == RDI_MAGIC_CONSTANT)
|
||||
{
|
||||
t->og_is_rdi = 1;
|
||||
}
|
||||
os_file_close(file);
|
||||
}
|
||||
U64 og_size = t->og_size;
|
||||
B32 og_is_rdi = t->og_is_rdi;
|
||||
|
||||
//- rjf: compute key's RDI path
|
||||
String8 rdi_path = {0};
|
||||
{
|
||||
if(og_is_rdi)
|
||||
{
|
||||
rdi_path = og_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
rdi_path = str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path));
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: determine if RDI is stale
|
||||
if(!t->rdi_analyzed)
|
||||
{
|
||||
t->rdi_analyzed = 1;
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, rdi_path);
|
||||
FileProperties props = os_properties_from_file(file);
|
||||
if(props.modified < og_min_timestamp)
|
||||
{
|
||||
t->rdi_is_stale = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
t->rdi_is_stale = 1;
|
||||
RDI_Header header = {0};
|
||||
if(os_file_read_struct(file, 0, &header) == sizeof(header))
|
||||
{
|
||||
t->rdi_is_stale = (header.encoding_version != RDI_ENCODING_VERSION);
|
||||
}
|
||||
}
|
||||
os_file_close(file);
|
||||
}
|
||||
B32 rdi_is_stale = t->rdi_is_stale;
|
||||
|
||||
//- rjf: calculate thread counts for conversion processes
|
||||
if(!og_is_rdi && rdi_is_stale && t->thread_count == 0)
|
||||
{
|
||||
U64 thread_count = 1;
|
||||
U64 max_thread_count = os_get_system_info()->logical_processor_count;
|
||||
{
|
||||
if(0){}
|
||||
else if(og_size <= MB(4)) {thread_count = 1;}
|
||||
else if(og_size <= MB(256)) {thread_count = max_thread_count/4;}
|
||||
else if(og_size <= MB(512)) {thread_count = max_thread_count/2;}
|
||||
else {thread_count = max_thread_count;}
|
||||
}
|
||||
thread_count = Max(1, thread_count);
|
||||
t->thread_count = thread_count;
|
||||
}
|
||||
|
||||
//- rjf: launch conversion processes
|
||||
if(!og_is_rdi && rdi_is_stale && t->thread_count != 0 && t->status != DI2_LoadTaskStatus_Active)
|
||||
{
|
||||
B32 should_compress = 0;
|
||||
OS_ProcessLaunchParams params = {0};
|
||||
params.path = os_get_process_info()->binary_path;
|
||||
params.inherit_env = 1;
|
||||
params.consoleless = 1;
|
||||
str8_list_pushf(scratch.arena, ¶ms.cmd_line, "raddbg");
|
||||
str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--bin");
|
||||
str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--quiet");
|
||||
if(should_compress)
|
||||
{
|
||||
str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--compress");
|
||||
}
|
||||
// str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--capture");
|
||||
str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--rdi");
|
||||
str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--out:%S", rdi_path);
|
||||
str8_list_pushf(scratch.arena, ¶ms.cmd_line, "--thread_count:%I64u", t->thread_count);
|
||||
str8_list_pushf(scratch.arena, ¶ms.cmd_line, "%S", og_path);
|
||||
t->process = os_process_launch(¶ms);
|
||||
t->status = DI2_LoadTaskStatus_Active;
|
||||
di2_shared->conversion_process_count += 1;
|
||||
di2_shared->conversion_thread_count += t->thread_count;
|
||||
}
|
||||
|
||||
//- rjf: if active & process has completed, mark as done
|
||||
{
|
||||
U64 exit_code = 0;
|
||||
if(t->status == DI2_LoadTaskStatus_Active && os_process_join(t->process, 0, &exit_code))
|
||||
{
|
||||
t->status = DI2_LoadTaskStatus_Done;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: if the RDI for this task is not stale, then we're already done - mark this
|
||||
// task as done & prepped for storing into the cache
|
||||
if(!rdi_is_stale)
|
||||
{
|
||||
t->status = DI2_LoadTaskStatus_Done;
|
||||
}
|
||||
|
||||
//- rjf: if task is done, retire & recycle task; gather path to load
|
||||
if(t->status == DI2_LoadTaskStatus_Done)
|
||||
{
|
||||
DLLRemove(di2_shared->first_load_task, di2_shared->last_load_task, t);
|
||||
SLLStackPush(di2_shared->free_load_task, t);
|
||||
di2_shared->conversion_process_count -= 1;
|
||||
di2_shared->conversion_thread_count -= t->thread_count;
|
||||
ParseTaskNode *n = push_array(scratch.arena, ParseTaskNode, 1);
|
||||
n->v.key = key;
|
||||
n->v.rdi_path = rdi_path;
|
||||
SLLQueuePush(first_parse_task, last_parse_task, n);
|
||||
parse_tasks_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
//- rjf: join all parse tasks
|
||||
//
|
||||
parse_tasks = push_array(scratch.arena, ParseTask, parse_tasks_count);
|
||||
{
|
||||
U64 idx = 0;
|
||||
for EachNode(n, ParseTaskNode, first_parse_task)
|
||||
{
|
||||
parse_tasks[idx] = n->v;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
lane_sync();
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: do wide load of all prepped RDIs
|
||||
//
|
||||
U64 parse_task_take_counter = 0;
|
||||
U64 *parse_task_take_counter_ptr = 0;
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
parse_task_take_counter_ptr = &parse_task_take_counter;
|
||||
}
|
||||
lane_sync_u64(&parse_task_take_counter_ptr, 0);
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
//- rjf: take next task
|
||||
U64 parse_task_idx = ins_atomic_u64_inc_eval(parse_task_take_counter_ptr);
|
||||
if(parse_task_idx >= parse_tasks_count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//- rjf: unpack task
|
||||
DI2_Key key = parse_tasks[parse_task_idx].key;
|
||||
String8 rdi_path = parse_tasks[parse_task_idx].rdi_path;
|
||||
|
||||
//- rjf: open file
|
||||
OS_Handle file = {0};
|
||||
OS_Handle file_map = {0};
|
||||
FileProperties file_props = {0};
|
||||
void *file_base = 0;
|
||||
{
|
||||
file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, rdi_path);
|
||||
file_map = os_file_map_open(OS_AccessFlag_Read, file);
|
||||
file_props = os_properties_from_file(file);
|
||||
file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size));
|
||||
}
|
||||
|
||||
//- rjf: do initial parse of rdi
|
||||
RDI_Parsed rdi_parsed_maybe_compressed = rdi_parsed_nil;
|
||||
{
|
||||
RDI_ParseStatus parse_status = rdi_parse((U8 *)file_base, file_props.size, &rdi_parsed_maybe_compressed);
|
||||
(void)parse_status;
|
||||
}
|
||||
|
||||
//- rjf: decompress & re-parse, if necessary
|
||||
Arena *rdi_parsed_arena = 0;
|
||||
RDI_Parsed rdi_parsed = rdi_parsed_maybe_compressed;
|
||||
{
|
||||
U64 decompressed_size = rdi_decompressed_size_from_parsed(&rdi_parsed_maybe_compressed);
|
||||
if(decompressed_size > file_props.size)
|
||||
{
|
||||
rdi_parsed_arena = arena_alloc();
|
||||
U8 *decompressed_data = push_array_no_zero(rdi_parsed_arena, U8, decompressed_size);
|
||||
rdi_decompress_parsed(decompressed_data, decompressed_size, &rdi_parsed_maybe_compressed);
|
||||
RDI_ParseStatus parse_status = rdi_parse(decompressed_data, decompressed_size, &rdi_parsed);
|
||||
(void)parse_status;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: commit parsed info to cache
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
}
|
||||
}
|
||||
lane_sync();
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DBG_INFO2_H
|
||||
#define DBG_INFO2_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unique Debug Info Key
|
||||
|
||||
typedef struct DI2_Key DI2_Key;
|
||||
struct DI2_Key
|
||||
{
|
||||
U64 u64[2];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Path / Timestamp => Key Cache Types
|
||||
|
||||
typedef struct DI2_KeyNode DI2_KeyNode;
|
||||
struct DI2_KeyNode
|
||||
{
|
||||
DI2_KeyNode *next;
|
||||
DI2_KeyNode *prev;
|
||||
String8 path;
|
||||
U64 min_timestamp;
|
||||
DI2_Key key;
|
||||
};
|
||||
|
||||
typedef struct DI2_KeySlot DI2_KeySlot;
|
||||
struct DI2_KeySlot
|
||||
{
|
||||
DI2_KeyNode *first;
|
||||
DI2_KeyNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Cache Types
|
||||
|
||||
typedef struct DI2_Node DI2_Node;
|
||||
struct DI2_Node
|
||||
{
|
||||
// rjf: links
|
||||
DI2_Node *next;
|
||||
DI2_Node *prev;
|
||||
|
||||
// rjf: metadata
|
||||
AccessPt access_pt;
|
||||
U64 refcount;
|
||||
U64 working_count;
|
||||
U64 completion_count;
|
||||
|
||||
// rjf: key
|
||||
DI2_Key key;
|
||||
|
||||
// rjf: value
|
||||
OS_Handle file;
|
||||
OS_Handle file_map;
|
||||
void *file_base;
|
||||
FileProperties file_props;
|
||||
Arena *arena;
|
||||
RDI_Parsed rdi;
|
||||
};
|
||||
|
||||
typedef struct DI2_Slot DI2_Slot;
|
||||
struct DI2_Slot
|
||||
{
|
||||
DI2_Node *first;
|
||||
DI2_Node *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Requests
|
||||
|
||||
typedef struct DI2_Request DI2_Request;
|
||||
struct DI2_Request
|
||||
{
|
||||
DI2_Key key;
|
||||
};
|
||||
|
||||
typedef struct DI2_RequestNode DI2_RequestNode;
|
||||
struct DI2_RequestNode
|
||||
{
|
||||
DI2_RequestNode *next;
|
||||
DI2_Request v;
|
||||
};
|
||||
|
||||
typedef struct DI2_RequestBatch DI2_RequestBatch;
|
||||
struct DI2_RequestBatch
|
||||
{
|
||||
Mutex mutex;
|
||||
Arena *arena;
|
||||
DI2_RequestNode *first;
|
||||
DI2_RequestNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Load Tasks
|
||||
|
||||
typedef enum DI2_LoadTaskStatus
|
||||
{
|
||||
DI2_LoadTaskStatus_Null,
|
||||
DI2_LoadTaskStatus_Active,
|
||||
DI2_LoadTaskStatus_Done,
|
||||
}
|
||||
DI2_LoadTaskStatus;
|
||||
|
||||
typedef struct DI2_LoadTask DI2_LoadTask;
|
||||
struct DI2_LoadTask
|
||||
{
|
||||
DI2_LoadTask *next;
|
||||
DI2_LoadTask *prev;
|
||||
|
||||
DI2_Key key;
|
||||
DI2_LoadTaskStatus status;
|
||||
|
||||
B32 og_analyzed;
|
||||
B32 og_is_rdi;
|
||||
U64 og_size;
|
||||
|
||||
B32 rdi_analyzed;
|
||||
B32 rdi_is_stale;
|
||||
|
||||
U64 thread_count;
|
||||
OS_Handle process;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State
|
||||
|
||||
typedef struct DI2_Shared DI2_Shared;
|
||||
struct DI2_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: key -> path cache
|
||||
U64 key_slots_count;
|
||||
DI2_KeySlot *key_slots;
|
||||
StripeArray key_stripes;
|
||||
|
||||
// rjf: path -> key cache
|
||||
U64 key_path_slots_count;
|
||||
DI2_KeySlot *key_path_slots;
|
||||
StripeArray key_path_stripes;
|
||||
|
||||
// rjf: debug info cache
|
||||
U64 slots_count;
|
||||
DI2_Slot *slots;
|
||||
StripeArray stripes;
|
||||
|
||||
// rjf: requests
|
||||
DI2_RequestBatch req_batches[2]; // [0] -> high priority, [1] -> low priority
|
||||
|
||||
// rjf: conversion tasks
|
||||
DI2_LoadTask *first_load_task;
|
||||
DI2_LoadTask *last_load_task;
|
||||
DI2_LoadTask *free_load_task;
|
||||
U64 conversion_process_count;
|
||||
U64 conversion_thread_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global DI2_Shared *di2_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal DI2_Key di2_key_zero(void);
|
||||
internal B32 di2_key_match(DI2_Key a, DI2_Key b);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void di2_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Path * Timestamp Cache Submission & Lookup
|
||||
|
||||
internal DI2_Key di2_key_from_path_timestamp(String8 path, U64 timestamp);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Opening / Closing
|
||||
|
||||
internal void di2_open(DI2_Key key);
|
||||
internal void di2_close(DI2_Key key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Lookups
|
||||
|
||||
internal RDI_Parsed *di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Asynchronous Tick
|
||||
|
||||
internal void di2_async_tick(void);
|
||||
|
||||
#endif // DBG_INFO2_H
|
||||
@@ -774,13 +774,13 @@ os_process_launch(OS_ProcessLaunchParams *params)
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_process_join(OS_Handle handle, U64 endt_us)
|
||||
os_process_join(OS_Handle handle, U64 endt_us, U64 *exit_code_out)
|
||||
{
|
||||
NotImplemented;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_process_join_exit_code(OS_Handle handle, U64 endt_us, int *exit_code_out)
|
||||
internal U64
|
||||
os_process_array_join(OS_HandleArray processes, U64 endt_us, U64 *exit_code_out)
|
||||
{
|
||||
NotImplemented;
|
||||
}
|
||||
|
||||
@@ -244,8 +244,7 @@ internal void os_sleep_milliseconds(U32 msec);
|
||||
//~ rjf: @os_hooks Child Processes (Implemented Per-OS)
|
||||
|
||||
internal OS_Handle os_process_launch(OS_ProcessLaunchParams *params);
|
||||
internal B32 os_process_join(OS_Handle handle, U64 endt_us);
|
||||
internal B32 os_process_join_exit_code(OS_Handle handle, U64 endt_us, int *exit_code_out);
|
||||
internal B32 os_process_join(OS_Handle handle, U64 endt_us, U64 *exit_code_out);
|
||||
internal void os_process_detach(OS_Handle handle);
|
||||
internal B32 os_process_kill(OS_Handle handle);
|
||||
|
||||
|
||||
@@ -1061,28 +1061,21 @@ os_process_launch(OS_ProcessLaunchParams *params)
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_process_join(OS_Handle handle, U64 endt_us)
|
||||
os_process_join(OS_Handle handle, U64 endt_us, U64 *exit_code_out)
|
||||
{
|
||||
HANDLE process = (HANDLE)(handle.u64[0]);
|
||||
DWORD sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us);
|
||||
DWORD result = WaitForSingleObject(process, sleep_ms);
|
||||
return (result == WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_process_join_exit_code(OS_Handle handle, U64 endt_us, int *exit_code_out)
|
||||
{
|
||||
B32 result = 0;
|
||||
if(os_process_join(handle, endt_us))
|
||||
B32 process_joined = (result == WAIT_OBJECT_0);
|
||||
if(process_joined && exit_code_out)
|
||||
{
|
||||
DWORD exit_code;
|
||||
if(GetExitCodeProcess((HANDLE)handle.u64[0], &exit_code))
|
||||
DWORD exit_code = 0;
|
||||
if(GetExitCodeProcess(process, &exit_code))
|
||||
{
|
||||
*exit_code_out = exit_code;
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return process_joined;
|
||||
}
|
||||
|
||||
internal B32
|
||||
|
||||
@@ -249,6 +249,7 @@
|
||||
#include "regs/regs.h"
|
||||
#include "regs/rdi/regs_rdi.h"
|
||||
#include "dbg_info/dbg_info.h"
|
||||
#include "dbg_info/dbg_info2.h"
|
||||
#include "disasm/disasm.h"
|
||||
#include "demon/demon_inc.h"
|
||||
#include "eval/eval_inc.h"
|
||||
@@ -296,6 +297,7 @@
|
||||
#include "regs/regs.c"
|
||||
#include "regs/rdi/regs_rdi.c"
|
||||
#include "dbg_info/dbg_info.c"
|
||||
#include "dbg_info/dbg_info2.c"
|
||||
#include "disasm/disasm.c"
|
||||
#include "demon/demon_inc.c"
|
||||
#include "eval/eval_inc.c"
|
||||
|
||||
@@ -114,7 +114,7 @@ for(Test *test = test_##name_identifier; test != 0; test = 0)
|
||||
}
|
||||
for(OS_HandleNode *n = processes.first; n != 0; n = n->next)
|
||||
{
|
||||
os_process_join(n->v, max_U64);
|
||||
os_process_join(n->v, max_U64, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ for(Test *test = test_##name_identifier; test != 0; test = 0)
|
||||
}
|
||||
for(OS_HandleNode *n = processes.first; n != 0; n = n->next)
|
||||
{
|
||||
os_process_join(n->v, max_U64);
|
||||
os_process_join(n->v, max_U64, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,9 @@ t_invoke_linker_with_time_out(U64 time_out, String8 cmdline)
|
||||
if (os_handle_match(linker_handle, os_handle_zero())) {
|
||||
fprintf(stderr, "unable to start process: %.*s\n", str8_varg(g_linker));
|
||||
} else {
|
||||
B32 was_joined = os_process_join_exit_code(linker_handle, time_out, &exit_code);
|
||||
U64 exit_code_u64 = 0;
|
||||
B32 was_joined = os_process_join(linker_handle, time_out, &exit_code_u64);
|
||||
exit_code = (int)exit_code_u64;
|
||||
if (!was_joined) {
|
||||
os_process_kill(linker_handle);
|
||||
exit_code = T_LINKER_TIME_OUT_EXIT_CODE;
|
||||
@@ -4428,8 +4430,8 @@ t_import_kernel32(void)
|
||||
str8_list_pushf(scratch.arena, &launch_opts.cmd_line, "%S/a.exe", g_wdir);
|
||||
OS_Handle handle = os_process_launch(&launch_opts);
|
||||
AssertAlways(!os_handle_match(handle, os_handle_zero()));
|
||||
int exit_code = -1;
|
||||
os_process_join_exit_code(handle, max_U64, &exit_code);
|
||||
U64 exit_code = max_U64;
|
||||
os_process_join(handle, max_U64, &exit_code);
|
||||
os_process_detach(handle);
|
||||
if (exit_code != 0) { goto exit; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user