mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 18:35:44 +03:00
Adding '-verbose' will print out the allocation information for the deployment. This also changes the job run command so that it now blocks until deployment is complete and adds timestamps to the output so that it's more in line with the output of node drain. This uses glint to print in place in running in a tty. Because glint doesn't yet support cmd/powershell, Windows workflows use a different library to print in place, which results in slightly different formatting: 1) different margins, and 2) no spinner indicating deployment in progress.
127 lines
4.3 KiB
Go
127 lines
4.3 KiB
Go
// Package ewma implements exponentially weighted moving averages.
|
|
package ewma
|
|
|
|
// Copyright (c) 2013 VividCortex, Inc. All rights reserved.
|
|
// Please see the LICENSE file for applicable license terms.
|
|
|
|
const (
|
|
// By default, we average over a one-minute period, which means the average
|
|
// age of the metrics in the period is 30 seconds.
|
|
AVG_METRIC_AGE float64 = 30.0
|
|
|
|
// The formula for computing the decay factor from the average age comes
|
|
// from "Production and Operations Analysis" by Steven Nahmias.
|
|
DECAY float64 = 2 / (float64(AVG_METRIC_AGE) + 1)
|
|
|
|
// For best results, the moving average should not be initialized to the
|
|
// samples it sees immediately. The book "Production and Operations
|
|
// Analysis" by Steven Nahmias suggests initializing the moving average to
|
|
// the mean of the first 10 samples. Until the VariableEwma has seen this
|
|
// many samples, it is not "ready" to be queried for the value of the
|
|
// moving average. This adds some memory cost.
|
|
WARMUP_SAMPLES uint8 = 10
|
|
)
|
|
|
|
// MovingAverage is the interface that computes a moving average over a time-
|
|
// series stream of numbers. The average may be over a window or exponentially
|
|
// decaying.
|
|
type MovingAverage interface {
|
|
Add(float64)
|
|
Value() float64
|
|
Set(float64)
|
|
}
|
|
|
|
// NewMovingAverage constructs a MovingAverage that computes an average with the
|
|
// desired characteristics in the moving window or exponential decay. If no
|
|
// age is given, it constructs a default exponentially weighted implementation
|
|
// that consumes minimal memory. The age is related to the decay factor alpha
|
|
// by the formula given for the DECAY constant. It signifies the average age
|
|
// of the samples as time goes to infinity.
|
|
func NewMovingAverage(age ...float64) MovingAverage {
|
|
if len(age) == 0 || age[0] == AVG_METRIC_AGE {
|
|
return new(SimpleEWMA)
|
|
}
|
|
return &VariableEWMA{
|
|
decay: 2 / (age[0] + 1),
|
|
}
|
|
}
|
|
|
|
// A SimpleEWMA represents the exponentially weighted moving average of a
|
|
// series of numbers. It WILL have different behavior than the VariableEWMA
|
|
// for multiple reasons. It has no warm-up period and it uses a constant
|
|
// decay. These properties let it use less memory. It will also behave
|
|
// differently when it's equal to zero, which is assumed to mean
|
|
// uninitialized, so if a value is likely to actually become zero over time,
|
|
// then any non-zero value will cause a sharp jump instead of a small change.
|
|
// However, note that this takes a long time, and the value may just
|
|
// decays to a stable value that's close to zero, but which won't be mistaken
|
|
// for uninitialized. See http://play.golang.org/p/litxBDr_RC for example.
|
|
type SimpleEWMA struct {
|
|
// The current value of the average. After adding with Add(), this is
|
|
// updated to reflect the average of all values seen thus far.
|
|
value float64
|
|
}
|
|
|
|
// Add adds a value to the series and updates the moving average.
|
|
func (e *SimpleEWMA) Add(value float64) {
|
|
if e.value == 0 { // this is a proxy for "uninitialized"
|
|
e.value = value
|
|
} else {
|
|
e.value = (value * DECAY) + (e.value * (1 - DECAY))
|
|
}
|
|
}
|
|
|
|
// Value returns the current value of the moving average.
|
|
func (e *SimpleEWMA) Value() float64 {
|
|
return e.value
|
|
}
|
|
|
|
// Set sets the EWMA's value.
|
|
func (e *SimpleEWMA) Set(value float64) {
|
|
e.value = value
|
|
}
|
|
|
|
// VariableEWMA represents the exponentially weighted moving average of a series of
|
|
// numbers. Unlike SimpleEWMA, it supports a custom age, and thus uses more memory.
|
|
type VariableEWMA struct {
|
|
// The multiplier factor by which the previous samples decay.
|
|
decay float64
|
|
// The current value of the average.
|
|
value float64
|
|
// The number of samples added to this instance.
|
|
count uint8
|
|
}
|
|
|
|
// Add adds a value to the series and updates the moving average.
|
|
func (e *VariableEWMA) Add(value float64) {
|
|
switch {
|
|
case e.count < WARMUP_SAMPLES:
|
|
e.count++
|
|
e.value += value
|
|
case e.count == WARMUP_SAMPLES:
|
|
e.count++
|
|
e.value = e.value / float64(WARMUP_SAMPLES)
|
|
e.value = (value * e.decay) + (e.value * (1 - e.decay))
|
|
default:
|
|
e.value = (value * e.decay) + (e.value * (1 - e.decay))
|
|
}
|
|
}
|
|
|
|
// Value returns the current value of the average, or 0.0 if the series hasn't
|
|
// warmed up yet.
|
|
func (e *VariableEWMA) Value() float64 {
|
|
if e.count <= WARMUP_SAMPLES {
|
|
return 0.0
|
|
}
|
|
|
|
return e.value
|
|
}
|
|
|
|
// Set sets the EWMA's value.
|
|
func (e *VariableEWMA) Set(value float64) {
|
|
e.value = value
|
|
if e.count <= WARMUP_SAMPLES {
|
|
e.count = WARMUP_SAMPLES + 1
|
|
}
|
|
}
|