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

Server performance statistics tracking. More...

Go to the source code of this file.

Data Structures

struct  server_stats_t
 Server performance statistics structure. More...
 

Functions

void * stats_logger_thread (void *arg)
 Main statistics collection and reporting thread function.
 
int stats_init (void)
 Initialize the stats mutex.
 
void stats_cleanup (void)
 Cleanup the stats mutex.
 
void update_server_stats (void)
 Update global server statistics (placeholder)
 
void log_server_stats (void)
 Log comprehensive server statistics summary.
 

Variables

server_stats_t g_stats
 Global server statistics structure.
 
mutex_t g_stats_mutex
 Mutex protecting global server statistics.
 

Detailed Description

Server performance statistics tracking.

This header provides server-side performance statistics tracking including frame capture/send rates, bandwidth metrics, and performance counters.

Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
September 2025

Definition in file stats.h.

Function Documentation

◆ log_server_stats()

void log_server_stats ( void  )

Log comprehensive server statistics summary.

Outputs a formatted summary of server performance statistics including frame processing rates, throughput metrics, and system health indicators. This function provides operational visibility into server performance.

STATISTICS REPORTED:

FRAME PROCESSING METRICS:

  • frames_captured: Total frames received from all clients
  • frames_sent: Total ASCII frames delivered to all clients
  • frames_dropped: Frames lost due to overload or errors

PERFORMANCE INDICATORS:

  • avg_capture_fps: Moving average of frame capture rate
  • avg_send_fps: Moving average of frame delivery rate

THREAD SAFETY:

  • Acquires g_stats_mutex for atomic statistics snapshot
  • Prevents inconsistent reporting during concurrent updates
  • Minimal lock hold time (only during data copy)

USAGE SCENARIOS:

  • Periodic performance reporting
  • Debug information during troubleshooting
  • System health monitoring
  • Performance trend analysis

OUTPUT FORMAT:

  • Human-readable format suitable for log analysis
  • Structured data for automated monitoring
  • Consistent formatting for operational visibility
Note
Function provides thread-safe access to global statistics
Statistics snapshot is atomic to ensure consistency
See also
update_server_stats() For statistics update implementation

Definition at line 559 of file stats.c.

