ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches

📊 Server performance monitoring: resource utilization tracking, client metrics, and health reporting More...

Go to the source code of this file.

Functions

int stats_init (void)
 Initialize the stats mutex.
 
void stats_cleanup (void)
 Cleanup the stats mutex.
 
void * stats_logger_thread (void *arg)
 Main statistics collection and reporting thread function.
 
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 = {0}
 Global server statistics structure.
 
mutex_t g_stats_mutex = {0}
 Mutex protecting global server statistics.
 

Detailed Description

📊 Server performance monitoring: resource utilization tracking, client metrics, and health reporting

1. Continuous monitoring of server performance metricsmetricsPer-client statistics collection and reportingreportingBuffer pool utilization trackingtrackingPacket queue performance analysisanalysisHash table efficiency monitoringmonitoringPeriodic statistics logging for operational visibility MONITORING ARCHITECTURE:

STATISTICS COLLECTION THREAD:

  • Dedicated background thread for non-intrusive monitoring
  • 30-second reporting intervals (configurable)
  • Interruptible sleep for responsive shutdown
  • Thread-safe data collection from all system components

PERFORMANCE IMPACT MINIMIZATION:

  • Read-only access to operational data structures
  • Minimal locking (reader locks where possible)
  • Background processing doesn't affect real-time performance
  • Throttled logging to prevent log spam

MONITORED SUBSYSTEMS:

CLIENT MANAGEMENT METRICS:

  • Active client count
  • Clients with audio capabilities
  • Clients with video capabilities
  • Connection duration and activity patterns

BUFFER POOL PERFORMANCE:

  • Global buffer pool utilization
  • Allocation/deallocation rates
  • Peak usage patterns
  • Memory efficiency metrics

PACKET QUEUE STATISTICS:

  • Per-client queue depths
  • Enqueue/dequeue rates
  • Packet drop rates under load
  • Queue overflow incidents

HASH TABLE EFFICIENCY:

  • Client lookup performance
  • Hash collision rates
  • Load factor monitoring
  • Access pattern analysis

FRAME PROCESSING METRICS:

  • Total frames captured
  • Total frames sent to clients
  • Frame drop rate under load
  • Blank frame count (no video sources)

THREAD SAFETY AND DATA CONSISTENCY:

NON-INTRUSIVE MONITORING:

  • Uses reader locks to avoid blocking operational threads
  • Takes atomic snapshots of volatile data
  • Minimal impact on render thread performance
  • Safe concurrent access to client data

STATISTICS ATOMICITY:

  • Global statistics protected by dedicated mutex
  • Consistent reporting even during concurrent updates
  • Thread-safe access to shared counters

OPERATIONAL INTEGRATION:

LIFECYCLE MANAGEMENT:

  • Statistics thread started in main.c during server initialization
  • Graceful shutdown coordination with other threads
  • Clean resource cleanup on server termination

DEBUGGING SUPPORT:

  • Extensive debug logging for troubleshooting
  • Performance bottleneck identification
  • System health monitoring
  • Operational visibility for administrators

EXTENSIBILITY FRAMEWORK:

METRIC ADDITION:

  • Easy addition of new performance counters
  • Modular statistics collection
  • Configurable reporting intervals
  • Custom metric aggregation

INTEGRATION POINTS:

  • client.c: Client lifecycle statistics
  • render.c: Frame processing metrics
  • buffer_pool.c: Memory utilization data
  • packet_queue.c: Queue performance data

WHY THIS MODULAR DESIGN:

The original server.c had no centralized monitoring, making it impossible to:

  • Understand system performance characteristics
  • Debug performance issues under load
  • Monitor resource utilization
  • Track client behavior patterns

This separation provides:

  • Centralized performance visibility
  • Non-intrusive monitoring infrastructure
  • Operational debugging capabilities
  • System health awareness

PERFORMANCE PHILOSOPHY:

  • Monitoring should never impact real-time performance
  • Statistics collection uses minimal CPU overhead
  • Background processing model
  • Graceful degradation under extreme load
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
September 2025
Version
2.0 (Post-Modularization)
See also
main.c For statistics thread lifecycle management
buffer_pool.c For memory utilization monitoring
packet_queue.c For queue performance metrics

Definition in file stats.c.

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

