ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
stats.c File Reference

📊 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)
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 domain 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 domain PERFORMANCE:

  • Global buffer domain 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.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.c For memory utilization monitoring
packet_queue.c For queue performance metrics

Definition in file src/server/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: Lifetime average of frame ingress rate
  • avg_send_fps: Lifetime 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 464 of file src/server/stats.c.

464 {
465 // Check if stats mutex is initialized (safe in debug builds where stats_init() may not be called)
466 if (!lifecycle_is_initialized(&g_stats_lc)) {
467 return; // Mutex not initialized, skip logging
468 }
469
470 // Now safe to use the mutex
471 mutex_lock(&g_stats_mutex);
472 log_info("Server Statistics:\n"
473 " frames_captured=%llu\n"
474 " frames_sent=%llu\n"
475 " frames_dropped=%llu\n"
476 " Average FPS: capture=%.2f, send=%.2f",
477 (unsigned long long)g_stats.frames_captured, (unsigned long long)g_stats.frames_sent,
478 (unsigned long long)g_stats.frames_dropped, g_stats.avg_capture_fps, g_stats.avg_send_fps);
479 mutex_unlock(&g_stats_mutex);
480}
#define log_info(...)
Log an INFO message.
Definition log/log.h:608
mutex_t g_stats_mutex
Mutex protecting global server statistics.

References g_stats_mutex, and log_info.

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 202 of file src/server/stats.c.

202 {
203 lifecycle_shutdown(&g_stats_lc);
204}

◆ stats_init()

int stats_init ( void )

Initialize the stats mutex.

Returns
0 on success, -1 on failure

Definition at line 189 of file src/server/stats.c.

189 {
190 if (!lifecycle_init(&g_stats_lc, "stats")) {
191 return 0; // Already initialized
192 }
193 return 0;
194}

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 domain 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 domain METRICS:

  • Global allocation/deallocation rates
  • Peak memory usage patterns
  • buffer domain 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 328 of file src/server/stats.c.

328 {
329 (void)arg;
330
331 while (!atomic_load_bool(&g_should_exit)) {
332 // Log buffer domain statistics every 10 seconds with fast exit checking (10ms intervals)
333 for (int i = 0; i < 1000 && !atomic_load_bool(&g_should_exit); i++) {
334 platform_sleep_us(10 * US_PER_MS_INT); // 10ms sleep
335 }
336
337 // Check exit condition before proceeding with statistics logging
338 // Check multiple times to avoid accessing freed resources during shutdown.
339 if (atomic_load_bool(&g_should_exit)) {
340 break;
341 }
342
347
348 // Collect all statistics data first
349#ifndef NDEBUG
350 char lock_debug_info[BUFFER_SIZE_MEDIUM] = {0};
351 // Check exit condition again before accessing lock_debug.
352 // lock_debug might be destroyed during shutdown
353 if (!atomic_load_bool(&g_should_exit) && debug_sync_is_initialized()) {
354 uint64_t total_acquired = 0, total_released = 0;
355 uint32_t currently_held = 0;
356 debug_sync_get_stats(&total_acquired, &total_released, &currently_held);
357
358 safe_snprintf(lock_debug_info, sizeof(lock_debug_info),
359 "Historical Mutex/RWLock Statistics:\n"
360 " Total locks acquired: %llu\n"
361 " Total locks released: %llu\n"
362 " Currently held: %u\n"
363 " Net locks (acquired - released): %lld",
364 (unsigned long long)total_acquired, (unsigned long long)total_released, currently_held,
365 (long long)total_acquired - (long long)total_released);
366 }
367#endif
368
369 // Collect client statistics
370 // Check exit condition again before accessing rwlock.
371 // rwlock might be destroyed during shutdown.
372 if (atomic_load_bool(&g_should_exit)) {
373 break;
374 }
375
377 int active_clients = 0;
378 int clients_with_audio = 0;
379 int clients_with_video = 0;
380
381 for (int i = 0; i < MAX_CLIENTS; i++) {
382 if (atomic_load_bool(&g_client_manager.clients[i].active)) {
383 active_clients++;
384 if (atomic_load_bool(&g_client_manager.clients[i].is_sending_audio)) {
385 clients_with_audio++;
386 }
387 if (atomic_load_bool(&g_client_manager.clients[i].is_sending_video)) {
388 clients_with_video++;
389 }
390 }
391 }
392
394
395 log_info("Stats: Clients: %d, Audio: %d, Video: %d", active_clients, clients_with_audio, clients_with_video);
396 }
397
399
401
402 // Clean up thread-local error context before exit
403
404 return NULL;
405}
void asciichat_error_stats_print(void)
void buffer_domain_log_stats(buffer_domain_t *domain, const char *name)
Definition buffer.c:392
buffer_domain_t * buffer_default_domain(void)
Definition buffer.c:423
void buffer_domain_trim(buffer_domain_t *domain)
Definition buffer.c:170
buffer_domain_t * buffer_control_domain(void)
Definition buffer.c:436
atomic_t g_should_exit
Global application exit flag (shared across all modes).
Definition globals.c:34
#define BUFFER_SIZE_MEDIUM
Medium buffer size (512 bytes).
unsigned int uint32_t
Definition common.h:62
unsigned long long uint64_t
Definition common.h:63
#define MAX_CLIENTS
Maximum possible clients (static array size) - actual runtime limit set by –max-clients (1-128).
#define US_PER_MS_INT
Definition time.h:172
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Platform-safe snprintf wrapper.
#define rwlock_rdlock(lock)
Acquire a read lock (with debug tracking in debug builds).
Definition rwlock.h:299
bool debug_sync_is_initialized(void)
#define rwlock_rdunlock(lock)
Release a read lock (with debug tracking in debug builds).
Definition rwlock.h:338
rwlock_t g_client_manager_rwlock
Reader-writer lock protecting the global client manager.
client_manager_t g_client_manager
Hash table entry for client packet dispatch.
void log_server_stats(void)
Log comprehensive server statistics summary.

