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

     1  // Copyright (c) 2017 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  	"math"
    25  	"math/rand"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/m3db/m3/src/aggregator/aggregation/quantile/cm"
    30  	"github.com/m3db/m3/src/x/instrument"
    31  )
    32  
    33  const (
    34  	_insertAndCompressEvery = 1024
    35  	_eps                    = 0.001
    36  	_capacity               = 32
    37  )
    38  
    39  var (
    40  	_aggregationOptions = NewOptions(instrument.NewOptions())
    41  	_now                = time.Now()
    42  	_cmOptions          cm.Options
    43  )
    44  
    45  func getTimer() Timer {
    46  	return NewTimer(testQuantiles, _cmOptions, _aggregationOptions)
    47  }
    48  
    49  func BenchmarkTimerValues(b *testing.B) {
    50  	timer := getTimer()
    51  	for i := 1; i <= 2500; i++ {
    52  		timer.Add(_now, float64(i), nil)
    53  	}
    54  	for n := 0; n < b.N; n++ {
    55  		timer.Sum()
    56  		timer.SumSq()
    57  		timer.Mean()
    58  		timer.Min()
    59  		timer.Max()
    60  		timer.Count()
    61  		timer.Stdev()
    62  		timer.Quantile(0.5)
    63  		timer.Quantile(0.5)
    64  		timer.Quantile(0.95)
    65  		timer.Quantile(0.99)
    66  	}
    67  }
    68  
    69  func BenchmarkTimerValueOf(b *testing.B) {
    70  	timer := getTimer()
    71  	for n := 0; n < b.N; n++ {
    72  		for _, aggType := range testAggTypes {
    73  			timer.ValueOf(aggType)
    74  		}
    75  	}
    76  }
    77  
    78  func BenchmarkTimerAddBatch(b *testing.B) {
    79  	for _, bench := range []struct {
    80  		name      string
    81  		num       int
    82  		batchSize int
    83  		sampleFn  func(*rand.Rand) float64
    84  	}{
    85  		{
    86  			name:      "100k samples 1000 batch size",
    87  			num:       100_000,
    88  			batchSize: 1000,
    89  			sampleFn: func(r *rand.Rand) float64 {
    90  				return r.Float64()
    91  			},
    92  		},
    93  		{
    94  			name:      "100k samples 1000 batch size 0..1,000,000 range",
    95  			num:       100_000,
    96  			batchSize: 1000,
    97  			sampleFn: func(r *rand.Rand) float64 {
    98  				return r.Float64() * 1_000_000
    99  			},
   100  		},
   101  		{
   102  			name:      "100k samples 1000 batch size 0..100,000 range",
   103  			num:       100_000,
   104  			batchSize: 1000,
   105  			sampleFn: func(r *rand.Rand) float64 {
   106  				return r.Float64() * 100_000
   107  			},
   108  		},
   109  		{
   110  			name:      "10k samples 1000 batch size",
   111  			num:       10_000,
   112  			batchSize: 1000,
   113  			sampleFn: func(r *rand.Rand) float64 {
   114  				return r.Float64()
   115  			},
   116  		},
   117  		{
   118  			name:      "10k samples 100 batch size",
   119  			num:       10_000,
   120  			batchSize: 100,
   121  			sampleFn: func(r *rand.Rand) float64 {
   122  				return r.Float64()
   123  			},
   124  		},
   125  		{
   126  			name:      "10k samples 100 batch size with negative values",
   127  			num:       10_000,
   128  			batchSize: 100,
   129  			sampleFn: func(r *rand.Rand) float64 {
   130  				return -1.0*r.Float64() + 10.0
   131  			},
   132  		},
   133  		{
   134  			name:      "1k samples 100 batch size",
   135  			num:       1_000,
   136  			batchSize: 100,
   137  			sampleFn: func(r *rand.Rand) float64 {
   138  				return r.Float64()
   139  			},
   140  		},
   141  	} {
   142  		bench := bench
   143  		samples, q := getTimerSamples(bench.num, bench.sampleFn, testQuantiles)
   144  		b.Run(bench.name, func(b *testing.B) {
   145  			benchAddBatch(b, samples, bench.batchSize, testQuantiles, q)
   146  		})
   147  	}
   148  }
   149  
   150  func benchAddBatch(
   151  	b *testing.B,
   152  	samples []float64,
   153  	batchSize int,
   154  	quantiles []float64,
   155  	quantileValues []float64,
   156  ) {
   157  	b.Helper()
   158  	b.SetBytes(int64(8 * len(samples)))
   159  	b.ResetTimer()
   160  	b.RunParallel(func(pb *testing.PB) {
   161  		for pb.Next() {
   162  			timer := getTimer()
   163  
   164  			for i := 0; i < len(samples); i += batchSize {
   165  				end := i + batchSize
   166  				if end >= len(samples) {
   167  					end = len(samples) - 1
   168  				}
   169  				timer.AddBatch(_now, samples[i:end], nil)
   170  			}
   171  
   172  			for i := range quantiles {
   173  				q := timer.Quantile(quantiles[i])
   174  				// error bound is quantile * epsilon
   175  				expected := (_eps / quantiles[i]) * quantileValues[i]
   176  				delta := math.Abs(q - quantileValues[i])
   177  				if delta > expected {
   178  					b.Logf("unexpected delta: value %f, expected delta %v, delta %f, quantile %f",
   179  						q, expected, delta, quantiles[i])
   180  					b.FailNow()
   181  				}
   182  			}
   183  			timer.Close()
   184  		}
   185  	})
   186  }
   187  
   188  func init() {
   189  	_aggregationOptions.ResetSetData(testAggTypes)
   190  	_cmOptions = cm.NewOptions().
   191  		SetInsertAndCompressEvery(_insertAndCompressEvery).
   192  		SetEps(_eps).
   193  		SetCapacity(_capacity)
   194  	_aggregationOptions.ResetSetData(testAggTypes)
   195  }