559 {
560 // Check if stats mutex is initialized before trying to lock it
561 // In debug builds, stats_init() may not be called (it's guarded by #ifdef NDEBUG)
562 // Skip logging if mutex is not initialized to avoid crashing
563 if (!g_stats_mutex_initialized) {
564 return; // Mutex not initialized, skip logging
565 }
567 log_info("Server Statistics:\n"
568 " frames_captured=%llu\n"
569 " frames_sent=%llu\n"
570 " frames_dropped=%llu\n"
571 " Average FPS: capture=%.2f, send=%.2f",
572 (unsigned long long)g_stats.frames_captured, (unsigned long long)g_stats.frames_sent,
575}
#define log_info(...)
Log an INFO message.
#define mutex_lock(mutex)
Lock a mutex (with debug tracking in debug builds)
Definition mutex.h:140
#define mutex_unlock(mutex)
Unlock a mutex (with debug tracking in debug builds)
Definition mutex.h:175
server_stats_t g_stats
Global server statistics structure.
Definition stats.c:159
mutex_t g_stats_mutex
Mutex protecting global server statistics.
Definition stats.c:168
uint64_t frames_dropped
Definition stats.h:50
double avg_capture_fps
Definition stats.h:52
uint64_t frames_captured
Definition stats.h:48
double avg_send_fps
Definition stats.h:53
uint64_t frames_sent
Definition stats.h:49

References server_stats_t::avg_capture_fps, server_stats_t::avg_send_fps, server_stats_t::frames_captured, server_stats_t::frames_dropped, server_stats_t::frames_sent, g_stats, g_stats_mutex, log_info, mutex_lock, and mutex_unlock.

Referenced by stats_logger_thread().

◆ stats_cleanup()

void stats_cleanup ( void  )

Cleanup the stats mutex.

Definition at line 195 of file stats.c.

195 {
196 if (g_stats_mutex_initialized) {
198 g_stats_mutex_initialized = false;
199 }
200}
int mutex_destroy(mutex_t *mutex)
Destroy a mutex.

References g_stats_mutex, and mutex_destroy().

Referenced by server_main().

◆ stats_init()

int stats_init ( void  )

Initialize the stats mutex.

Returns
0 on success, -1 on failure

Definition at line 184 of file stats.c.

184 {
185 int ret = mutex_init(&g_stats_mutex);
186 if (ret == 0) {
187 g_stats_mutex_initialized = true;
188 }
189 return ret;
190}
int mutex_init(mutex_t *mutex)
Initialize a mutex.

References g_stats_mutex, and mutex_init().

Referenced by server_main().

◆ stats_logger_thread()

void * stats_logger_thread ( void *  arg)

Main statistics collection and reporting thread function.

This background thread performs continuous monitoring of server performance and logs comprehensive statistics reports at regular intervals. It operates independently of the main server processing threads to avoid performance impact.

THREAD EXECUTION FLOW:

  1. INITIALIZATION:
    • Log thread startup (with debug instrumentation)
    • Initialize loop counters for debugging
    • Set up monitoring infrastructure
  2. MAIN MONITORING LOOP:
    • Check shutdown flag frequently (every 10ms)
    • Sleep in small intervals to maintain responsiveness
    • Collect statistics from all system components every 30 seconds
    • Generate comprehensive performance reports
  3. STATISTICS COLLECTION:
    • Global buffer pool utilization
    • Per-client connection and activity status
    • Packet queue performance metrics
    • Hash table efficiency statistics
    • Frame processing counters
  4. CLEANUP AND EXIT:
    • Detect shutdown signal and exit loop gracefully
    • Log thread termination for debugging
    • Return NULL to indicate clean exit

MONITORING METHODOLOGY:

NON-BLOCKING DATA COLLECTION:

  • Uses reader locks on shared data structures
  • Takes atomic snapshots of volatile counters
  • Minimal impact on operational performance
  • Safe concurrent access with render threads

RESPONSIVE SHUTDOWN:

  • Checks g_server_should_exit every 10ms during sleep periods
  • Exits monitoring loop immediately when shutdown detected
  • No hanging or delayed shutdown behavior
  • Clean resource cleanup

PERFORMANCE METRICS COLLECTED:

CLIENT STATISTICS:

  • Total active clients
  • Clients with audio queues active
  • Clients with video queues active
  • Per-client connection duration

BUFFER POOL METRICS:

  • Global allocation/deallocation rates
  • Peak memory usage patterns
  • Buffer pool efficiency
  • Memory fragmentation indicators

PACKET QUEUE PERFORMANCE:

  • Per-client enqueue/dequeue rates
  • Packet drop incidents
  • Queue depth histograms
  • Overflow frequency analysis

HASH TABLE EFFICIENCY:

  • Client lookup performance
  • Hash collision statistics
  • Load balancing effectiveness
  • Access pattern analysis

DEBUGGING AND TROUBLESHOOTING:

EXTENSIVE DEBUG LOGGING: The function contains detailed debug printf statements for troubleshooting threading issues. This instrumentation helps diagnose:

  • Thread startup/shutdown problems
  • Shutdown detection timing issues
  • Sleep/wake cycle behavior
  • Statistics collection reliability

DEBUG OUTPUT INCLUDES:

  • Function entry/exit points
  • Loop iteration counts
  • Shutdown flag state changes
  • Sleep cycle progression
  • Statistics collection timing

ERROR HANDLING:

  • Graceful handling of data access failures
  • Continued operation if individual metrics fail
  • No fatal errors that would crash statistics thread
  • Degraded reporting if subsystems unavailable

PERFORMANCE CONSIDERATIONS:

  • 30-second reporting interval balances visibility vs overhead
  • 10ms sleep granularity provides responsive shutdown
  • Read-only access minimizes lock contention
  • Background processing doesn't affect real-time performance
Parameters
argThread argument (unused - required by thread interface)
Returns
NULL on clean thread termination
Note
This function runs continuously until server shutdown
Debug printf statements help diagnose threading issues
All statistics collection is non-blocking and read-only
Warning
Thread must be properly joined to prevent resource leaks

Definition at line 332 of file stats.c.

332 {
333 (void)arg;
334
335 while (!atomic_load(&g_server_should_exit)) {
336 // Log buffer pool statistics every 10 seconds with fast exit checking (10ms intervals)
337 for (int i = 0; i < 1000 && !atomic_load(&g_server_should_exit); i++) {
338 platform_sleep_usec(10000); // 10ms sleep
339 }
340
341 // Check exit condition before proceeding with statistics logging
342 // CRITICAL: Check multiple times to avoid accessing freed resources during shutdown
343 if (atomic_load(&g_server_should_exit)) {
344 break;
345 }
346
347 // Collect all statistics data first
348#ifndef NDEBUG
349 char lock_debug_info[512] = {0};
350 // CRITICAL: Check exit condition again before accessing lock_debug
351 // lock_debug might be destroyed during shutdown
352 if (!atomic_load(&g_server_should_exit) && lock_debug_is_initialized()) {
353 uint64_t total_acquired = 0, total_released = 0;
354 uint32_t currently_held = 0;
355 lock_debug_get_stats(&total_acquired, &total_released, &currently_held);
356
357 safe_snprintf(lock_debug_info, sizeof(lock_debug_info),
358 "Historical Mutex/RWLock Statistics:\n"
359 " Total locks acquired: %llu\n"
360 " Total locks released: %llu\n"
361 " Currently held: %u\n"
362 " Net locks (acquired - released): %lld",
363 (unsigned long long)total_acquired, (unsigned long long)total_released, currently_held,
364 (long long)total_acquired - (long long)total_released);
365 }
366#endif
367
368 // Collect client statistics
369 // CRITICAL: Check exit condition again before accessing rwlock
370 // rwlock might be destroyed during shutdown
371 if (atomic_load(&g_server_should_exit)) {
372 break;
373 }
374
376 int active_clients = 0;
377 int clients_with_audio = 0;
378 int clients_with_video = 0;
379 char client_details[2048] = {0};
380 int client_details_len = 0;
381
382 for (int i = 0; i < MAX_CLIENTS; i++) {
383 if (atomic_load(&g_client_manager.clients[i].active)) {
384 active_clients++;
386 clients_with_audio++;
387 }
389 clients_with_video++;
390 }
391 }
392 }
393
394 // Collect per-client details
395 for (int i = 0; i < MAX_CLIENTS; i++) {
397 bool is_active = atomic_load(&client->active);
398 uint32_t client_id_snapshot = atomic_load(&client->client_id);
399
400 if (is_active && client_id_snapshot != 0) {
401 // Check audio queue stats
402 if (client->audio_queue) {
403 uint64_t enqueued, dequeued, dropped;
404 packet_queue_get_stats(client->audio_queue, &enqueued, &dequeued, &dropped);
405 if (enqueued > 0 || dequeued > 0 || dropped > 0) {
406 int len =
407 snprintf(client_details + client_details_len, sizeof(client_details) - client_details_len,
408 " Client %u audio queue: %llu enqueued, %llu dequeued, %llu dropped", client_id_snapshot,
409 (unsigned long long)enqueued, (unsigned long long)dequeued, (unsigned long long)dropped);
410 if (len > 0 && client_details_len + len < (int)sizeof(client_details)) {
411 client_details_len += len;
412 }
413 }
414 }
415 // Check video buffer stats
416 if (client->outgoing_video_buffer) {
419 if (stats.total_frames > 0) {
420 int len = snprintf(client_details + client_details_len, sizeof(client_details) - client_details_len,
421 " Client %u video buffer: %llu frames, %llu dropped (%.1f%% drop rate)",
422 client_id_snapshot, (unsigned long long)stats.total_frames,
423 (unsigned long long)stats.dropped_frames, stats.drop_rate * 100.0f);
424 if (len > 0 && client_details_len + len < (int)sizeof(client_details)) {
425 client_details_len += len;
426 }
427 }
428 }
429 }
430 }
432
433 // Single comprehensive log statement
434 if (client_details_len > 0) {
435 log_info("Stats: Clients: %d, Audio: %d, Video: %d\n%s", active_clients, clients_with_audio, clients_with_video,
436 client_details);
437 }
438 }
439
441
443
444 // Clean up thread-local error context before exit
446
447 return NULL;
448}
unsigned int uint32_t
Definition common.h:58
unsigned long long uint64_t
Definition common.h:59
void asciichat_error_stats_print(void)
Print error statistics to stderr.
void asciichat_errno_cleanup(void)
Cleanup error system resources.
#define MAX_CLIENTS
Maximum possible clients (static array size) - actual runtime limit set by –max-clients (1-32)
Definition limits.h:23
void packet_queue_get_stats(packet_queue_t *queue, uint64_t *enqueued, uint64_t *dequeued, uint64_t *dropped)
Get queue statistics.
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe version of snprintf that ensures null termination.
#define rwlock_rdlock(lock)
Acquire a read lock (with debug tracking in debug builds)
Definition rwlock.h:194
void platform_sleep_usec(unsigned int usec)
High-precision sleep function with microsecond precision.
bool lock_debug_is_initialized(void)
#define rwlock_rdunlock(lock)
Release a read lock (with debug tracking in debug builds)
Definition rwlock.h:231
void video_frame_get_stats(video_frame_buffer_t *vfb, video_frame_stats_t *stats)
Get frame statistics for quality monitoring.
rwlock_t g_client_manager_rwlock
Reader-writer lock protecting the global client manager.
client_manager_t g_client_manager
Global client manager singleton - central coordination point.
void log_server_stats(void)
Log comprehensive server statistics summary.
Definition stats.c:559
atomic_bool g_server_should_exit
Global shutdown flag from main.c - coordinate statistics thread termination.
Per-client state structure for server-side client management.
atomic_uint client_id
video_frame_buffer_t * outgoing_video_buffer
packet_queue_t * audio_queue
atomic_bool active
client_info_t clients[MAX_CLIENTS]
Array of client_info_t structures (backing storage)
Frame statistics structure.
uint64_t dropped_frames
Total frames dropped (due to buffer full or errors)
uint64_t total_frames
Total frames received since creation.
float drop_rate
Frame drop rate (dropped_frames / total_frames, 0.0-1.0)

