call resource callbacks in job

This commit is contained in:
jacob 2025-07-01 01:03:06 -05:00
parent fea0346982
commit 892daa5ed2
16 changed files with 177 additions and 100 deletions

BIN
res/sprite/tim.ase (Stored with Git LFS)

Binary file not shown.

View File

@ -236,13 +236,13 @@ void app_entry_point(struct string args_str)
i32 worker_count;
{
/* FIXME: Switch this on to utilize all cores. Only decreasing worker count for testing purposes. */
#if !PROFILING && !RTC || 1
i32 min_worker_count = min_i32(NUM_APP_DEDICATED_WORKERS + 2, JOB_MIN_WORKERS);
#if !PROFILING && !RTC
i32 max_worker_count = JOB_MAX_WORKERS;
i32 min_worker_count = clamp_i32(NUM_APP_DEDICATED_WORKERS + 2, JOB_MIN_WORKERS, max_worker_count);
i32 target_worker_count = (i32)sys_num_logical_processors() * 0.75;
worker_count = clamp_i32(target_worker_count, min_worker_count, max_worker_count);
#else
worker_count = 8;
worker_count = 5;
#endif
}

View File

@ -76,7 +76,7 @@ void *arena_push_bytes_no_zero(struct arena *arena, u64 size, u64 align)
u64 new_pos = aligned_start_pos + size;
if (new_pos > arena->committed) {
__profscope(_arena_push_bytes_COMMIT);
__profscope(Arena commit);
/* Commit new block(s) */
u64 blocks_needed = (new_pos - arena->committed + ARENA_BLOCK_SIZE - 1) / ARENA_BLOCK_SIZE;
u64 commit_bytes = blocks_needed * ARENA_BLOCK_SIZE;

View File

@ -732,7 +732,7 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct stri
}
{
__profscope(assemble_image);
__profscope(Build image from cels);
/* Assemble image from cels */
for (struct cel *cel = cel_head; cel; cel = cel->next) {

View File

@ -653,7 +653,7 @@ struct host_event_list host_update_begin(struct arena *arena, struct host *host)
i64 now_ns = sys_time_ns();
{
__profscope(host_update_read_packets);
__profscope(Read host packets);
struct string read_buff = ZI;
read_buff.len = PACKET_DATA_MAX_LEN;
read_buff.text = arena_push_array_no_zero(scratch.arena, u8, read_buff.len);
@ -829,7 +829,7 @@ struct host_event_list host_update_begin(struct arena *arena, struct host *host)
/* Update channels */
{
__profscope(host_update_channels);
__profscope(Update host channels);
for (u64 i = 0; i < host->num_channels_reserved; ++i) {
struct host_channel *channel = &host->channels[i];
if (channel->valid) {
@ -903,7 +903,7 @@ void host_update_end(struct host *host)
/* Process cmds into sendable packets */
/* TODO: Unreliable packets don't need to be allocated into unreliable packet queue, should just send them and forget */
{
__profscope(host_update_process_cmds);
__profscope(Process host cmds);
for (struct host_cmd *cmd = host->first_cmd; cmd; cmd = cmd->next) {
enum host_cmd_kind kind = cmd->kind;
struct host_channel_id channel_id = cmd->channel_id;
@ -1018,7 +1018,7 @@ void host_update_end(struct host *host)
/* Send packets */
/* TODO: Aggregate small packets */
{
__profscope(host_update_send_packets);
__profscope(Send host packets);
for (u64 i = 0; i < host->num_channels_reserved; ++i) {
struct sock *sock = host->sock;
struct host_channel *channel = &host->channels[i];

View File

@ -236,17 +236,27 @@ INTERNAL struct job_handle job_dispatch_ex(struct job_desc desc)
/* Queue job */
if (job_queue) {
__profscope(Queue);
__profscope(Queue job);
struct sys_lock lock = sys_mutex_lock_e(G.queued_jobs_mutex);
{
/* Push to queue */
{
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
if (job_queue->last) {
job_queue->last->next = job;
} else {
job_queue->first = job;
}
job->prev = job_queue->last;
job_queue->last = job;
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
}
++G.queue_submit_gen;
/* Signal workers */
@ -272,8 +282,12 @@ INTERNAL struct job_handle job_dispatch_ex(struct job_desc desc)
while (!stop) {
/* Remove job from queue */
if (job_queue && job_id == (job_count - 1)) {
__profscope(Dequeue job);
struct sys_lock queue_lock = sys_mutex_lock_e(G.queued_jobs_mutex);
{
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
struct worker_job *prev = job->prev;
struct worker_job *next = job->next;
if (prev) {
@ -286,11 +300,15 @@ INTERNAL struct job_handle job_dispatch_ex(struct job_desc desc)
} else {
job_queue->last = prev;
}
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
}
sys_mutex_unlock(&queue_lock);
}
/* Run */
{
__profscope(Run job);
data.id = job_id;
job_func(data);
}
@ -313,8 +331,12 @@ INTERNAL struct job_handle job_dispatch_ex(struct job_desc desc)
}
}
if (should_release) {
__profscope(Release job);
struct sys_lock fj_lock = sys_mutex_lock_e(G.free_jobs_mutex);
{
if (job->queue && (job->queue->first == job || job->queue->last == job)) {
DEBUGBREAK;
}
job->next_free = G.first_free_job;
G.first_free_job = job;
}
@ -326,7 +348,7 @@ INTERNAL struct job_handle job_dispatch_ex(struct job_desc desc)
/* Wait for job completion */
if (wait && !is_done) {
__profscope(Wait for job);
struct sys_lock lock = sys_mutex_lock_s(job->mutex);
struct sys_lock lock = sys_mutex_lock_e(job->mutex);
is_done = atomic_u64_eval(&job->gen) != handle.gen;
while (!is_done) {
sys_condition_variable_wait(job->gen_cv, &lock);
@ -411,6 +433,9 @@ void job_wait(struct job_handle handle)
__profscope(Dequeue job);
struct sys_lock queue_lock = sys_mutex_lock_e(G.queued_jobs_mutex);
{
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
struct worker_job *prev = job->prev;
struct worker_job *next = job->next;
if (prev) {
@ -423,6 +448,9 @@ void job_wait(struct job_handle handle)
} else {
job_queue->last = prev;
}
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
}
sys_mutex_unlock(&queue_lock);
}
@ -451,6 +479,9 @@ void job_wait(struct job_handle handle)
__profscope(Release job);
struct sys_lock fj_lock = sys_mutex_lock_e(G.free_jobs_mutex);
{
if (job->queue && (job->queue->first == job || job->queue->last == job)) {
DEBUGBREAK;
}
job->next_free = G.first_free_job;
G.first_free_job = job;
}
@ -462,7 +493,7 @@ void job_wait(struct job_handle handle)
/* Wait for job completion */
if (!is_done) {
__profscope(Wait for job);
struct sys_lock lock = sys_mutex_lock_s(job->mutex);
struct sys_lock lock = sys_mutex_lock_e(job->mutex);
is_done = atomic_u64_eval(&job->gen) != handle.gen;
while (!is_done) {
sys_condition_variable_wait(job->gen_cv, &lock);
@ -485,7 +516,7 @@ INTERNAL SYS_THREAD_DEF(worker_thread_entry_point, thread_arg)
struct worker_ctx *ctx = thread_local_var_eval(&tl_worker_ctx);
ctx->worker_id = worker_id;
struct worker_job_queues *queues[] = { &G.pinned_queues[worker_id], &G.global_queue };
struct worker_job_queue *queues[] = { &G.pinned_queues[worker_id], &G.global_queue };
u64 seen_queue_submit_gen = 0;
struct sys_lock queue_lock = sys_mutex_lock_s(G.queued_jobs_mutex);
@ -503,7 +534,7 @@ INTERNAL SYS_THREAD_DEF(worker_thread_entry_point, thread_arg)
queue_lock = sys_mutex_lock_s(G.queued_jobs_mutex);
{
seen_queue_submit_gen = G.queue_submit_gen;
for (i32 queue_index = 0; queue_index < ARRAY_COUNT(queues); ++queue_index) {
for (i32 queue_index = 0; queue_index < (i32)ARRAY_COUNT(queues); ++queue_index) {
struct worker_job_queue *queue = queues[queue_index];
struct worker_job *tmp = queue->first;
while (!job && tmp) {
@ -511,8 +542,6 @@ INTERNAL SYS_THREAD_DEF(worker_thread_entry_point, thread_arg)
{
i32 tmp_id = tmp->num_dispatched;
i32 tmp_count = tmp->count;
i32 tmp_pinned_worker = tmp->pinned_worker_id;
b32 tmp_is_pinned_to_worker = tmp_pinned_worker == worker_id;
if (tmp_id < tmp_count) {
/* Pick job */
++tmp->num_workers;
@ -537,6 +566,9 @@ INTERNAL SYS_THREAD_DEF(worker_thread_entry_point, thread_arg)
__profscope(Dequeue job);
queue_lock = sys_mutex_lock_e(G.queued_jobs_mutex);
{
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
struct worker_job *prev = job->prev;
struct worker_job *next = job->next;
if (prev) {
@ -549,6 +581,9 @@ INTERNAL SYS_THREAD_DEF(worker_thread_entry_point, thread_arg)
} else {
job_queue->last = prev;
}
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
}
sys_mutex_unlock(&queue_lock);
}

View File

@ -291,7 +291,7 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
/* Update & read mixes */
mixes = arena_push_array_no_zero(scratch.arena, struct mix *, G.track_playing_count);
for (struct track *track = G.track_first_playing; track; track = track->next) {
__profscope(prepare_track);
__profscope(Prepare track);
struct mix *mix = &track->mix;
mix->desc = track->desc;
mixes[mixes_count++] = mix;
@ -301,7 +301,7 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
}
for (u64 mix_index = 0; mix_index < mixes_count; ++mix_index) {
__profscope(mix_track);
__profscope(Mix track);
struct mix *mix = mixes[mix_index];
if (mix->source->pcm.count <= 0) {
@ -354,7 +354,7 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
/* Transform 16 bit source -> 32 bit stereo at output duration */
{
__profscope(resample);
__profscope(Resample);
f32 *out_samples = mix_pcm.samples;
u64 out_frames_count = mix_pcm.count / 2;
@ -408,7 +408,7 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
* ========================== */
if (desc.flags & MIXER_FLAG_SPATIALIZE) {
__profscope(spatialize);
__profscope(Spatialize);
/* Algorithm constants */
const f32 rolloff_height = 1.2f;
@ -469,7 +469,7 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
}
{
__profscope(update_track_effect_data);
__profscope(Update track effect data);
struct sys_lock lock = sys_mutex_lock_e(G.mutex);
for (u64 i = 0; i < mixes_count; ++i) {
struct mix *mix = mixes[i];

View File

@ -1254,7 +1254,7 @@ void phys_step(struct phys_step_ctx *ctx, f32 timestep)
f32 remaining_dt = timestep;
while (remaining_dt > 0) {
__profscope(step_part);
__profscope(Step part);
++phys_iteration;
struct arena_temp scratch = scratch_begin_no_conflict();
@ -1282,7 +1282,7 @@ void phys_step(struct phys_step_ctx *ctx, f32 timestep)
f32 substep_dt = step_dt / SIM_PHYSICS_SUBSTEPS;
for (u32 i = 0; i < SIM_PHYSICS_SUBSTEPS; ++i) {
__profscope(substep);
__profscope(Substep);
/* Warm start */
#if SIM_PHYSICS_ENABLE_WARM_STARTING

View File

@ -9,9 +9,12 @@
/* Include tracy client */
#define TRACY_ENABLE
#define TRACY_MANUAL_LIFETIME
#define TRACY_DELAYED_INIT
#if 1
#if 0
/* Enable manual lifetime */
# define TRACY_MANUAL_LIFETIME
# define TRACY_DELAYED_INIT
#endif
#if 0
/* Disable system tracing (very slow) */
# define TRACY_NO_CALLSTACK
# define TRACY_NO_SYSTEM_TRACING
@ -19,7 +22,7 @@
#include STRINGIZE(TRACY_INCLUDE_PATH)
#define PROFILING_CAPTURE_FRAME_IMAGE 0
#define PROFILING_LOCKS 0
#define PROFILING_LOCKS 1
#define PROFILING_D3D 1
#define PROFILING_CMD_WSTR L"tracy-profiler.exe -a 127.0.0.1"

View File

@ -4,6 +4,7 @@
#include "tar.h"
#include "incbin.h"
#include "util.h"
#include "job.h"
/* ========================== *
* Global data
@ -218,6 +219,20 @@ INTERNAL SYS_THREAD_DEF(resource_watch_monitor_thread_entry_point, _)
#define WATCH_DISPATCHER_DELAY_SECONDS 0.050
#define WATCH_DISPATCHER_DEDUP_DICT_BINS 128
struct resource_watch_callback_job_sig {
struct string name;
resource_watch_callback **callbacks;
};
INTERNAL JOB_DEF(resource_watch_callback_job, job)
{
__prof;
struct resource_watch_callback_job_sig *sig = job.sig;
struct string name = sig->name;
resource_watch_callback *callback = sig->callbacks[job.id];
callback(name);
}
INTERNAL SYS_THREAD_DEF(resource_watch_dispatcher_thread_entry_point, _)
{
(UNUSED)_;
@ -227,8 +242,10 @@ INTERNAL SYS_THREAD_DEF(resource_watch_dispatcher_thread_entry_point, _)
while (!atomic_i32_eval(&G.watch_shutdown)) {
sys_condition_variable_wait(G.watch_dispatcher_cv, &watch_dispatcher_lock);
if (!atomic_i32_eval(&G.watch_shutdown) && G.watch_dispatcher_info_arena->pos > 0) {
__profscope(Dispatch resource watch callbacks);
/* Unlock and sleep a bit so duplicate events pile up */
{
__profscope(Delay);
sys_mutex_unlock(&watch_dispatcher_lock);
sys_sleep(WATCH_DISPATCHER_DELAY_SECONDS);
watch_dispatcher_lock = sys_mutex_lock_e(G.watch_dispatcher_mutex);
@ -241,12 +258,25 @@ INTERNAL SYS_THREAD_DEF(resource_watch_dispatcher_thread_entry_point, _)
MEMZERO_STRUCT(&G.watch_dispatcher_info_list);
arena_reset(G.watch_dispatcher_info_arena);
/* Build callbacks array */
u64 num_callbacks = 0;
resource_watch_callback **callbacks = NULL;
struct sys_lock callbacks_lock = sys_mutex_lock_s(G.watch_callbacks_mutex);
{
num_callbacks = G.num_watch_callbacks;
callbacks = arena_push_array_no_zero(temp.arena, resource_watch_callback *, num_callbacks);
for (u64 i = 0; i < num_callbacks; ++i) {
callbacks[i] = G.watch_callbacks[i];
}
}
sys_mutex_unlock(&callbacks_lock);
/* Unlock and run callbacks */
sys_mutex_unlock(&watch_dispatcher_lock);
{
__profscope(run_resource_watch_callbacks);
struct dict *dedup_dict = dict_init(temp.arena, WATCH_DISPATCHER_DEDUP_DICT_BINS);
for (struct sys_watch_info *info = watch_info_list.first; info; info = info->next) {
__profscope(Dispatch);
/* Do not run callbacks for the same file more than once */
b32 skip = false;
u64 hash = hash_fnv64(HASH_FNV64_BASIS, info->name);
@ -256,12 +286,10 @@ INTERNAL SYS_THREAD_DEF(resource_watch_dispatcher_thread_entry_point, _)
dict_set(temp.arena, dedup_dict, hash, 1);
}
if (!skip) {
struct sys_lock callbacks_lock = sys_mutex_lock_s(G.watch_callbacks_mutex);
for (u64 i = 0; i < G.num_watch_callbacks; ++i) {
resource_watch_callback *callback = G.watch_callbacks[i];
callback(info->name);
}
sys_mutex_unlock(&callbacks_lock);
struct resource_watch_callback_job_sig sig = ZI;
sig.name = info->name;
sig.callbacks = callbacks;
job_dispatch_wait(num_callbacks, resource_watch_callback_job, &sig);
}
}
}

View File

@ -649,7 +649,7 @@ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_client *client, str
/* Blend entities */
{
__profscope(snapshot_lerp_entities);
__profscope(Lerp snapshot entities);
u64 num_entities = min_u64(ss0->num_ents_reserved, ss1->num_ents_reserved);
for (u64 i = 0; i < num_entities; ++i) {
struct sim_ent *e = &ss->ents[i];

View File

@ -153,11 +153,10 @@ GLOBAL struct {
/* Evictor thread */
struct atomic_i32 evictor_cycle;
b32 evictor_shutdown;
struct sys_mutex *evictor_mutex;
struct sys_condition_variable *evictor_cv;
struct sys_thread *evictor_thread;
b32 evictor_scheduler_shutdown;
struct sys_mutex *evictor_scheduler_mutex;
struct sys_condition_variable *evictor_scheduler_shutdown_cv;
struct sys_thread *evictor_scheduler_thread;
} G = ZI, DEBUG_ALIAS(G, G_sprite);
/* ========================== *
@ -204,7 +203,7 @@ INTERNAL struct image_rgba generate_purple_black_image(struct arena *arena, u32
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sprite_shutdown);
INTERNAL JOB_DEF(sprite_load_job, arg);
INTERNAL SYS_THREAD_DEF(sprite_evictor_thread_entry_point, arg);
INTERNAL SYS_THREAD_DEF(sprite_evictor_scheduler_thread_entry_point, arg);
#if RESOURCE_RELOADING
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, info);
@ -256,10 +255,10 @@ struct sprite_startup_receipt sprite_startup(struct gp_startup_receipt *gp_sr,
G.scopes_arena = arena_alloc(GIGABYTE(64));
G.evictor_mutex = sys_mutex_alloc();
G.evictor_cv = sys_condition_variable_alloc();
G.evictor_scheduler_mutex = sys_mutex_alloc();
G.evictor_scheduler_shutdown_cv = sys_condition_variable_alloc();
G.evictor_thread = sys_thread_alloc(sprite_evictor_thread_entry_point, NULL, LIT("[P2] Sprite evictor"));
G.evictor_scheduler_thread = sys_thread_alloc(sprite_evictor_scheduler_thread_entry_point, NULL, LIT("[P2] Sprite evictor scheduler"));
app_register_exit_callback(&sprite_shutdown);
resource_register_watch_callback(&sprite_resource_watch_callback);
@ -272,12 +271,12 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sprite_shutdown)
__prof;
/* Signal evictor shutdown */
{
struct sys_lock lock = sys_mutex_lock_e(G.evictor_mutex);
G.evictor_shutdown = true;
sys_condition_variable_broadcast(G.evictor_cv);
struct sys_lock lock = sys_mutex_lock_e(G.evictor_scheduler_mutex);
G.evictor_scheduler_shutdown = true;
sys_condition_variable_broadcast(G.evictor_scheduler_shutdown_cv);
sys_mutex_unlock(&lock);
}
sys_thread_wait_release(G.evictor_thread);
sys_thread_wait_release(G.evictor_scheduler_thread);
}
/* ========================== *
@ -430,7 +429,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
/* Init frames */
{
__profscope(init_frames);
__profscope(Init frames);
sheet.image_size = ase.image_size;
sheet.frame_size = ase.frame_size;
sheet.frames = arena_push_array(arena, struct sprite_sheet_frame, ase.num_frames);
@ -452,7 +451,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
/* Init spans */
sheet.spans_count = ase.num_spans;
if (ase.num_spans > 0) {
__profscope(init_spans);
__profscope(Init spans);
sheet.spans = arena_push_array(arena, struct sprite_sheet_span, sheet.spans_count);
sheet.spans_dict = dict_init(arena, (u64)(ase.num_spans * SHEET_SPAN_LOOKUP_TABLE_BIN_RATIO));
u64 index = 0;
@ -470,7 +469,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
/* Init slices */
if (ase.num_slice_keys > 0) {
__profscope(init_slices);
__profscope(Init slices);
struct arena_temp scratch = scratch_begin(arena);
struct temp_ase_slice_key_node {
@ -1209,7 +1208,7 @@ INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, name)
#endif
/* ========================== *
* Evictor thread
* Evictor job
* ========================== */
struct evict_node {
@ -1230,34 +1229,21 @@ INTERNAL SORT_COMPARE_FUNC_DEF(evict_sort, arg_a, arg_b, udata)
return (b_cycle > a_cycle) - (a_cycle > b_cycle);
}
/* NOTE:
* A cache node is safe from eviction as long as:
* - Its bin mutex is locked
* - Any references are held to the node (its refcount > 0)
*
* An attempt to evict a cache node will occur when:
* - Its refcount = 0 and
* - The cache is over its memory budget and the node's last reference is longer ago than the grace period
* - Resource reloading is enabled and the node is out of date due to a change to its original resource file
*/
INTERNAL SYS_THREAD_DEF(sprite_evictor_thread_entry_point, arg)
INTERNAL JOB_DEF(sprite_evictor_job, _)
{
(UNUSED)arg;
struct sys_lock evictor_lock = sys_mutex_lock_e(G.evictor_mutex);
while (!G.evictor_shutdown) {
struct arena_temp scratch = scratch_begin_no_conflict();
(UNUSED)_;
__prof;
struct arena_temp scratch = scratch_begin_no_conflict();
{
u64 evict_array_count = 0;
struct evict_node *evict_array = arena_push_dry(scratch.arena, struct evict_node);
if (!G.evictor_shutdown) {
{
i32 cur_cycle = atomic_i32_eval(&G.evictor_cycle);
/* Scan for evictable nodes */
b32 cache_over_budget_threshold = atomic_u64_eval(&G.cache.memory_usage) > CACHE_MEMORY_BUDGET_THRESHOLD;
if (cache_over_budget_threshold || RESOURCE_RELOADING) {
__profscope(eviction_scan);
__profscope(Evictor scan);
for (u64 i = 0; i < CACHE_BINS_COUNT; ++i) {
struct cache_bin *bin = &G.cache.bins[i];
struct sys_lock bin_lock = sys_mutex_lock_s(bin->mutex);
@ -1298,14 +1284,14 @@ INTERNAL SYS_THREAD_DEF(sprite_evictor_thread_entry_point, arg)
/* Sort evict nodes */
{
__profscope(eviction_sort);
__profscope(Evictor sort);
merge_sort(evict_array, evict_array_count, sizeof(*evict_array), evict_sort, NULL);
}
/* Remove evictable nodes from cache until under budget */
struct evict_node *first_evicted = NULL;
{
__profscope(eviction_cache_removal);
__profscope(Evictor cache removal);
b32 stop_evicting = false;
for (u64 i = 0; i < evict_array_count && !stop_evicting; ++i) {
struct evict_node *en = &evict_array[i];
@ -1351,7 +1337,7 @@ INTERNAL SYS_THREAD_DEF(sprite_evictor_thread_entry_point, arg)
if (first_evicted) {
/* Release evicted node memory */
{
__profscope(eviction_memory_release);
__profscope(Evictor memory release);
for (struct evict_node *en = first_evicted; en; en = en->next_evicted) {
struct cache_entry *n = en->cache_entry;
if (n->kind == CACHE_ENTRY_KIND_TEXTURE && n->texture->valid) {
@ -1363,7 +1349,7 @@ INTERNAL SYS_THREAD_DEF(sprite_evictor_thread_entry_point, arg)
/* Add evicted nodes to free list */
{
__profscope(eviction_free_list_append);
__profscope(Evictor free list append);
struct sys_lock pool_lock = sys_mutex_lock_e(G.cache.entry_pool_mutex);
for (struct evict_node *en = first_evicted; en; en = en->next_evicted) {
struct cache_entry *n = en->cache_entry;
@ -1376,9 +1362,28 @@ INTERNAL SYS_THREAD_DEF(sprite_evictor_thread_entry_point, arg)
}
atomic_i32_eval_add(&G.evictor_cycle, 1);
scratch_end(scratch);
}
/* Wait */
sys_condition_variable_wait_time(G.evictor_cv, &evictor_lock, SECONDS_FROM_NS(EVICTOR_CYCLE_INTERVAL_NS));
}
/* NOTE:
* A cache node is safe from eviction as long as:
* - Its bin mutex is locked
* - Any references are held to the node (its refcount > 0)
*
* An attempt to evict a cache node will occur when:
* - Its refcount = 0 and
* - The cache is over its memory budget and the node's last reference is longer ago than the grace period
* - Resource reloading is enabled and the node is out of date due to a change to its original resource file
*/
INTERNAL SYS_THREAD_DEF(sprite_evictor_scheduler_thread_entry_point, arg)
{
(UNUSED)arg;
struct sys_lock evictor_lock = sys_mutex_lock_e(G.evictor_scheduler_mutex);
while (!G.evictor_scheduler_shutdown) {
job_dispatch_wait(1, sprite_evictor_job, NULL);
sys_condition_variable_wait_time(G.evictor_scheduler_shutdown_cv, &evictor_lock, SECONDS_FROM_NS(EVICTOR_CYCLE_INTERVAL_NS));
}
sys_mutex_unlock(&evictor_lock);
}

View File

@ -282,6 +282,7 @@ struct sys_watch_info {
struct sys_watch_info_list {
struct sys_watch_info *first;
struct sys_watch_info *last;
u64 count;
};
struct sys_watch *sys_watch_alloc(struct string path);

View File

@ -418,7 +418,7 @@ struct sys_file sys_file_open_read_wait(struct string path)
HANDLE handle;
while ((handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_SHARING_VIOLATION) {
__profscope(file_share_conflict_delay);
__profscope(File share conflict delay);
Sleep(delay_ms);
if (delay_ms < 1024) {
delay_ms *= 2;
@ -800,11 +800,11 @@ struct sys_watch_info_list sys_watch_wait(struct arena *arena, struct sys_watch
if (list.last) {
list.last->next = info;
info->prev = list.last;
list.last = info;
} else {
list.first = info;
list.last = info;
}
list.last = info;
++list.count;
struct string16 name16 = ZI;
name16.text = res->FileName;
@ -856,6 +856,7 @@ struct sys_watch_info_list sys_watch_wait(struct arena *arena, struct sys_watch
}
}
} else if (wait_res == WAIT_OBJECT_0 + 1) {
ResetEvent(w32_watch->wake_handle);
done = true;
} else {
ASSERT(false);
@ -886,6 +887,7 @@ struct sys_watch_info_list sys_watch_info_copy(struct arena *arena, struct sys_w
dst_list.first = dst;
dst_list.last = dst;
}
dst_list.count = src_list.count;
}
return dst_list;
}
@ -1634,6 +1636,7 @@ void sys_mutex_release(struct sys_mutex *mutex)
struct sys_lock sys_mutex_lock_e(struct sys_mutex *mutex)
{
__prof;
struct win32_mutex *m = (struct win32_mutex *)mutex;
__proflock_before_exclusive_lock(m->profiling_ctx);
AcquireSRWLockExclusive((SRWLOCK *)&m->srwlock);
@ -1650,6 +1653,7 @@ struct sys_lock sys_mutex_lock_e(struct sys_mutex *mutex)
struct sys_lock sys_mutex_lock_s(struct sys_mutex *mutex)
{
__prof;
struct win32_mutex *m = (struct win32_mutex *)mutex;
__proflock_before_shared_lock(m->profiling_ctx);
AcquireSRWLockShared((SRWLOCK *)&m->srwlock);
@ -1664,6 +1668,7 @@ struct sys_lock sys_mutex_lock_s(struct sys_mutex *mutex)
void sys_mutex_unlock(struct sys_lock *lock)
{
__prof;
struct win32_mutex *m = (struct win32_mutex *)lock->mutex;
#if RTC
atomic_i64_eval_add(&m->count, -1);
@ -1743,6 +1748,7 @@ void sys_condition_variable_release(struct sys_condition_variable *sys_cv)
void sys_condition_variable_wait(struct sys_condition_variable *sys_cv, struct sys_lock *lock)
{
__prof;
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
struct win32_mutex *m = (struct win32_mutex *)lock->mutex;
b32 exclusive = lock->exclusive;
@ -1780,6 +1786,7 @@ void sys_condition_variable_wait(struct sys_condition_variable *sys_cv, struct s
void sys_condition_variable_wait_time(struct sys_condition_variable *sys_cv, struct sys_lock *lock, f64 seconds)
{
__prof;
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
struct win32_mutex *m = (struct win32_mutex *)lock->mutex;
b32 exclusive = lock->exclusive;
@ -1818,6 +1825,7 @@ void sys_condition_variable_wait_time(struct sys_condition_variable *sys_cv, str
void sys_condition_variable_signal(struct sys_condition_variable *sys_cv, u32 count)
{
__prof;
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
/* Windows will wake all waiters if many single-wakes occur anyway, so we
* might as well wake all ourselves.
@ -1833,6 +1841,7 @@ void sys_condition_variable_signal(struct sys_condition_variable *sys_cv, u32 co
void sys_condition_variable_broadcast(struct sys_condition_variable *sys_cv)
{
__prof;
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
WakeAllConditionVariable(&cv->condition_variable);
}
@ -2232,7 +2241,7 @@ INTERNAL void win32_precise_sleep_timer(f64 seconds, HANDLE timer)
i64 max_ticks = (i64)scheduler_period_ms * 9500;
while (true) {
__profscope(win32_sleep_part);
__profscope(Sleep part);
/* Break sleep up into parts that are lower than scheduler period */
f64 remaining_seconds = (f64)(target_qpc - qpc.QuadPart) / (f64)qpc_per_second;
i64 sleep_ticks = (i64)((remaining_seconds - tolerance) * 10000000);
@ -2248,7 +2257,7 @@ INTERNAL void win32_precise_sleep_timer(f64 seconds, HANDLE timer)
/* Spin for any remaining time */
{
__profscope(sleep_spin);
__profscope(Sleep spin);
while (qpc.QuadPart < target_qpc) {
YieldProcessor();
QueryPerformanceCounter(&qpc);
@ -2276,18 +2285,14 @@ INTERNAL void win32_precise_sleep_legacy(f64 seconds)
f64 sleep_ms = (seconds * 1000) - tolerance;
i32 sleep_slices = (i32)(sleep_ms / scheduler_period_ms);
if (sleep_slices > 0) {
__profscope(win32_sleep);
__profscope(Legacy sleep part);
Sleep((DWORD)sleep_slices * scheduler_period_ms);
}
{
__profscope(win32_qpc);
QueryPerformanceCounter(&qpc);
}
QueryPerformanceCounter(&qpc);
/* Spin for any remaining time */
{
__profscope(sleep_spin);
__profscope(Legacy sleep spin);
while (qpc.QuadPart < target_qpc) {
YieldProcessor();
QueryPerformanceCounter(&qpc);

View File

@ -63,7 +63,7 @@ volatile void *_thread_local_var_eval(struct thread_local_var_meta *meta)
{
u64 id_plus_one = atomic_u64_eval(&meta->id_plus_one);
if (id_plus_one == 0) {
__profscope(_thread_local_var_eval__REGISTER);
__profscope(Register thread local var);
metas_lock();
{
id_plus_one = atomic_u64_eval(&meta->id_plus_one); /* Reevaluate now that we've locked */
@ -89,7 +89,7 @@ volatile void *_thread_local_var_eval(struct thread_local_var_meta *meta)
/* Allocate var for thread if unallocated */
if (!data) {
__profscope(_thread_local_var_eval__ALLOC);
__profscope(Alloc thread local var);
/* Allocate */
arena_align(t->arena, meta->align);
data = arena_push_array_no_zero(t->arena, u8, meta->size);

View File

@ -1162,7 +1162,7 @@ INTERNAL void user_update(void)
{
/* Copy valid entities */
{
__profscope(copy_sprites_for_sorting);
__profscope(Build ents list for sorting);
for (u64 ent_index = 0; ent_index < G.ss_blended->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &G.ss_blended->ents[ent_index];
if (sim_ent_is_valid_and_active(ent)) {
@ -1173,7 +1173,7 @@ INTERNAL void user_update(void)
}
/* Sort */
{
__profscope(sort_sprites);
__profscope(Sort ents);
merge_sort(sorted, sorted_count, sizeof(*sorted), ent_draw_order_cmp, NULL);
}
}
@ -1183,7 +1183,7 @@ INTERNAL void user_update(void)
* ========================== */
{
__profscope(draw_entities);
__profscope(Draw entities);
for (u64 sorted_index = 0; sorted_index < sorted_count; ++sorted_index) {
struct sim_ent *ent = sorted[sorted_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
@ -1709,7 +1709,7 @@ INTERNAL void user_update(void)
/* Draw crosshair or show cursor */
if (!G.debug_camera) {
__profscope(draw_crosshair);
__profscope(Draw crosshair);
struct v2 crosshair_pos = G.user_cursor;
struct sprite_tag crosshair_tag = sprite_tag_from_path(LIT("sprite/crosshair.ase"));
@ -1726,7 +1726,7 @@ INTERNAL void user_update(void)
sys_window_cursor_hide(G.window);
sys_window_cursor_enable_clip(G.window, cursor_clip);
} else {
__profscope(update_window_cursor);
__profscope(Update windows cursor);
sys_window_cursor_disable_clip(G.window);
sys_window_cursor_show(G.window);
}
@ -2055,7 +2055,7 @@ INTERNAL void user_update(void)
* ========================== */
{
__profscope(render);
__profscope(Render);
struct rect user_viewport = RECT_FROM_V2(V2(0, 0), G.user_size);
struct v2i32 user_resolution = v2_round_to_int(user_viewport.size);