mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-11 16:18:07 +00:00
slow & highly contentious implementation of barriers using more basic sync primitives; fall back if sync barriers not present in win32 version
This commit is contained in:
+2
-2
@@ -49,13 +49,13 @@ commands =
|
||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
.f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
.f1 = { .win = "build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
//- rjf: [raddbg wsl]
|
||||
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
//- rjf: [scratch]
|
||||
.f2 = { .win = "wsl ./build.sh radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
.f2 = { .win = "pushd build && for /l %i in (1, 1, 3) do (radbin --capture --rdi mule_main.pdb --async_thread_count=1 --thread_count=8)", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
//- rjf: [textperf]
|
||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta telemetry textperf && raddbg_stable --ipc bring_to_front && raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
@@ -253,13 +253,13 @@
|
||||
# include <intrin.h>
|
||||
# if ARCH_X64
|
||||
# define ins_atomic_u128_eval_cond_assign(x,k,c) (B32)InterlockedCompareExchange128((__int64 *)(x), ((__int64 *)&(k))[1], ((__int64 *)&(k))[0], (__int64 *)c)
|
||||
# define ins_atomic_u64_eval(x) *((volatile U64 *)(x))
|
||||
# define ins_atomic_u64_eval(x) InterlockedAdd64((__int64 *)(x), 0)
|
||||
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((__int64 *)(x))
|
||||
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((__int64 *)(x))
|
||||
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((__int64 *)(x),(c))
|
||||
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd64((__int64 *)(x), c)
|
||||
# define ins_atomic_u64_eval_cond_assign(x,k,c) InterlockedCompareExchange64((__int64 *)(x),(k),(c))
|
||||
# define ins_atomic_u32_eval(x) *((volatile U32 *)(x))
|
||||
# define ins_atomic_u32_eval(x) InterlockedAdd((LONG *)(x), 0)
|
||||
# define ins_atomic_u32_inc_eval(x) InterlockedIncrement((LONG *)(x))
|
||||
# define ins_atomic_u32_dec_eval(x) InterlockedDecrement((LONG *)(x))
|
||||
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((LONG *)(x),(c))
|
||||
|
||||
@@ -58,3 +58,137 @@ set_thread_namef(char *fmt, ...)
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Platform-Abstracted Synchronization Primitive Functions
|
||||
|
||||
//- rjf: slow barriers
|
||||
|
||||
typedef struct BarrierNode BarrierNode;
|
||||
struct BarrierNode
|
||||
{
|
||||
BarrierNode *next;
|
||||
U64 count;
|
||||
U64 threads_left_to_enter;
|
||||
U64 threads_left_to_leave;
|
||||
RWMutex rw_mutex;
|
||||
CondVar cv;
|
||||
};
|
||||
|
||||
typedef struct BarrierTCTX BarrierTCTX;
|
||||
struct BarrierTCTX
|
||||
{
|
||||
Arena *arena;
|
||||
BarrierNode *free_barrier_node;
|
||||
};
|
||||
|
||||
thread_static BarrierTCTX *barrier_tctx = 0;
|
||||
|
||||
internal Barrier
|
||||
slow_barrier_alloc(U64 count)
|
||||
{
|
||||
if(barrier_tctx == 0)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
barrier_tctx = push_array(arena, BarrierTCTX, 1);
|
||||
barrier_tctx->arena = arena;
|
||||
}
|
||||
BarrierNode *n = barrier_tctx->free_barrier_node;
|
||||
if(n != 0)
|
||||
{
|
||||
SLLStackPop(barrier_tctx->free_barrier_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
n = push_array_no_zero(barrier_tctx->arena, BarrierNode, 1);
|
||||
}
|
||||
MemoryZeroStruct(n);
|
||||
n->count = count;
|
||||
n->threads_left_to_enter = count;
|
||||
n->rw_mutex = rw_mutex_alloc();
|
||||
n->cv = cond_var_alloc();
|
||||
Barrier result = {(U64)n};
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
slow_barrier_release(Barrier barrier)
|
||||
{
|
||||
if(barrier_tctx == 0)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
barrier_tctx = push_array(arena, BarrierTCTX, 1);
|
||||
barrier_tctx->arena = arena;
|
||||
}
|
||||
BarrierNode *n = (BarrierNode *)barrier.u64[0];
|
||||
rw_mutex_release(n->rw_mutex);
|
||||
cond_var_release(n->cv);
|
||||
SLLStackPush(barrier_tctx->free_barrier_node, n);
|
||||
}
|
||||
|
||||
internal void
|
||||
slow_barrier_wait(Barrier barrier)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
BarrierNode *n = (BarrierNode *)barrier.u64[0];
|
||||
U64 threads_left_to_enter = ins_atomic_u64_dec_eval(&n->threads_left_to_enter);
|
||||
|
||||
//- rjf: threads left to enter > 0 => wait
|
||||
if(threads_left_to_enter > 0)
|
||||
{
|
||||
// rjf: first try a spin loop
|
||||
B32 done_waiting = 0;
|
||||
ProfScope("spin loop wait") for(U64 spin_count = 0; spin_count < 10000; spin_count += 1)
|
||||
{
|
||||
if(ins_atomic_u64_eval(&n->threads_left_to_leave) != 0)
|
||||
{
|
||||
done_waiting = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: not done waiting -> need to do slow wait on condition variable
|
||||
if(!done_waiting) ProfScope("slow wait")
|
||||
{
|
||||
RWMutexScope(n->rw_mutex, 0) for(;;)
|
||||
{
|
||||
if(ins_atomic_u64_eval(&n->threads_left_to_leave) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
cond_var_wait_rw(n->cv, n->rw_mutex, 0, max_U64);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: decrement leave counter
|
||||
if(ins_atomic_u64_dec_eval(&n->threads_left_to_leave) > 0)
|
||||
{
|
||||
ProfScope("signal") cond_var_signal(n->cv);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: threads left to enter == 0 -> last thread, wakeup
|
||||
else
|
||||
{
|
||||
ins_atomic_u64_eval_assign(&n->threads_left_to_enter, n->count);
|
||||
ProfScope("wake up") RWMutexScope(n->rw_mutex, 1)
|
||||
{
|
||||
ins_atomic_u64_eval_assign(&n->threads_left_to_leave, n->count-1);
|
||||
}
|
||||
ProfScope("signal") cond_var_signal(n->cv);
|
||||
}
|
||||
|
||||
//- rjf: wait for threads left to leave == 0
|
||||
ProfScope("wait for threads to leave")
|
||||
{
|
||||
for(U64 spin_count = 0;; spin_count += 1)
|
||||
{
|
||||
if(ins_atomic_u64_eval(&n->threads_left_to_leave) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
+11
-3
@@ -131,9 +131,9 @@ internal B32 semaphore_take(Semaphore semaphore, U64 endt_us);
|
||||
internal void semaphore_drop(Semaphore semaphore);
|
||||
|
||||
//- rjf: barriers
|
||||
internal Barrier barrier_alloc(U64 count);
|
||||
internal void barrier_release(Barrier barrier);
|
||||
internal void barrier_wait(Barrier barrier);
|
||||
internal Barrier barrier_alloc(U64 count);
|
||||
internal void barrier_release(Barrier barrier);
|
||||
internal void barrier_wait(Barrier barrier);
|
||||
|
||||
//- rjf: scope macros
|
||||
#define MutexScope(mutex) DeferLoop(mutex_take(mutex), mutex_drop(mutex))
|
||||
@@ -142,6 +142,14 @@ internal void barrier_wait(Barrier barrier);
|
||||
#define MutexScopeW(mutex) DeferLoop(rw_mutex_take_w(mutex), rw_mutex_drop_w(mutex))
|
||||
#define MutexScopeRWPromote(mutex) DeferLoop((rw_mutex_drop_r(mutex), rw_mutex_take_w(mutex)), (rw_mutex_drop_w(mutex), rw_mutex_take_r(mutex)))
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Platform-Abstracted Synchronization Primitive Functions
|
||||
|
||||
//- rjf: slow barriers
|
||||
internal Barrier slow_barrier_alloc(U64 count);
|
||||
internal void slow_barrier_release(Barrier barrier);
|
||||
internal void slow_barrier_wait(Barrier barrier);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: @per_os_impl Safe Calls
|
||||
|
||||
|
||||
@@ -56,6 +56,28 @@ rb_thread_entry_point(void *p)
|
||||
log_select(log);
|
||||
log_scope_begin();
|
||||
|
||||
#if 0
|
||||
ProfScope("work")
|
||||
{
|
||||
for(int i = 0; i < 5; i += 1)
|
||||
{
|
||||
int sum = 0;
|
||||
ProfScope("do work")
|
||||
{
|
||||
for(int x = 0; x < 10000; x += 1)
|
||||
{
|
||||
for(int y = 0; y < 10000; y += 1)
|
||||
{
|
||||
sum += x*y + x-y;
|
||||
}
|
||||
}
|
||||
}
|
||||
lane_sync();
|
||||
}
|
||||
}
|
||||
abort_self(0);
|
||||
#endif
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: set up shared state
|
||||
//
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
// [ ] value coloring view in watch window, so you can quickly scroll & see values outside of a threshold
|
||||
// [x] step out of scopes / loops
|
||||
//
|
||||
// [x] policy for closing debug info which is no longer relevant?
|
||||
// [ ] codebase-internal barrier impl (win7/linux support)
|
||||
// [ ] asan pass
|
||||
// [ ] external window focusing bugs
|
||||
// [ ] PDB -> RDI conversion memory usage
|
||||
// [x] policy for closing debug info which is no longer relevant?
|
||||
// [x] killing/restarting thread performance (#780)
|
||||
//
|
||||
// [ ] project/user file improvements
|
||||
|
||||
+47
-16
@@ -8,6 +8,12 @@
|
||||
|
||||
typedef HRESULT W32_SetThreadDescription_Type(HANDLE hThread, PCWSTR lpThreadDescription);
|
||||
global W32_SetThreadDescription_Type *w32_SetThreadDescription_func = 0;
|
||||
typedef BOOL W32_InitializeSynchronizationBarrier_Type(W32_SYNCHRONIZATION_BARRIER *lpBarrier, LONG lTotalThreads, LONG lSpinCount);
|
||||
global W32_InitializeSynchronizationBarrier_Type *w32_InitializeSynchronizationBarrier_func = 0;
|
||||
typedef BOOL W32_DeleteSynchronizationBarrier_Type(W32_SYNCHRONIZATION_BARRIER *lpBarrier);
|
||||
global W32_DeleteSynchronizationBarrier_Type *w32_DeleteSynchronizationBarrier_func = 0;
|
||||
typedef BOOL W32_EnterSynchronizationBarrier_Type(W32_SYNCHRONIZATION_BARRIER *lpBarrier, DWORD dwFlags);
|
||||
global W32_EnterSynchronizationBarrier_Type *w32_EnterSynchronizationBarrier_func = 0;
|
||||
global RIO_EXTENSION_FUNCTION_TABLE w32_rio_functions = {0};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -42,10 +48,10 @@ w32_date_time_from_system_time(DateTime *out, SYSTEMTIME *in)
|
||||
out->year = in->wYear;
|
||||
out->mon = in->wMonth - 1;
|
||||
out->wday = in->wDayOfWeek;
|
||||
out->day = in->wDay;
|
||||
out->hour = in->wHour;
|
||||
out->min = in->wMinute;
|
||||
out->sec = in->wSecond;
|
||||
out->day = in->wDay;
|
||||
out->hour = in->wHour;
|
||||
out->min = in->wMinute;
|
||||
out->sec = in->wSecond;
|
||||
out->msec = in->wMilliseconds;
|
||||
}
|
||||
|
||||
@@ -681,34 +687,56 @@ semaphore_drop(Semaphore semaphore)
|
||||
internal Barrier
|
||||
barrier_alloc(U64 count)
|
||||
{
|
||||
W32_Entity *entity = w32_entity_alloc(W32_EntityKind_Barrier);
|
||||
if(entity != 0)
|
||||
Barrier result = {0};
|
||||
if(w32_InitializeSynchronizationBarrier_func != 0)
|
||||
{
|
||||
BOOL init_good = InitializeSynchronizationBarrier(&entity->sb, count, -1);
|
||||
(void)init_good;
|
||||
W32_Entity *entity = w32_entity_alloc(W32_EntityKind_Barrier);
|
||||
if(entity != 0)
|
||||
{
|
||||
BOOL init_good = w32_InitializeSynchronizationBarrier_func(&entity->sb, count, -1);
|
||||
(void)init_good;
|
||||
}
|
||||
result.u64[0] = IntFromPtr(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = slow_barrier_alloc(count);
|
||||
}
|
||||
Barrier result = {IntFromPtr(entity)};
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
barrier_release(Barrier barrier)
|
||||
{
|
||||
W32_Entity *entity = (W32_Entity*)PtrFromInt(barrier.u64[0]);
|
||||
if(entity != 0)
|
||||
if(w32_InitializeSynchronizationBarrier_func != 0)
|
||||
{
|
||||
DeleteSynchronizationBarrier(&entity->sb);
|
||||
w32_entity_release(entity);
|
||||
W32_Entity *entity = (W32_Entity*)PtrFromInt(barrier.u64[0]);
|
||||
if(entity != 0)
|
||||
{
|
||||
w32_DeleteSynchronizationBarrier_func(&entity->sb);
|
||||
w32_entity_release(entity);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
slow_barrier_release(barrier);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
barrier_wait(Barrier barrier)
|
||||
{
|
||||
W32_Entity *entity = (W32_Entity*)PtrFromInt(barrier.u64[0]);
|
||||
if(entity != 0)
|
||||
if(w32_InitializeSynchronizationBarrier_func != 0)
|
||||
{
|
||||
EnterSynchronizationBarrier(&entity->sb, 0);
|
||||
W32_Entity *entity = (W32_Entity*)PtrFromInt(barrier.u64[0]);
|
||||
if(entity != 0)
|
||||
{
|
||||
w32_EnterSynchronizationBarrier_func(&entity->sb, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
slow_barrier_wait(barrier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1741,6 +1769,9 @@ w32_entry_point_caller(int argc, WCHAR **wargv)
|
||||
{
|
||||
HMODULE module = LoadLibraryA("kernel32.dll");
|
||||
w32_SetThreadDescription_func = (W32_SetThreadDescription_Type *)GetProcAddress(module, "SetThreadDescription");
|
||||
w32_InitializeSynchronizationBarrier_func = (W32_InitializeSynchronizationBarrier_Type *)GetProcAddress(module, "InitializeSynchronizationBarrier");
|
||||
w32_DeleteSynchronizationBarrier_func = (W32_DeleteSynchronizationBarrier_Type *)GetProcAddress(module, "DeleteSynchronizationBarrier");
|
||||
w32_EnterSynchronizationBarrier_func = (W32_EnterSynchronizationBarrier_Type *)GetProcAddress(module, "EnterSynchronizationBarrier");
|
||||
FreeLibrary(module);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,16 @@ typedef enum W32_EntityKind
|
||||
}
|
||||
W32_EntityKind;
|
||||
|
||||
typedef struct W32_SYNCHRONIZATION_BARRIER W32_SYNCHRONIZATION_BARRIER;
|
||||
struct W32_SYNCHRONIZATION_BARRIER
|
||||
{
|
||||
U32 reserved_0;
|
||||
U32 reserved_1;
|
||||
U64 reserved_2[2];
|
||||
U32 reserved_3;
|
||||
U32 reserved_4;
|
||||
};
|
||||
|
||||
typedef struct W32_Entity W32_Entity;
|
||||
struct W32_Entity
|
||||
{
|
||||
@@ -70,7 +80,7 @@ struct W32_Entity
|
||||
CRITICAL_SECTION mutex;
|
||||
SRWLOCK rw_mutex;
|
||||
CONDITION_VARIABLE cv;
|
||||
SYNCHRONIZATION_BARRIER sb;
|
||||
W32_SYNCHRONIZATION_BARRIER sb;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user