Commit: bc3d47016040d28aada1425abd2998afd983a185
Parent: 8d6215f453e9a5b420743dfa44165d474feea45e
Author: Randy Palamar
Date: Tue, 20 Jan 2026 10:04:33 -0700
os: add os_timer_count() to platform requirements
Since the beamformer has multiple timelines running at different
update rates a single timer tick delta (or even absolute
timestamp) is not sufficient. This adds os_timer_count() to the
platform requirements so that each timeline may track its own time
as necessary.
Diffstat:
9 files changed, 36 insertions(+), 36 deletions(-)
diff --git a/beamformer.h b/beamformer.h
@@ -81,12 +81,16 @@ typedef struct {
uint8_t path_separator_byte;
} OSSystemInfo;
-BEAMFORMER_IMPORT OSSystemInfo * os_get_system_info(void);
+BEAMFORMER_IMPORT OSSystemInfo * os_system_info(void);
BEAMFORMER_IMPORT OSThread os_create_thread(const char *name, void *user_context, os_thread_entry_point_fn *fn);
BEAMFORMER_IMPORT OSBarrier os_barrier_alloc(uint32_t thread_count);
BEAMFORMER_IMPORT void os_barrier_enter(OSBarrier);
+/* NOTE(rnp): since the beamformer may spawn threads, which may need to keep time,
+ * passing in a single timer value with the rest of the input is insufficient. */
+BEAMFORMER_IMPORT uint64_t os_timer_count(void);
+
BEAMFORMER_IMPORT void os_add_file_watch(const char *path, int64_t path_length, void *user_context);
BEAMFORMER_IMPORT int64_t os_read_entire_file(const char *file, void *buffer, int64_t buffer_capacity);
@@ -154,8 +158,6 @@ typedef struct {
uint8_t * shared_memory_name;
uint32_t shared_memory_name_length;
- uint64_t timer_ticks;
-
float mouse_x;
float mouse_y;
float last_mouse_x;
diff --git a/beamformer_core.c b/beamformer_core.c
@@ -1533,7 +1533,9 @@ beamformer_frame_step(BeamformerInput *input)
{
BeamformerCtx *ctx = BeamformerContextMemory(input->memory);
- dt_for_frame = (f64)(input->timer_ticks) / os_get_system_info()->timer_frequency;
+ u64 current_time = os_timer_count();
+ dt_for_frame = (f64)(current_time - ctx->frame_timestamp) / os_system_info()->timer_frequency;
+ ctx->frame_timestamp = current_time;
if (IsWindowResized()) {
ctx->window_size.h = GetScreenHeight();
diff --git a/beamformer_internal.h b/beamformer_internal.h
@@ -19,7 +19,7 @@
#define beamformer_info(s) s8("[info] " s "\n")
-#define os_path_separator() (s8){.data = &os_get_system_info()->path_separator_byte, .len = 1}
+#define os_path_separator() (s8){.data = &os_system_info()->path_separator_byte, .len = 1}
///////////////////////////////
// NOTE: CUDA Library Bindings
@@ -311,6 +311,8 @@ typedef struct {
void *ui;
u32 ui_dirty_parameter_blocks;
+ u64 frame_timestamp;
+
BeamformerComputeContext compute_context;
/* TODO(rnp): ideally this would go in the UI but its hard to manage with the UI
diff --git a/build.c b/build.c
@@ -3591,7 +3591,7 @@ metagen_file_direct(Arena arena, char *filename)
i32
main(i32 argc, char *argv[])
{
- u64 start_time = os_get_timer_counter();
+ u64 start_time = os_timer_count();
g_argv0 = argv[0];
b32 result = 1;
@@ -3630,7 +3630,7 @@ main(i32 argc, char *argv[])
if (config.debug) result &= build_beamformer_as_library(arena);
if (config.time) {
- f64 seconds = (f64)(os_get_timer_counter() - start_time) / (f64)os_get_timer_frequency();
+ f64 seconds = (f64)(os_timer_count() - start_time) / (f64)os_timer_frequency();
build_log_info("took %0.03f [s]", seconds);
}
diff --git a/main_linux.c b/main_linux.c
@@ -59,7 +59,7 @@ typedef struct {
global OSLinux_Context os_linux_context;
BEAMFORMER_IMPORT OSSystemInfo *
-os_get_system_info(void)
+os_system_info(void)
{
return &os_linux_context.system_info;
}
@@ -247,13 +247,15 @@ load_platform_libraries(BeamformerInput *input)
}
function void
-dispatch_file_watch_events(BeamformerInput *input, u64 current_time)
+dispatch_file_watch_events(BeamformerInput *input)
{
OSLinux_FileWatchDirectoryList *fwctx = &os_linux_context.file_watch_list;
Arena arena = os_linux_context.arena;
u8 *mem = arena_alloc(&arena, .size = 4096, .align = 16);
struct inotify_event *event;
+ u64 current_time = os_timer_count();
+
iz rlen;
while ((rlen = read(os_linux_context.inotify_handle, mem, 4096)) > 0) {
for (u8 *data = mem; data < mem + rlen; data += sizeof(*event) + event->len) {
@@ -296,7 +298,7 @@ dispatch_file_watch_events(BeamformerInput *input, u64 current_time)
extern i32
main(void)
{
- os_linux_context.system_info.timer_frequency = os_get_timer_frequency();
+ os_linux_context.system_info.timer_frequency = os_timer_frequency();
os_linux_context.system_info.logical_processor_count = os_number_of_processors();
os_linux_context.system_info.page_size = ARCH_X64? KB(4) : getauxval(AT_PAGESZ);
os_linux_context.system_info.path_separator_byte = '/';
@@ -328,21 +330,16 @@ main(void)
fds[0].fd = os_linux_context.inotify_handle;
fds[0].events = POLLIN;
- u64 last_time = os_get_timer_counter();
while (!WindowShouldClose() && !beamformer_should_close(input)) {
- u64 now = os_get_timer_counter();
-
poll(fds, countof(fds), 0);
if (fds[0].revents & POLLIN)
- dispatch_file_watch_events(input, now);
+ dispatch_file_watch_events(input);
Vector2 new_mouse = GetMousePosition();
input->last_mouse_x = input->mouse_x;
input->last_mouse_y = input->mouse_y;
input->mouse_x = new_mouse.x;
input->mouse_y = new_mouse.y;
- input->timer_ticks = now - last_time;
- last_time = now;
beamformer_frame_step(input);
diff --git a/main_w32.c b/main_w32.c
@@ -95,7 +95,7 @@ typedef struct {
global OSW32_Context os_w32_context;
BEAMFORMER_IMPORT OSSystemInfo *
-os_get_system_info(void)
+os_system_info(void)
{
return &os_w32_context.system_info;
}
@@ -297,11 +297,13 @@ load_platform_libraries(BeamformerInput *input)
}
function void
-dispatch_file_watch(BeamformerInput *input, Arena arena, u64 current_time, OSW32_FileWatchDirectory *fw_dir)
+dispatch_file_watch(BeamformerInput *input, Arena arena, OSW32_FileWatchDirectory *fw_dir)
{
TempArena save_point = {0};
i64 offset = 0;
+ u64 current_time = os_timer_count();
+
w32_file_notify_info *fni = (w32_file_notify_info *)fw_dir->buffer;
do {
end_temp_arena(save_point);
@@ -349,7 +351,7 @@ dispatch_file_watch(BeamformerInput *input, Arena arena, u64 current_time, OSW32
}
function void
-clear_io_queue(BeamformerInput *input, Arena arena, u64 current_time)
+clear_io_queue(BeamformerInput *input, Arena arena)
{
iptr handle = os_w32_context.io_completion_handle;
w32_overlapped *overlapped;
@@ -360,7 +362,7 @@ clear_io_queue(BeamformerInput *input, Arena arena, u64 current_time)
switch (event->tag) {
case W32IOEvent_FileWatch:{
OSW32_FileWatchDirectory *dir = (OSW32_FileWatchDirectory *)event->context;
- dispatch_file_watch(input, arena, current_time, dir);
+ dispatch_file_watch(input, arena, dir);
zero_struct(&dir->overlapped);
ReadDirectoryChangesW(dir->handle, dir->buffer, OSW32_FileWatchDirectoryBufferSize, 0,
FILE_NOTIFY_CHANGE_LAST_WRITE, 0, &dir->overlapped, 0);
@@ -374,7 +376,7 @@ main(void)
{
os_w32_context.error_handle = GetStdHandle(STD_ERROR_HANDLE);
os_w32_context.io_completion_handle = CreateIoCompletionPort(INVALID_FILE, 0, 0, 0);
- os_w32_context.system_info.timer_frequency = os_get_timer_frequency();
+ os_w32_context.system_info.timer_frequency = os_timer_frequency();
os_w32_context.system_info.path_separator_byte = '\\';
{
w32_system_info info = {0};
@@ -405,13 +407,10 @@ main(void)
beamformer_init(input);
- u64 last_time = os_get_timer_counter();
while (!WindowShouldClose() && !beamformer_should_close(input)) {
- u64 now = os_get_timer_counter();
-
DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock))
{
- clear_io_queue(input, os_w32_context.arena, now);
+ clear_io_queue(input, os_w32_context.arena);
}
Vector2 new_mouse = GetMousePosition();
@@ -419,8 +418,6 @@ main(void)
input->last_mouse_y = input->mouse_y;
input->mouse_x = new_mouse.x;
input->mouse_y = new_mouse.y;
- input->timer_ticks = now - last_time;
- last_time = now;
beamformer_frame_step(input);
diff --git a/os_linux.c b/os_linux.c
@@ -43,13 +43,13 @@ os_exit(i32 code)
}
function u64
-os_get_timer_frequency(void)
+os_timer_frequency(void)
{
return 1000000000ULL;
}
-function u64
-os_get_timer_counter(void)
+BEAMFORMER_IMPORT u64
+os_timer_count(void)
{
struct timespec time = {0};
clock_gettime(CLOCK_MONOTONIC, &time);
diff --git a/os_win32.c b/os_win32.c
@@ -137,15 +137,15 @@ os_exit(i32 code)
}
function u64
-os_get_timer_frequency(void)
+os_timer_frequency(void)
{
u64 result;
QueryPerformanceFrequency(&result);
return result;
}
-function u64
-os_get_timer_counter(void)
+BEAMFORMER_IMPORT u64
+os_timer_count(void)
{
u64 result;
QueryPerformanceCounter(&result);
diff --git a/tests/throughput.c b/tests/throughput.c
@@ -402,11 +402,11 @@ execute_study(s8 study, Arena arena, Stream path, Options *options)
u32 frame = 0;
f32 times[32] = {0};
f32 data_size = (f32)(bp.raw_data_dimensions.E[0] * bp.raw_data_dimensions.E[1] * sizeof(*data));
- u64 start = os_get_timer_counter();
- f64 frequency = os_get_timer_frequency();
+ u64 start = os_timer_count();
+ f64 frequency = os_timer_frequency();
for (;!g_should_exit;) {
if (send_frame(data, &bp)) {
- u64 now = os_get_timer_counter();
+ u64 now = os_timer_count();
f64 delta = (now - start) / frequency;
start = now;