rclone/vendor/github.com/spacemonkeygo/monkit/v3/distgen.go.m4
2020-05-12 15:56:50 +00:00

186 lines
4.6 KiB
Plaintext

// Copyright (C) 2016 Space Monkey, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// WARNING: THE NON-M4 VERSIONS OF THIS FILE ARE GENERATED BY GO GENERATE!
// ONLY MAKE CHANGES TO THE M4 FILE
//
package monkit
import (
"sort"
_IMPORT_
)
// _NAME_`Dist' keeps statistics about values such as
// low/high/recent/average/quantiles. Not threadsafe. Construct with
// `New'_NAME_`Dist'(). Fields are expected to be read from but not written to.
type _NAME_`Dist' struct {
// Low and High are the lowest and highest values observed since
// construction or the last reset.
Low, High _TYPE_
// Recent is the last observed value.
Recent _TYPE_
// Count is the number of observed values since construction or the last
// reset.
Count int64
// Sum is the sum of all the observed values since construction or the last
// reset.
Sum _TYPE_
key SeriesKey
reservoir [ReservoirSize]float32
rng xorshift128
sorted bool
}
func `init'_NAME_`Dist'(v *_NAME_`Dist', key SeriesKey) {
v.key = key
v.rng = newXORShift128()
}
// `New'_NAME_`Dist' creates a distribution of _TYPE_`s'.
func `New'_NAME_`Dist'(key SeriesKey) (d *_NAME_`Dist') {
d = &_NAME_`Dist'{}
`init'_NAME_`Dist'(d, key)
return d
}
// Insert adds a value to the distribution, updating appropriate values.
func (d *_NAME_`Dist') Insert(val _TYPE_) {
if d.Count != 0 {
if val < d.Low {
d.Low = val
}
if val > d.High {
d.High = val
}
} else {
d.Low = val
d.High = val
}
d.Recent = val
d.Sum += val
index := d.Count
d.Count += 1
if index < ReservoirSize {
d.reservoir[index] = float32(val)
d.sorted = false
} else {
window := d.Count
// careful, the capitalization of Window is important
if Window > 0 && window > Window {
window = Window
}
// fast, but kind of biased. probably okay
j := d.rng.Uint64() % uint64(window)
if j < ReservoirSize {
d.reservoir[int(j)] = float32(val)
d.sorted = false
}
}
}
// FullAverage calculates and returns the average of all inserted values.
func (d *_NAME_`Dist') FullAverage() _TYPE_ {
if d.Count > 0 {
return d.Sum / _TYPE_`(d.Count)'
}
return 0
}
// ReservoirAverage calculates the average of the current reservoir.
func (d *_NAME_`Dist') ReservoirAverage() _TYPE_ {
amount := ReservoirSize
if d.Count < int64(amount) {
amount = int(d.Count)
}
if amount <= 0 {
return 0
}
var sum float32
for i := 0; i < amount; i++ {
sum += d.reservoir[i]
}
return _TYPE_`(sum / float32(amount))'
}
// Query will return the approximate value at the given quantile from the
// reservoir, where 0 <= quantile <= 1.
func (d *_NAME_`Dist') Query(quantile float64) _TYPE_ {
rlen := int(ReservoirSize)
if int64(rlen) > d.Count {
rlen = int(d.Count)
}
if rlen < 2 {
return _TYPE_`(d.reservoir[0])'
}
reservoir := d.reservoir[:rlen]
if !d.sorted {
sort.Sort(float32Slice(reservoir))
d.sorted = true
}
if quantile <= 0 {
return _TYPE_`(reservoir[0])'
}
if quantile >= 1 {
return _TYPE_`(reservoir[rlen-1])'
}
idx_float := quantile * float64(rlen-1)
idx := int(idx_float)
diff := idx_float - float64(idx)
prior := float64(reservoir[idx])
return _TYPE_`(prior + diff*(float64(reservoir[idx+1])-prior))'
}
// Copy returns a full copy of the entire distribution.
func (d *_NAME_`Dist') Copy() *_NAME_`Dist' {
cp := *d
cp.rng = newXORShift128()
return &cp
}
func (d *_NAME_`Dist') Reset() {
d.Low, d.High, d.Recent, d.Count, d.Sum = 0, 0, 0, 0, 0
// resetting count will reset the quantile reservoir
}
func (d *_NAME_`Dist') Stats(cb func(key SeriesKey, field string, val float64)) {
count := d.Count
cb(d.key, "count", float64(count))
if count > 0 {
cb(d.key, "sum", d.toFloat64(d.Sum))
cb(d.key, "min", d.toFloat64(d.Low))
cb(d.key, "avg", d.toFloat64(d.FullAverage()))
cb(d.key, "max", d.toFloat64(d.High))
cb(d.key, "rmin", d.toFloat64(d.Query(0)))
cb(d.key, "ravg", d.toFloat64(d.ReservoirAverage()))
cb(d.key, "r10", d.toFloat64(d.Query(.1)))
cb(d.key, "r50", d.toFloat64(d.Query(.5)))
cb(d.key, "r90", d.toFloat64(d.Query(.9)))
cb(d.key, "rmax", d.toFloat64(d.Query(1)))
cb(d.key, "recent", d.toFloat64(d.Recent))
}
}