ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
callback_timing.h File Reference

WebSocket callback timing instrumentation. More...

Go to the source code of this file.

Data Structures

struct  websocket_callback_stats_t
 Per-callback timing statistics. More...
 
struct  websocket_callback_timing_t
 WebSocket callback timing data for protocol lifecycle. More...
 

Functions

void websocket_callback_timing_record (websocket_callback_stats_t *stats, uint64_t start_ns, uint64_t end_ns)
 Record callback invocation.
 
void websocket_callback_timing_log_stats (void)
 Log current callback statistics.
 
void websocket_callback_timing_reset (void)
 Reset timing statistics.
 

Variables

websocket_callback_timing_t g_ws_callback_timing
 Global timing tracker.
 

Detailed Description

WebSocket callback timing instrumentation.

Tracks timing and frequency of libwebsockets callbacks to diagnose performance issues (Issue #305: WebSocket FPS bug).

Author
Claude (Anthropic)
Date
February 2026

Definition in file callback_timing.h.

Function Documentation

◆ websocket_callback_timing_log_stats()

void websocket_callback_timing_log_stats ( void  )

Log current callback statistics.

Prints aggregate statistics for all tracked callbacks to help diagnose callback frequency and performance issues.

Definition at line 66 of file callback_timing.c.

66 {
71
72 log_info("\n===== WEBSOCKET CALLBACK TIMING STATISTICS =====");
73 log_info("Timestamp: %lu ns", websocket_callback_timing_start());
74
75 // PROTOCOL_INIT stats
76 log_info("LWS_CALLBACK_PROTOCOL_INIT:");
77 log_info(" Total invocations: %lu", protocol_init_count);
78 if (protocol_init_count > 0) {
80 uint64_t avg_duration = total_duration / protocol_init_count;
81 log_info(" Avg duration: %lu ns", avg_duration);
82 }
83
84 // PROTOCOL_DESTROY stats
85 log_info("LWS_CALLBACK_PROTOCOL_DESTROY:");
86 log_info(" Total invocations: %lu", protocol_destroy_count);
87 if (protocol_destroy_count > 0) {
89 uint64_t avg_duration = total_duration / protocol_destroy_count;
90 log_info(" Avg duration: %lu ns", avg_duration);
91 }
92
93 // SERVER_WRITEABLE stats
94 log_info("LWS_CALLBACK_SERVER_WRITEABLE:");
95 log_info(" Total invocations: %lu", writeable_count);
96 if (writeable_count > 0) {
98 uint64_t avg_duration = total_duration / writeable_count;
101 log_info(" Avg duration: %lu ns", avg_duration);
102 if (min_interval != UINT64_MAX) {
103 log_info(" Min interval between callbacks: %lu ns (%.2f Hz)", min_interval, 1e9 / (double)min_interval);
104 }
105 if (max_interval > 0) {
106 log_info(" Max interval between callbacks: %lu ns (%.2f Hz)", max_interval, 1e9 / (double)max_interval);
107 }
108 }
109
110 // RECEIVE stats
111 log_info("LWS_CALLBACK_RECEIVE:");
112 log_info(" Total invocations: %lu", receive_count);
113 if (receive_count > 0) {
115 uint64_t avg_duration = total_duration / receive_count;
118 log_info(" Avg duration: %lu ns", avg_duration);
119 if (min_interval != UINT64_MAX) {
120 log_info(" Min interval between callbacks: %lu ns (%.2f Hz)", min_interval, 1e9 / (double)min_interval);
121 }
122 if (max_interval > 0) {
123 log_info(" Max interval between callbacks: %lu ns (%.2f Hz)", max_interval, 1e9 / (double)max_interval);
124 }
125 }
126
127 log_info("===== END TIMING STATISTICS =====\n");
128}
uint64_t atomic_load_u64(atomic_t *a)
Atomically load a uint64_t value.
Definition atomic.c:233
websocket_callback_timing_t g_ws_callback_timing
Global timing tracker - shared across all WebSocket connections.
unsigned long long uint64_t
Definition common.h:59
#define log_info(...)
Log an INFO message.
Definition log/log.h:561
websocket_callback_stats_t receive
websocket_callback_stats_t protocol_destroy
websocket_callback_stats_t server_writeable
websocket_callback_stats_t protocol_init

References atomic_load_u64(), websocket_callback_stats_t::count, g_ws_callback_timing, log_info, websocket_callback_stats_t::max_interval_ns, websocket_callback_stats_t::min_interval_ns, websocket_callback_timing_t::protocol_destroy, websocket_callback_timing_t::protocol_init, websocket_callback_timing_t::receive, websocket_callback_timing_t::server_writeable, and websocket_callback_stats_t::total_duration_ns.

◆ websocket_callback_timing_record()

void websocket_callback_timing_record ( websocket_callback_stats_t *  stats,
uint64_t  start_ns,
uint64_t  end_ns 
)

Record callback invocation.

Updates statistics for the given callback type with timing information.

Parameters
statsPointer to callback statistics structure
start_nsStart timestamp from websocket_callback_timing_start()
end_nsEnd timestamp (typically current time)

Definition at line 21 of file callback_timing.c.

21 {
22 if (!stats) {
23 return;
24 }
25
26 uint64_t duration_ns = (end_ns > start_ns) ? (end_ns - start_ns) : 0;
27 uint64_t count = atomic_fetch_add_u64(&stats->count, 1);
28
29 // Track cumulative duration
30 atomic_fetch_add_u64(&stats->total_duration_ns, duration_ns);
31
32 // Update last timestamp (atomically swap)
33 uint64_t prev_last_ns = atomic_load_u64(&stats->last_ns);
34 while (!atomic_cas_u64(&stats->last_ns, &prev_last_ns, end_ns)) {
35 // Retry if CAS failed due to concurrent update
36 }
37
38 // Calculate interval from previous callback (if not the first one)
39 if (count > 0 && prev_last_ns > 0) {
40 uint64_t interval_ns = (end_ns > prev_last_ns) ? (end_ns - prev_last_ns) : 0;
41
42 // Track min intervals (atomic compare-and-swap loop to avoid TOCTOU race)
43 if (interval_ns > 0) {
44 uint64_t current_min = atomic_load_u64(&stats->min_interval_ns);
45 while (interval_ns < current_min) {
46 if (atomic_cas_u64(&stats->min_interval_ns, &current_min, interval_ns)) {
47 break;
48 }
49 // CAS failed - reload current value and retry if still applicable
50 current_min = atomic_load_u64(&stats->min_interval_ns);
51 }
52 }
53
54 // Track max intervals (atomic compare-and-swap loop to avoid TOCTOU race)
55 uint64_t current_max = atomic_load_u64(&stats->max_interval_ns);
56 while (interval_ns > current_max) {
57 if (atomic_cas_u64(&stats->max_interval_ns, &current_max, interval_ns)) {
58 break;
59 }
60 // CAS failed - reload current value and retry if still applicable
61 current_max = atomic_load_u64(&stats->max_interval_ns);
62 }
63 }
64}
asciichat_error_stats_t stats
uint64_t atomic_fetch_add_u64(atomic_t *a, uint64_t delta)
Atomically add to a uint64_t and return the previous value.
Definition atomic.c:248
bool atomic_cas_u64(atomic_t *a, uint64_t *expected, uint64_t new_value)
Atomically compare-and-swap a uint64_t.
Definition atomic.c:264

References atomic_cas_u64(), atomic_fetch_add_u64(), atomic_load_u64(), and stats.

◆ websocket_callback_timing_reset()

void websocket_callback_timing_reset ( void  )

Variable Documentation

◆ g_ws_callback_timing

websocket_callback_timing_t g_ws_callback_timing
extern

Global timing tracker.

Shared across all WebSocket connections to profile callback efficiency.

Global timing tracker.

Definition at line 19 of file callback_timing.c.

19{0};

Referenced by websocket_callback_timing_log_stats(), and websocket_callback_timing_reset().