References client_info::active, asciichat_errno_cleanup(), asciichat_error_stats_print(), client_info::audio_queue, client_info::client_id, client_manager_t::clients, video_frame_stats_t::drop_rate, video_frame_stats_t::dropped_frames, g_client_manager, g_client_manager_rwlock, g_server_should_exit, lock_debug_is_initialized(), log_info, log_server_stats(), MAX_CLIENTS, client_info::outgoing_video_buffer, packet_queue_get_stats(), platform_sleep_usec(), rwlock_rdlock, rwlock_rdunlock, safe_snprintf(), video_frame_stats_t::total_frames, and video_frame_get_stats().

Referenced by server_main().

◆ update_server_stats()

void update_server_stats ( void  )

Update global server statistics (placeholder)

This function is intended to update the global server statistics structure with current performance metrics. Currently unimplemented but provides the framework for centralized statistics updates.

PLANNED FUNCTIONALITY:

  • Aggregate per-client frame counts into global totals
  • Calculate moving averages for FPS metrics
  • Update system health indicators
  • Compute performance trend data

IMPLEMENTATION STRATEGY:

  • Thread-safe updates using g_stats_mutex
  • Atomic operations for frequently updated counters
  • Efficient aggregation algorithms
  • Minimal performance impact

INTEGRATION POINTS:

  • Called by render threads when updating frame counts
  • Invoked by client management code for connection metrics
  • Used by packet queue systems for throughput tracking

    Todo:
    Implement comprehensive statistics aggregation
    Note
    Function currently serves as placeholder for future development

