mirror of
https://github.com/tailscale/tailscale.git
synced 2026-06-11 21:02:39 +08:00
Some checks failed
checklocks / checklocks (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
Dockerfile build / deploy (push) Has been cancelled
CI / race-root-integration (1/4) (push) Has been cancelled
CI / race-root-integration (2/4) (push) Has been cancelled
CI / race-root-integration (3/4) (push) Has been cancelled
CI / race-root-integration (4/4) (push) Has been cancelled
CI / test (-race, amd64, 1/3) (push) Has been cancelled
CI / test (-race, amd64, 2/3) (push) Has been cancelled
CI / test (-race, amd64, 3/3) (push) Has been cancelled
CI / test (386) (push) Has been cancelled
CI / test (amd64) (push) Has been cancelled
CI / windows (push) Has been cancelled
CI / privileged (push) Has been cancelled
CI / vm (push) Has been cancelled
CI / race-build (push) Has been cancelled
CI / cross (386, linux) (push) Has been cancelled
CI / cross (amd64, darwin) (push) Has been cancelled
CI / cross (amd64, freebsd) (push) Has been cancelled
CI / cross (amd64, openbsd) (push) Has been cancelled
CI / cross (amd64, windows) (push) Has been cancelled
CI / cross (arm, 5, linux) (push) Has been cancelled
CI / cross (arm, 7, linux) (push) Has been cancelled
CI / cross (arm64, darwin) (push) Has been cancelled
CI / cross (arm64, linux) (push) Has been cancelled
CI / cross (arm64, windows) (push) Has been cancelled
CI / cross (loong64, linux) (push) Has been cancelled
CI / ios (push) Has been cancelled
CI / crossmin (amd64, illumos) (push) Has been cancelled
CI / crossmin (amd64, plan9) (push) Has been cancelled
CI / crossmin (amd64, solaris) (push) Has been cancelled
CI / crossmin (ppc64, aix) (push) Has been cancelled
CI / android (push) Has been cancelled
CI / wasm (push) Has been cancelled
CI / tailscale_go (push) Has been cancelled
CI / fuzz (push) Has been cancelled
CI / depaware (push) Has been cancelled
CI / go_generate (push) Has been cancelled
CI / go_mod_tidy (push) Has been cancelled
CI / licenses (push) Has been cancelled
CI / staticcheck (386, windows) (push) Has been cancelled
CI / staticcheck (amd64, darwin) (push) Has been cancelled
CI / staticcheck (amd64, linux) (push) Has been cancelled
CI / staticcheck (amd64, windows) (push) Has been cancelled
update-flake / update-flake (push) Has been cancelled
CI / notify_slack (push) Has been cancelled
CI / check_mergeability (push) Has been cancelled
In order to improve latency tracking, we will use an exponentially weighted moving average that will smooth change over time and suppress large outlier values. Updates tailscale/corp#26649 Signed-off-by: James Tucker <james@tailscale.com>
73 lines
1.7 KiB
Go
73 lines
1.7 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
// Package maths contains additional mathematical functions or structures not
|
|
// found in the standard library.
|
|
package maths
|
|
|
|
import (
|
|
"math"
|
|
"time"
|
|
)
|
|
|
|
// EWMA is an exponentially weighted moving average supporting updates at
|
|
// irregular intervals with at most nanosecond resolution.
|
|
// The zero value will compute a half-life of 1 second.
|
|
// It is not safe for concurrent use.
|
|
// TODO(raggi): de-duplicate with tstime/rate.Value, which has a more complex
|
|
// and synchronized interface and does not provide direct access to the stable
|
|
// value.
|
|
type EWMA struct {
|
|
value float64 // current value of the average
|
|
lastTime int64 // time of last update in unix nanos
|
|
halfLife float64 // half-life in seconds
|
|
}
|
|
|
|
// NewEWMA creates a new EWMA with the specified half-life. If halfLifeSeconds
|
|
// is 0, it defaults to 1.
|
|
func NewEWMA(halfLifeSeconds float64) *EWMA {
|
|
return &EWMA{
|
|
halfLife: halfLifeSeconds,
|
|
}
|
|
}
|
|
|
|
// Update adds a new sample to the average. If t is zero or precedes the last
|
|
// update, the update is ignored.
|
|
func (e *EWMA) Update(value float64, t time.Time) {
|
|
if t.IsZero() {
|
|
return
|
|
}
|
|
hl := e.halfLife
|
|
if hl == 0 {
|
|
hl = 1
|
|
}
|
|
tn := t.UnixNano()
|
|
if e.lastTime == 0 {
|
|
e.value = value
|
|
e.lastTime = tn
|
|
return
|
|
}
|
|
|
|
dt := (time.Duration(tn-e.lastTime) * time.Nanosecond).Seconds()
|
|
if dt < 0 {
|
|
// drop out of order updates
|
|
return
|
|
}
|
|
|
|
// decay = 2^(-dt/halfLife)
|
|
decay := math.Exp2(-dt / hl)
|
|
e.value = e.value*decay + value*(1-decay)
|
|
e.lastTime = tn
|
|
}
|
|
|
|
// Get returns the current value of the average
|
|
func (e *EWMA) Get() float64 {
|
|
return e.value
|
|
}
|
|
|
|
// Reset clears the EWMA to its initial state
|
|
func (e *EWMA) Reset() {
|
|
e.value = 0
|
|
e.lastTime = 0
|
|
}
|