mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-01 14:47:38 +00:00
7f4fb34182
It is better developing vmctl tool in VictoriaMetrics repository, so it could be released together with the rest of vmutils tools such as vmalert, vmagent, vmbackup, vmrestore and vmauth.
83 lines
2 KiB
Go
83 lines
2 KiB
Go
package pb
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"time"
|
|
|
|
"github.com/VividCortex/ewma"
|
|
)
|
|
|
|
var speedAddLimit = time.Second / 2
|
|
|
|
type speed struct {
|
|
ewma ewma.MovingAverage
|
|
lastStateId uint64
|
|
prevValue, startValue int64
|
|
prevTime, startTime time.Time
|
|
}
|
|
|
|
func (s *speed) value(state *State) float64 {
|
|
if s.ewma == nil {
|
|
s.ewma = ewma.NewMovingAverage()
|
|
}
|
|
if state.IsFirst() || state.Id() < s.lastStateId {
|
|
s.reset(state)
|
|
return 0
|
|
}
|
|
if state.Id() == s.lastStateId {
|
|
return s.ewma.Value()
|
|
}
|
|
if state.IsFinished() {
|
|
return s.absValue(state)
|
|
}
|
|
dur := state.Time().Sub(s.prevTime)
|
|
if dur < speedAddLimit {
|
|
return s.ewma.Value()
|
|
}
|
|
diff := math.Abs(float64(state.Value() - s.prevValue))
|
|
lastSpeed := diff / dur.Seconds()
|
|
s.prevTime = state.Time()
|
|
s.prevValue = state.Value()
|
|
s.lastStateId = state.Id()
|
|
s.ewma.Add(lastSpeed)
|
|
return s.ewma.Value()
|
|
}
|
|
|
|
func (s *speed) reset(state *State) {
|
|
s.lastStateId = state.Id()
|
|
s.startTime = state.Time()
|
|
s.prevTime = state.Time()
|
|
s.startValue = state.Value()
|
|
s.prevValue = state.Value()
|
|
s.ewma = ewma.NewMovingAverage()
|
|
}
|
|
|
|
func (s *speed) absValue(state *State) float64 {
|
|
if dur := state.Time().Sub(s.startTime); dur > 0 {
|
|
return float64(state.Value()) / dur.Seconds()
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func getSpeedObj(state *State) (s *speed) {
|
|
if sObj, ok := state.Get(speedObj).(*speed); ok {
|
|
return sObj
|
|
}
|
|
s = new(speed)
|
|
state.Set(speedObj, s)
|
|
return
|
|
}
|
|
|
|
// ElementSpeed calculates current speed by EWMA
|
|
// Optionally can take one or two string arguments.
|
|
// First string will be used as value for format speed, default is "%s p/s".
|
|
// Second string will be used when speed not available, default is "? p/s"
|
|
// In template use as follows: {{speed .}} or {{speed . "%s per second"}} or {{speed . "%s ps" "..."}
|
|
var ElementSpeed ElementFunc = func(state *State, args ...string) string {
|
|
sp := getSpeedObj(state).value(state)
|
|
if sp == 0 {
|
|
return argsHelper(args).getNotEmptyOr(1, "? p/s")
|
|
}
|
|
return fmt.Sprintf(argsHelper(args).getNotEmptyOr(0, "%s p/s"), state.Format(int64(round(sp))))
|
|
}
|