123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- /*
- *
- * Copyright 2017 gRPC authors.
- *
- * 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.
- *
- */
- // Copyright (c) 2015 Arista Networks, Inc.
- // Use of this source code is governed by the Apache License 2.0
- // that can be found in the COPYING file.
- package stats
- import (
- "math"
- "time"
- )
- // timeseries holds the history of a changing value over a predefined period of
- // time.
- type timeseries struct {
- size int // The number of time slots. Equivalent to len(slots).
- resolution time.Duration // The time resolution of each slot.
- stepCount int64 // The number of intervals seen since creation.
- head int // The position of the current time in slots.
- time time.Time // The time at the beginning of the current time slot.
- slots []int64 // A circular buffer of time slots.
- }
- // newTimeSeries returns a newly allocated timeseries that covers the requested
- // period with the given resolution.
- func newTimeSeries(initialTime time.Time, period, resolution time.Duration) *timeseries {
- size := int(period.Nanoseconds()/resolution.Nanoseconds()) + 1
- return ×eries{
- size: size,
- resolution: resolution,
- stepCount: 1,
- time: initialTime,
- slots: make([]int64, size),
- }
- }
- // advanceTimeWithFill moves the timeseries forward to time t and fills in any
- // slots that get skipped in the process with the given value. Values older than
- // the timeseries period are lost.
- func (ts *timeseries) advanceTimeWithFill(t time.Time, value int64) {
- advanceTo := t.Truncate(ts.resolution)
- if !advanceTo.After(ts.time) {
- // This is shortcut for the most common case of a busy counter
- // where updates come in many times per ts.resolution.
- ts.time = advanceTo
- return
- }
- steps := int(advanceTo.Sub(ts.time).Nanoseconds() / ts.resolution.Nanoseconds())
- ts.stepCount += int64(steps)
- if steps > ts.size {
- steps = ts.size
- }
- for steps > 0 {
- ts.head = (ts.head + 1) % ts.size
- ts.slots[ts.head] = value
- steps--
- }
- ts.time = advanceTo
- }
- // advanceTime moves the timeseries forward to time t and fills in any slots
- // that get skipped in the process with the head value. Values older than the
- // timeseries period are lost.
- func (ts *timeseries) advanceTime(t time.Time) {
- ts.advanceTimeWithFill(t, ts.slots[ts.head])
- }
- // set sets the current value of the timeseries.
- func (ts *timeseries) set(value int64) {
- ts.slots[ts.head] = value
- }
- // incr sets the current value of the timeseries.
- func (ts *timeseries) incr(delta int64) {
- ts.slots[ts.head] += delta
- }
- // headValue returns the latest value from the timeseries.
- func (ts *timeseries) headValue() int64 {
- return ts.slots[ts.head]
- }
- // headTime returns the time of the latest value from the timeseries.
- func (ts *timeseries) headTime() time.Time {
- return ts.time
- }
- // tailValue returns the oldest value from the timeseries.
- func (ts *timeseries) tailValue() int64 {
- if ts.stepCount < int64(ts.size) {
- return 0
- }
- return ts.slots[(ts.head+1)%ts.size]
- }
- // tailTime returns the time of the oldest value from the timeseries.
- func (ts *timeseries) tailTime() time.Time {
- size := int64(ts.size)
- if ts.stepCount < size {
- size = ts.stepCount
- }
- return ts.time.Add(-time.Duration(size-1) * ts.resolution)
- }
- // delta returns the difference between the newest and oldest values from the
- // timeseries.
- func (ts *timeseries) delta() int64 {
- return ts.headValue() - ts.tailValue()
- }
- // rate returns the rate of change between the oldest and newest values from
- // the timeseries in units per second.
- func (ts *timeseries) rate() float64 {
- deltaTime := ts.headTime().Sub(ts.tailTime()).Seconds()
- if deltaTime == 0 {
- return 0
- }
- return float64(ts.delta()) / deltaTime
- }
- // min returns the smallest value from the timeseries.
- func (ts *timeseries) min() int64 {
- to := ts.size
- if ts.stepCount < int64(ts.size) {
- to = ts.head + 1
- }
- tail := (ts.head + 1) % ts.size
- min := int64(math.MaxInt64)
- for b := 0; b < to; b++ {
- if b != tail && ts.slots[b] < min {
- min = ts.slots[b]
- }
- }
- return min
- }
- // max returns the largest value from the timeseries.
- func (ts *timeseries) max() int64 {
- to := ts.size
- if ts.stepCount < int64(ts.size) {
- to = ts.head + 1
- }
- tail := (ts.head + 1) % ts.size
- max := int64(math.MinInt64)
- for b := 0; b < to; b++ {
- if b != tail && ts.slots[b] > max {
- max = ts.slots[b]
- }
- }
- return max
- }
- // reset resets the timeseries to an empty state.
- func (ts *timeseries) reset(t time.Time) {
- ts.head = 0
- ts.time = t
- ts.stepCount = 1
- ts.slots = make([]int64, ts.size)
- }
|