ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
Utilities

🛠️ Core utility functions for string manipulation, paths, IP parsing, and formatting More...

Files

file  time.c
 ⏱️ High-precision timing utilities implementation
 
file  time.h
 ⏱️ High-precision timing utilities using sokol_time.h and uthash
 

Data Structures

struct  timer_record
 Individual timer record for a named timing operation. More...
 
struct  adaptive_sleep_config_t
 Configuration for adaptive sleep behavior. More...
 
struct  adaptive_sleep_state_t
 Runtime state for adaptive sleep. More...
 

Macros

#define START_TIMER(name_fmt, ...)
 Start a timer with formatted name.
 
#define STOP_TIMER(name_fmt, ...)
 Stop a timer with formatted name and return elapsed time.
 
#define NS_PER_US   1000.0
 
#define NS_PER_MS   1000000.0
 
#define NS_PER_SEC   1000000000.0
 
#define NS_PER_MIN   (NS_PER_SEC * 60.0)
 
#define NS_PER_HOUR   (NS_PER_MIN * 60.0)
 
#define NS_PER_DAY   (NS_PER_HOUR * 24.0)
 
#define NS_PER_YEAR   (NS_PER_DAY * 365.25)
 
#define STOP_TIMER_AND_LOG(timer_name, log_func, msg_fmt, ...)
 Stop a timer and log the result with a custom message.
 

Typedefs

typedef struct timer_record timer_record_t
 Individual timer record for a named timing operation.
 

Functions

bool timer_system_init (void)
 Initialize the timing system.
 
void timer_system_cleanup (void)
 Cleanup the timing system.
 
bool timer_start (const char *name)
 Start a named timer.
 
double timer_stop (const char *name)
 Stop a named timer and return elapsed time.
 
bool timer_is_initialized (void)
 Check if timing system is initialized.
 
int format_duration_ms (double milliseconds, char *buffer, size_t buffer_size)
 Format milliseconds as human-readable duration string.
 
int format_duration_ns (double nanoseconds, char *buffer, size_t buffer_size)
 Format nanoseconds as human-readable duration string.
 
int format_duration_s (double seconds, char *buffer, size_t buffer_size)
 Format seconds as human-readable duration string.
 
void adaptive_sleep_init (adaptive_sleep_state_t *state, const adaptive_sleep_config_t *config)
 Initialize adaptive sleep state with configuration.
 
uint64_t adaptive_sleep_calculate (adaptive_sleep_state_t *state, size_t queue_depth, size_t target_depth)
 Calculate adaptive sleep time based on queue depth.
 
void adaptive_sleep_do (adaptive_sleep_state_t *state, size_t queue_depth, size_t target_depth)
 Calculate sleep time and immediately sleep for that duration.
 

Detailed Description

🛠️ Core utility functions for string manipulation, paths, IP parsing, and formatting

String utilities, path handling, IP address parsing, UTF-8 support, CRC32, and formatting.

This module provides a simple timing API for performance measurement:

Features:

Example usage:

START_TIMER("process_frame_%d", frame_num);
// ... do work ...
double elapsed_ns = STOP_TIMER("process_frame_%d", frame_num);
// Use format_duration_ns() for human-readable output
char duration_str[32];
format_duration_ns(elapsed_ns, duration_str, sizeof(duration_str));
log_info("Frame took %s", duration_str);
#define log_info(...)
Log an INFO message.
int format_duration_ns(double nanoseconds, char *buffer, size_t buffer_size)
Format nanoseconds as human-readable duration string.
Definition time.c:187
#define START_TIMER(name_fmt,...)
Start a timer with formatted name.
Definition time.h:141
#define STOP_TIMER(name_fmt,...)
Stop a timer with formatted name and return elapsed time.
Definition time.h:165
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
September 2025

Macro Definition Documentation

◆ NS_PER_DAY

#define NS_PER_DAY   (NS_PER_HOUR * 24.0)

#include <time.h>

Definition at line 185 of file time.h.

◆ NS_PER_HOUR

#define NS_PER_HOUR   (NS_PER_MIN * 60.0)

#include <time.h>

Definition at line 184 of file time.h.

