mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-23 01:55:10 -07:00
Add a lock-free MetricsRegistry that accumulates per-command processing times in preallocated histogram slots (one per protobuf command type, bucketed at 1/5/10/25/50/100/250/500/1000/2500/5000 ms +Inf). The hot-path observeCommand() uses only relaxed atomic adds — no locks, no allocations, no cache-line ping-pong beyond the unavoidable counter updates. Wire the registry into AbstractServerSocketInterface::processCommandContainer() so every processed command is attributed with its container's wall-clock time. When a container exceeds metrics/slow_command_ms (default 500), a warning is logged including the connected username. Add an EventLoopWatchdog heartbeat that runs on every socket pool thread. If a heartbeat overshoots metrics/stall_warn_ms (default 2000 ms), the overshoot is recorded in atomic counters and a warning is logged. Both thresholds are configurable in servatrice.ini; setting stall_warn_ms to 0 disables the watchdogs entirely. Track game-start durations via a separate histogram in MetricsRegistry. Server_Game::startGameNow() measures the time from zone creation through player materialization and reports it via Server::observeGameStartDurationMs(). Add a live card-count gauge: Server_Game exposes getCardsInGame() and Servatrice::getCardsInGamesTotal() sums across all running games under the appropriate read locks. Include a standalone metrics_registry_test (Google Test) that validates empty registries, single/multi-sample histograms, kind encoding, overflow-slot collapse, negative-duration clamping, gauge rendering, and the game-start histogram separation. Took 10 minutes
50 lines
1.3 KiB
C++
50 lines
1.3 KiB
C++
/**
|
|
* @file event_loop_watchdog.h
|
|
* @ingroup Servatrice
|
|
*/
|
|
|
|
#ifndef EVENT_LOOP_WATCHDOG_H
|
|
#define EVENT_LOOP_WATCHDOG_H
|
|
|
|
#include <QElapsedTimer>
|
|
#include <QObject>
|
|
#include <QString>
|
|
|
|
class Servatrice;
|
|
class QTimer;
|
|
|
|
/**
|
|
* @brief Detects blocked or overloaded worker event loops.
|
|
*
|
|
* One instance lives in each socket pool thread. A heartbeat timer tick that
|
|
* arrives late means the loop spent that time elsewhere: busy work, a queued
|
|
* slot, or a hard wedge. Overshoots past the configured threshold bump
|
|
* lock-free counters on the metrics registry and log one warning per stall,
|
|
* so a stuck pool thread becomes visible instead of silent lag.
|
|
*/
|
|
class EventLoopWatchdog : public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
/// How often the heartbeat expects to fire. Small enough to catch short stalls.
|
|
static constexpr int HeartbeatIntervalMs = 500;
|
|
|
|
EventLoopWatchdog(Servatrice *_servatrice, QString _threadName);
|
|
|
|
/**
|
|
* Starts the heartbeat timer. Must be invoked queued after the instance
|
|
* was moved to its target thread so the timer lives there too.
|
|
*/
|
|
void start();
|
|
|
|
private slots:
|
|
void checkHeartbeat();
|
|
|
|
private:
|
|
Servatrice *servatrice;
|
|
QString threadName;
|
|
QElapsedTimer sinceLastTick;
|
|
QTimer *heartbeatTimer = nullptr;
|
|
};
|
|
|
|
#endif
|