ogl_beamforming

Ultrasound Beamforming Implemented with OpenGL
git clone anongit@rnpnr.xyz:ogl_beamforming.git
Log | Files | Refs | Feed | Submodules | README | LICENSE

Commit: 59fbe3b6b7927d78ed9243b6ce297dc9590bd30f
Parent: cd01e42f6d9bb69901d3e0d1b2599fb414de0f08
Author: Randy Palamar
Date:   Sat,  7 Jun 2025 15:50:34 -0600

core: do our own frame timing

also add compiler agnostic `--time` option to build (report
removed since its not that useful)

Diffstat:
Mbeamformer.c | 2+-
Mbeamformer.h | 1+
Mbuild.c | 27+++++++++++++++------------
Mmain_linux.c | 4++++
Mmain_w32.c | 9+++++++--
Mos_linux.c | 19+++++++++++++++++++
Mos_win32.c | 23++++++++++++++++++++---
7 files changed, 67 insertions(+), 18 deletions(-)

diff --git a/beamformer.c b/beamformer.c @@ -686,7 +686,7 @@ DEBUG_EXPORT BEAMFORMER_COMPLETE_COMPUTE_FN(beamformer_complete_compute) DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step) { - dt_for_frame = GetFrameTime(); + dt_for_frame = input->dt; if (IsWindowResized()) { ctx->window_size.h = GetScreenHeight(); diff --git a/beamformer.h b/beamformer.h @@ -22,6 +22,7 @@ typedef struct { v2 mouse; v2 last_mouse; b32 executable_reloaded; + f32 dt; } BeamformerInput; #define CUDA_INIT_FN(name) void name(u32 *input_dims, u32 *decoded_dims) diff --git a/build.c b/build.c @@ -109,8 +109,8 @@ typedef struct { typedef struct { b32 debug; b32 generic; - b32 report; b32 sanitize; + b32 time; } Options; #define die(fmt, ...) die_("%s: " fmt, __FUNCTION__, ##__VA_ARGS__) @@ -377,12 +377,6 @@ cmd_base(Arena *a, Options *o) else printf("warning: santizers not supported with this compiler\n"); } - if (o->report) { - if (is_clang) cmd_append(a, &result, "-fproc-stat-report"); - else printf("warning: timing not supported with this compiler\n"); - /* TODO(rnp): basic timing */ - } - return result; } @@ -433,11 +427,11 @@ s8_equal(s8 a, s8 b) function void usage(char *argv0) { - die("%s [--debug] [--report] [--sanitize]\n" + die("%s [--debug] [--sanitize] [--time]\n" " --debug: dynamically link and build with debug symbols\n" " --generic: compile for a generic target (x86-64-v3 or armv8 with NEON)\n" - " --report: print compilation stats (clang only)\n" " --sanitize: build with ASAN and UBSAN\n" + " --time: print build time\n" , argv0); } @@ -454,10 +448,10 @@ parse_options(i32 argc, char *argv[]) result.debug = 1; } else if (s8_equal(str, s8("--generic"))) { result.generic = 1; - } else if (s8_equal(str, s8("--report"))) { - result.report = 1; } else if (s8_equal(str, s8("--sanitize"))) { result.sanitize = 1; + } else if (s8_equal(str, s8("--time"))) { + result.time = 1; } else { usage(argv0); } @@ -626,6 +620,8 @@ build_beamformer_as_library(Arena arena, CommandList cc) i32 main(i32 argc, char *argv[]) { + u64 start_time = os_get_timer_counter(); + Arena arena = os_alloc_arena((Arena){0}, MB(8)); check_rebuild_self(arena, argc, argv); @@ -662,5 +658,12 @@ main(i32 argc, char *argv[]) } cmd_append(&arena, &c, (void *)0); - return !run_synchronous(arena, &c); + i32 result = !run_synchronous(arena, &c); + + if (options.time) { + f64 seconds = (f64)(os_get_timer_counter() - start_time) / os_get_timer_frequency(); + printf("info: took %0.03f [s]\n", seconds); + } + + return result; } diff --git a/main_linux.c b/main_linux.c @@ -92,13 +92,17 @@ main(void) fds[0].fd = ctx.os.file_watch_context.handle; fds[0].events = POLLIN; + u64 last_time = os_get_timer_counter(); while (!ctx.should_exit) { poll(fds, countof(fds), 0); if (fds[0].revents & POLLIN) dispatch_file_watch_events(&ctx.os, temp_memory); + u64 now = os_get_timer_counter(); input.last_mouse = input.mouse; input.mouse.rl = GetMousePosition(); + input.dt = (f64)(now - last_time) / os_get_timer_frequency(); + last_time = now; beamformer_frame_step(&ctx, &temp_memory, &input); diff --git a/main_w32.c b/main_w32.c @@ -73,7 +73,7 @@ dispatch_file_watch(OS *os, FileWatchDirectory *fw_dir, u8 *buf, Arena arena) function void clear_io_queue(OS *os, BeamformerInput *input, Arena arena) { - w32_context *ctx = (w32_context *)os->context; + os_w32_context *ctx = (os_w32_context *)os->context; iptr handle = ctx->io_completion_handle; w32_overlapped *overlapped; @@ -109,8 +109,9 @@ main(void) OS_FNS #undef X - w32_context w32_ctx = {0}; + os_w32_context w32_ctx = {0}; w32_ctx.io_completion_handle = CreateIoCompletionPort(INVALID_FILE, 0, 0, 0); + w32_ctx.timer_frequency = os_get_timer_frequency(); ctx.os.context = (iptr)&w32_ctx; ctx.os.compute_worker.asleep = 1; @@ -121,11 +122,15 @@ main(void) setup_beamformer(&ctx, &temp_memory); os_wake_waiters(&ctx.os.compute_worker.sync_variable); + u64 last_time = os_get_timer_counter(); while (!ctx.should_exit) { clear_io_queue(&ctx.os, &input, temp_memory); + u64 now = os_get_timer_counter(); input.last_mouse = input.mouse; input.mouse.rl = GetMousePosition(); + input.dt = (f64)(now - last_time) / w32_ctx.timer_frequency; + last_time = now; beamformer_frame_step(&ctx, &temp_memory, &input); diff --git a/os_linux.c b/os_linux.c @@ -23,8 +23,12 @@ #include <unistd.h> /* NOTE(rnp): hidden behind feature flags -> screw compiler/standards idiots */ +#ifndef CLOCK_MONOTONIC + #define CLOCK_MONOTONIC 1 +#endif i32 ftruncate(i32, i64); i64 syscall(i64, ...); +i32 clock_gettime(i32, struct timespec *); #ifdef _DEBUG function void * @@ -64,6 +68,21 @@ os_fatal(s8 msg) unreachable(); } +function u64 +os_get_timer_frequency(void) +{ + return 1000000000ULL; +} + +function u64 +os_get_timer_counter(void) +{ + struct timespec time = {0}; + clock_gettime(CLOCK_MONOTONIC, &time); + u64 result = time.tv_sec * 1000000000ULL + time.tv_nsec; + return result; +} + function OS_ALLOC_ARENA_FN(os_alloc_arena) { Arena result; diff --git a/os_win32.c b/os_win32.c @@ -70,9 +70,8 @@ typedef struct { typedef struct { iptr io_completion_handle; - u64 timer_start_time; u64 timer_frequency; -} w32_context; +} os_w32_context; typedef enum { W32_IO_FILE_WATCH, @@ -104,6 +103,8 @@ W32(iptr) GetStdHandle(i32); W32(void) GetSystemInfo(void *); W32(void *) LoadLibraryA(c8 *); W32(void *) MapViewOfFile(iptr, u32, u32, u32, u64); +W32(b32) QueryPerformanceCounter(u64 *); +W32(b32) QueryPerformanceFrequency(u64 *); W32(b32) ReadDirectoryChangesW(iptr, u8 *, u32, b32, u32, u32 *, void *, void *); W32(b32) ReadFile(iptr, u8 *, i32, i32 *, void *); W32(b32) ReleaseSemaphore(iptr, i64, i64 *); @@ -150,6 +151,22 @@ os_fatal(s8 msg) unreachable(); } +function u64 +os_get_timer_frequency(void) +{ + u64 result; + QueryPerformanceFrequency(&result); + return result; +} + +function u64 +os_get_timer_counter(void) +{ + u64 result; + QueryPerformanceCounter(&result); + return result; +} + function OS_ALLOC_ARENA_FN(os_alloc_arena) { Arena result = old; @@ -328,7 +345,7 @@ function OS_ADD_FILE_WATCH_FN(os_add_file_watch) OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, 0); - w32_context *ctx = (w32_context *)os->context; + os_w32_context *ctx = (os_w32_context *)os->context; w32_io_completion_event *event = push_struct(a, typeof(*event)); event->tag = W32_IO_FILE_WATCH; event->context = (iptr)dir;