majorly improve outputdebugstring performance

This commit is contained in:
Ryan Fleury
2024-05-30 07:06:29 -07:00
parent 89c8f84498
commit da54fd1217
+87 -45
View File
@@ -1418,6 +1418,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
//- rjf: write all traps into memory //- rjf: write all traps into memory
// //
U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, ctrls->traps.trap_count); U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, ctrls->traps.trap_count);
ProfScope("write all traps into memory")
{ {
U64 trap_idx = 0; U64 trap_idx = 0;
for(DMN_TrapChunkNode *n = ctrls->traps.first; n != 0; n = n->next) for(DMN_TrapChunkNode *n = ctrls->traps.first; n != 0; n = n->next)
@@ -1438,6 +1439,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
// //
DMN_W32_EntityNode *first_run_thread = 0; DMN_W32_EntityNode *first_run_thread = 0;
DMN_W32_EntityNode *last_run_thread = 0; DMN_W32_EntityNode *last_run_thread = 0;
ProfScope("produce list of threads which will run")
{ {
//- rjf: scan all processes //- rjf: scan all processes
for(DMN_W32_Entity *process = dmn_w32_shared->entities_base->first; for(DMN_W32_Entity *process = dmn_w32_shared->entities_base->first;
@@ -1519,6 +1521,8 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
////////////////////////// //////////////////////////
//- rjf: resume threads which will run //- rjf: resume threads which will run
// //
ProfScope("resume threads which will run")
{
for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next) for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next)
{ {
DMN_W32_Entity *thread = n->v; DMN_W32_Entity *thread = n->v;
@@ -1543,8 +1547,17 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
}break; }break;
} }
} }
}
////////////////////////// //////////////////////////
//- rjf: loop, consume win32 debug events until we produce the relevant demon events
//
String8List debug_strings = {0};
for(B32 keep_going = 1; keep_going;)
{
keep_going = 0;
////////////////////////
//- rjf: choose win32 resume code //- rjf: choose win32 resume code
// //
DWORD resume_code = DBG_CONTINUE; DWORD resume_code = DBG_CONTINUE;
@@ -1556,11 +1569,12 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
} }
} }
////////////////////////// ////////////////////////
//- rjf: inform windows that we're resuming, run, & obtain next debug event //- rjf: inform windows that we're resuming, run, & obtain next debug event
// //
DEBUG_EVENT evt = {0}; DEBUG_EVENT evt = {0};
B32 evt_good = 0; B32 evt_good = 0;
ProfScope("inform windows that we're resuming, run, & obtain next debug event")
{ {
B32 resume_good = 1; B32 resume_good = 1;
if(dmn_w32_shared->resume_needed) if(dmn_w32_shared->resume_needed)
@@ -1586,43 +1600,10 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
} }
} }
////////////////////////// ////////////////////////
//- rjf: suspend threads which ran
//
if(evt_good) for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next)
{
DMN_W32_Entity *thread = n->v;
DWORD suspend_result = SuspendThread(thread->handle);
switch(suspend_result)
{
case 0xffffffffu:
{
// TODO(rjf): error - unknown cause. need to do do GetLastError, FormatMessage
//
// NOTE(rjf): this can happen when the event is EXIT_THREAD_DEBUG_EVENT
// or EXIT_PROCESS_DEBUG_EVENT. after such an event, SuspendThread
// gives error code 5 (access denied). this has no adverse effects, but
// if we want to start reporting errors we should take care to avoid
// calling SuspendThread in that case.
}break;
default:
{
DWORD desired_counter = 1;
DWORD current_counter = suspend_result + 1;
if(current_counter != desired_counter)
{
// NOTE(rjf): Warning. We've suspended to something higher than 1.
// In this case, it means the user probably created the thread in
// a suspended state, or they called SuspendThread.
}
}break;
}
}
//////////////////////////
//- rjf: process the new event //- rjf: process the new event
// //
if(evt_good) if(evt_good) ProfScope("process the new event")
{ {
switch(evt.dwDebugEventCode) switch(evt.dwDebugEventCode)
{ {
@@ -2166,21 +2147,32 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
U64 string_size = (U64)evt.u.DebugString.nDebugStringLength; U64 string_size = (U64)evt.u.DebugString.nDebugStringLength;
// rjf: read memory // rjf: read memory
U8 *buffer = push_array_no_zero(arena, U8, string_size + 1); U8 *buffer = push_array_no_zero(scratch.arena, U8, string_size + 1);
dmn_w32_process_read(process->handle, r1u64(string_address, string_address+string_size), buffer); dmn_w32_process_read(process->handle, r1u64(string_address, string_address+string_size), buffer);
buffer[string_size] = 0; buffer[string_size] = 0;
// rjf: generate event // rjf: extract into string
String8 debug_string = str8(buffer, string_size);
if(debug_string.size != 0 && buffer[string_size-1] == 0)
{ {
debug_string.size -= 1;
}
// rjf: push into debug strings
str8_list_push(scratch.arena, &debug_strings, debug_string);
keep_going = 1;
// rjf: generate event, given sufficient amount of text
if(debug_strings.total_size >= KB(4))
{
String8 debug_strings_joined = str8_list_join(arena, &debug_strings, 0);
MemoryZeroStruct(&debug_strings);
DMN_Event *e = dmn_event_list_push(arena, &events); DMN_Event *e = dmn_event_list_push(arena, &events);
e->kind = DMN_EventKind_DebugString; e->kind = DMN_EventKind_DebugString;
e->process = dmn_w32_handle_from_entity(process); e->process = dmn_w32_handle_from_entity(process);
e->thread = dmn_w32_handle_from_entity(thread); e->thread = dmn_w32_handle_from_entity(thread);
e->string = str8(buffer, string_size); e->string = debug_strings_joined;
if(string_size != 0 && buffer[string_size-1] == 0) keep_going = 0;
{
e->string.size -= 1;
}
} }
}break; }break;
@@ -2206,9 +2198,58 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
}break; }break;
} }
} }
}
////////////////////////
//- rjf: send out event for any remaining debug strings
//
if(debug_strings.total_size != 0)
{
String8 debug_strings_joined = str8_list_join(arena, &debug_strings, 0);
MemoryZeroStruct(&debug_strings);
DMN_Event *e = dmn_event_list_push(arena, &events);
e->kind = DMN_EventKind_DebugString;
e->string = debug_strings_joined;
}
////////////////////////
//- rjf: suspend threads which ran
//
ProfScope("suspend threads which ran")
{
for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next)
{
DMN_W32_Entity *thread = n->v;
DWORD suspend_result = SuspendThread(thread->handle);
switch(suspend_result)
{
case 0xffffffffu:
{
// TODO(rjf): error - unknown cause. need to do do GetLastError, FormatMessage
//
// NOTE(rjf): this can happen when the event is EXIT_THREAD_DEBUG_EVENT
// or EXIT_PROCESS_DEBUG_EVENT. after such an event, SuspendThread
// gives error code 5 (access denied). this has no adverse effects, but
// if we want to start reporting errors we should take care to avoid
// calling SuspendThread in that case.
}break;
default:
{
DWORD desired_counter = 1;
DWORD current_counter = suspend_result + 1;
if(current_counter != desired_counter)
{
// NOTE(rjf): Warning. We've suspended to something higher than 1.
// In this case, it means the user probably created the thread in
// a suspended state, or they called SuspendThread.
}
}break;
}
}
}
//- rjf: gather new thread-names //- rjf: gather new thread-names
if(dmn_w32_GetThreadDescription != 0) ProfScope("gather new thread names") if(dmn_w32_GetThreadDescription != 0)
{ {
for(DMN_W32_Entity *process = dmn_w32_shared->entities_base->first; for(DMN_W32_Entity *process = dmn_w32_shared->entities_base->first;
process != &dmn_w32_entity_nil; process != &dmn_w32_entity_nil;
@@ -2252,6 +2293,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
////////////////////////// //////////////////////////
//- rjf: restore original memory at trap locations //- rjf: restore original memory at trap locations
// //
ProfScope("restore original memory at trap locations")
{ {
U64 trap_idx = 0; U64 trap_idx = 0;
for(DMN_TrapChunkNode *n = ctrls->traps.first; n != 0; n = n->next) for(DMN_TrapChunkNode *n = ctrls->traps.first; n != 0; n = n->next)
@@ -2271,7 +2313,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
////////////////////////// //////////////////////////
//- rjf: unset single step bit //- rjf: unset single step bit
// //
if(!dmn_handle_match(ctrls->single_step_thread, dmn_handle_zero())) if(!dmn_handle_match(ctrls->single_step_thread, dmn_handle_zero())) ProfScope("unset single step bit")
{ {
DMN_W32_Entity *thread = dmn_w32_entity_from_handle(ctrls->single_step_thread); DMN_W32_Entity *thread = dmn_w32_entity_from_handle(ctrls->single_step_thread);
Architecture arch = thread->arch; Architecture arch = thread->arch;