This commit is contained in:
jacob 2025-02-23 03:23:17 -06:00
parent ca731215ee
commit 4d419da97b
12 changed files with 99 additions and 296 deletions

View File

@ -33,8 +33,6 @@ struct exit_callback {
struct sys_thread thread;
};
struct app_statistics _g_app_statistics = ZI;
GLOBAL struct {
struct arena arena;
struct string write_path;

View File

@ -4,20 +4,6 @@
#define APP_EXIT_CALLBACK_FUNC_DEF(name) void name(void)
typedef APP_EXIT_CALLBACK_FUNC_DEF(app_exit_callback_func);
struct app_statistics {
struct atomic_u64 sock_bytes_sent;
struct atomic_u64 sock_bytes_received;
struct atomic_u64 memory_committed;
struct atomic_u64 memory_reserved;
struct atomic_u64 num_arenas;
};
INLINE struct app_statistics *app_statistics(void)
{
extern struct app_statistics _g_app_statistics;
return &_g_app_statistics;
}
struct string app_write_path_cat(struct arena *arena, struct string filename);
/* Register a function that will be called when the application exits */

View File

@ -3,7 +3,7 @@
#include "memory.h"
#include "string.h"
#include "atomic.h"
#include "app.h"
#include "gstat.h"
/* Arbitrary block size */
#define ARENA_BLOCK_SIZE 4096
@ -27,7 +27,7 @@ struct arena arena_alloc(u64 reserve)
sys_panic(LIT("Failed to reserve memory"));
}
arena.reserved = reserve;
atomic_u64_eval_add_u64(&app_statistics()->memory_reserved, arena.reserved);
gstat_add(GSTAT_MEMORY_RESERVED, arena.reserved);
/* Commit one block to start with */
arena.base = sys_memory_commit(arena.base, ARENA_BLOCK_SIZE);
@ -36,14 +36,14 @@ struct arena arena_alloc(u64 reserve)
sys_panic(LIT("Failed to commit initial memory block: System may be out of memory"));
}
arena.committed = ARENA_BLOCK_SIZE;
atomic_u64_eval_add_u64(&app_statistics()->memory_committed, arena.committed);
gstat_add(GSTAT_MEMORY_COMMITTED, arena.committed);
__profalloc(arena.base, ARENA_BLOCK_SIZE);
ASAN_POISON(arena.base, ARENA_BLOCK_SIZE);
/* Arena should be 64k aligned */
ASSERT(((u64)arena.base & 0xFFFF) == 0);
atomic_u64_inc_eval(&app_statistics()->num_arenas);
gstat_add(GSTAT_NUM_ARENAS, 1);
return arena;
}
@ -53,9 +53,9 @@ void arena_release(struct arena *arena)
ASAN_UNPOISON(arena->base, arena->committed);
__prof;
__proffree(arena->base);
atomic_u64_eval_add_i64(&app_statistics()->memory_committed, -((i64)arena->committed));
atomic_u64_eval_add_i64(&app_statistics()->memory_reserved, -((i64)arena->reserved));
atomic_u64_dec_eval(&app_statistics()->num_arenas);
gstat_sub(GSTAT_MEMORY_COMMITTED, arena->committed);
gstat_sub(GSTAT_MEMORY_RESERVED, arena->reserved);
gstat_sub(GSTAT_NUM_ARENAS, 1);
sys_memory_release(arena->base);
}
@ -89,7 +89,7 @@ void *arena_push_bytes(struct arena *arena, u64 size, u64 align)
sys_panic(LIT("Failed to commit new memory block: System may be out of memory"));
}
arena->committed += commit_bytes;
atomic_u64_eval_add_u64(&app_statistics()->memory_committed, commit_bytes);
gstat_add(GSTAT_MEMORY_COMMITTED, commit_bytes);
__proffree(arena->base);
__profalloc(arena->base, arena->committed + commit_bytes);
ASAN_POISON(commit_address, commit_bytes);
@ -124,7 +124,7 @@ void arena_decommit_unused_blocks(struct arena *arena)
u64 decommit_size = (arena->base + arena->committed) - decommit_start;
sys_memory_decommit(decommit_start, decommit_size);
arena->committed = next_block_pos;
atomic_u64_eval_add_i64(&app_statistics()->memory_committed, -((i64)decommit_size));
gstat_sub(GSTAT_MEMORY_COMMITTED, decommit_size);
}
}

View File

