github.com/m3db/m3@v1.5.0/src/aggregator/aggregation/timer.go (about)

     1  // Copyright (c) 2016 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package aggregation
    22  
    23  import (
    24  	"time"
    25  
    26  	"github.com/m3db/m3/src/aggregator/aggregation/quantile/cm"
    27  	"github.com/m3db/m3/src/metrics/aggregation"
    28  )
    29  
    30  // Timer aggregates timer values. Timer APIs are not thread-safe.
    31  type Timer struct {
    32  	lastAt                   time.Time
    33  	stream                   *cm.Stream // Stream of values received.
    34  	annotation               []byte
    35  	count                    int64   // Number of values received.
    36  	sum                      float64 // Sum of the values.
    37  	sumSq                    float64 // Sum of squared values.
    38  	hasExpensiveAggregations bool
    39  }
    40  
    41  // NewTimer creates a new timer
    42  func NewTimer(quantiles []float64, streamOpts cm.Options, opts Options) Timer {
    43  	stream := streamOpts.StreamPool().Get()
    44  	stream.ResetSetData(quantiles)
    45  	return Timer{
    46  		hasExpensiveAggregations: opts.HasExpensiveAggregations,
    47  		stream:                   stream,
    48  	}
    49  }
    50  
    51  // Add adds a timer value.
    52  func (t *Timer) Add(timestamp time.Time, value float64, annotation []byte) {
    53  	t.AddBatch(timestamp, []float64{value}, annotation)
    54  }
    55  
    56  // AddBatch adds a batch of timer values.
    57  func (t *Timer) AddBatch(timestamp time.Time, values []float64, annotation []byte) {
    58  	// Record last at just once.
    59  	t.recordLastAt(timestamp)
    60  	t.count += int64(len(values))
    61  
    62  	if t.hasExpensiveAggregations {
    63  		for _, v := range values {
    64  			t.sum += v
    65  			t.sumSq += v * v
    66  		}
    67  	} else {
    68  		for _, v := range values {
    69  			t.sum += v
    70  		}
    71  	}
    72  
    73  	t.stream.AddBatch(values)
    74  
    75  	t.annotation = MaybeReplaceAnnotation(t.annotation, annotation)
    76  }
    77  
    78  func (t *Timer) recordLastAt(timestamp time.Time) {
    79  	if t.lastAt.IsZero() || timestamp.After(t.lastAt) {
    80  		// NB(r): Only set the last value if this value arrives
    81  		// after the wall clock timestamp of previous values, not
    82  		// the arrival time (i.e. order received).
    83  		t.lastAt = timestamp
    84  	}
    85  }
    86  
    87  // LastAt returns the time of the last value received.
    88  func (t *Timer) LastAt() time.Time { return t.lastAt }
    89  
    90  // Quantile returns the value at a given quantile.
    91  func (t *Timer) Quantile(q float64) float64 {
    92  	t.stream.Flush()
    93  	return t.stream.Quantile(q)
    94  }
    95  
    96  // Count returns the number of values received.
    97  func (t *Timer) Count() int64 { return t.count }
    98  
    99  // Min returns the minimum timer value.
   100  func (t *Timer) Min() float64 {
   101  	t.stream.Flush()
   102  	return t.stream.Min()
   103  }
   104  
   105  // Max returns the maximum timer value.
   106  func (t *Timer) Max() float64 {
   107  	t.stream.Flush()
   108  	return t.stream.Max()
   109  }
   110  
   111  // Sum returns the sum of timer values.
   112  func (t *Timer) Sum() float64 { return t.sum }
   113  
   114  // SumSq returns the squared sum of timer values.
   115  func (t *Timer) SumSq() float64 { return t.sumSq }
   116  
   117  // Mean returns the mean timer value.
   118  func (t *Timer) Mean() float64 {
   119  	if t.count == 0 {
   120  		return 0.0
   121  	}
   122  	return t.sum / float64(t.count)
   123  }
   124  
   125  // Stdev returns the standard deviation timer value.
   126  func (t *Timer) Stdev() float64 {
   127  	return stdev(t.count, t.sumSq, t.sum)
   128  }
   129  
   130  // ValueOf returns the value for the aggregation type.
   131  func (t *Timer) ValueOf(aggType aggregation.Type) float64 {
   132  	if q, ok := aggType.Quantile(); ok {
   133  		return t.Quantile(q)
   134  	}
   135  
   136  	switch aggType {
   137  	case aggregation.Min:
   138  		return t.Min()
   139  	case aggregation.Max:
   140  		return t.Max()
   141  	case aggregation.Mean:
   142  		return t.Mean()
   143  	case aggregation.Count:
   144  		return float64(t.Count())
   145  	case aggregation.Sum:
   146  		return t.Sum()
   147  	case aggregation.SumSq:
   148  		return t.SumSq()
   149  	case aggregation.Stdev:
   150  		return t.Stdev()
   151  	}
   152  	return 0
   153  }
   154  
   155  // Annotation returns the annotation associated with the timer.
   156  func (t *Timer) Annotation() []byte {
   157  	return t.annotation
   158  }
   159  
   160  // Close closes the timer.
   161  func (t *Timer) Close() { t.stream.Close() }