allocate counters in sys layer

This commit is contained in:
jacob 2025-07-05 16:18:07 -05:00
parent ca5c1d6ee3
commit 5e99224b28
9 changed files with 94 additions and 46 deletions

View File

@ -191,7 +191,9 @@ void asset_cache_wait(struct asset *asset)
{ {
if (asset->status != ASSET_STATUS_READY) { if (asset->status != ASSET_STATUS_READY) {
/* Wait on job */ /* Wait on job */
sys_wait(&asset->counter); if (asset->counter) {
sys_wait(asset->counter);
}
/* Wait for asset to be ready */ /* Wait for asset to be ready */
sync_flag_wait(&asset->asset_ready_sf); sync_flag_wait(&asset->asset_ready_sf);
} }

View File

@ -18,7 +18,7 @@ struct asset {
u64 hash; u64 hash;
struct string key; struct string key;
struct sys_counter counter; struct sys_counter *counter;
/* Managed via asset_cache_mark_x functions */ /* Managed via asset_cache_mark_x functions */
enum asset_status status; enum asset_status status;

View File

@ -188,7 +188,10 @@ struct asset *font_load_asset(struct string path, f32 point_size, b32 wait)
/* Push task */ /* Push task */
asset_cache_mark_loading(asset); 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) { if (wait) {
asset_cache_wait(asset); asset_cache_wait(asset);
} }

View File

@ -927,9 +927,12 @@ INTERNAL SYS_JOB_DEF(pipeline_init_job, job)
if (success) { if (success) {
struct shader_compile_job_param *params[] = { &vs, &ps }; struct shader_compile_job_param *params[] = { &vs, &ps };
struct shader_compile_job_sig comp_sig = { .params = params }; struct shader_compile_job_sig comp_sig = { .params = params };
struct sys_counter counter = ZI; struct sys_counter *counter = sys_counter_alloc();
sys_run(countof(params), shader_compile_job, &comp_sig, SYS_PRIORITY_HIGH, &counter); {
sys_wait(&counter); 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; 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) INTERNAL void pipeline_alloc(u64 num_pipelines, struct pipeline_desc *descs_in, struct pipeline **pipelines_out)
{ {
__prof; __prof;
struct sys_counter counter = ZI;
struct pipeline_init_job_sig sig = { .descs_in = descs_in, .pipelines_out = pipelines_out }; 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); struct sys_counter *counter = sys_counter_alloc();
sys_wait(&counter); {
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) INTERNAL void pipeline_release_now(struct pipeline *pipeline)

View File

@ -288,9 +288,12 @@ INTERNAL SYS_THREAD_DEF(resource_watch_dispatcher_thread_entry_point, _)
struct resource_watch_callback_job_sig sig = ZI; struct resource_watch_callback_job_sig sig = ZI;
sig.name = info->name; sig.name = info->name;
sig.callbacks = callbacks; sig.callbacks = callbacks;
struct sys_counter counter = ZI; struct sys_counter *counter = sys_counter_alloc();
sys_run(num_callbacks, resource_watch_callback_job, &sig, SYS_PRIORITY_BACKGROUND, &counter); {
sys_wait(&counter); sys_run(num_callbacks, resource_watch_callback_job, &sig, SYS_PRIORITY_BACKGROUND, counter);
sys_wait(counter);
}
sys_counter_release(counter);
} }
} }
} }

View File

@ -181,7 +181,10 @@ struct asset *sound_load_asset(struct string path, u32 flags, b32 wait)
/* Push task */ /* Push task */
asset_cache_mark_loading(asset); 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) { if (wait) {
asset_cache_wait(asset); asset_cache_wait(asset);
} }

View File