@ -63,6 +63,9 @@
#define BITBUFF_DEBUG 0
#define BITBUFF_TEST RTC
/* If enabled, things like network writes & memory allocations will be tracked in a global statistics struct */
#define GSTAT_ENABLED 1
/* ========================== *
* Settings
* ========================== */

5
src/gstat.c Normal file
View File

@ -0,0 +1,5 @@
#include "gstat.h"
#if GSTAT_ENABLED
struct _gstats _g_gstats = ZI;
#endif

33
src/gstat.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef GSTAT_H
#define GSTAT_H
/* Program-wide statistics */
#if GSTAT_ENABLED
#include "atomic.h"
struct _gstats {
struct atomic_u64 GSTAT_SOCK_BYTES_SENT;
struct atomic_u64 GSTAT_SOCK_BYTES_RECEIVED;
struct atomic_u64 GSTAT_MEMORY_COMMITTED;
struct atomic_u64 GSTAT_MEMORY_RESERVED;
struct atomic_u64 GSTAT_NUM_ARENAS;
};
extern struct _gstats _g_gstats;
#define gstat_add(name, v) atomic_u64_eval_add_u64(&_g_gstats.name, (v))
#define gstat_sub(name, v) atomic_u64_eval_add_i64(&_g_gstats.name, -((i64)(v)))
#define gstat_get(name) atomic_u64_eval(&_g_gstats.name)
#else
#define gstat_add(name, v)
#define gstat_sub(name, v)
#define gstat_get(name) 0
#endif
#endif

View File

@ -117,6 +117,33 @@ void sim_ent_release(struct sim_ent *ent)
sim_ent_release_raw(ent);
}
void sim_ent_release_all_with_prop(struct sim_snapshot *ss, enum sim_ent_prop prop)
{
struct temp_arena scratch = scratch_begin_no_conflict();
struct sim_ent **ents_to_release = arena_dry_push(scratch.arena, struct sim_ent *);
u64 ents_to_release_count = 0;
for (u64 ent_index = 0; ent_index < ss->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ss->ents[ent_index];
if (ent->valid && sim_ent_has_prop(ent, prop)) {
*arena_push(scratch.arena, struct sim_ent *) = ent;
++ents_to_release_count;
}
}
/* Release from snapshot */
/* TODO: Breadth first iteration to only release parent entities (since
* child entities will be released along with parent anyway) */
for (u64 i = 0; i < ents_to_release_count; ++i) {
struct sim_ent *ent = ents_to_release[i];
if (ent->is_top && !ent->is_root) {
sim_ent_release(ent);
}
}
scratch_end(scratch);
}
/* ========================== *
* Activate
* ========================== */

View File