References asciichat_error_stats_print(), buffer_control_domain(), buffer_default_domain(), buffer_domain_log_stats(), buffer_domain_trim(), BUFFER_SIZE_MEDIUM, debug_sync_is_initialized(), g_client_manager, g_client_manager_rwlock, g_should_exit, log_info, log_server_stats(), MAX_CLIENTS, rwlock_rdlock, rwlock_rdunlock, safe_snprintf(), and US_PER_MS_INT.

Referenced by server_main().

◆ update_server_stats()

void update_server_stats ( void )

Copy actual lifetime event counts; disconnects do not erase history.

Definition at line 408 of file src/server/stats.c.

408 {
409 stats_snapshot_t snapshot;
410 if (!lifecycle_is_initialized(&g_stats_lc) || stats_scope_snapshot(stats_runtime_scope(), &snapshot) != ASCIICHAT_OK)
411 return;
412 mutex_lock(&g_stats_mutex);
413 g_stats.frames_captured = snapshot.counters[STATS_COUNTER_FRAMES_RECEIVED];
414 g_stats.frames_sent = snapshot.counters[STATS_COUNTER_FRAMES_SENT];
415 g_stats.frames_dropped = snapshot.counters[STATS_COUNTER_FRAMES_DROPPED];
416 double seconds = (double)(snapshot.sampled_ns - snapshot.started_ns) / 1e9;
417 g_stats.avg_capture_fps = seconds > 0 ? (double)g_stats.frames_captured / seconds : 0;
418 g_stats.avg_send_fps = seconds > 0 ? (double)g_stats.frames_sent / seconds : 0;
419 mutex_unlock(&g_stats_mutex);
420}
@ ASCIICHAT_OK
Definition error_codes.h:46
asciichat_error_t stats_scope_snapshot(const stats_scope_t *scope, stats_snapshot_t *out)
stats sampler config keeps the values that move through the subsystem: window_ns, resolution_ns....
stats_scope_t * stats_runtime_scope(void)
Definition runtime.c:80
uint64_t counters[STATS_COUNTER_COUNT]

References ASCIICHAT_OK, stats_snapshot_t::counters, g_stats_mutex, stats_snapshot_t::sampled_ns, stats_snapshot_t::started_ns, STATS_COUNTER_FRAMES_DROPPED, STATS_COUNTER_FRAMES_RECEIVED, STATS_COUNTER_FRAMES_SENT, stats_runtime_scope(), and stats_scope_snapshot().

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: Lifetime average of frame ingress rate
  • avg_send_fps: Lifetime average of frame delivery rate

Definition at line 164 of file src/server/stats.c.

164{0};

◆ 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 173 of file src/server/stats.c.

173{0};

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