java.lang.Object
net.i2p.router.Tuner.SystemHealth
Enclosing class:
Tuner

static class Tuner.SystemHealthextends Object
Tracks overall router health score for adaptive tuning decisions.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    private final RouterContext
    The router being scored.
    private double
    The computed health score, NaN before the first computation.
    private final long
    Router uptime when this score was created.
    (package private) static final double
    Share of the fast or high-capacity tier that ghost exclusions may consume before the factor starts to bite, and the share at which it bottoms out.
    (package private) static final double
    Share of the tier at which the ghost-exclusion factor bottoms out at 0.0.
    (package private) static final double
    Floor applied to each factor before the composite is computed.
  • Constructor Summary

    Constructors
    Constructor
    Description
    System health.
  • Method Summary

    Modifier and Type
    Method
    Description
    private static double
    clamp(double v)
    Limits a score to the valid range.
    (package private) static double
    compositeScore(double[] factors, double[] weights)
    Weighted geometric mean of the available factors.
    private void
    Scores every subsystem and combines them into the health score.
    (package private) Map<String,double[]>
    Compute per-subsystem health scores for the ring chart dashboard.
    private double
    Fetch the event count for a stat using the 60s period.
    private double
    getEventCount(String statName, long period)
    Fetch the event count for a stat using the given period (ms).
    private double
    Return lifetime event count for a stat.
    (package private) double
    Computed score.
    private double
    getStatValue(String statName)
    Read a stat's average value using the 60s period.
    private double
    getStatValue(String statName, long period)
    Read a stat's average value using the given period (ms).
    private boolean
    True if any transport reports firewalled status.
    private double
    Scores the average UDP retransmit timeout.
    private double
    Scores how often peers are banned on contact.
    private double
    Scores the tunnel build handler queue depth.
    private double
    Build storms: 0 concurrent = 1.0, linear decay to 0 at 100.
    private double
    Build success rate from 60-second event counts.
    private double
    Congestion: fraction of message send outcomes that triggered a window-reduction (congestion) event.
    private double
    Crypto: DH queue empty events vs used events.
    private double
    Dropped jobs per interval — any dropped job is a severe overload signal.
    private double
    Ghost exclusions as a fraction of the fast or high-capacity tier — the pool tunnel builds actually draw from.
    private double
    Scores I2CP client session health.
    private double
    Job queue lag: 0ms = 1.0, >50ms = degraded, >200ms = 0.0 Also considers jobRunSlow (jobs >1s) as sustained overload signal.
    private double
    How long jobs wait in the queue before execution.
    private double
    Message send latency: how long an outbound message waits in the transport send queue (transport.sendProcessingTime).
    private double
    Scores network database lookup success and speed.
    private double
    Scores peer connectivity and profile quality.
    private double
    Fraction of registered tunnel pools that are alive.
    private double
    Fraction of alive pools meeting their target tunnel count.
    private double
    Ready (queued) jobs as a fraction of pool capacity.
    private double
    Transport send failure rate: failed sends vs total sends.
    private double
    Scores the UDP send pool saturation.
    private double
    Streaming health: multi-signal score combining connection success rate, RTT at close, retransmission overhead, and inbound reset rate.
    private double
    Scores transit capacity against the tunnels offered.

    Methods inherited from class Object

    clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • MIN_FACTOR_SCORE

      static final double MIN_FACTOR_SCORE
      Floor applied to each factor before the composite is computed.

      The composite is a weighted geometric mean, so its factors multiply: one factor that saturates at 0.0 drives the product — and therefore the health shown on the tuning page — to exactly 0% no matter how healthy the rest of the router is. That 0% is also below BaseParam.DEGRADED_THRESHOLD, so a score pinned there silently freezes every auto-tuned param at its factory default, which makes the page read "Degraded (0%)" and stops tuning without any hint why. Flooring keeps one saturated factor worth only its own weight share while the all-bad worst case still sits well under the degraded threshold, so the safety behaviour is preserved.

      See Also:
    • _ctx

      private final RouterContext _ctx
      The router being scored.
    • _score

      private double _score
      The computed health score, NaN before the first computation.
    • _uptime

      private final long _uptime
      Router uptime when this score was created.
    • GHOST_TIER_FREE

      static final double GHOST_TIER_FREE
      Share of the fast or high-capacity tier that ghost exclusions may consume before the factor starts to bite, and the share at which it bottoms out.
      See Also:
    • GHOST_TIER_ZERO

      static final double GHOST_TIER_ZERO
      Share of the tier at which the ghost-exclusion factor bottoms out at 0.0.
      See Also:
  • Constructor Details

    • SystemHealth

      SystemHealth(RouterContext ctx)
      System health.
      Parameters:
      ctx - router context supplying uptime and the stats the score reads
  • Method Details

    • getScore

      double getScore()
      Computed score.
      Returns:
      the health score, where 1.0 is healthy and lower is worse
    • compositeScore

      static double compositeScore(double[] factors, double[] weights)
      Weighted geometric mean of the available factors.

      NaN factors mean "insufficient data" and are skipped along with their weights, so the remaining weights are renormalized to 1.0. Every participating factor is floored at MIN_FACTOR_SCORE first — without that floor a single saturated factor zeroes the aggregate and the score stops discriminating between bad and catastrophic.

      Parameters:
      factors - per-factor scores in [0,1]; NaN for no data
      weights - matching per-factor weights, summing to 1.0
      Returns:
      the composite score in [0,1], or 1.0 if no factor has data
      See Also:
    • compute

      private void compute()
      Scores every subsystem and combines them into the health score.
    • scoreJobLag

      private double scoreJobLag()
      Job queue lag: 0ms = 1.0, >50ms = degraded, >200ms = 0.0 Also considers jobRunSlow (jobs >1s) as sustained overload signal.
      Returns:
      the job-lag health factor in [0,1], or NaN if the period holds fewer than three job-lag events
    • scoreReadyJobs

      private double scoreReadyJobs()
      Ready (queued) jobs as a fraction of pool capacity. >50% of pool capacity queued = overload indicator.
      Returns:
      the ready-jobs health factor in [0,1], or NaN if the period holds fewer than three samples
    • scoreDroppedJobs

      private double scoreDroppedJobs()
      Dropped jobs per interval — any dropped job is a severe overload signal.
      Returns:
      the dropped-jobs health factor in [0,1], 1.0 when nothing was dropped, or NaN if the stat is unavailable
    • scoreJobWait

      private double scoreJobWait()
      How long jobs wait in the queue before execution. 0ms→1.0, 500ms→0.5, 2000ms→0.0.
      Returns:
      the job-wait health factor in [0,1], or NaN if the period holds fewer than three samples
    • scoreBuildSuccess

      private double scoreBuildSuccess()
      Build success rate from 60-second event counts. More responsive than SystemVersion's 10-minute window and avoids NaN when that window hasn't accumulated events yet. Requires 10+ total events (exploratory + client) for stability. When firewalled, lower thresholds since inbound builds are rejected.
      Returns:
      the build-success health factor in [0,1], or NaN if fewer than 10 build events landed in the period
    • scorePoolAlive

      private double scorePoolAlive()
      Fraction of registered tunnel pools that are alive. 1.0 = all alive, 0.0 = half or more dead.
      Returns:
      the pool-alive health factor in [0,1], or NaN when no tunnel pools are configured
    • scorePoolDeficit

      private double scorePoolDeficit()
      Fraction of alive pools meeting their target tunnel count. 1.0 = all pools meet target, 0.0 = none do. Linear ramp: 0%→0.0, 70%→1.0. Pools still building at startup won't penalize until sufficient time has passed to meet targets.
      Returns:
      the pool-target health factor in [0,1], or NaN when no tunnel pools are configured
    • isFirewalled

      private boolean isFirewalled()
      True if any transport reports firewalled status.
      Returns:
      true if a transport is firewalled
    • getEventCount

      private double getEventCount(String statName, long period)
      Fetch the event count for a stat using the given period (ms).
      Parameters:
      statName - the statManager rate name to read
      period - the rate period in ms, e.g. RateConstants.ONE_HOUR
      Returns:
      the event count in that period, 0 if the stat or rate has no data
    • getEventCount

      private double getEventCount(String statName)
      Fetch the event count for a stat using the 60s period.
      Parameters:
      statName - the statManager rate name to read
      Returns:
      the event count in the 60s period, 0 if the stat has no data
    • getLifetimeEventCount

      private double getLifetimeEventCount(String statName)
      Return lifetime event count for a stat. Use for low-frequency stats where 60s window is too narrow.
      Parameters:
      statName - the statManager rate name to read
      Returns:
      the number of events recorded since the stat was created, 0 if the stat is unavailable
    • scoreBuildStorms

      private double scoreBuildStorms()
      Build storms: 0 concurrent = 1.0, linear decay to 0 at 100. Startup bursts (30-50 concurrent) are normal; only penalize sustained high concurrency.
      Returns:
      the build-storm health factor in [0,1], or NaN if the period holds fewer than five samples
    • scoreSendFailure

      private double scoreSendFailure()
      Transport send failure rate: failed sends vs total sends. Uses event counts (each send = 1 event, each failure = 1 event). Requires 500+ sends to skip noisy startup window. <1% = 1.0, >10% = 0.0.
      Returns:
      the send-failure health factor in [0,1], or NaN if fewer than 500 sends were recorded in the period
    • scoreLatency

      private double scoreLatency()
      Message send latency: how long an outbound message waits in the transport send queue (transport.sendProcessingTime). ≤1s → 1.0, 4s → 0.5, ≥10s → 0.0.

      Anchored on what the router itself treats as normal versus congested: RouterThrottleImpl documents ~25ms for NTCP and ~1000ms for SSU as ordinary (SSU includes ack time and can be much more than RTT), and starts refusing participating tunnel requests once the smoothed average passes maxProcessingTime — 2000ms, 3000ms on slow systems. BuildExecutor likewise backs builds off above a 2000ms average. The old mapping reached 0.0 at 5000ms, only 2.5× the router's own congestion gate, so a plain SSU router sitting at its documented average scored 0.5 and one with slow acks scored 0.0.

      Returns:
      the send-latency health factor in [0,1], or NaN if the period holds fewer than three samples
    • scoreGhostPeers

      private double scoreGhostPeers()
      Ghost exclusions as a fraction of the fast or high-capacity tier — the pool tunnel builds actually draw from. Up to GHOST_TIER_FREE of the tier excluded is free; the factor then ramps to 0.0 at GHOST_TIER_ZERO.

      Fraction, not absolute count: marks accrue routinely (a few per minute against multi-minute cooldowns), expire on their own, and clear the moment the peer answers, so any fixed count threshold fires on every healthy router — which is what pinned the composite to 0%. Scaling by the tier keeps a large router free while still catching the case that matters, where exclusions consume enough of the preferred pool to starve selection.

      Numerator and denominator must cover the same population: the count is tier-matched, because dividing an all-tier ghost count by a tier size would overstate whenever the tier is smaller than the ghost population.

      Returns:
      the ghost health factor in [0,1], or NaN if the tier is unknown
    • scoreStreaming

      private double scoreStreaming()
      Streaming health: multi-signal score combining connection success rate, RTT at close, retransmission overhead, and inbound reset rate. Connection success rate dominates for client-heavy routers.
      Returns:
      the weighted streaming health factor in [0,1], or NaN when no signal has enough events to score
    • clamp

      private static double clamp(double v)
      Limits a score to the valid range.
      Parameters:
      v - the raw score
      Returns:
      the score, clamped to 0 to 1
    • computeSubsystemScores

      Map<String,double[]> computeSubsystemScores()
      Compute per-subsystem health scores for the ring chart dashboard. Each subsystem gets a score based on its most relevant stat(s).
      Returns:
      map of subsystem key → {score, ...detail}
    • scoreTransit

      private double scoreTransit()
      Scores transit capacity against the tunnels offered.
      Returns:
      the score, 0 to 1
    • scoreBuildQueue

      private double scoreBuildQueue()
      Scores the tunnel build handler queue depth.
      Returns:
      the score, 0 to 1
    • scoreBanHit

      private double scoreBanHit()
      Scores how often peers are banned on contact.
      Returns:
      the score, 0 to 1
    • scoreSendPool

      private double scoreSendPool()
      Scores the UDP send pool saturation.
      Returns:
      the score, 0 to 1
    • scoreAvgRTO

      private double scoreAvgRTO()
      Scores the average UDP retransmit timeout.
      Returns:
      the score, 0 to 1
    • scoreNetDbHealth

      private double scoreNetDbHealth()
      Scores network database lookup success and speed.
      Returns:
      the score, 0 to 1
    • scoreI2cpHealth

      private double scoreI2cpHealth()
      Scores I2CP client session health.
      Returns:
      the score, 0 to 1
    • scorePeerHealth

      private double scorePeerHealth()
      Scores peer connectivity and profile quality.
      Returns:
      the score, 0 to 1
    • scoreCongestion

      private double scoreCongestion()
      Congestion: fraction of message send outcomes that triggered a window-reduction (congestion) event.

      The denominator is udp.sendConfirmTime, which fires once per ACKed message, so this is a true per-message congestion rate rather than a per-packet count. udp.congestionOccurred fires per RTO-timeout or fast-retransmit window reduction.

      Thresholds are calibrated for UDP/SSU over a lossy anonymizing overlay, where normal AIMD keeps a busy router in the 5-15% band. A wired-TCP-style 5% cap would flag healthy routers as congested. <=5% congestion → 1.0, 25% → 0.0.

      Requires at least 100 confirmed sends in the period for a stable ratio.

      Returns:
      the worst of the congestion, retransmit, expiry and inbound-drop health factors, each in [0,1]
    • scoreCryptoPressure

      private double scoreCryptoPressure()
      Crypto: DH queue empty events vs used events. Frequent empty queue = key generation bottleneck. Only evaluates pools with actual activity; returns NaN when no crypto ops.
      Returns:
      the worst crypto-pool health factor in [0,1], or NaN when no pool did any work in the window
    • getStatValue

      private double getStatValue(String statName, long period)
      Read a stat's average value using the given period (ms). Returns NaN if stat unavailable.
      Parameters:
      statName - the statManager rate name to read
      period - the rate period in ms, e.g. STAT_PERIOD_LONG
      Returns:
      the stat's average value over that period, NaN if unavailable
    • getStatValue

      private double getStatValue(String statName)
      Read a stat's average value using the 60s period. Returns NaN if stat unavailable.
      Parameters:
      statName - the statManager rate name to read
      Returns:
      the stat's average value over 60s, NaN if unavailable