@ -400,6 +400,7 @@ struct sim_ent *sim_ent_alloc_sync_dst(struct sim_ent *parent, struct sim_client
void sim_ent_release_raw(struct sim_ent *ent);
void sim_ent_release(struct sim_ent *ent);
void sim_ent_release_all_with_prop(struct sim_snapshot *ss, enum sim_ent_prop prop);
/* Activate */
void sim_ent_activate(struct sim_ent *ent, u64 current_tick);

View File

@ -16,114 +16,6 @@
#include "bitbuff.h"
#include "host.h"
/* ========================== *
* Ent lookup
* ========================== */
struct sim_lookup sim_lookup_alloc(u64 num_buckets)
{
ASSERT(num_buckets > 0);
struct sim_lookup l = ZI;
l.arena = arena_alloc(GIGABYTE(64));
l.num_buckets = num_buckets;
sim_lookup_reset(&l);
return l;
}
void sim_lookup_release(struct sim_lookup *l)
{
arena_release(&l->arena);
}
void sim_lookup_reset(struct sim_lookup *l)
{
arena_reset(&l->arena);
l->buckets = arena_push_array_zero(&l->arena, struct sim_lookup_bucket, l->num_buckets);
l->first_free_entry = NULL;
}
struct sim_lookup_entry *sim_lookup_get(struct sim_lookup *l, struct sim_lookup_key key)
{
u64 index = key.hash % l->num_buckets;
struct sim_lookup_bucket *bucket = &l->buckets[index];
struct sim_lookup_entry *res = NULL;
for (struct sim_lookup_entry *e = bucket->first; e; e = e->next) {
if (e->key.hash == key.hash) {
res = e;
break;
}
}
return res;
}
void sim_lookup_set(struct sim_lookup *l, struct sim_lookup_key key, struct sim_ent_handle handle)
{
u64 index = key.hash % l->num_buckets;
struct sim_lookup_bucket *bucket = &l->buckets[index];
struct sim_lookup_entry *prev = NULL;
struct sim_lookup_entry **slot = &bucket->first;
while (*slot) {
if ((*slot)->key.hash == key.hash) {
break;
}
prev = *slot;
slot = &(*slot)->next;
}
struct sim_lookup_entry *entry = *slot;
if (entry) {
/* Set existing entry */
entry->ent = handle;
} else {
/* Allocate entry */
if (l->first_free_entry) {
entry = l->first_free_entry;
l->first_free_entry->prev = NULL;
l->first_free_entry = entry->next;
} else {
entry = arena_push(&l->arena, struct sim_lookup_entry);
}
MEMZERO_STRUCT(entry);
entry->key = key;
entry->ent = handle;
if (prev) {
entry->prev = prev;
prev->next = entry;
}
bucket->last = entry;
*slot = entry;
}
}
void sim_lookup_remove(struct sim_lookup *l, struct sim_lookup_entry *entry)
{
struct sim_lookup_bucket *bucket = &l->buckets[entry->key.hash % l->num_buckets];
struct sim_lookup_entry *prev = entry->prev;
struct sim_lookup_entry *next = entry->next;
if (prev) {
prev->next = next;
} else {
bucket->first = next;
}
if (next) {
next->prev = prev;
} else {
bucket->last = prev;
}
if (l->first_free_entry) {
l->first_free_entry->prev = entry;
}
entry->next = l->first_free_entry;
entry->prev = NULL;
l->first_free_entry = entry;
}
/* ========================== *
* Sim accel
* ========================== */
@ -140,10 +32,8 @@ void sim_accel_release(struct sim_accel *accel)
space_release(accel->space);
}
void sim_accel_rebuild(struct sim_snapshot *ss, struct sim_accel *accel)
void sim_accel_reset(struct sim_snapshot *ss, struct sim_accel *accel)
{
/* FIXME: Rebuild collision debug lookup */
space_reset(accel->space);
/* Reset ent space handles */
@ -153,8 +43,6 @@ void sim_accel_rebuild(struct sim_snapshot *ss, struct sim_accel *accel)
MEMZERO_STRUCT(&ent->space_handle);
}
}
/* NOTE: Not rebuilding space since it'll happen during phys step */
}
/* ========================== *
@ -349,93 +237,6 @@ INTERNAL void test_clear_level(struct sim_snapshot *world)
}
}
/* ========================== *
* Release entities
* ========================== */
#if 0
INTERNAL void release_entities_with_prop(struct sim_snapshot *ss_blended, enum sim_ent_prop prop)
{
struct temp_arena scratch = scratch_begin_no_conflict();
struct space *space = ss_blended->space;
struct sim_ent **ents_to_release = arena_dry_push(scratch.arena, struct sim_ent *);
u64 ents_to_release_count = 0;
for (u64 ent_index = 0; ent_index < ss_blended->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ss_blended->ents[ent_index];
if (ent->valid && sim_ent_has_prop(ent, prop)) {
*arena_push(scratch.arena, struct sim_ent *) = ent;
++ents_to_release_count;
}
}
/* Release references */
for (u64 i = 0; i < ents_to_release_count; ++i) {
struct sim_ent *ent = ents_to_release[i];
/* Release space entry */
{
struct space_entry *space_entry = space_entry_from_handle(space, ent->space_handle);
if (space_entry->valid) {
space_entry_release(space_entry);
}
}
}
/* Release from snapshot */
/* TODO: Breadth first iteration to only release parent entities (since
* child entities will be released along with parent anyway) */
for (u64 i = 0; i < ents_to_release_count; ++i) {
struct sim_ent *ent = ents_to_release[i];
if (ent->is_top && !ent->is_root) {
sim_ent_release(ent);
}
}
scratch_end(scratch);
}
#else
INTERNAL void release_entities_with_prop(struct sim_step_ctx *ctx, enum sim_ent_prop prop)
{
struct temp_arena scratch = scratch_begin_no_conflict();
struct sim_snapshot *world = ctx->world;
struct space *space = ctx->accel->space;
struct sim_ent **ents_to_release = arena_dry_push(scratch.arena, struct sim_ent *);
u64 ents_to_release_count = 0;
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (ent->valid && sim_ent_has_prop(ent, prop)) {
*arena_push(scratch.arena, struct sim_ent *) = ent;
++ents_to_release_count;
}
}
/* Release references */
for (u64 i = 0; i < ents_to_release_count; ++i) {
struct sim_ent *ent = ents_to_release[i];
/* Release space entry */
{
struct space_entry *space_entry = space_entry_from_handle(space, ent->space_handle);
if (space_entry->valid) {
space_entry_release(space_entry);
}
}
}
/* Release from snapshot */
/* TODO: Breadth first iteration to only release parent entities (since
* child entities will be released along with parent anyway) */
for (u64 i = 0; i < ents_to_release_count; ++i) {
struct sim_ent *ent = ents_to_release[i];
if (ent->is_top && !ent->is_root) {
sim_ent_release(ent);
}
}
scratch_end(scratch);
}
#endif
/* ========================== *
* Respond to physics collisions
* ========================== */
@ -551,10 +352,11 @@ void sim_step(struct sim_step_ctx *ctx)
struct sim_ent *root = sim_ent_from_handle(world, SIM_ENT_ROOT_HANDLE);
/* ========================== *
* Release entities
* Release entities at beginning of frame
* ========================== */
release_entities_with_prop(ctx, SIM_ENT_PROP_RELEASE);
sim_ent_release_all_with_prop(world, SIM_ENT_PROP_RELEASE);
sim_accel_reset(world, ctx->accel);
if (ctx->is_master) {
/* ========================== *
@ -1394,10 +1196,10 @@ void sim_step(struct sim_step_ctx *ctx)
}
/* ========================== *
* Release entities
* Release entities at end of frame
* ========================== */
release_entities_with_prop(ctx, SIM_ENT_PROP_RELEASE);
sim_ent_release_all_with_prop(world, SIM_ENT_PROP_RELEASE);
/* ========================== *
* End frame

View File

@ -4,45 +4,6 @@
struct space;
struct sim_snapshot;
struct sim_snapshot_list;
struct sim_lookup;
/* ========================== *
* Sim lookup
* ========================== */
/* Structure used to accelerate up entity lookup (rebuilt every step) */
/* TODO: Remove this and do something better. Just a hack to de-couple old sim ctx from step. */
struct sim_lookup_key {
u64 hash;
};
struct sim_lookup_entry {
struct sim_lookup_key key;
struct sim_ent_handle ent;
struct sim_lookup_entry *next;
struct sim_lookup_entry *prev;
};
struct sim_lookup_bucket {
struct sim_lookup_entry *first;
struct sim_lookup_entry *last;
};
struct sim_lookup {
struct arena arena;
struct sim_lookup_bucket *buckets;
u64 num_buckets;
struct sim_lookup_entry *first_free_entry;
};
struct sim_lookup sim_lookup_alloc(u64 num_buckets);
void sim_lookup_release(struct sim_lookup *l);
void sim_lookup_reset(struct sim_lookup *l);
struct sim_lookup_entry *sim_lookup_get(struct sim_lookup *l, struct sim_lookup_key key);
void sim_lookup_set(struct sim_lookup *l, struct sim_lookup_key key, struct sim_ent_handle handle);
void sim_lookup_remove(struct sim_lookup *l, struct sim_lookup_entry *entry);
/* ========================== *
* Sim accel
@ -57,7 +18,7 @@ struct sim_accel {
struct sim_accel sim_accel_alloc(void);
void sim_accel_release(struct sim_accel *accel);
void sim_accel_rebuild(struct sim_snapshot *ss, struct sim_accel *accel);
void sim_accel_reset(struct sim_snapshot *ss, struct sim_accel *accel);
/* ========================== *
* Sim step

View File

@ -5,8 +5,7 @@
#include "scratch.h"
#include "string.h"
#include "log.h"
#include "app.h"
#include "atomic.h"
#include "gstat.h"
#define WIN32_LEAN_AND_MEAN
#define UNICODE
@ -414,7 +413,7 @@ struct sock_read_result sock_read(struct sock *sock, struct string read_buff)
res.address = sock_address_from_win32_address(ws_addr);
if (size >= 0) {
atomic_u64_eval_add_u64(&app_statistics()->sock_bytes_received, size);
gstat_add(GSTAT_SOCK_BYTES_RECEIVED, size);
res.data.text = read_buff.text;
res.data.len = size;
res.valid = true;
@ -440,7 +439,7 @@ void sock_write(struct sock *sock, struct sock_address address, struct string da
struct win32_address ws_addr = win32_address_from_sock_address(address);
i32 size = sendto(ws->sock, (char *)data.text, data.len, 0, &ws_addr.sa, ws_addr.size);
if (size > 0) {
atomic_u64_eval_add_u64(&app_statistics()->sock_bytes_sent, size);
gstat_add(GSTAT_SOCK_BYTES_SENT, size);
}
#if RTC
if (size != (i32)data.len) {

View File

@ -1,5 +1,4 @@
#include "user.h"
#include "app.h"
#include "sim.h"
#include "sim_ent.h"
#include "sim_step.h"
@ -8,7 +7,6 @@
#include "sprite.h"
#include "draw.h"
#include "intrinsics.h"
#include "app.h"
#include "asset_cache.h"
#include "string.h"
#include "scratch.h"
@ -22,6 +20,8 @@
#include "sock.h"
#include "host.h"
#include "bitbuff.h"
#include "gstat.h"
#include "app.h"
struct bind_state {
b32 is_held; /* Is this bind held down this frame */
@ -362,11 +362,11 @@ INTERNAL struct string get_ent_debug_text(struct arena *arena, struct sim_ent *e
b32 transmitting = sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_SRC);
b32 receiving = sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_DST);
if (transmitting & receiving) {
res.len += string_copy(arena, LIT(" recv & send")).len;
res.len += string_copy(arena, LIT(" synced (send & recv)")).len;
} else if (transmitting) {
res.len += string_copy(arena, LIT(" send")).len;
res.len += string_copy(arena, LIT(" synced (send)")).len;
} else if (receiving) {
res.len += string_copy(arena, LIT(" recv")).len;
res.len += string_copy(arena, LIT(" synced (recv)")).len;
} else {
res.len += string_copy(arena, LIT(" local")).len;
}
@ -1551,8 +1551,8 @@ INTERNAL void user_update(void)
{
/* Update network usage stats */
i64 stat_now_ns = sys_time_ns();
G.net_bytes_read.last_second_end = atomic_u64_eval(&app_statistics()->sock_bytes_received);
G.net_bytes_sent.last_second_end = atomic_u64_eval(&app_statistics()->sock_bytes_sent);
G.net_bytes_read.last_second_end = gstat_get(GSTAT_SOCK_BYTES_RECEIVED);
G.net_bytes_sent.last_second_end = gstat_get(GSTAT_SOCK_BYTES_SENT);
if (stat_now_ns - G.last_second_reset_ns > NS_FROM_SECONDS(1)) {
G.last_second_reset_ns = stat_now_ns;
G.net_bytes_read.last_second = G.net_bytes_read.last_second_end - G.net_bytes_read.last_second_start;
@ -1635,13 +1635,13 @@ INTERNAL void user_update(void)
pos.y += spacing;
pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Memory usage: %F MiB"), FMT_FLOAT_P((f64)atomic_u64_eval(&app_statistics()->memory_committed) / 1024 / 1024, 3)));
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Memory usage: %F MiB"), FMT_FLOAT_P((f64)gstat_get(GSTAT_MEMORY_COMMITTED) / 1024 / 1024, 3)));
pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Virtual memory usage: %F TiB"), FMT_FLOAT_P((f64)atomic_u64_eval(&app_statistics()->memory_reserved) / 1024 / 1024 / 1024 / 1024, 3)));
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Virtual memory usage: %F TiB"), FMT_FLOAT_P((f64)gstat_get(GSTAT_MEMORY_RESERVED) / 1024 / 1024 / 1024 / 1024, 3)));
pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Arenas allocated: %F"), FMT_UINT(atomic_u64_eval(&app_statistics()->num_arenas))));
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Arenas allocated: %F"), FMT_UINT(gstat_get(GSTAT_NUM_ARENAS))));
pos.y += spacing;
pos.y += spacing;
@ -1946,6 +1946,7 @@ INTERNAL void sim_snapshot_sync(struct sim_snapshot *local_ss, struct sim_snapsh
}
}
}
sim_ent_release_all_with_prop(local_ss, SIM_ENT_PROP_RELEASE);
}
@ -2193,9 +2194,6 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
struct sim_snapshot *prev_local_ss = sim_snapshot_from_tick(local_client, local_client->last_tick);
struct sim_snapshot *local_ss = sim_snapshot_alloc(local_client, prev_local_ss, step_tick);
/* Rebuild acceleration tables */
sim_accel_rebuild(local_ss, &accel);
/* Sync remote ents with client */
{
struct sim_ent *local_root = sim_ent_from_handle(local_ss, SIM_ENT_ROOT_HANDLE);
@ -2386,16 +2384,6 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
/* Publish snapshot to remote clients */
for (u64 i = 0; i < store->num_clients_reserved; ++i) {
struct sim_client *client = &store->clients[i];