memory & network usage statistics

This commit is contained in:
jacob 2025-02-08 09:28:38 -06:00
parent a78c5e1a47
commit ca664ac291
10 changed files with 91 additions and 14 deletions

View File

@ -31,6 +31,8 @@ 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,6 +4,19 @@
#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 host_bytes_sent;
struct atomic_u64 host_bytes_received;
struct atomic_u64 memory_committed;
struct atomic_u64 memory_reserved;
};
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

@ -2,6 +2,8 @@
#include "sys.h"
#include "memory.h"
#include "string.h"
#include "atomic.h"
#include "app.h"
/* Arbitrary block size */
#define ARENA_BLOCK_SIZE 4096
@ -25,16 +27,18 @@ 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);
/* Commit one block to start with */
arena.base = sys_memory_commit(arena.base, ARENA_BLOCK_SIZE);
__profalloc(arena.base, ARENA_BLOCK_SIZE);
ASAN_POISON(arena.base, ARENA_BLOCK_SIZE);
if (!arena.base) {
/* Hard fail on commit failure */
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);
__profalloc(arena.base, ARENA_BLOCK_SIZE);
ASAN_POISON(arena.base, ARENA_BLOCK_SIZE);
/* Arena should be 64k aligned */
ASSERT(((u64)arena.base & 0xFFFF) == 0);
@ -44,9 +48,11 @@ struct arena arena_alloc(u64 reserve)
void arena_release(struct arena *arena)
{
ASAN_UNPOISON(arena->base, arena->committed);
__prof;
__proffree(arena->base);
ASAN_UNPOISON(arena->base, arena->committed);
atomic_u64_eval_add_i64(&app_statistics()->memory_committed, -((i64)arena->committed));
atomic_u64_eval_add_i64(&app_statistics()->memory_reserved, -((i64)arena->reserved));
sys_memory_release(arena->base);
}
@ -79,10 +85,11 @@ void *arena_push_bytes(struct arena *arena, u64 size, u64 align)
/* Hard fail on memory allocation failure for now */
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);
__proffree(arena->base);
__profalloc(arena->base, arena->committed + commit_bytes);
ASAN_POISON(commit_address, commit_bytes);
arena->committed += commit_bytes;
}
start = arena->base + aligned_start_pos;
arena->pos = new_pos;
@ -114,6 +121,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));
}
}

View File

