From 5e99224b28ac2294e0bde8ff330eeefb47497381 Mon Sep 17 00:00:00 2001 From: jacob Date: Sat, 5 Jul 2025 16:18:07 -0500 Subject: [PATCH] allocate counters in sys layer --- src/asset_cache.c | 4 ++- src/asset_cache.h | 2 +- src/font.c | 5 ++- src/gp_dx12.c | 18 +++++++---- src/resource.c | 9 ++++-- src/sound.c | 5 ++- src/sprite.c | 7 ++-- src/sys.h | 9 +++--- src/sys_win32.c | 81 +++++++++++++++++++++++++++++++++-------------- 9 files changed, 94 insertions(+), 46 deletions(-) diff --git a/src/asset_cache.c b/src/asset_cache.c index 18712ee7..b773b560 100644 --- a/src/asset_cache.c +++ b/src/asset_cache.c @@ -191,7 +191,9 @@ void asset_cache_wait(struct asset *asset) { if (asset->status != ASSET_STATUS_READY) { /* Wait on job */ - sys_wait(&asset->counter); + if (asset->counter) { + sys_wait(asset->counter); + } /* Wait for asset to be ready */ sync_flag_wait(&asset->asset_ready_sf); } diff --git a/src/asset_cache.h b/src/asset_cache.h index b539c03f..463e5c13 100644 --- a/src/asset_cache.h +++ b/src/asset_cache.h @@ -18,7 +18,7 @@ struct asset { u64 hash; struct string key; - struct sys_counter counter; + struct sys_counter *counter; /* Managed via asset_cache_mark_x functions */ enum asset_status status; diff --git a/src/font.c b/src/font.c index 99a291f0..d256f019 100644 --- a/src/font.c +++ b/src/font.c @@ -188,7 +188,10 @@ struct asset *font_load_asset(struct string path, f32 point_size, b32 wait) /* Push task */ asset_cache_mark_loading(asset); - sys_run(1, font_load_asset_job, params, SYS_PRIORITY_BACKGROUND, &asset->counter); + if (wait) { + asset->counter = sys_counter_alloc(); + } + sys_run(1, font_load_asset_job, params, SYS_PRIORITY_BACKGROUND, asset->counter); if (wait) { asset_cache_wait(asset); } diff --git a/src/gp_dx12.c b/src/gp_dx12.c index a945e9bd..54a92cdb 100644 --- a/src/gp_dx12.c +++ b/src/gp_dx12.c @@ -927,9 +927,12 @@ INTERNAL SYS_JOB_DEF(pipeline_init_job, job) if (success) { struct shader_compile_job_param *params[] = { &vs, &ps }; struct shader_compile_job_sig comp_sig = { .params = params }; - struct sys_counter counter = ZI; - sys_run(countof(params), shader_compile_job, &comp_sig, SYS_PRIORITY_HIGH, &counter); - sys_wait(&counter); + struct sys_counter *counter = sys_counter_alloc(); + { + sys_run(countof(params), shader_compile_job, &comp_sig, SYS_PRIORITY_HIGH, counter); + sys_wait(counter); + } + sys_counter_release(counter); success = vs.success && ps.success; } @@ -1120,10 +1123,13 @@ INTERNAL SYS_JOB_DEF(pipeline_init_job, job) INTERNAL void pipeline_alloc(u64 num_pipelines, struct pipeline_desc *descs_in, struct pipeline **pipelines_out) { __prof; - struct sys_counter counter = ZI; struct pipeline_init_job_sig sig = { .descs_in = descs_in, .pipelines_out = pipelines_out }; - sys_run(num_pipelines, pipeline_init_job, &sig, SYS_PRIORITY_HIGH, &counter); - sys_wait(&counter); + struct sys_counter *counter = sys_counter_alloc(); + { + sys_run(num_pipelines, pipeline_init_job, &sig, SYS_PRIORITY_HIGH, counter); + sys_wait(counter); + } + sys_counter_release(counter); } INTERNAL void pipeline_release_now(struct pipeline *pipeline) diff --git a/src/resource.c b/src/resource.c index 325a3dd1..cbedc6b6 100644 --- a/src/resource.c +++ b/src/resource.c @@ -288,9 +288,12 @@ INTERNAL SYS_THREAD_DEF(resource_watch_dispatcher_thread_entry_point, _) struct resource_watch_callback_job_sig sig = ZI; sig.name = info->name; sig.callbacks = callbacks; - struct sys_counter counter = ZI; - sys_run(num_callbacks, resource_watch_callback_job, &sig, SYS_PRIORITY_BACKGROUND, &counter); - sys_wait(&counter); + struct sys_counter *counter = sys_counter_alloc(); + { + sys_run(num_callbacks, resource_watch_callback_job, &sig, SYS_PRIORITY_BACKGROUND, counter); + sys_wait(counter); + } + sys_counter_release(counter); } } } diff --git a/src/sound.c b/src/sound.c index 27edb9af..a667b22c 100644 --- a/src/sound.c +++ b/src/sound.c @@ -181,7 +181,10 @@ struct asset *sound_load_asset(struct string path, u32 flags, b32 wait) /* Push task */ asset_cache_mark_loading(asset); - sys_run(1, sound_load_asset_job, params, SYS_PRIORITY_BACKGROUND, &asset->counter); + if (wait) { + asset->counter = sys_counter_alloc(); + } + sys_run(1, sound_load_asset_job, params, SYS_PRIORITY_BACKGROUND, asset->counter); if (wait) { asset_cache_wait(asset); } diff --git a/src/sprite.c b/src/sprite.c index 86d35567..1a084f2a 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -1377,12 +1377,11 @@ INTERNAL SYS_JOB_DEF(sprite_evictor_job, _) INTERNAL SYS_THREAD_DEF(sprite_evictor_scheduler_thread_entry_point, arg) { (UNUSED)arg; - + struct sys_counter *job_counter = sys_counter_alloc(); struct sys_lock evictor_lock = sys_mutex_lock_e(G.evictor_scheduler_mutex); while (!G.evictor_scheduler_shutdown) { - struct sys_counter counter = ZI; - sys_run(1, sprite_evictor_job, NULL, SYS_PRIORITY_BACKGROUND, &counter); - sys_wait(&counter); + sys_run(1, sprite_evictor_job, NULL, SYS_PRIORITY_BACKGROUND, job_counter); + sys_wait(job_counter); sys_condition_variable_wait_time(G.evictor_scheduler_shutdown_cv, &evictor_lock, SECONDS_FROM_NS(EVICTOR_CYCLE_INTERVAL_NS)); } sys_mutex_unlock(&evictor_lock); diff --git a/src/sys.h b/src/sys.h index d98c2bb8..209581a1 100644 --- a/src/sys.h +++ b/src/sys.h @@ -482,13 +482,12 @@ b32 sys_run_command(struct string cmd); * Counter * ========================== */ -struct sys_counter { - struct atomic_i64 v; -}; +struct sys_counter *sys_counter_alloc(void); +void sys_counter_release(struct sys_counter *counter); -void sys_counter_add(struct sys_counter *sys_counter, i64 amount); +void sys_counter_add(struct sys_counter *counter, i64 amount); -void sys_wait(struct sys_counter *sys_counter); +void sys_wait(struct sys_counter *counter); /* ========================== * * Fiber diff --git a/src/sys_win32.c b/src/sys_win32.c index ce71f6e3..3aa2eb45 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -118,12 +118,14 @@ struct win32_window { -#define MAX_COUNTERS 4096 struct alignas(64) counter { /* =================================================== */ - i32 id; /* 4 bytes */ - struct atomic_i32 value; /* 4 bytes */ + struct atomic_i64 v; /* 8 bytes */ + /* =================================================== */ + struct counter *next_free; /* 8 bytes */ + /* =================================================== */ + u8 _pad0[8]; /* 8 bytes (padding) */ /* =================================================== */ u8 _pad1[8]; /* 8 bytes (padding) */ /* =================================================== */ @@ -134,10 +136,6 @@ struct alignas(64) counter { u8 _pad4[8]; /* 8 bytes (padding) */ /* =================================================== */ u8 _pad5[8]; /* 8 bytes (padding) */ - /* =================================================== */ - u8 _pad6[8]; /* 8 bytes (padding) */ - /* =================================================== */ - u8 _pad7[8]; /* 8 bytes (padding) */ }; STATIC_ASSERT(sizeof(struct counter) == 64); /* Assume counter fits in one cache line (increase if necessary) */ STATIC_ASSERT(alignof(struct counter) == 64); /* Avoid false sharing */ @@ -217,7 +215,7 @@ struct job_info { i32 count; sys_job_func *func; void *sig; - struct sys_counter *counter; + struct counter *counter; struct job_info *next; }; @@ -301,10 +299,9 @@ GLOBAL struct { /* Counters */ - i32 num_counters; + struct arena *counters_arena; struct atomic_i32 counters_lock; /* TODO: Prevent false sharing */ - i32 first_free_counter_id; - struct counter counters[MAX_COUNTERS]; + struct counter *first_free_counter; /* Fibers */ i32 num_fibers; @@ -333,7 +330,36 @@ GLOBAL struct { * Counters * ========================== */ -void sys_counter_add(struct sys_counter *counter, i64 amount) +INTERNAL struct counter *counter_alloc(void) +{ + struct counter *counter = NULL; + { + while (atomic_i32_fetch_test_set(&G.counters_lock, 0, 1) != 0) ix_pause(); + { + if (G.first_free_counter) { + counter = G.first_free_counter; + G.first_free_counter = counter->next_free; + } else { + counter = arena_push_no_zero(G.counters_arena, struct counter); + } + } + atomic_i32_fetch_set(&G.counters_lock, 0); + } + MEMZERO_STRUCT(counter); + return counter; +} + +INTERNAL void counter_release(struct counter *counter) +{ + while (atomic_i32_fetch_test_set(&G.counters_lock, 0, 1) != 0) ix_pause(); + { + counter->next_free = G.first_free_counter; + G.first_free_counter = counter; + } + atomic_i32_fetch_set(&G.counters_lock, 0); +} + +INTERNAL void counter_add(struct counter *counter, i64 amount) { i64 old_v = atomic_i64_fetch_add(&counter->v, amount); i64 new_v = old_v + amount; @@ -344,21 +370,27 @@ void sys_counter_add(struct sys_counter *counter, i64 amount) } } -void sys_wait(struct sys_counter *sys_counter) +INTERNAL void counter_wait(struct counter *counter) { __prof; - while (atomic_i64_fetch(&sys_counter->v) > 0) { + /* TODO: Yield with configurable spin count */ + while (atomic_i64_fetch(&counter->v) > 0) { ix_pause(); } } +struct sys_counter *sys_counter_alloc(void) { return (struct sys_counter *)counter_alloc(); } +void sys_counter_release(struct sys_counter *counter) { counter_release((struct counter *)counter); } +void sys_counter_add(struct sys_counter *counter, i64 amount) { counter_add((struct counter *)counter, amount); } +void sys_wait(struct sys_counter *counter) { counter_wait((struct counter *)counter); } + /* ========================== * * Fibers * ========================== */ enum fiber_kind { FIBER_KIND_CONVERTED_THREAD, - FIBER_KIND_JOB_RUNNER + FIBER_KIND_JOB_WORKER }; INTERNAL void job_fiber_entry(void *id_ptr); @@ -372,7 +404,7 @@ INTERNAL struct fiber *fiber_alloc(enum fiber_kind kind) while (atomic_i32_fetch_test_set(&G.fibers_lock, 0, 1) != 0) ix_pause(); { fiber_id = G.first_free_fiber_id; - if (fiber_id && kind == FIBER_KIND_JOB_RUNNER) { + if (fiber_id && kind == FIBER_KIND_JOB_WORKER) { fiber = &G.fibers[fiber_id]; G.first_free_fiber_id = fiber->parent_id; } else { @@ -419,7 +451,7 @@ INTERNAL struct fiber *fiber_alloc(enum fiber_kind kind) fiber->name_cstr = new_name_cstr; /* Init win32 fiber */ - if (kind == FIBER_KIND_JOB_RUNNER) { + if (kind == FIBER_KIND_JOB_WORKER) { fiber->addr = CreateFiber(FIBER_STACK_SIZE, job_fiber_entry, (void *)(i64)fiber_id); } else { fiber->addr = ConvertThreadToFiber((void *)(i64)fiber_id); @@ -488,9 +520,10 @@ void sys_yield(void) void sys_run(i32 count, sys_job_func *func, void *sig, enum sys_priority priority, struct sys_counter *counter) { + struct counter *job_counter = (struct counter *)counter; if (count > 0) { - if (counter) { - sys_counter_add(counter, count); + if (job_counter) { + counter_add(job_counter, count); } struct fiber *fiber = fiber_from_id(sys_current_fiber_id()); priority = clamp_i32(priority, fiber->job_priority, SYS_PRIORITY_BACKGROUND); /* A job cannot create a job with a higher priority than itself */ @@ -510,7 +543,7 @@ void sys_run(i32 count, sys_job_func *func, void *sig, enum sys_priority priorit info->count = count; info->func = func; info->sig = sig; - info->counter = counter; + info->counter = job_counter; if (queue->last) { queue->last->next = info; } else { @@ -574,7 +607,7 @@ INTERNAL SYS_THREAD_DEF(worker_entry, worker_ctx_arg) i32 job_id = 0; sys_job_func *job_func = 0; void *job_sig = 0; - struct sys_counter *job_counter = 0; + struct counter *job_counter = 0; { //__profscope(Pull job); for (u32 queue_index = 0; queue_index < countof(queues) && !job_func; ++queue_index) { @@ -613,7 +646,7 @@ INTERNAL SYS_THREAD_DEF(worker_entry, worker_ctx_arg) if (job_func) { __profscope(Run fiber); if (!job_fiber) { - job_fiber = fiber_alloc(FIBER_KIND_JOB_RUNNER); + job_fiber = fiber_alloc(FIBER_KIND_JOB_WORKER); } job_fiber->job_func = job_func; job_fiber->job_sig = job_sig; @@ -640,7 +673,7 @@ INTERNAL SYS_THREAD_DEF(worker_entry, worker_ctx_arg) case YIELD_KIND_DONE: { if (job_counter) { - sys_counter_add(job_counter, -1); + counter_add(job_counter, -1); } /* TODO: remove this */ @@ -2918,7 +2951,7 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, __profthread("Main thread", PROF_THREAD_GROUP_MAIN); /* Init counters */ - G.num_counters = 1; /* Counter at index 0 always nil */ + G.counters_arena = arena_alloc(GIGABYTE(64)); /* Init fibers */ G.num_fibers = 1; /* Fiber at index 0 always nil */