Definition at line 478 of file stats.c.

478 {
479 // Aggregate statistics from all active clients
480 uint64_t total_frames_sent = 0;
481 uint64_t total_frames_dropped = 0;
482
483 // Read-lock to safely iterate over all clients
485
486 for (int i = 0; i < MAX_CLIENTS; i++) {
488 if (atomic_load(&client->client_id) != 0 && atomic_load(&client->active)) {
489 // Aggregate frames sent to all clients
490 total_frames_sent += client->frames_sent;
491
492 // Get dropped frame statistics from outgoing video buffer
493 if (client->outgoing_video_buffer) {
496 total_frames_dropped += stats.dropped_frames;
497 }
498 }
499 }
500
502
503 // Update global statistics atomically
505 g_stats.frames_sent = total_frames_sent;
506 g_stats.frames_dropped = total_frames_dropped;
507
508 // Calculate frames_captured from frames_sent and frames_dropped
509 // frames_captured = frames_sent + frames_dropped (total output frames)
510 if (total_frames_sent > 0 || total_frames_dropped > 0) {
511 g_stats.frames_captured = total_frames_sent + total_frames_dropped;
512 }
513
515}

References client_info::active, client_info::client_id, client_manager_t::clients, video_frame_stats_t::dropped_frames, server_stats_t::frames_captured, server_stats_t::frames_dropped, client_info::frames_sent, server_stats_t::frames_sent, g_client_manager, g_client_manager_rwlock, g_stats, g_stats_mutex, MAX_CLIENTS, mutex_lock, mutex_unlock, client_info::outgoing_video_buffer, rwlock_rdlock, rwlock_rdunlock, and video_frame_get_stats().

Variable Documentation

◆ g_stats

server_stats_t g_stats
extern

Global server statistics structure.

Maintains aggregated performance metrics for the entire server including frame processing rates, client counts, and system health indicators. All access to this structure must be protected by g_stats_mutex.

CONTENTS:

  • frames_captured: Total frames received from all clients
  • frames_sent: Total ASCII frames delivered to all clients
  • frames_dropped: Frames lost due to buffer overflows or processing delays
  • avg_capture_fps: Moving average of frame capture rate
  • avg_send_fps: Moving average of frame delivery rate

Definition at line 159 of file stats.c.

159{0};

Referenced by log_server_stats(), server_main(), and update_server_stats().

◆ g_stats_mutex

mutex_t g_stats_mutex
extern

Mutex protecting global server statistics.

Ensures thread-safe access to g_stats structure from both the statistics collection thread and any operational threads that update counters. Uses standard mutex (not reader-writer) due to relatively infrequent access.

Definition at line 168 of file stats.c.

168{0};

Referenced by log_server_stats(), server_main(), stats_cleanup(), stats_init(), and update_server_stats().