fiber testing
This commit is contained in:
parent
53f38271e6
commit
e2a0d38e70
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#if PROFILING
|
#if PROFILING
|
||||||
|
|
||||||
#define PROFILING_SYSTEM_TRACE 1
|
#define PROFILING_SYSTEM_TRACE 0
|
||||||
#define PROFILING_CAPTURE_FRAME_IMAGE 0
|
#define PROFILING_CAPTURE_FRAME_IMAGE 0
|
||||||
#define PROFILING_LOCKS 0
|
#define PROFILING_LOCKS 0
|
||||||
#define PROFILING_D3D 1
|
#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_PREFIX_CSTR "Fiber #"
|
||||||
#define FIBER_NAME_MAX_SIZE 64
|
#define FIBER_NAME_MAX_SIZE 64
|
||||||
|
|
||||||
@ -142,9 +175,12 @@ struct alignas(64) fiber {
|
|||||||
void *job_sig; /* 8 bytes */
|
void *job_sig; /* 8 bytes */
|
||||||
/* =================================================== */
|
/* =================================================== */
|
||||||
i32 job_id; /* 4 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(sizeof(struct fiber) == 64); /* Assume fiber fits in one cache line (increase if necessary) */
|
||||||
STATIC_ASSERT(alignof(struct fiber) == 64); /* Avoid false sharing */
|
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 */
|
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(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 */
|
STATIC_ASSERT(alignof(struct fiber_ctx) == 64); /* Avoid false sharing */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct alignas(64) runner_ctx {
|
struct alignas(64) runner_ctx {
|
||||||
i32 id;
|
i32 id;
|
||||||
HANDLE sleep_timer;
|
HANDLE sleep_timer;
|
||||||
@ -174,16 +221,6 @@ struct job_info {
|
|||||||
struct job_info *next;
|
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 {
|
enum job_queue_kind {
|
||||||
JOB_QUEUE_KIND_HIGH_PRIORITY,
|
JOB_QUEUE_KIND_HIGH_PRIORITY,
|
||||||
JOB_QUEUE_KIND_NORMAL_PRIORITY,
|
JOB_QUEUE_KIND_NORMAL_PRIORITY,
|
||||||
@ -192,7 +229,17 @@ enum job_queue_kind {
|
|||||||
NUM_JOB_QUEUE_KINDS
|
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
|
* 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 */
|
/* Fibers */
|
||||||
i32 num_fibers;
|
i32 num_fibers;
|
||||||
i32 first_free_fiber_id;
|
i32 first_free_fiber_id;
|
||||||
struct arena *fiber_names_arena;
|
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 fibers[SYS_MAX_FIBERS];
|
||||||
struct fiber_ctx fiber_contexts[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];
|
struct job_queue job_queues[NUM_JOB_QUEUE_KINDS];
|
||||||
|
|
||||||
/* Runners */
|
/* Runners */
|
||||||
struct atomic_i32 runners_shutdown;
|
struct atomic_i32 runners_shutdown; /* TODO: Prevent false sharing */
|
||||||
i32 num_runner_threads;
|
i32 num_runner_threads;
|
||||||
struct arena *runner_threads_arena;
|
struct arena *runner_threads_arena;
|
||||||
struct sys_thread **runner_threads;
|
struct sys_thread **runner_threads;
|
||||||
struct runner_ctx *runner_contexts;
|
struct runner_ctx *runner_contexts;
|
||||||
|
|
||||||
struct atomic_i32 runner_wake_gen;
|
|
||||||
|
|
||||||
} G = ZI, DEBUG_ALIAS(G, G_sys_win32);
|
} G = ZI, DEBUG_ALIAS(G, G_sys_win32);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Counters
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Fibers
|
* Fibers
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -346,6 +410,7 @@ INTERNAL struct fiber *fiber_alloc(enum fiber_kind kind)
|
|||||||
fiber->job_func = 0;
|
fiber->job_func = 0;
|
||||||
fiber->job_sig = 0;
|
fiber->job_sig = 0;
|
||||||
fiber->job_id = 0;
|
fiber->job_id = 0;
|
||||||
|
fiber->job_priority = 0;
|
||||||
fiber->yield_kind = 0;
|
fiber->yield_kind = 0;
|
||||||
fiber->parent_id = 0;
|
fiber->parent_id = 0;
|
||||||
return fiber;
|
return fiber;
|
||||||
@ -405,9 +470,10 @@ void sys_yield(void)
|
|||||||
|
|
||||||
void sys_run(i32 count, sys_job_func *func, enum sys_job_priority priority)
|
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 > 0) {
|
||||||
if (count >= 1 && func && priority >= 0 && priority < NUM_SYS_JOB_PRIORITIES) {
|
struct fiber *fiber = fiber_from_id(sys_current_fiber_id());
|
||||||
STATIC_ASSERT((i32)NUM_SYS_JOB_PRIORITIES == (i32)NUM_JOB_QUEUE_KINDS); /* Enums must have 1:1 mapping */
|
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;
|
enum job_queue_kind queue_kind = (enum job_queue_kind)priority;
|
||||||
struct job_queue *queue = &G.job_queues[queue_kind];
|
struct job_queue *queue = &G.job_queues[queue_kind];
|
||||||
while (atomic_i32_fetch_test_set(&queue->lock, 0, 1) != 0) ix_pause();
|
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;
|
info = queue->first_free;
|
||||||
queue->first_free = info->next;
|
queue->first_free = info->next;
|
||||||
} else {
|
} 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->count = count;
|
||||||
info->func = func;
|
info->func = func;
|
||||||
if (queue->last) {
|
if (queue->last) {
|
||||||
@ -429,9 +496,6 @@ void sys_run(i32 count, sys_job_func *func, enum sys_job_priority priority)
|
|||||||
queue->last = info;
|
queue->last = info;
|
||||||
}
|
}
|
||||||
atomic_i32_fetch_set(&queue->lock, 0);
|
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);
|
Sleep(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Job fiber func
|
* Job fiber func
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -497,8 +560,11 @@ INTERNAL SYS_THREAD_DEF(runner_entry, runner_ctx_arg)
|
|||||||
queues[i] = &G.job_queues[i];
|
queues[i] = &G.job_queues[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct fiber *job_fiber = NULL;
|
||||||
|
|
||||||
while (!atomic_i32_fetch(&G.runners_shutdown)) {
|
while (!atomic_i32_fetch(&G.runners_shutdown)) {
|
||||||
/* Pull job from queue */
|
/* Pull job from queue */
|
||||||
|
enum sys_job_priority job_priority = 0;
|
||||||
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;
|
||||||
@ -512,6 +578,8 @@ INTERNAL SYS_THREAD_DEF(runner_entry, runner_ctx_arg)
|
|||||||
job_id = info->num_dispatched++;
|
job_id = info->num_dispatched++;
|
||||||
if (job_id < info->count) {
|
if (job_id < info->count) {
|
||||||
/* Pick job */
|
/* 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_func = info->func;
|
||||||
job_sig = info->sig;
|
job_sig = info->sig;
|
||||||
if (job_id == (info->count - 1)) {
|
if (job_id == (info->count - 1)) {
|
||||||
@ -533,15 +601,18 @@ INTERNAL SYS_THREAD_DEF(runner_entry, runner_ctx_arg)
|
|||||||
/* Execute fiber */
|
/* Execute fiber */
|
||||||
if (job_func) {
|
if (job_func) {
|
||||||
__profscope(Execute fiber);
|
__profscope(Execute fiber);
|
||||||
struct fiber *fiber = fiber_alloc(FIBER_KIND_JOB_RUNNER);
|
if (!job_fiber) {
|
||||||
fiber->job_func = job_func;
|
job_fiber = fiber_alloc(FIBER_KIND_JOB_RUNNER);
|
||||||
fiber->job_sig = job_sig;
|
}
|
||||||
fiber->job_id = job_id;
|
job_fiber->job_func = job_func;
|
||||||
fiber->parent_id = runner_fiber_id;
|
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;
|
b32 done = false;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
SwitchToFiber(fiber->addr);
|
SwitchToFiber(job_fiber->addr);
|
||||||
enum yield_kind yield_kind = fiber->yield_kind;
|
enum yield_kind yield_kind = job_fiber->yield_kind;
|
||||||
switch (yield_kind) {
|
switch (yield_kind) {
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@ -557,7 +628,8 @@ INTERNAL SYS_THREAD_DEF(runner_entry, runner_ctx_arg)
|
|||||||
|
|
||||||
case YIELD_KIND_DONE:
|
case YIELD_KIND_DONE:
|
||||||
{
|
{
|
||||||
fiber_release(fiber, fiber->id);
|
/* TODO: remove this */
|
||||||
|
(UNUSED)fiber_release;
|
||||||
done = true;
|
done = true;
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
@ -574,6 +646,7 @@ INTERNAL SYS_THREAD_DEF(test_entry, _)
|
|||||||
/* Init job queues */
|
/* Init job queues */
|
||||||
for (u32 i = 0; i < countof(G.job_queues); ++i) {
|
for (u32 i = 0; i < countof(G.job_queues); ++i) {
|
||||||
struct job_queue *queue = &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));
|
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);
|
__profthread("Main thread", PROF_THREAD_GROUP_MAIN);
|
||||||
|
|
||||||
|
/* Init counters */
|
||||||
|
G.num_counters = 1; /* Counter at index 0 always nil */
|
||||||
|
|
||||||
/* Init fibers */
|
/* Init fibers */
|
||||||
G.num_fibers = 1; /* Fiber at index 0 always nil */
|
G.num_fibers = 1; /* Fiber at index 0 always nil */
|
||||||
G.fiber_names_arena = arena_alloc(GIGABYTE(64));
|
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 APP_EXIT_CALLBACK_FUNC_DEF(user_shutdown);
|
||||||
INTERNAL LOG_EVENT_CALLBACK_FUNC_DEF(debug_console_log_callback, log);
|
INTERNAL LOG_EVENT_CALLBACK_FUNC_DEF(debug_console_log_callback, log);
|
||||||
INTERNAL JOB_DEF(user_job, _);
|
INTERNAL SYS_JOB_DEF(user_job, _);
|
||||||
INTERNAL JOB_DEF(local_sim_job , _);
|
INTERNAL SYS_JOB_DEF(local_sim_job , _);
|
||||||
INTERNAL SYS_WINDOW_EVENT_CALLBACK_FUNC_DEF(window_event_callback, event);
|
INTERNAL SYS_WINDOW_EVENT_CALLBACK_FUNC_DEF(window_event_callback, event);
|
||||||
|
|
||||||
struct user_startup_receipt user_startup(struct gp_startup_receipt *gp_sr,
|
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);
|
sys_window_register_event_callback(G.window, &window_event_callback);
|
||||||
|
|
||||||
/* Start jobs */
|
/* Start jobs */
|
||||||
|
#if 0
|
||||||
job_dispatch_pinned(APP_DEDICATED_WORKER_ID_SIM, local_sim_job, NULL);
|
job_dispatch_pinned(APP_DEDICATED_WORKER_ID_SIM, local_sim_job, NULL);
|
||||||
job_dispatch_pinned(APP_DEDICATED_WORKER_ID_USER, user_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);
|
app_register_exit_callback(&user_shutdown);
|
||||||
|
|
||||||
return (struct user_startup_receipt) { 0 };
|
return (struct user_startup_receipt) { 0 };
|
||||||
@ -2092,7 +2097,7 @@ INTERNAL void user_update(void)
|
|||||||
* User thread
|
* User thread
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL JOB_DEF(user_job, _)
|
INTERNAL SYS_JOB_DEF(user_job, _)
|
||||||
{
|
{
|
||||||
(UNUSED)_;
|
(UNUSED)_;
|
||||||
i64 last_frame_ns = 0;
|
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)_;
|
(UNUSED)_;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user