@ -22,7 +22,8 @@ FORCE_INLINE volatile i64 *atomic_i64_raw(struct atomic_i64 *x) { return &x->_v;
FORCE_INLINE u32 atomic_u32_eval(struct atomic_u32 *x) { return (u32)_InterlockedExchangeAdd((volatile long *)&x->_v, 0); }
FORCE_INLINE u32 atomic_u32_inc_eval(struct atomic_u32 *x) { return (u32)_InterlockedIncrement((volatile long *)&x->_v); }
FORCE_INLINE u32 atomic_u32_dec_eval(struct atomic_u32 *x) { return (u32)_InterlockedDecrement((volatile long *)&x->_v); }
FORCE_INLINE u32 atomic_u32_eval_add(struct atomic_u32 *x, u32 a) { return (u32)_InterlockedExchangeAdd((volatile long *)&x->_v, (long)a); }
FORCE_INLINE u32 atomic_u32_eval_add_u32(struct atomic_u32 *x, u32 a) { return (u32)_InterlockedExchangeAdd((volatile long *)&x->_v, (long)a); }
FORCE_INLINE u32 atomic_u32_eval_add_i32(struct atomic_u32 *x, i32 a) { return (u32)_InterlockedExchangeAdd((volatile long *)&x->_v, (long)a); }
FORCE_INLINE u32 atomic_u32_eval_exchange(struct atomic_u32 *x, u32 e) { return (u32)_InterlockedExchange((volatile long *)&x->_v, (long)e); }
FORCE_INLINE u32 atomic_u32_eval_compare_exchange(struct atomic_u32 *x, u32 c, u32 e) { return (u32)_InterlockedCompareExchange((volatile long *)&x->_v, (long)e, (long)c); }
FORCE_INLINE volatile u32 *atomic_u32_raw(struct atomic_u32 *x) { return &x->_v; }
@ -30,7 +31,8 @@ FORCE_INLINE volatile u32 *atomic_u32_raw(struct atomic_u32 *x) { return &x->_v;
FORCE_INLINE u64 atomic_u64_eval(struct atomic_u64 *x) { return (u64)_InterlockedOr64((volatile i64 *)&x->_v, 0); }
FORCE_INLINE u64 atomic_u64_inc_eval(struct atomic_u64 *x) { return (u64)_InterlockedIncrement64((volatile i64 *)&x->_v); }
FORCE_INLINE u64 atomic_u64_dec_eval(struct atomic_u64 *x) { return (u64)_InterlockedDecrement64((volatile i64 *)&x->_v); }
FORCE_INLINE u64 atomic_u64_eval_add(struct atomic_u64 *x, u64 a) { return (u64)_InterlockedExchangeAdd64((volatile i64 *)&x->_v, (i64)a); }
FORCE_INLINE u64 atomic_u64_eval_add_u64(struct atomic_u64 *x, u64 a) { return (u64)_InterlockedExchangeAdd64((volatile i64 *)&x->_v, (i64)a); }
FORCE_INLINE u64 atomic_u64_eval_add_i64(struct atomic_u64 *x, i64 a) { return (u64)_InterlockedExchangeAdd64((volatile i64 *)&x->_v, (i64)a); }
FORCE_INLINE u64 atomic_u64_eval_exchange(struct atomic_u64 *x, u64 e) { return (u64)_InterlockedExchange64((volatile i64 *)&x->_v, (i64)e); }
FORCE_INLINE u64 atomic_u64_eval_compare_exchange(struct atomic_u64 *x, u64 c, u64 e) { return (u64)_InterlockedCompareExchange64((volatile i64 *)&x->_v, (i64)e, (i64)c); }
FORCE_INLINE volatile u64 *atomic_u64_raw(struct atomic_u64 *x) { return &x->_v; }

View File

@ -100,6 +100,7 @@ INTERNAL void reset_world(void)
/* Release world */
world_release(&G.tick);
/* Release bookkeeping */
space_release(G.space);
#if COLLIDER_DEBUG
entity_lookup_release(&G.collision_debug_lookup);
#endif

View File

@ -6,6 +6,8 @@
#include "util.h"
#include "log.h"
#include "buddy.h"
#include "app.h"
#include "atomic.h"
//#define HOST_NETWORK_ADDRESS_STRING(str)
//#define HOST_NETWORK_ADDRESS_ALL_LOCAL_INTERFACES(port)
@ -768,6 +770,8 @@ void host_update(struct host *host)
default: break;
}
}
host->bytes_received += packet->data.len;
atomic_u64_eval_add_u64(&app_statistics()->host_bytes_received, packet->data.len);
}
}
/* Reset read buffer */
@ -931,15 +935,18 @@ void host_update(struct host *host)
for (u64 i = 0; i < host->num_channels_reserved; ++i) {
struct sock *sock = host->sock;
struct host_channel *channel = &host->channels[i];
u64 total_sent = 0;
if (channel->valid) {
struct sock_address address = channel->address;
/* Send reliable packets to channel */
for (struct host_snd_packet *host_packet = channel->first_reliable_packet; host_packet; host_packet = host_packet->next) {
sock_write(sock, address, STRING(host_packet->data_len, host_packet->data));
for (struct host_snd_packet *packet = channel->first_reliable_packet; packet; packet = packet->next) {
sock_write(sock, address, STRING(packet->data_len, packet->data));
total_sent += packet->data_len;
}
/* Send unreliable packets to channel */
for (struct host_snd_packet *host_packet = channel->first_unreliable_packet; host_packet; host_packet = host_packet->next) {
sock_write(sock, address, STRING(host_packet->data_len, host_packet->data));
for (struct host_snd_packet *packet = channel->first_unreliable_packet; packet; packet = packet->next) {
sock_write(sock, address, STRING(packet->data_len, packet->data));
total_sent += packet->data_len;
}
/* Release unreliable packets */
if (channel->first_unreliable_packet) {
@ -949,6 +956,8 @@ void host_update(struct host *host)
channel->last_unreliable_packet = NULL;
channel->num_unreliable_packets = 0;
}
host->bytes_sent += total_sent;
atomic_u64_eval_add_u64(&app_statistics()->host_bytes_sent, total_sent);
}
}
}

View File

@ -77,7 +77,7 @@ struct host {
struct host_channel *first_free_channel;
u64 num_channels_reserved;
struct host_snd_packet *first_free_packet; /* Allocated in `arena` */
struct host_snd_packet *first_free_packet; /* Allocated in `arena` */
struct host_msg_assembler *first_free_msg_assembler; /* Allocated in `arena` */
struct host_channel_lookup_bucket *channel_lookup_buckets; /* Allocated in `arena` */
@ -91,6 +91,9 @@ struct host {
struct host_rcv_buffer *rcv_buffer_read;
struct host_rcv_buffer *rcv_buffer_write;
u64 bytes_received;
u64 bytes_sent;
struct sys_thread receiver_thread;
};

View File

@ -381,7 +381,7 @@ INTERNAL void cache_node_load_texture(struct cache_node *n, struct sprite_tag ta
}
arena_set_readonly(&n->arena);
n->memory_usage = n->arena.committed + memory_size;
atomic_u64_eval_add(&G.cache.memory_usage, n->memory_usage);
atomic_u64_eval_add_u64(&G.cache.memory_usage, n->memory_usage);
f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns);
logf_info("Finished loading sprite texture \"%F\" in %F seconds (cache size: %F bytes).",
@ -681,7 +681,7 @@ INTERNAL void cache_node_load_sheet(struct cache_node *n, struct sprite_tag tag)
#endif
arena_set_readonly(&n->arena);
n->memory_usage = n->arena.committed;
atomic_u64_eval_add(&G.cache.memory_usage, n->memory_usage);
atomic_u64_eval_add_u64(&G.cache.memory_usage, n->memory_usage);
f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns);
logf_info("Finished loading sprite sheet \"%F\" in %F seconds (cache size: %F bytes).",
@ -1178,7 +1178,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
if (n->next_hash) {
n->next_hash->prev_hash = n->prev_hash;
}
atomic_u64_eval_add(&G.cache.memory_usage, -((i64)n->memory_usage));
atomic_u64_eval_add_i64(&G.cache.memory_usage, -((i64)n->memory_usage));
/* Add to evicted list */
en->next_evicted = head_evicted;
head_evicted = en;

View File

@ -35,6 +35,12 @@ struct blend_tick {
struct world world;
};
struct second_stat {
u64 last_second_start;
u64 last_second_end;
u64 last_second;
};
GLOBAL struct {
struct atomic_i32 user_thread_shutdown;
struct sys_thread user_thread;
@ -45,6 +51,11 @@ GLOBAL struct {
struct host *host;
/* Usage stats */
i64 last_second_reset_ns;
struct second_stat client_bytes_read;
struct second_stat client_bytes_sent;
/* Render targets */
struct renderer_texture final_texture;
struct renderer_texture world_texture;
@ -1608,6 +1619,20 @@ INTERNAL void user_update(void)
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("entities: %F/%F"), FMT_UINT(G.world.entity_store->num_allocated), FMT_UINT(G.world.entity_store->num_reserved)));
pos.y += spacing;
pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Client data read: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_read.last_second * 8 / 1024 / 1024, 2)));
pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Client data sent: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_sent.last_second * 8 / 1024 / 1024, 2)));
pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Memory committed: %F MiB"), FMT_FLOAT_P((f64)atomic_u64_eval(&app_statistics()->memory_committed) / 1024 / 1024, 2)));
pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Memory reserved: %F TiB"), FMT_FLOAT_P((f64)atomic_u64_eval(&app_statistics()->memory_reserved) / 1024 / 1024 / 1024 / 1024, 2)));
pos.y += spacing;
#if 0
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("screen_size: (%F, %F)"), FMT_FLOAT((f64)G.screen_size.x), FMT_FLOAT((f64)G.screen_size.y)));
pos.y += spacing;
@ -1652,6 +1677,7 @@ INTERNAL void user_update(void)
struct v2 player_pos = entity_get_xform(entity_find_first_match_one(store, ENTITY_PROP_PLAYER_CONTROLLED)).og;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("player pos: (%F, %F)"), FMT_FLOAT_P((f64)player_pos.x, 12), FMT_FLOAT_P((f64)player_pos.y, 12)));
pos.y += spacing;
#endif
#if COLLIDER_DEBUG
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("collider gjk steps: %F"), FMT_UINT(collider_debug_steps)));
@ -1675,6 +1701,17 @@ INTERNAL void user_update(void)
host_update(G.host);
/* Update network usage stats */
G.client_bytes_read.last_second_end = G.host->bytes_received;
G.client_bytes_sent.last_second_end = G.host->bytes_sent;
if (now_ns - G.last_second_reset_ns > NS_FROM_SECONDS(1)) {
G.last_second_reset_ns = now_ns;
G.client_bytes_read.last_second = G.client_bytes_read.last_second_end - G.client_bytes_read.last_second_start;
G.client_bytes_sent.last_second = G.client_bytes_sent.last_second_end - G.client_bytes_sent.last_second_start;
G.client_bytes_read.last_second_start = G.client_bytes_read.last_second_end;
G.client_bytes_sent.last_second_start = G.client_bytes_sent.last_second_end;
}
/* ========================== *
* Render
* ========================== */

View File

@ -15,6 +15,8 @@
* Hash utils
* ========================== */
/* TODO: Replace with better hash functions */
/* FNV-1a parameters for different hash sizes:
* https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters
*/