@ -1377,12 +1377,11 @@ INTERNAL SYS_JOB_DEF(sprite_evictor_job, _)
INTERNAL SYS_THREAD_DEF(sprite_evictor_scheduler_thread_entry_point, arg) INTERNAL SYS_THREAD_DEF(sprite_evictor_scheduler_thread_entry_point, arg)
{ {
(UNUSED)arg; (UNUSED)arg;
struct sys_counter *job_counter = sys_counter_alloc();
struct sys_lock evictor_lock = sys_mutex_lock_e(G.evictor_scheduler_mutex); struct sys_lock evictor_lock = sys_mutex_lock_e(G.evictor_scheduler_mutex);
while (!G.evictor_scheduler_shutdown) { while (!G.evictor_scheduler_shutdown) {
struct sys_counter counter = ZI; sys_run(1, sprite_evictor_job, NULL, SYS_PRIORITY_BACKGROUND, job_counter);
sys_run(1, sprite_evictor_job, NULL, SYS_PRIORITY_BACKGROUND, &counter); sys_wait(job_counter);
sys_wait(&counter);
sys_condition_variable_wait_time(G.evictor_scheduler_shutdown_cv, &evictor_lock, SECONDS_FROM_NS(EVICTOR_CYCLE_INTERVAL_NS)); sys_condition_variable_wait_time(G.evictor_scheduler_shutdown_cv, &evictor_lock, SECONDS_FROM_NS(EVICTOR_CYCLE_INTERVAL_NS));
} }
sys_mutex_unlock(&evictor_lock); sys_mutex_unlock(&evictor_lock);

View File

@ -482,13 +482,12 @@ b32 sys_run_command(struct string cmd);
* Counter * Counter
* ========================== */ * ========================== */
struct sys_counter { struct sys_counter *sys_counter_alloc(void);
struct atomic_i64 v; 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 * Fiber

View File

@ -118,12 +118,14 @@ struct win32_window {
#define MAX_COUNTERS 4096
struct alignas(64) counter { struct alignas(64) counter {
/* =================================================== */ /* =================================================== */
i32 id; /* 4 bytes */ struct atomic_i64 v; /* 8 bytes */
struct atomic_i32 value; /* 4 bytes */ /* =================================================== */
struct counter *next_free; /* 8 bytes */
/* =================================================== */
u8 _pad0[8]; /* 8 bytes (padding) */
/* =================================================== */ /* =================================================== */
u8 _pad1[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 _pad4[8]; /* 8 bytes (padding) */
/* =================================================== */ /* =================================================== */
u8 _pad5[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(sizeof(struct counter) == 64); /* Assume counter fits in one cache line (increase if necessary) */
STATIC_ASSERT(alignof(struct counter) == 64); /* Avoid false sharing */ STATIC_ASSERT(alignof(struct counter) == 64); /* Avoid false sharing */
@ -217,7 +215,7 @@ struct job_info {
i32 count; i32 count;
sys_job_func *func; sys_job_func *func;
void *sig; void *sig;
struct sys_counter *counter; struct counter *counter;
struct job_info *next; struct job_info *next;
}; };
@ -301,10 +299,9 @@ GLOBAL struct {
/* Counters */ /* Counters */
i32 num_counters; struct arena *counters_arena;
struct atomic_i32 counters_lock; /* TODO: Prevent false sharing */ struct atomic_i32 counters_lock; /* TODO: Prevent false sharing */
i32 first_free_counter_id; struct counter *first_free_counter;
struct counter counters[MAX_COUNTERS];
/* Fibers */ /* Fibers */
i32 num_fibers; i32 num_fibers;
@ -333,7 +330,36 @@ GLOBAL struct {
* Counters * 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 old_v = atomic_i64_fetch_add(&counter->v, amount);
i64 new_v = old_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; __prof;
while (atomic_i64_fetch(&sys_counter->v) > 0) { /* TODO: Yield with configurable spin count */
while (atomic_i64_fetch(&counter->v) > 0) {
ix_pause(); 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 * Fibers
* ========================== */ * ========================== */
enum fiber_kind { enum fiber_kind {
FIBER_KIND_CONVERTED_THREAD, FIBER_KIND_CONVERTED_THREAD,
FIBER_KIND_JOB_RUNNER FIBER_KIND_JOB_WORKER
}; };
INTERNAL void job_fiber_entry(void *id_ptr); 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(); while (atomic_i32_fetch_test_set(&G.fibers_lock, 0, 1) != 0) ix_pause();
{ {
fiber_id = G.first_free_fiber_id; 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]; fiber = &G.fibers[fiber_id];
G.first_free_fiber_id = fiber->parent_id; G.first_free_fiber_id = fiber->parent_id;
} else { } else {
@ -419,7 +451,7 @@ INTERNAL struct fiber *fiber_alloc(enum fiber_kind kind)
fiber->name_cstr = new_name_cstr; fiber->name_cstr = new_name_cstr;
/* Init win32 fiber */ /* 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); fiber->addr = CreateFiber(FIBER_STACK_SIZE, job_fiber_entry, (void *)(i64)fiber_id);
} else { } else {
fiber->addr = ConvertThreadToFiber((void *)(i64)fiber_id); 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) 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 (count > 0) {
if (counter) { if (job_counter) {
sys_counter_add(counter, count); counter_add(job_counter, count);
} }
struct fiber *fiber = fiber_from_id(sys_current_fiber_id()); 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 */ 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->count = count;
info->func = func; info->func = func;
info->sig = sig; info->sig = sig;
info->counter = counter; info->counter = job_counter;
if (queue->last) { if (queue->last) {
queue->last->next = info; queue->last->next = info;
} else { } else {
@ -574,7 +607,7 @@ INTERNAL SYS_THREAD_DEF(worker_entry, worker_ctx_arg)
i32 job_id = 0; i32 job_id = 0;
sys_job_func *job_func = 0; sys_job_func *job_func = 0;
void *job_sig = 0; void *job_sig = 0;
struct sys_counter *job_counter = 0; struct counter *job_counter = 0;
{ {
//__profscope(Pull job); //__profscope(Pull job);
for (u32 queue_index = 0; queue_index < countof(queues) && !job_func; ++queue_index) { 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) { if (job_func) {
__profscope(Run fiber); __profscope(Run fiber);
if (!job_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_func = job_func;
job_fiber->job_sig = job_sig; job_fiber->job_sig = job_sig;
@ -640,7 +673,7 @@ INTERNAL SYS_THREAD_DEF(worker_entry, worker_ctx_arg)
case YIELD_KIND_DONE: case YIELD_KIND_DONE:
{ {
if (job_counter) { if (job_counter) {
sys_counter_add(job_counter, -1); counter_add(job_counter, -1);
} }
/* TODO: remove this */ /* 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); __profthread("Main thread", PROF_THREAD_GROUP_MAIN);
/* Init counters */ /* Init counters */
G.num_counters = 1; /* Counter at index 0 always nil */ G.counters_arena = arena_alloc(GIGABYTE(64));
/* Init fibers */ /* Init fibers */
G.num_fibers = 1; /* Fiber at index 0 always nil */ G.num_fibers = 1; /* Fiber at index 0 always nil */