allocate counters in sys layer
This commit is contained in:
parent
ca5c1d6ee3
commit
5e99224b28
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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 */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user