◆ NS_PER_MIN

#define NS_PER_MIN   (NS_PER_SEC * 60.0)

#include <time.h>

Definition at line 183 of file time.h.

◆ NS_PER_MS

#define NS_PER_MS   1000000.0

#include <time.h>

Definition at line 181 of file time.h.

◆ NS_PER_SEC

#define NS_PER_SEC   1000000000.0

#include <time.h>

Definition at line 182 of file time.h.

◆ NS_PER_US

#define NS_PER_US   1000.0

#include <time.h>

Definition at line 180 of file time.h.

◆ NS_PER_YEAR

#define NS_PER_YEAR   (NS_PER_DAY * 365.25)

#include <time.h>

Definition at line 186 of file time.h.

◆ START_TIMER

#define START_TIMER (   name_fmt,
  ... 
)

#include <time.h>

Value:
do { \
char _timer_name_buf[256]; \
snprintf(_timer_name_buf, sizeof(_timer_name_buf), name_fmt, ##__VA_ARGS__); \
(void)timer_start(_timer_name_buf); \
} \
} while (0)
bool timer_start(const char *name)
Start a named timer.
Definition time.c:84
bool timer_is_initialized(void)
Check if timing system is initialized.
Definition time.c:179

Start a timer with formatted name.

The timer name is created by formatting the name_fmt string with the provided arguments. This complete formatted string becomes the unique key in the hashtable.

IMPORTANT: Timer names must be unique. If a timer with the same formatted name already exists, timer_start() will return false and log an error.

Usage: START_TIMER("lock_%p", lock_ptr); // Unique per lock address START_TIMER("process_frame_%d", frame_id); // Unique per frame START_TIMER("client_%u_decode", client_id); // Unique per client

Parameters
name_fmtPrintf-style format string for timer name
...Format arguments to create unique key

Definition at line 141 of file time.h.

142 { \
143 if (timer_is_initialized()) { \
144 char _timer_name_buf[256]; \
145 snprintf(_timer_name_buf, sizeof(_timer_name_buf), name_fmt, ##__VA_ARGS__); \
146 (void)timer_start(_timer_name_buf); \
147 } \
148 } while (0)

◆ STOP_TIMER

#define STOP_TIMER (   name_fmt,
  ... 
)

#include <time.h>

Value:
({ \
double _elapsed = -1.0; \
char _timer_name_buf[256]; \
snprintf(_timer_name_buf, sizeof(_timer_name_buf), name_fmt, ##__VA_ARGS__); \
_elapsed = timer_stop(_timer_name_buf); \
} \
_elapsed; \
})
double timer_stop(const char *name)
Stop a named timer and return elapsed time.
Definition time.c:135

Stop a timer with formatted name and return elapsed time.

The timer name must match exactly (including all format arguments) with the name used in START_TIMER(). The formatted string is used as the hashtable key lookup.

Usage: double ns = STOP_TIMER("lock_%p", lock_ptr); double ns = STOP_TIMER("process_frame_%d", frame_id);

Parameters
name_fmtPrintf-style format string for timer name (must match START_TIMER)
...Format arguments (must match START_TIMER to create same key)
Returns
Elapsed time in nanoseconds, or -1.0 if timer not found

Definition at line 165 of file time.h.

166 { \
167 double _elapsed = -1.0; \
168 if (timer_is_initialized()) { \
169 char _timer_name_buf[256]; \
170 snprintf(_timer_name_buf, sizeof(_timer_name_buf), name_fmt, ##__VA_ARGS__); \
171 _elapsed = timer_stop(_timer_name_buf); \
172 } \
173 _elapsed; \
174 })

◆ STOP_TIMER_AND_LOG

#define STOP_TIMER_AND_LOG (   timer_name,
  log_func,
  msg_fmt,
  ... 
)

#include <time.h>

