diff --git a/src/prof_tracy.h b/src/prof_tracy.h index 125ce687..1a08dc11 100644 --- a/src/prof_tracy.h +++ b/src/prof_tracy.h @@ -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 diff --git a/src/sys_win32.c b/src/sys_win32.c index c1a1b1a0..7598bb86 100644 --- a/src/sys_win32.c +++ b/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)); diff --git a/src/user.c b/src/user.c index 9d4a3315..12e45626 100644 --- a/src/user.c +++ b/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)_;