Documentation
¶
Overview ¶
Package engine holds the pure, clock-free measurement logic of netquality: latency statistics, the draft's stability criterion, and (after extraction) the per-interval decisions. It performs no I/O so it can be driven by real transports or by a simulator.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Responsiveness ¶
func Responsiveness(foreign, self []LatencySample, tmp float64) (total, foreignRPM, selfRPM float64)
Responsiveness computes the draft's RPM figures over a sample set.
Types ¶
type Confidence ¶
type Confidence string
Confidence is the draft's Section 5.4.1 confidence score.
const ( // ConfidenceLow: fewer than MAD intervals ran; moving average is partial. ConfidenceLow Confidence = "low" // ConfidenceMedium: at least MAD intervals ran but stability was not reached. ConfidenceMedium Confidence = "medium" // ConfidenceHigh: stability was reached. ConfidenceHigh Confidence = "high" )
type Decision ¶
type Decision struct {
// AddFlows is how many load-generating connections to open now.
AddFlows int
// Stop is true when both series are stable and the phase should end.
Stop bool
// Interval-level figures for progress reporting.
Interval int
ThroughputBPS float64 // moving-average goodput
RPM float64 // 0 until the ramp is done or throughput is stable
ThroughputStable, ResponsivenessStable bool
// Hold is true when no flow was added into this interval and it was not
// a drain interval.
Hold bool
// Drain is true when the interval was excluded from measurement because
// the send-buffer credit of newly opened flows would inflate it.
Drain bool
}
Decision is what the engine asks the I/O layer to do after an observation.
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine implements the draft's per-interval algorithm without any I/O or clock: feed it one Observation per interval and act on the Decision. It is safe for concurrent use of ProbeGap with Interval.
Deviations from the draft's ramp: flows are added in doubling steps and the ramp stops when a step adds less than RampGainTolerance of goodput; an interval inflated by send-buffer credit is excluded (see StabilityParams); a goodput drop beyond ChangeTolerance restarts goodput tracking.
func New ¶
func New(p StabilityParams, maxFlows int) *Engine
New returns an engine for one load phase.
func (*Engine) InitialFlows ¶
InitialFlows is how many connections to open before the first interval.
func (*Engine) Interval ¶
func (e *Engine) Interval(o Observation) Decision
Interval processes one completed interval and returns what to do next.
func (*Engine) ProbeGap ¶
ProbeGap is the spacing between individual probes: 1/MPS, stretched so that probe traffic stays under PTC of the current goodput estimate.
func (*Engine) Summary ¶
func (e *Engine) Summary(currentForeign, currentSelf []LatencySample) Summary
Summary computes the final figures. current holds samples of an interval that was in progress when the phase ended; they are used only when no interval completed at all.
type LatencySample ¶
type LatencySample struct {
Total time.Duration // full wall time of the probe (foreign: incl. connect+TLS; self: request only)
DNS time.Duration
Connect time.Duration // TCP handshake
TLS time.Duration // raw TLS handshake time
TLSRTTs int // number of round trips the negotiated TLS version needs (0 = no TLS)
TTFB time.Duration // request sent -> first response byte
HTTP time.Duration // request sent -> full body read (http_f / http_l in the draft)
Staged bool // true when DNS/Connect/TLS/TTFB are populated (fresh connection)
}
LatencySample is one probe measurement.
func (LatencySample) TLSPerRTT ¶
func (s LatencySample) TLSPerRTT() time.Duration
TLSPerRTT returns the TLS handshake time normalised to one round trip.
type LatencyStats ¶
type LatencyStats struct {
Samples int `json:"samples"`
Min time.Duration `json:"min_ns"`
Median time.Duration `json:"median_ns"`
Mean time.Duration `json:"mean_ns"`
P80 time.Duration `json:"p80_ns,omitempty"`
P90 time.Duration `json:"p90_ns,omitempty"`
P95 time.Duration `json:"p95_ns,omitempty"`
P99 time.Duration `json:"p99_ns,omitempty"`
Max time.Duration `json:"max_ns"`
Jitter time.Duration `json:"jitter_ns"`
Stages *StageMedians `json:"stages,omitempty"`
}
LatencyStats summarises a set of latency samples.
Percentiles use the nearest-rank method, which returns the maximum for any percentile above 100·(n-1)/n. A percentile field is therefore present only when the sample count makes it a real order statistic distinct from the maximum: P80 from 5 samples, P90 from 10, P95 from 20, P99 from 100. A field never holds a lower percentile than its name says; absent means "not enough samples", never zero.
Jitter is the mean absolute deviation of the samples from their mean. Stages holds per-stage medians (dns, connect, tls, ttfb) when the samples carry stage timings (foreign probes and idle probes do; self probes do not).
func ComputeLatencyStats ¶
func ComputeLatencyStats(samples []LatencySample) LatencyStats
ComputeLatencyStats builds LatencyStats from samples, using Total as the headline value. Stage medians are computed only over staged samples.
func (LatencyStats) HighestPercentile ¶
func (s LatencyStats) HighestPercentile() (float64, time.Duration)
HighestPercentile returns the largest percentile present and its value, or (0, 0) when the set is too small for any.
type Observation ¶
type Observation struct {
// Elapsed is the wall time since the previous observation (or phase start).
Elapsed time.Duration
// Bytes is the cumulative byte count of the phase so far.
Bytes int64
// Flows is the number of load-generating connections currently open.
Flows int
// Foreign and Self are the probe samples completed during this interval.
Foreign, Self []LatencySample
}
Observation is what the I/O layer reports to the engine once per interval.
type StabilityParams ¶
type StabilityParams struct {
// MovingAverageDistance (MAD): number of intervals in the moving average.
MovingAverageDistance int
// Interval (ID): how often stability is re-evaluated and flows are added.
Interval time.Duration
// TrimmedMeanPercent (TMP): single-sided trimmed-mean percentile for latency.
TrimmedMeanPercent float64
// StdDevTolerance (SDT): stability is declared when the standard deviation of
// the last MAD moving averages is below this fraction of the current one.
StdDevTolerance float64
// InitialFlows (INP) and FlowIncrement (INC). The ramp doubles the flow
// count at each step; FlowIncrement is the floor of a step.
InitialFlows int
FlowIncrement int
// MaxProbesPerSecond (MPS) and ProbeCapacityPercent (PTC).
MaxProbesPerSecond int
ProbeCapacityPercent float64
// SendBufferBytes is the per-flow credit the transport accepts before
// bytes reach the wire (HTTP/2 stream window plus socket buffer). An
// interval in which the credit of newly opened flows exceeds
// StdDevTolerance of the interval's goodput is a drain interval: it is
// neither measured nor used for decisions. 0 (the default) disables it;
// the I/O layer sets it for uploads, where bytes are counted on hand-over.
SendBufferBytes int64
// RampGainTolerance stops the flow ramp: after an add, if goodput grew by
// less than this fraction the link is saturated and no more flows open.
// Negative never stops the ramp (flows are added up to the maximum).
RampGainTolerance float64
// ChangeTolerance restarts goodput stability tracking when a hold
// interval's goodput drops by more than this fraction below the moving
// average (a capacity change mid-run).
ChangeTolerance float64
}
StabilityParams are the draft's algorithm parameters (Section 5.2).
func DefaultStabilityParams ¶
func DefaultStabilityParams() StabilityParams
DefaultStabilityParams returns the draft-09 defaults, except Interval, which is 1s instead of 5s so that a phase can stabilise within the 12s MaxDuration budget (see README "Deviations").
func (StabilityParams) WithDefaults ¶
func (p StabilityParams) WithDefaults() StabilityParams
type StageMedians ¶
type StageMedians struct {
DNS time.Duration `json:"dns_ns"`
Connect time.Duration `json:"connect_ns"`
TLS time.Duration `json:"tls_ns"`
TLSPerRTT time.Duration `json:"tls_per_rtt_ns"`
TTFB time.Duration `json:"ttfb_ns"`
}
StageMedians holds median per-stage timings from net/http/httptrace. TLS is the raw handshake time; TLSPerRTT is the same value normalised to a single round trip (TLS 1.3 = 1 RTT, TLS 1.2 = 2 RTTs) as the draft requires.
type Summary ¶
type Summary struct {
Intervals int
ThroughputBPS, PeakThroughputBPS float64
ThroughputStable, ResponsivenessStable bool
ThroughputConfidence Confidence
ResponsivenessConfidence Confidence
RPM, ForeignRPM, SelfRPM float64
Foreign, Self []LatencySample // samples the final figures were computed from
// LowerBoundBPS is the lowest goodput of the latest sustained window:
// MovingAverageDistance consecutive measured (non-drain) intervals whose
// goodputs are within StdDevTolerance of their mean — agreement across a
// flow add shows the add changed nothing. 0 when no such window formed.
// LowerBoundStart is the 1-based first interval of the window and
// LowerBoundIntervals its length.
LowerBoundBPS float64
LowerBoundStart int
LowerBoundIntervals int
// RPMUpperBound is the responsiveness over the lower-bound window. The
// queue may not have been full, so it bounds the loaded RPM from above.
RPMUpperBound float64
// WindowFrom is the 1-based first interval the RPM and the Foreign/Self
// samples were taken from (through the last interval). PhaseForeign and
// PhaseSelf count the samples of the whole phase, so a caller can tell a
// series that never produced a sample from one whose samples all fell
// outside the window.
WindowFrom int
PhaseForeign, PhaseSelf int
}
Summary is the engine's final view of a phase; the I/O layer adds bytes, duration, protocol and error facts.
type Tracker ¶
type Tracker struct {
// contains filtered or unexported fields
}
Tracker implements the draft's moving-average stability criterion for a single series (goodput or responsiveness). It is deterministic and independent of wall time: callers push one value per interval.
func NewTracker ¶
func NewWindowedTracker ¶ added in v0.4.0
NewWindowedTracker returns a tracker for values that are already means over MAD intervals.
func (*Tracker) Confidence ¶
func (t *Tracker) Confidence() Confidence