fiber testing
This commit is contained in:
parent
53f38271e6
commit
e2a0d38e70
@ -7,7 +7,7 @@
|
||||
|
||||
#if PROFILING
|
||||
|
||||
#define PROFILING_SYSTEM_TRACE 1
|
||||
#define PROFILING_SYSTEM_TRACE 0
|
||||
#define PROFILING_CAPTURE_FRAME_IMAGE 0
|
||||
#define PROFILING_LOCKS 0
|
||||
#define PROFILING_D3D 1
|
||||
|
||||
142
src/sys_win32.c
142
src/sys_win32.c
@ -116,6 +116,39 @@ struct win32_window {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define MAX_COUNTERS 4096
|
||||
|
||||
struct alignas(64) counter {
|
||||
/* =================================================== */
|
||||
i32 id; /* 4 bytes */
|
||||
struct atomic_i32 value; /* 4 bytes */
|
||||
/* =================================================== */
|
||||
u8 _pad1[8]; /* 8 bytes (padding) */
|
||||
/* =================================================== */
|
||||
u8 _pad2[8]; /* 8 bytes (padding) */
|
||||
/* =================================================== */
|
||||
u8 _pad3[8]; /* 8 bytes (padding) */
|
||||
/* =================================================== */
|
||||
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 */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define FIBER_NAME_PREFIX_CSTR "Fiber #"
|
||||
#define FIBER_NAME_MAX_SIZE 64
|
||||
|
||||
@ -142,9 +175,12 @@ struct alignas(64) fiber {
|
||||
void *job_sig; /* 8 bytes */
|
||||
/* =================================================== */
|
||||
i32 job_id; /* 4 bytes */
|
||||
enum yield_kind yield_kind; /* 4 bytes */
|
||||
i32 job_priority; /* 4 bytes */
|
||||
/* =================================================== */
|
||||
u8 _pad[16]; /* 8 bytes (padding) */
|
||||
enum yield_kind yield_kind; /* 4 bytes */
|
||||
u8 _pad0[4]; /* 4 bytes (padding) */
|
||||
/* =================================================== */
|
||||
u8 _pad1[8]; /* 8 bytes (padding) */
|
||||
};
|
||||
STATIC_ASSERT(sizeof(struct fiber) == 64); /* Assume fiber fits in one cache line (increase if necessary) */
|
||||
STATIC_ASSERT(alignof(struct fiber) == 64); /* Avoid false sharing */
|
||||
@ -153,12 +189,23 @@ struct alignas(64) fiber_ctx {
|
||||
/* ==================================================== */
|
||||
struct sys_scratch_ctx scratch_ctx; /* 16 bytes */
|
||||
/* ==================================================== */
|
||||
u8 _pad[40]; /* 40 bytes (padding) */
|
||||
u8 _pad0[8]; /* 8 bytes (padding) */
|
||||
/* ==================================================== */
|
||||
u8 _pad1[8]; /* 8 bytes (padding) */
|
||||
/* ==================================================== */
|
||||
u8 _pad2[8]; /* 8 bytes (padding) */
|
||||
/* ==================================================== */
|
||||
u8 _pad3[8]; /* 8 bytes (padding) */
|
||||
/* ==================================================== */
|
||||
u8 _pad4[8]; /* 8 bytes (padding) */
|
||||
};
|
||||
STATIC_ASSERT(sizeof(struct fiber_ctx) == 64); /* Assume ctx fits in one cache line (increase if necessary) */
|
||||
STATIC_ASSERT(alignof(struct fiber_ctx) == 64); /* Avoid false sharing */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct alignas(64) runner_ctx {
|
||||
i32 id;
|
||||
HANDLE sleep_timer;
|
||||
@ -174,16 +221,6 @@ struct job_info {
|
||||
struct job_info *next;
|
||||
};
|
||||
|
||||
struct alignas(64) job_queue {
|
||||
struct atomic_i32 lock;
|
||||
struct arena *arena;
|
||||
|
||||
struct job_info *first;
|
||||
struct job_info *last;
|
||||
|
||||
struct job_info *first_free;
|
||||
};
|
||||
|
||||
enum job_queue_kind {
|
||||
JOB_QUEUE_KIND_HIGH_PRIORITY,
|
||||
JOB_QUEUE_KIND_NORMAL_PRIORITY,
|
||||
@ -192,7 +229,17 @@ enum job_queue_kind {
|
||||
NUM_JOB_QUEUE_KINDS
|
||||
};
|
||||
|
||||
struct alignas(64) job_queue {
|
||||
enum job_queue_kind kind;
|
||||
|
||||
struct atomic_i32 lock;
|
||||
struct arena *arena;
|
||||
|
||||
struct job_info *first;
|
||||
struct job_info *last;
|
||||
|
||||
struct job_info *first_free;
|
||||
};
|
||||
|
||||
/* ========================== *
|
||||
* Global state
|
||||
@ -247,11 +294,22 @@ GLOBAL struct {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Counters */
|
||||
i32 num_counters;
|
||||
struct atomic_i32 counters_lock; /* TODO: Prevent false sharing */
|
||||
i32 first_free_counter_id;
|
||||
struct counter counters[MAX_COUNTERS];
|
||||
|
||||
/* Fibers */
|
||||
i32 num_fibers;
|
||||
i32 first_free_fiber_id;
|
||||
struct arena *fiber_names_arena;
|
||||
alignas(64) struct atomic_i32 fibers_lock;
|
||||
struct atomic_i32 fibers_lock; /* TODO: Prevent false sharing */
|
||||
struct fiber fibers[SYS_MAX_FIBERS];
|
||||
struct fiber_ctx fiber_contexts[SYS_MAX_FIBERS];
|
||||
|
||||
@ -259,17 +317,23 @@ GLOBAL struct {
|
||||
struct job_queue job_queues[NUM_JOB_QUEUE_KINDS];
|
||||
|
||||
/* Runners */
|
||||
struct atomic_i32 runners_shutdown;
|
||||
struct atomic_i32 runners_shutdown; /* TODO: Prevent false sharing */
|
||||
i32 num_runner_threads;
|
||||
struct arena *runner_threads_arena;
|
||||
struct sys_thread **runner_threads;
|
||||
struct runner_ctx *runner_contexts;
|
||||
|
||||
struct atomic_i32 runner_wake_gen;
|
||||
|
||||
} G = ZI, DEBUG_ALIAS(G, G_sys_win32);
|
||||
|
||||
|
||||
|
||||
|
||||
/* ========================== *
|
||||
* Counters
|
||||
* ========================== */
|
||||
|
||||
|
||||
|
||||
/* ========================== *
|
||||
* Fibers
|
||||
* ========================== */
|
||||
@ -346,6 +410,7 @@ INTERNAL struct fiber *fiber_alloc(enum fiber_kind kind)
|
||||
fiber->job_func = 0;
|
||||
fiber->job_sig = 0;
|
||||
fiber->job_id = 0;
|
||||
fiber->job_priority = 0;
|
||||
fiber->yield_kind = 0;
|
||||
fiber->parent_id = 0;
|
||||
return fiber;
|
||||
@ -405,9 +470,10 @@ void sys_yield(void)
|
||||
|
||||
void sys_run(i32 count, sys_job_func *func, enum sys_job_priority priority)
|
||||
{
|
||||
//priority = min_i32(priority, current_fiber_job_priority); /* Jobs can't create higher priority jobs */
|
||||
if (count >= 1 && func && priority >= 0 && priority < NUM_SYS_JOB_PRIORITIES) {
|
||||
STATIC_ASSERT((i32)NUM_SYS_JOB_PRIORITIES == (i32)NUM_JOB_QUEUE_KINDS); /* Enums must have 1:1 mapping */
|
||||
if (count > 0) {
|
||||
struct fiber *fiber = fiber_from_id(sys_current_fiber_id());
|
||||
priority = clamp_i32(priority, fiber->job_priority, SYS_JOB_PRIORITY_BACKGROUND); /* A job cannot create a job with a higher priority than itself */
|
||||
STATIC_ASSERT((i32)NUM_SYS_JOB_PRIORITIES == (i32)NUM_JOB_QUEUE_KINDS); /* Priority & queue kind enums must have 1:1 mapping */
|
||||
enum job_queue_kind queue_kind = (enum job_queue_kind)priority;
|
||||
struct job_queue *queue = &G.job_queues[queue_kind];
|
||||
while (atomic_i32_fetch_test_set(&queue->lock, 0, 1) != 0) ix_pause();
|
||||
@ -417,8 +483,9 @@ void sys_run(i32 count, sys_job_func *func, enum sys_job_priority priority)
|
||||
info = queue->first_free;
|
||||
queue->first_free = info->next;
|
||||
} else {
|
||||
info = arena_push(queue->arena, struct job_info);
|
||||
info = arena_push_no_zero(queue->arena, struct job_info);
|
||||
}
|
||||
MEMZERO_STRUCT(info);
|
||||
info->count = count;
|
||||
info->func = func;
|
||||
if (queue->last) {
|
||||
@ -429,9 +496,6 @@ void sys_run(i32 count, sys_job_func *func, enum sys_job_priority priority)
|
||||
queue->last = info;
|
||||
}
|
||||
atomic_i32_fetch_set(&queue->lock, 0);
|
||||
} else {
|
||||
/* Invalid job parameters */
|
||||
sys_panic(LIT("Invalid job parameters"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -451,7 +515,6 @@ INTERNAL SYS_JOB_DEF(bla_job, job)
|
||||
Sleep(20);
|
||||
}
|
||||
|
||||
|
||||
/* ========================== *
|
||||
* Job fiber func
|
||||
* ========================== */
|
||||
@ -497,8 +560,11 @@ INTERNAL SYS_THREAD_DEF(runner_entry, runner_ctx_arg)
|
||||
queues[i] = &G.job_queues[i];
|
||||
}
|
||||
|
||||
struct fiber *job_fiber = NULL;
|
||||
|
||||
while (!atomic_i32_fetch(&G.runners_shutdown)) {
|
||||
/* Pull job from queue */
|
||||
enum sys_job_priority job_priority = 0;
|
||||
i32 job_id = 0;
|
||||
sys_job_func *job_func = 0;
|
||||
void *job_sig = 0;
|
||||
@ -512,6 +578,8 @@ INTERNAL SYS_THREAD_DEF(runner_entry, runner_ctx_arg)
|
||||
job_id = info->num_dispatched++;
|
||||
if (job_id < info->count) {
|
||||
/* Pick job */
|
||||
STATIC_ASSERT((i32)NUM_SYS_JOB_PRIORITIES == (i32)NUM_JOB_QUEUE_KINDS); /* Priority & queue kind enums must have 1:1 mapping */
|
||||
job_priority = (enum sys_job_priority)queue->kind;
|
||||
job_func = info->func;
|
||||
job_sig = info->sig;
|
||||
if (job_id == (info->count - 1)) {
|
||||
@ -533,15 +601,18 @@ INTERNAL SYS_THREAD_DEF(runner_entry, runner_ctx_arg)
|
||||
/* Execute fiber */
|
||||
if (job_func) {
|
||||
__profscope(Execute fiber);
|
||||
struct fiber *fiber = fiber_alloc(FIBER_KIND_JOB_RUNNER);
|
||||
fiber->job_func = job_func;
|
||||
fiber->job_sig = job_sig;
|
||||
fiber->job_id = job_id;
|
||||
fiber->parent_id = runner_fiber_id;
|
||||
if (!job_fiber) {
|
||||
job_fiber = fiber_alloc(FIBER_KIND_JOB_RUNNER);
|
||||
}
|
||||
job_fiber->job_func = job_func;
|
||||
job_fiber->job_sig = job_sig;
|
||||
job_fiber->job_id = job_id;
|
||||
job_fiber->job_priority = job_priority;
|
||||
job_fiber->parent_id = runner_fiber_id;
|
||||
b32 done = false;
|
||||
while (!done) {
|
||||
SwitchToFiber(fiber->addr);
|
||||
enum yield_kind yield_kind = fiber->yield_kind;
|
||||
SwitchToFiber(job_fiber->addr);
|
||||
enum yield_kind yield_kind = job_fiber->yield_kind;
|
||||
switch (yield_kind) {
|
||||
default:
|
||||
{
|
||||
@ -557,7 +628,8 @@ INTERNAL SYS_THREAD_DEF(runner_entry, runner_ctx_arg)
|
||||
|
||||
case YIELD_KIND_DONE:
|
||||
{
|
||||
fiber_release(fiber, fiber->id);
|
||||
/* TODO: remove this */
|
||||
(UNUSED)fiber_release;
|
||||
done = true;
|
||||
} break;
|
||||
}
|
||||
@ -574,6 +646,7 @@ INTERNAL SYS_THREAD_DEF(test_entry, _)
|
||||
/* Init job queues */
|
||||
for (u32 i = 0; i < countof(G.job_queues); ++i) {
|
||||
struct job_queue *queue = &G.job_queues[i];
|
||||
queue->kind = (enum job_queue_kind)i;
|
||||
queue->arena = arena_alloc(GIGABYTE(64));
|
||||
}
|
||||
|
||||
@ -2826,6 +2899,9 @@ 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 */
|
||||
|
||||
/* Init fibers */
|
||||
G.num_fibers = 1; /* Fiber at index 0 always nil */
|
||||
G.fiber_names_arena = arena_alloc(GIGABYTE(64));
|
||||
|
||||
13
src/user.c
13
src/user.c
@ -192,8 +192,8 @@ GLOBAL READONLY enum user_bind_kind g_binds[SYS_BTN_COUNT] = {
|
||||
|
||||
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(user_shutdown);
|
||||
INTERNAL LOG_EVENT_CALLBACK_FUNC_DEF(debug_console_log_callback, log);
|
||||
INTERNAL JOB_DEF(user_job, _);
|
||||
INTERNAL JOB_DEF(local_sim_job , _);
|
||||
INTERNAL SYS_JOB_DEF(user_job, _);
|
||||
INTERNAL SYS_JOB_DEF(local_sim_job , _);
|
||||
INTERNAL SYS_WINDOW_EVENT_CALLBACK_FUNC_DEF(window_event_callback, event);
|
||||
|
||||
struct user_startup_receipt user_startup(struct gp_startup_receipt *gp_sr,
|
||||
@ -259,8 +259,13 @@ struct user_startup_receipt user_startup(struct gp_startup_receipt *gp_sr,
|
||||
sys_window_register_event_callback(G.window, &window_event_callback);
|
||||
|
||||
/* Start jobs */
|
||||
#if 0
|
||||
job_dispatch_pinned(APP_DEDICATED_WORKER_ID_SIM, local_sim_job, NULL);
|
||||
job_dispatch_pinned(APP_DEDICATED_WORKER_ID_USER, user_job, NULL);
|
||||
#else
|
||||
sys_run(1, local_sim_job, SYS_JOB_PRIORITY_HIGH);
|
||||
sys_run(1, user_job, SYS_JOB_PRIORITY_HIGH);
|
||||
#endif
|
||||
app_register_exit_callback(&user_shutdown);
|
||||
|
||||
return (struct user_startup_receipt) { 0 };
|
||||
@ -2092,7 +2097,7 @@ INTERNAL void user_update(void)
|
||||
* User thread
|
||||
* ========================== */
|
||||
|
||||
INTERNAL JOB_DEF(user_job, _)
|
||||
INTERNAL SYS_JOB_DEF(user_job, _)
|
||||
{
|
||||
(UNUSED)_;
|
||||
i64 last_frame_ns = 0;
|
||||
@ -2181,7 +2186,7 @@ struct sim_decode_queue {
|
||||
};
|
||||
|
||||
|
||||
INTERNAL JOB_DEF(local_sim_job, _)
|
||||
INTERNAL SYS_JOB_DEF(local_sim_job, _)
|
||||
{
|
||||
(UNUSED)_;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user