ascii-chat 0.8.38
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 563 of file stats.c.

563 {
564 // Use static_mutex to protect initialization check (TOCTOU race prevention)
565 // In debug builds, stats_init() may not be called (it's guarded by #ifdef NDEBUG)
566 // Use lock to prevent cleanup from destroying mutex while we're about to lock it
567 static_mutex_lock(&g_stats_init_check_mutex);
568 if (!g_stats_mutex_initialized) {
569 static_mutex_unlock(&g_stats_init_check_mutex);
570 return; // Mutex not initialized, skip logging
571 }
572 static_mutex_unlock(&g_stats_init_check_mutex);
573
574 // Now safe to use the mutex (it was initialized and not being cleaned up)
575 mutex_lock(&g_stats_mutex);
576 log_info("Server Statistics:\n"
577 " frames_captured=%llu\n"
578 " frames_sent=%llu\n"
579 " frames_dropped=%llu\n"
580 " Average FPS: capture=%.2f, send=%.2f",
581 (unsigned long long)g_stats.frames_captured, (unsigned long long)g_stats.frames_sent,
583 mutex_unlock(&g_stats_mutex);
584}
server_stats_t g_stats
Global server statistics structure.
Definition stats.c:162
mutex_t g_stats_mutex
Mutex protecting global server statistics.
Definition stats.c:171
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, and g_stats_mutex.

Referenced by stats_logger_thread().

◆ stats_cleanup()

void stats_cleanup ( void  )

Cleanup the stats mutex.

Uses static_mutex to protect flag changes (TOCTOU race prevention). Ensures other threads don't attempt to use the mutex after it's destroyed.

Definition at line 203 of file stats.c.

203 {
204 static_mutex_lock(&g_stats_init_check_mutex);
205 if (g_stats_mutex_initialized) {
206 g_stats_mutex_initialized = false; // Clear flag before destroying mutex
207 static_mutex_unlock(&g_stats_init_check_mutex);
209 } else {
210 static_mutex_unlock(&g_stats_init_check_mutex);
211 }
212}
int mutex_destroy(mutex_t *mutex)
Definition threading.c:21

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 189 of file stats.c.

189 {
190 int ret = mutex_init(&g_stats_mutex);
191 if (ret == 0) {
192 g_stats_mutex_initialized = true;
193 }
194 return ret;
195}
int mutex_init(mutex_t *mutex)
Definition threading.c:16

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 336 of file stats.c.

336 {
337 (void)arg;
338
339 while (!atomic_load(&g_server_should_exit)) {
340 // Log buffer pool statistics every 10 seconds with fast exit checking (10ms intervals)
341 for (int i = 0; i < 1000 && !atomic_load(&g_server_should_exit); i++) {
342 platform_sleep_us(10 * US_PER_MS_INT); // 10ms sleep
343 }
344
345 // Check exit condition before proceeding with statistics logging
346 // Check multiple times to avoid accessing freed resources during shutdown.
347 if (atomic_load(&g_server_should_exit)) {
348 break;
349 }
350
351 // Collect all statistics data first
352#ifndef NDEBUG
353 char lock_debug_info[BUFFER_SIZE_MEDIUM] = {0};
354 // Check exit condition again before accessing lock_debug.
355 // lock_debug might be destroyed during shutdown
356 if (!atomic_load(&g_server_should_exit) && lock_debug_is_initialized()) {
357 uint64_t total_acquired = 0, total_released = 0;
358 uint32_t currently_held = 0;
359 lock_debug_get_stats(&total_acquired, &total_released, &currently_held);
360
361 safe_snprintf(lock_debug_info, sizeof(lock_debug_info),
362 "Historical Mutex/RWLock Statistics:\n"
363 " Total locks acquired: %llu\n"
364 " Total locks released: %llu\n"
365 " Currently held: %u\n"
366 " Net locks (acquired - released): %lld",
367 (unsigned long long)total_acquired, (unsigned long long)total_released, currently_held,
368 (long long)total_acquired - (long long)total_released);
369 }
370#endif
371
372 // Collect client statistics
373 // Check exit condition again before accessing rwlock.
374 // rwlock might be destroyed during shutdown.
375 if (atomic_load(&g_server_should_exit)) {
376 break;
377 }
378
379 rwlock_rdlock(&g_client_manager_rwlock);
380 int active_clients = 0;
381 int clients_with_audio = 0;
382 int clients_with_video = 0;
383 char client_details[BUFFER_SIZE_XLARGE] = {0};
384 int client_details_len = 0;
385
386 for (int i = 0; i < MAX_CLIENTS; i++) {
387 if (atomic_load(&g_client_manager.clients[i].active)) {
388 active_clients++;
389 if (g_client_manager.clients[i].audio_queue) {
390 clients_with_audio++;
391 }
392 if (g_client_manager.clients[i].outgoing_video_buffer) {
393 clients_with_video++;
394 }
395 }
396 }
397
398 // Collect per-client details
399 for (int i = 0; i < MAX_CLIENTS; i++) {
400 client_info_t *client = &g_client_manager.clients[i];
401 bool is_active = atomic_load(&client->active);
402 uint32_t client_id_snapshot = atomic_load(&client->client_id);
403
404 if (is_active && client_id_snapshot != 0) {
405 // Check audio queue stats
406 if (client->audio_queue) {
407 uint64_t enqueued, dequeued, dropped;
408 packet_queue_get_stats(client->audio_queue, &enqueued, &dequeued, &dropped);
409 if (enqueued > 0 || dequeued > 0 || dropped > 0) {
410 int len =
411 safe_snprintf(client_details + client_details_len, sizeof(client_details) - client_details_len,
412 " Client %u audio queue: %llu enqueued, %llu dequeued, %llu dropped", client_id_snapshot,
413 (unsigned long long)enqueued, (unsigned long long)dequeued, (unsigned long long)dropped);
414 if (len > 0 && client_details_len + len < (int)sizeof(client_details)) {
415 client_details_len += len;
416 }
417 }
418 }
419 // Check video buffer stats
420 if (client->outgoing_video_buffer) {
421 video_frame_stats_t stats;
422 video_frame_get_stats(client->outgoing_video_buffer, &stats);
423 if (stats.total_frames > 0) {
424 int len = safe_snprintf(client_details + client_details_len, sizeof(client_details) - client_details_len,
425 " Client %u video buffer: %llu frames, %llu dropped (%.1f%% drop rate)",
426 client_id_snapshot, (unsigned long long)stats.total_frames,
427 (unsigned long long)stats.dropped_frames, stats.drop_rate * 100.0f);
428 if (len > 0 && client_details_len + len < (int)sizeof(client_details)) {
429 client_details_len += len;
430 }
431 }
432 }
433 }
434 }
435 rwlock_rdunlock(&g_client_manager_rwlock);
436
437 // Single comprehensive log statement
438 if (client_details_len > 0) {
439 log_info("Stats: Clients: %d, Audio: %d, Video: %d\n%s", active_clients, clients_with_audio, clients_with_video,
440 client_details);
441 }
442 }
443
445
447
448 // Clean up thread-local error context before exit
450
451 return NULL;
452}
void asciichat_error_stats_print(void)
void asciichat_errno_destroy(void)
void lock_debug_get_stats(uint64_t *total_acquired, uint64_t *total_released, uint32_t *currently_held)
Definition lock.c:1372
bool lock_debug_is_initialized(void)
Definition lock.c:1380
void packet_queue_get_stats(packet_queue_t *queue, uint64_t *enqueued, uint64_t *dequeued, uint64_t *dropped)
void platform_sleep_us(unsigned int us)
atomic_bool g_server_should_exit
Global atomic shutdown flag shared across all threads.
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:563
client_info_t clients[MAX_CLIENTS]
Array of client_info_t structures (backing storage)
Definition client.h:65
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.
Definition system.c:456
void video_frame_get_stats(video_frame_buffer_t *vfb, video_frame_stats_t *stats)

References asciichat_errno_destroy(), asciichat_error_stats_print(), client_manager_t::clients, g_client_manager, g_client_manager_rwlock, g_server_should_exit, lock_debug_get_stats(), lock_debug_is_initialized(), log_server_stats(), packet_queue_get_stats(), platform_sleep_us(), safe_snprintf(), 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 482 of file stats.c.

482 {
483 // Aggregate statistics from all active clients
484 uint64_t total_frames_sent = 0;
485 uint64_t total_frames_dropped = 0;
486
487 // Read-lock to safely iterate over all clients
488 rwlock_rdlock(&g_client_manager_rwlock);
489
490 for (int i = 0; i < MAX_CLIENTS; i++) {
491 client_info_t *client = &g_client_manager.clients[i];
492 if (atomic_load(&client->client_id) != 0 && atomic_load(&client->active)) {
493 // Aggregate frames sent to all clients
494 total_frames_sent += client->frames_sent;
495
496 // Get dropped frame statistics from outgoing video buffer
497 if (client->outgoing_video_buffer) {
498 video_frame_stats_t stats;
499 video_frame_get_stats(client->outgoing_video_buffer, &stats);
500 total_frames_dropped += stats.dropped_frames;
501 }
502 }
503 }
504
505 rwlock_rdunlock(&g_client_manager_rwlock);
506
507 // Update global statistics atomically
508 mutex_lock(&g_stats_mutex);
509 g_stats.frames_sent = total_frames_sent;
510 g_stats.frames_dropped = total_frames_dropped;
511
512 // Calculate frames_captured from frames_sent and frames_dropped
513 // frames_captured = frames_sent + frames_dropped (total output frames)
514 if (total_frames_sent > 0 || total_frames_dropped > 0) {
515 g_stats.frames_captured = total_frames_sent + total_frames_dropped;
516 }
517
518 mutex_unlock(&g_stats_mutex);
519}

References client_manager_t::clients, server_stats_t::frames_captured, server_stats_t::frames_dropped, server_stats_t::frames_sent, g_client_manager, g_client_manager_rwlock, g_stats, g_stats_mutex, 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 162 of file stats.c.

162{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 171 of file stats.c.

171{0};

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