554 {
555 // Check if stats mutex is initialized (safe in debug builds where stats_init() may not be called)
556 if (!lifecycle_is_initialized(&g_stats_lc)) {
557 return; // Mutex not initialized, skip logging
558 }
559
560 // Now safe to use the mutex
562 log_info("Server Statistics:\n"
563 " frames_captured=%llu\n"
564 " frames_sent=%llu\n"
565 " frames_dropped=%llu\n"
566 " Average FPS: capture=%.2f, send=%.2f",
567 (unsigned long long)g_stats.frames_captured, (unsigned long long)g_stats.frames_sent,
570}
#define log_info(...)
Log an INFO message.
Definition log/log.h:561
#define mutex_lock(mutex)
Lock a mutex (with debug tracking in debug builds)
#define mutex_unlock(mutex)
Unlock a mutex (with debug tracking in debug builds)
bool lifecycle_is_initialized(const lifecycle_t *lc)
Definition lifecycle.c:155
server_stats_t g_stats
Global server statistics structure.
Definition stats.c:163
mutex_t g_stats_mutex
Mutex protecting global server statistics.
Definition stats.c:172
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, lifecycle_is_initialized(), log_info, mutex_lock, and mutex_unlock.

Referenced by stats_logger_thread().

◆ stats_cleanup()

void stats_cleanup ( void  )

Cleanup the stats mutex.

Uses lifecycle gate to safely destroy the stats mutex. Ensures other threads don't attempt to use the mutex after it's destroyed.

Definition at line 201 of file stats.c.

201 {
202 lifecycle_shutdown(&g_stats_lc);
203}
bool lifecycle_shutdown(lifecycle_t *lc)
Definition lifecycle.c:108

References lifecycle_shutdown().

◆ stats_init()

int stats_init ( void  )

Initialize the stats mutex.

Returns
0 on success, -1 on failure

Definition at line 188 of file stats.c.

188 {
189 if (!lifecycle_init(&g_stats_lc, "stats")) {
190 return 0; // Already initialized
191 }
192 return 0;
193}
bool lifecycle_init(lifecycle_t *lc, const char *name)
Definition lifecycle.c:26

References lifecycle_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_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 327 of file stats.c.

327 {
328 (void)arg;
329
331 // Log buffer pool statistics every 10 seconds with fast exit checking (10ms intervals)
332 for (int i = 0; i < 1000 && !atomic_load_bool(&g_should_exit); i++) {
333 platform_sleep_us(10 * US_PER_MS_INT); // 10ms sleep
334 }
335
336 // Check exit condition before proceeding with statistics logging
337 // Check multiple times to avoid accessing freed resources during shutdown.
339 break;
340 }
341
342 // Collect all statistics data first
343#ifndef NDEBUG
344 char lock_debug_info[BUFFER_SIZE_MEDIUM] = {0};
345 // Check exit condition again before accessing lock_debug.
346 // lock_debug might be destroyed during shutdown
348 uint64_t total_acquired = 0, total_released = 0;
349 uint32_t currently_held = 0;
350 debug_sync_get_stats(&total_acquired, &total_released, &currently_held);
351
352 safe_snprintf(lock_debug_info, sizeof(lock_debug_info),
353 "Historical Mutex/RWLock Statistics:\n"
354 " Total locks acquired: %llu\n"
355 " Total locks released: %llu\n"
356 " Currently held: %u\n"
357 " Net locks (acquired - released): %lld",
358 (unsigned long long)total_acquired, (unsigned long long)total_released, currently_held,
359 (long long)total_acquired - (long long)total_released);
360 }
361#endif
362
363 // Collect client statistics
364 // Check exit condition again before accessing rwlock.
365 // rwlock might be destroyed during shutdown.
367 break;
368 }
369
371 int active_clients = 0;
372 int clients_with_audio = 0;
373 int clients_with_video = 0;
374 char client_details[BUFFER_SIZE_XLARGE] = {0};
375 int client_details_len = 0;
376
377 for (int i = 0; i < MAX_CLIENTS; i++) {
379 active_clients++;
381 clients_with_audio++;
382 }
384 clients_with_video++;
385 }
386 }
387 }
388
389 // Collect per-client details
390 for (int i = 0; i < MAX_CLIENTS; i++) {
392 bool is_active = atomic_load_bool(&client->active);
393 const char *client_id_snapshot = client->client_id;
394
395 if (is_active && client_id_snapshot != 0) {
396 // Check audio queue stats
397 if (client->audio_queue) {
398 uint64_t enqueued, dequeued, dropped;
399 packet_queue_get_stats(client->audio_queue, &enqueued, &dequeued, &dropped);
400 if (enqueued > 0 || dequeued > 0 || dropped > 0) {
401 int len =
402 safe_snprintf(client_details + client_details_len, sizeof(client_details) - client_details_len,
403 " Client %u audio queue: %llu enqueued, %llu dequeued, %llu dropped", client_id_snapshot,
404 (unsigned long long)enqueued, (unsigned long long)dequeued, (unsigned long long)dropped);
405 if (len > 0 && client_details_len + len < (int)sizeof(client_details)) {
406 client_details_len += len;
407 }
408 }
409 }
410 // Check video buffer stats
411 if (client->outgoing_video_buffer) {
414 if (stats.total_frames > 0) {
415 int len = safe_snprintf(client_details + client_details_len, sizeof(client_details) - client_details_len,
416 " Client %u video buffer: %llu frames, %llu dropped (%.1f%% drop rate)",
417 client_id_snapshot, (unsigned long long)stats.total_frames,
418 (unsigned long long)stats.dropped_frames, stats.drop_rate * 100.0f);
419 if (len > 0 && client_details_len + len < (int)sizeof(client_details)) {
420 client_details_len += len;
421 }
422 }
423 }
424 }
425 }
427
428 // Single comprehensive log statement
429 if (client_details_len > 0) {
430 log_info("Stats: Clients: %d, Audio: %d, Video: %d\n%s", active_clients, clients_with_audio, clients_with_video,
431 client_details);
432 }
433 }
434
436
438
439 // Clean up thread-local error context before exit
441
442 return NULL;
443}
asciichat_error_stats_t stats
bool atomic_load_bool(atomic_t *a)
Atomically load a boolean value.
Definition atomic.c:169
atomic_t g_should_exit
Global application exit flag (shared across all modes)
Definition globals.c:34
#define BUFFER_SIZE_XLARGE
Extra large buffer size (2048 bytes)
#define BUFFER_SIZE_MEDIUM
Medium buffer size (512 bytes)
unsigned int uint32_t
Definition common.h:58
unsigned long long uint64_t
Definition common.h:59
void debug_sync_get_stats(uint64_t *total_acquired, uint64_t *total_released, uint32_t *currently_held)
Get synchronization statistics.
Definition sync.c:722
void asciichat_error_stats_print(void)
Print error statistics to stderr.
void asciichat_errno_destroy(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:26
#define US_PER_MS_INT
Definition time.h:160
void packet_queue_get_stats(packet_queue_t *queue, uint64_t *enqueued, uint64_t *dequeued, uint64_t *dropped)
Get queue statistics.
Definition queue.c:637
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.
Definition system.c:148
#define rwlock_rdlock(lock)
Acquire a read lock (with debug tracking in debug builds)
Definition rwlock.h:294
bool debug_sync_is_initialized(void)
Definition sync.c:820
void platform_sleep_us(unsigned int us)
High-precision sleep function with microsecond precision.
#define rwlock_rdunlock(lock)
Release a read lock (with debug tracking in debug builds)
Definition rwlock.h:331
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:554
Per-client state structure for server-side client management.
video_frame_buffer_t * outgoing_video_buffer
char client_id[MAX_CLIENT_ID_LEN]
client_info_t clients[MAX_CLIENTS]
Array of client_info_t structures (backing storage)
Frame statistics structure.

References client_info::active, asciichat_errno_destroy(), asciichat_error_stats_print(), atomic_load_bool(), client_info::audio_queue, BUFFER_SIZE_MEDIUM, BUFFER_SIZE_XLARGE, client_info::client_id, client_manager_t::clients, debug_sync_get_stats(), debug_sync_is_initialized(), g_client_manager, g_client_manager_rwlock, g_should_exit, log_info, log_server_stats(), MAX_CLIENTS, client_info::outgoing_video_buffer, packet_queue_get_stats(), platform_sleep_us(), rwlock_rdlock, rwlock_rdunlock, safe_snprintf(), stats, US_PER_MS_INT, 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 473 of file stats.c.

473 {
474 // Aggregate statistics from all active clients
475 uint64_t total_frames_sent = 0;
476 uint64_t total_frames_dropped = 0;
477
478 // Read-lock to safely iterate over all clients
480
481 for (int i = 0; i < MAX_CLIENTS; i++) {
483 if (client->client_id[0] != '\0' && atomic_load_bool(&client->active)) {
484 // Aggregate frames sent to all clients
485 total_frames_sent += client->frames_sent;
486
487 // Get dropped frame statistics from outgoing video buffer
488 if (client->outgoing_video_buffer) {
491 total_frames_dropped += stats.dropped_frames;
492 }
493 }
494 }
495
497
498 // Update global statistics atomically
500 g_stats.frames_sent = total_frames_sent;
501 g_stats.frames_dropped = total_frames_dropped;
502
503 // Calculate frames_captured from frames_sent and frames_dropped
504 // frames_captured = frames_sent + frames_dropped (total output frames)
505 if (total_frames_sent > 0 || total_frames_dropped > 0) {
506 g_stats.frames_captured = total_frames_sent + total_frames_dropped;
507 }
508
510}

References client_info::active, atomic_load_bool(), client_info::client_id, client_manager_t::clients, 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, stats, and video_frame_get_stats().

Variable Documentation

◆ g_stats

server_stats_t g_stats = {0}

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

163{0};

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

◆ g_stats_mutex

mutex_t g_stats_mutex = {0}

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

172{0};

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