Value:
do { \
double _elapsed_ns = STOP_TIMER(timer_name, ##__VA_ARGS__); \
if (_elapsed_ns >= 0.0) { \
char _duration_str[32]; \
format_duration_ns(_elapsed_ns, _duration_str, sizeof(_duration_str)); \
log_func(msg_fmt " in %s", ##__VA_ARGS__, _duration_str); \
} \
} while (0)

Stop a timer and log the result with a custom message.

Combines STOP_TIMER() with logging. The timer is stopped, elapsed time is retrieved, and a log message is generated with the elapsed time appended in human-readable format.

Usage: STOP_TIMER_AND_LOG("client_handshake", log_info, "Crypto handshake completed successfully"); STOP_TIMER_AND_LOG("process_frame_%d", log_debug, "Frame %d processed", frame_id, frame_id);

The macro will append " in X.XXms" (or appropriate unit) to your message automatically.

Parameters
timer_nameTimer name (must match START_TIMER call)
log_funcLogging function to use (log_info, log_debug, etc.)
msg_fmtPrintf-style format string for the message
...Format arguments for both timer name and message

Definition at line 271 of file time.h.

272 { \
273 double _elapsed_ns = STOP_TIMER(timer_name, ##__VA_ARGS__); \
274 if (_elapsed_ns >= 0.0) { \
275 char _duration_str[32]; \
276 format_duration_ns(_elapsed_ns, _duration_str, sizeof(_duration_str)); \
277 log_func(msg_fmt " in %s", ##__VA_ARGS__, _duration_str); \
278 } \
279 } while (0)

Typedef Documentation

◆ timer_record_t

typedef struct timer_record timer_record_t

#include <time.h>

Individual timer record for a named timing operation.

Function Documentation

◆ adaptive_sleep_calculate()

uint64_t adaptive_sleep_calculate ( adaptive_sleep_state_t state,
size_t  queue_depth,
size_t  target_depth 
)

#include <time.h>

Calculate adaptive sleep time based on queue depth.

Evaluates current queue depth against target and adjusts the speed multiplier:

  • If queue_depth > target_depth: speed up (reduce sleep, drain queue faster)
  • If queue_depth < target_depth: slow down (increase sleep back to baseline)
  • Speed multiplier changes gradually based on speedup_rate/slowdown_rate

The actual sleep time is calculated as: baseline_sleep_ns / current_speed_multiplier

Example usage:

.baseline_sleep_ns = 16666667, // ~60 FPS (16.67ms)
.min_speed_multiplier = 1.0, // Never slower than baseline
.max_speed_multiplier = 4.0, // Can process up to 4x faster (240 FPS)
.speedup_rate = 0.1, // Ramp up 10% per frame
.slowdown_rate = 0.05 // Ramp down 5% per frame
};
adaptive_sleep_init(&sleep_state, &config);
while (running) {
// Process one frame/packet/unit of work
process_data();
// Sleep adaptively based on queue depth
size_t queue_depth = get_queue_size();
uint64_t sleep_ns = adaptive_sleep_calculate(&sleep_state, queue_depth, 10);
platform_sleep_usec(sleep_ns / 1000);
}
unsigned long long uint64_t
Definition common.h:59
uint64_t adaptive_sleep_calculate(adaptive_sleep_state_t *state, size_t queue_depth, size_t target_depth)
Calculate adaptive sleep time based on queue depth.
Definition time.c:300
void adaptive_sleep_init(adaptive_sleep_state_t *state, const adaptive_sleep_config_t *config)
Initialize adaptive sleep state with configuration.
Definition time.c:285
void platform_sleep_usec(unsigned int usec)
High-precision sleep function with microsecond precision.
Configuration for adaptive sleep behavior.
Definition time.h:294
uint64_t baseline_sleep_ns
Normal sleep time in nanoseconds (when queue is at target)
Definition time.h:295
Runtime state for adaptive sleep.
Definition time.h:310
Parameters
statePointer to adaptive sleep state (will be updated)
queue_depthCurrent number of items in queue/buffer
target_depthDesired queue depth (0 = empty queue target)
Returns
Sleep time in nanoseconds

Definition at line 300 of file time.c.

300 {
301 if (!state) {
302 return 0;
303 }
304
305 const adaptive_sleep_config_t *cfg = &state->config;
306
307 // Determine if we need to speed up or slow down
308 double desired_multiplier;
309
310 if (queue_depth > target_depth) {
311 // Queue is building up - speed up processing
312 // The more items in queue, the faster we should process
313 size_t backlog = queue_depth - target_depth;
314
315 // Calculate desired speed based on backlog
316 // Each item above target increases speed proportionally
317 // This ensures we drain the queue faster the more backed up we are
318 double backlog_factor = 1.0 + ((double)backlog / (double)(target_depth + 1));
319 desired_multiplier = cfg->min_speed_multiplier * backlog_factor;
320
321 // Clamp to max speed
322 if (desired_multiplier > cfg->max_speed_multiplier) {
323 desired_multiplier = cfg->max_speed_multiplier;
324 }
325
326 // Ramp up gradually based on speedup_rate
327 double delta = desired_multiplier - state->current_speed_multiplier;
328 state->current_speed_multiplier += delta * cfg->speedup_rate;
329
330 } else {
331 // Queue is at or below target - slow down to baseline
332 desired_multiplier = cfg->min_speed_multiplier;
333
334 // Ramp down gradually based on slowdown_rate
335 double delta = desired_multiplier - state->current_speed_multiplier;
336 state->current_speed_multiplier += delta * cfg->slowdown_rate;
337 }
338
339 // Ensure we stay within configured bounds
342 }
345 }
346
347 // Calculate actual sleep time: baseline / speed_multiplier
348 // Higher multiplier = shorter sleep = faster processing
350
351 // Store for debugging
352 state->last_sleep_ns = sleep_ns;
353
354 return sleep_ns;
355}
double min_speed_multiplier
Minimum speed (max sleep) - usually 1.0 (baseline speed)
Definition time.h:296
double max_speed_multiplier
Maximum speed (min sleep) - e.g., 4.0 = process 4x faster.
Definition time.h:297
double speedup_rate
Ramp-up rate when queue builds (0.0-1.0, higher = faster ramp)
Definition time.h:298
double slowdown_rate
Ramp-down rate when queue empties (0.0-1.0, higher = faster ramp)
Definition time.h:299
double current_speed_multiplier
Current speed state (1.0 = baseline, >1.0 = faster)
Definition time.h:312
uint64_t last_sleep_ns
Last calculated sleep time (for debugging)
Definition time.h:313
adaptive_sleep_config_t config
Configuration (copied, not referenced)
Definition time.h:311

References adaptive_sleep_config_t::baseline_sleep_ns, adaptive_sleep_state_t::config, adaptive_sleep_state_t::current_speed_multiplier, adaptive_sleep_state_t::last_sleep_ns, adaptive_sleep_config_t::max_speed_multiplier, adaptive_sleep_config_t::min_speed_multiplier, adaptive_sleep_config_t::slowdown_rate, and adaptive_sleep_config_t::speedup_rate.

Referenced by adaptive_sleep_do().

◆ adaptive_sleep_do()

void adaptive_sleep_do ( adaptive_sleep_state_t state,
size_t  queue_depth,
size_t  target_depth 
)

#include <time.h>

Calculate sleep time and immediately sleep for that duration.

Convenience wrapper that combines adaptive_sleep_calculate() with platform_sleep_usec(). Useful for simple loops that don't need to inspect the calculated sleep time.

Parameters
statePointer to adaptive sleep state (will be updated)
queue_depthCurrent number of items in queue/buffer
target_depthDesired queue depth (0 = empty queue target)

Definition at line 357 of file time.c.

357 {
358 uint64_t sleep_ns = adaptive_sleep_calculate(state, queue_depth, target_depth);
359
360 if (sleep_ns > 0) {
361 // Convert nanoseconds to microseconds for platform_sleep_usec
362 uint64_t sleep_us = sleep_ns / 1000;
363 if (sleep_us > 0) {
364 platform_sleep_usec(sleep_us);
365 }
366 }
367}

References adaptive_sleep_calculate(), and platform_sleep_usec().

◆ adaptive_sleep_init()

void adaptive_sleep_init ( adaptive_sleep_state_t state,
const adaptive_sleep_config_t config 
)

#include <time.h>

Initialize adaptive sleep state with configuration.

Sets up an adaptive sleep state structure with the provided configuration. The configuration is copied internally, so the caller doesn't need to keep the config structure alive.

Parameters
statePointer to adaptive sleep state to initialize
configPointer to configuration (will be copied)

Definition at line 285 of file time.c.

285 {
286 if (!state || !config) {
287 return;
288 }
289
290 // Copy configuration
291 state->config = *config;
292
293 // Start at baseline speed (no speedup initially)
295
296 // Initial sleep is the baseline
297 state->last_sleep_ns = config->baseline_sleep_ns;
298}

References adaptive_sleep_config_t::baseline_sleep_ns, adaptive_sleep_state_t::config, adaptive_sleep_state_t::current_speed_multiplier, adaptive_sleep_state_t::last_sleep_ns, and adaptive_sleep_config_t::min_speed_multiplier.

◆ format_duration_ms()

int format_duration_ms ( double  milliseconds,
char *  buffer,
size_t  buffer_size 
)

#include <time.h>

Format milliseconds as human-readable duration string.

Parameters
millisecondsDuration in milliseconds
bufferOutput buffer for formatted string
buffer_sizeSize of output buffer
Returns
Number of characters written (excluding null terminator), or -1 on error

Formats a duration in milliseconds into a human-readable string. The function automatically selects the most appropriate units and precision based on the duration magnitude.

Format rules:

  • For sub-millisecond durations: shows ns or µs
  • For sub-second durations: shows ms
  • For sub-minute durations: shows seconds with decimal
  • For sub-hour durations: shows minutes and seconds (e.g., "1m30s")
  • For sub-day durations: shows hours, minutes, and seconds (e.g., "5h30m0s")
  • For sub-year durations: shows days, hours, minutes, and seconds (e.g., "1d4h48m0s")
  • For year+ durations: shows years with decimal
Note
Buffer should be at least 32 bytes for all possible outputs
Thread-safe (no global state)

Definition at line 269 of file time.c.

269 {
270 // Convert milliseconds to nanoseconds and use the nanosecond formatter
271 double nanoseconds = milliseconds * NS_PER_MS;
272 return format_duration_ns(nanoseconds, buffer, buffer_size);
273}
#define NS_PER_MS
Definition time.h:181

References format_duration_ns(), and NS_PER_MS.

Referenced by broadcast_server_state_to_all_clients().

◆ format_duration_ns()

int format_duration_ns ( double  nanoseconds,
char *  buffer,
size_t  buffer_size 
)

#include <time.h>

Format nanoseconds as human-readable duration string.

Parameters
nanosecondsDuration in nanoseconds
bufferOutput buffer for formatted string
buffer_sizeSize of output buffer
Returns
Number of characters written (excluding null terminator), or -1 on error

Similar to format_duration_ms() but accepts nanosecond precision input. Useful for high-precision timing measurements.

Note
Buffer should be at least 32 bytes for all possible outputs
Thread-safe (no global state)

Definition at line 187 of file time.c.

187 {
188 if (!buffer || buffer_size == 0) {
189 return -1;
190 }
191
192 // Handle negative durations
193 if (nanoseconds < 0) {
194 nanoseconds = -nanoseconds;
195 }
196
197 int written = 0;
198
199 // Nanoseconds (< 1µs)
200 if (nanoseconds < NS_PER_US) {
201 written = snprintf(buffer, buffer_size, "%.0fns", nanoseconds);
202 }
203 // Microseconds (< 1ms)
204 else if (nanoseconds < NS_PER_MS) {
205 double us = nanoseconds / NS_PER_US;
206 if (us < 10.0) {
207 written = snprintf(buffer, buffer_size, "%.1fµs", us);
208 } else {
209 written = snprintf(buffer, buffer_size, "%.0fµs", us);
210 }
211 }
212 // Milliseconds (< 1s)
213 else if (nanoseconds < NS_PER_SEC) {
214 double ms = nanoseconds / NS_PER_MS;
215 if (ms < 10.0) {
216 written = snprintf(buffer, buffer_size, "%.1fms", ms);
217 } else {
218 written = snprintf(buffer, buffer_size, "%.0fms", ms);
219 }
220 }
221 // Seconds (< 1m)
222 else if (nanoseconds < NS_PER_MIN) {
223 double s = nanoseconds / NS_PER_SEC;
224 if (s < 10.0) {
225 written = snprintf(buffer, buffer_size, "%.2fs", s);
226 } else {
227 written = snprintf(buffer, buffer_size, "%.1fs", s);
228 }
229 }
230 // Minutes (< 1h) - show minutes and seconds
231 else if (nanoseconds < NS_PER_HOUR) {
232 int minutes = (int)(nanoseconds / NS_PER_MIN);
233 int seconds = (int)((nanoseconds - (minutes * NS_PER_MIN)) / NS_PER_SEC);
234 written = snprintf(buffer, buffer_size, "%dm%ds", minutes, seconds);
235 }
236 // Hours (< 1d) - show hours, minutes, and seconds
237 else if (nanoseconds < NS_PER_DAY) {
238 int hours = (int)(nanoseconds / NS_PER_HOUR);
239 double remaining_ns = nanoseconds - ((double)hours * NS_PER_HOUR);
240 int minutes = (int)(remaining_ns / NS_PER_MIN);
241 double remaining_after_min = remaining_ns - ((double)minutes * NS_PER_MIN);
242 int seconds = (int)(remaining_after_min / NS_PER_SEC);
243 written = snprintf(buffer, buffer_size, "%dh%dm%ds", hours, minutes, seconds);
244 }
245 // Days (< 1y) - show days, hours, minutes, and seconds
246 else if (nanoseconds < NS_PER_YEAR) {
247 int days = (int)(nanoseconds / NS_PER_DAY);
248 double remaining_ns = nanoseconds - ((double)days * NS_PER_DAY);
249 int hours = (int)(remaining_ns / NS_PER_HOUR);
250 remaining_ns = remaining_ns - ((double)hours * NS_PER_HOUR);
251 int minutes = (int)(remaining_ns / NS_PER_MIN);
252 double remaining_after_min = remaining_ns - ((double)minutes * NS_PER_MIN);
253 int seconds = (int)(remaining_after_min / NS_PER_SEC);
254 written = snprintf(buffer, buffer_size, "%dd%dh%dm%ds", days, hours, minutes, seconds);
255 }
256 // Years - show years with one decimal
257 else {
258 double years = nanoseconds / NS_PER_YEAR;
259 written = snprintf(buffer, buffer_size, "%.1fy", years);
260 }
261
262 if (written < 0 || (size_t)written >= buffer_size) {
263 return -1;
264 }
265
266 return written;
267}
#define NS_PER_HOUR
Definition time.h:184
#define NS_PER_MIN
Definition time.h:183
#define NS_PER_DAY
Definition time.h:185
#define NS_PER_YEAR
Definition time.h:186
#define NS_PER_US
Definition time.h:180
#define NS_PER_SEC
Definition time.h:182

References NS_PER_DAY, NS_PER_HOUR, NS_PER_MIN, NS_PER_MS, NS_PER_SEC, NS_PER_US, and NS_PER_YEAR.

Referenced by asciichat_instr_log_line(), format_duration_ms(), format_duration_s(), mixer_process_excluding_source(), and timer_stop().

◆ format_duration_s()

int format_duration_s ( double  seconds,
char *  buffer,
size_t  buffer_size 
)

#include <time.h>

Format seconds as human-readable duration string.

Parameters
secondsDuration in seconds
bufferOutput buffer for formatted string
buffer_sizeSize of output buffer
Returns
Number of characters written (excluding null terminator), or -1 on error

Similar to format_duration_ms() but accepts seconds as input. Useful for timing measurements already in seconds.

Note
Buffer should be at least 32 bytes for all possible outputs
Thread-safe (no global state)

Definition at line 275 of file time.c.

275 {
276 // Convert seconds to nanoseconds and use the nanosecond formatter
277 double nanoseconds = seconds * NS_PER_SEC;
278 return format_duration_ns(nanoseconds, buffer, buffer_size);
279}

References format_duration_ns(), and NS_PER_SEC.

Referenced by crypto_init(), and crypto_rekey_init().

◆ timer_is_initialized()

bool timer_is_initialized ( void  )

#include <time.h>

Check if timing system is initialized.

Returns
true if initialized, false otherwise

Definition at line 179 of file time.c.

179 {
180 return g_timer_manager.initialized;
181}

◆ timer_start()

bool timer_start ( const char *  name)

#include <time.h>

Start a named timer.

Creates a new timer record and stores the start time. If a timer with the same name exists, it will be overwritten.

Parameters
nameTimer name (must be unique, will be copied)
Returns
true on success, false on failure

Definition at line 84 of file time.c.

84 {
85 if (!g_timer_manager.initialized) {
86 SET_ERRNO(ERROR_INVALID_STATE, "Timer system not initialized");
87 return false;
88 }
89
90 if (!name) {
91 SET_ERRNO(ERROR_INVALID_PARAM, "Timer name is NULL");
92 return false;
93 }
94
95 rwlock_wrlock(&g_timer_manager.rwlock);
96
97 // Check if timer already exists - this is an error, timers must be unique
98 timer_record_t *existing = NULL;
99 HASH_FIND_STR(g_timer_manager.timers, name, existing);
100
101 if (existing) {
102 rwlock_wrunlock(&g_timer_manager.rwlock);
103 SET_ERRNO(ERROR_INVALID_STATE, "Timer '%s' already exists - timers must have unique names", name);
104 return false;
105 }
106
107 // Create new timer record
109 if (!timer) {
110 rwlock_wrunlock(&g_timer_manager.rwlock);
111 SET_ERRNO(ERROR_MEMORY, "Failed to allocate timer record");
112 return false;
113 }
114
115 // Use platform-safe string duplication
116 size_t name_len = strlen(name) + 1;
117 timer->name = SAFE_MALLOC(name_len, char *);
118 if (!timer->name) {
119 SAFE_FREE(timer);
120 rwlock_wrunlock(&g_timer_manager.rwlock);
121 SET_ERRNO(ERROR_MEMORY, "Failed to allocate timer name");
122 return false;
123 }
124 SAFE_STRNCPY(timer->name, name, name_len);
125
126 timer->start_ticks = stm_now();
127
128 // Add to hashtable
129 HASH_ADD_KEYPTR(hh, g_timer_manager.timers, timer->name, strlen(timer->name), timer);
130
131 rwlock_wrunlock(&g_timer_manager.rwlock);
132 return true;
133}
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:358
#define SAFE_FREE(ptr)
Definition common.h:320
#define SAFE_MALLOC(size, cast)
Definition common.h:208
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
@ ERROR_INVALID_STATE
@ ERROR_MEMORY
Definition error_codes.h:53
@ ERROR_INVALID_PARAM
#define rwlock_wrunlock(lock)
Release a write lock (with debug tracking in debug builds)
Definition rwlock.h:249
#define rwlock_wrlock(lock)
Acquire a write lock (with debug tracking in debug builds)
Definition rwlock.h:213
Individual timer record for a named timing operation.
Definition time.h:56
uint64_t start_ticks
Start time in sokol ticks.
Definition time.h:58
char * name
Timer name (heap-allocated, unique key)
Definition time.h:57

References ERROR_INVALID_PARAM, ERROR_INVALID_STATE, ERROR_MEMORY, timer_record::name, rwlock_wrlock, rwlock_wrunlock, SAFE_FREE, SAFE_MALLOC, SAFE_STRNCPY, SET_ERRNO, and timer_record::start_ticks.

◆ timer_stop()

double timer_stop ( const char *  name)

#include <time.h>

Stop a named timer and return elapsed time.

Looks up the timer by name, calculates elapsed time, logs it, and removes the timer from the hashtable.

Parameters
nameTimer name to stop
Returns
Elapsed time in nanoseconds, or -1.0 if timer not found

Definition at line 135 of file time.c.

135 {
136 if (!g_timer_manager.initialized) {
137 SET_ERRNO(ERROR_INVALID_STATE, "Timer system not initialized");
138 return -1.0;
139 }
140
141 if (!name) {
142 SET_ERRNO(ERROR_INVALID_PARAM, "Timer name is NULL");
143 return -1.0;
144 }
145
146 rwlock_wrlock(&g_timer_manager.rwlock);
147
148 // Find timer
149 timer_record_t *timer = NULL;
150 HASH_FIND_STR(g_timer_manager.timers, name, timer);
151
152 if (!timer) {
153 rwlock_wrunlock(&g_timer_manager.rwlock);
154 log_warn("Timer '%s' not found", name);
155 return -1.0;
156 }
157
158 // Calculate elapsed time in nanoseconds for maximum precision
159 uint64_t end_ticks = stm_now();
160 uint64_t elapsed_ticks = stm_diff(end_ticks, timer->start_ticks);
161 double elapsed_ns = stm_ns(elapsed_ticks);
162
163 // Format duration for human-readable logging
164 char duration_str[32];
165 format_duration_ns(elapsed_ns, duration_str, sizeof(duration_str));
166
167 // Log the result (debug level - caller can use return value for production logging)
168 log_debug("Timer '%s': %s", name, duration_str);
169
170 // Remove from hashtable
171 HASH_DEL(g_timer_manager.timers, timer);
172 SAFE_FREE(timer->name);
173 SAFE_FREE(timer);
174
175 rwlock_wrunlock(&g_timer_manager.rwlock);
176 return elapsed_ns; // Return nanoseconds
177}
#define log_warn(...)
Log a WARN message.
#define log_debug(...)
Log a DEBUG message.

References ERROR_INVALID_PARAM, ERROR_INVALID_STATE, format_duration_ns(), log_debug, log_warn, timer_record::name, rwlock_wrlock, rwlock_wrunlock, SAFE_FREE, SET_ERRNO, and timer_record::start_ticks.

◆ timer_system_cleanup()

void timer_system_cleanup ( void  )

#include <time.h>

Cleanup the timing system.

Frees all timer records and destroys mutex. Should be called at program exit.

Definition at line 60 of file time.c.

60 {
61 if (!g_timer_manager.initialized) {
62 return;
63 }
64
65 rwlock_wrlock(&g_timer_manager.rwlock);
66
67 // Free all timer records
68 timer_record_t *current, *tmp;
69 HASH_ITER(hh, g_timer_manager.timers, current, tmp) {
70 HASH_DEL(g_timer_manager.timers, current);
71 SAFE_FREE(current->name);
72 SAFE_FREE(current);
73 }
74
75 g_timer_manager.timers = NULL;
76 g_timer_manager.initialized = false;
77
78 rwlock_wrunlock(&g_timer_manager.rwlock);
79 rwlock_destroy(&g_timer_manager.rwlock);
80
81 log_debug("Timer system cleaned up");
82}
int rwlock_destroy(rwlock_t *lock)
Destroy a read-write lock.

References log_debug, timer_record::name, rwlock_destroy(), rwlock_wrlock, rwlock_wrunlock, and SAFE_FREE.

◆ timer_system_init()

bool timer_system_init ( void  )

#include <time.h>

Initialize the timing system.

Must be called before using any timer functions. Automatically calls stm_setup() for sokol_time initialization.

Returns
true on success, false on failure

Definition at line 39 of file time.c.

39 {
40 if (g_timer_manager.initialized) {
41 return true;
42 }
43
44 // Initialize sokol_time
45 stm_setup();
46
47 // Initialize rwlock (uthash requires external locking for writes, rwlock allows concurrent reads)
48 if (rwlock_init(&g_timer_manager.rwlock) != 0) {
49 SET_ERRNO(ERROR_PLATFORM_INIT, "Failed to initialize timer rwlock");
50 return false;
51 }
52
53 g_timer_manager.timers = NULL;
54 g_timer_manager.initialized = true;
55
56 log_debug("Timer system initialized");
57 return true;
58}
@ ERROR_PLATFORM_INIT
Definition error_codes.h:57
int rwlock_init(rwlock_t *lock)
Initialize a read-write lock.

References ERROR_PLATFORM_INIT, log_debug, rwlock_init(), and SET_ERRNO.