github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/trace/histogram_test.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package trace
     6  
     7  import (
     8  	"math"
     9  	"testing"
    10  )
    11  
    12  type sumTest struct {
    13  	value        int64
    14  	sum          int64
    15  	sumOfSquares float64
    16  	total        int64
    17  }
    18  
    19  var sumTests = []sumTest{
    20  	{100, 100, 10000, 1},
    21  	{50, 150, 12500, 2},
    22  	{50, 200, 15000, 3},
    23  	{50, 250, 17500, 4},
    24  }
    25  
    26  type bucketingTest struct {
    27  	in     int64
    28  	log    int
    29  	bucket int
    30  }
    31  
    32  var bucketingTests = []bucketingTest{
    33  	{0, 0, 0},
    34  	{1, 1, 0},
    35  	{2, 2, 1},
    36  	{3, 2, 1},
    37  	{4, 3, 2},
    38  	{1000, 10, 9},
    39  	{1023, 10, 9},
    40  	{1024, 11, 10},
    41  	{1000000, 20, 19},
    42  }
    43  
    44  type multiplyTest struct {
    45  	in                   int64
    46  	ratio                float64
    47  	expectedSum          int64
    48  	expectedTotal        int64
    49  	expectedSumOfSquares float64
    50  }
    51  
    52  var multiplyTests = []multiplyTest{
    53  	{15, 2.5, 37, 2, 562.5},
    54  	{128, 4.6, 758, 13, 77953.9},
    55  }
    56  
    57  type percentileTest struct {
    58  	fraction float64
    59  	expected int64
    60  }
    61  
    62  var percentileTests = []percentileTest{
    63  	{0.25, 48},
    64  	{0.5, 96},
    65  	{0.6, 109},
    66  	{0.75, 128},
    67  	{0.90, 205},
    68  	{0.95, 230},
    69  	{0.99, 256},
    70  }
    71  
    72  func TestSum(t *testing.T) {
    73  	var h histogram
    74  
    75  	for _, test := range sumTests {
    76  		h.addMeasurement(test.value)
    77  		sum := h.sum
    78  		if sum != test.sum {
    79  			t.Errorf("h.Sum = %v WANT: %v", sum, test.sum)
    80  		}
    81  
    82  		sumOfSquares := h.sumOfSquares
    83  		if sumOfSquares != test.sumOfSquares {
    84  			t.Errorf("h.SumOfSquares = %v WANT: %v", sumOfSquares, test.sumOfSquares)
    85  		}
    86  
    87  		total := h.total()
    88  		if total != test.total {
    89  			t.Errorf("h.Total = %v WANT: %v", total, test.total)
    90  		}
    91  	}
    92  }
    93  
    94  func TestMultiply(t *testing.T) {
    95  	var h histogram
    96  	for i, test := range multiplyTests {
    97  		h.addMeasurement(test.in)
    98  		h.Multiply(test.ratio)
    99  		if h.sum != test.expectedSum {
   100  			t.Errorf("#%v: h.sum = %v WANT: %v", i, h.sum, test.expectedSum)
   101  		}
   102  		if h.total() != test.expectedTotal {
   103  			t.Errorf("#%v: h.total = %v WANT: %v", i, h.total(), test.expectedTotal)
   104  		}
   105  		if h.sumOfSquares != test.expectedSumOfSquares {
   106  			t.Errorf("#%v: h.SumOfSquares = %v WANT: %v", i, test.expectedSumOfSquares, h.sumOfSquares)
   107  		}
   108  	}
   109  }
   110  
   111  func TestBucketingFunctions(t *testing.T) {
   112  	for _, test := range bucketingTests {
   113  		log := log2(test.in)
   114  		if log != test.log {
   115  			t.Errorf("log2 = %v WANT: %v", log, test.log)
   116  		}
   117  
   118  		bucket := getBucket(test.in)
   119  		if bucket != test.bucket {
   120  			t.Errorf("getBucket = %v WANT: %v", bucket, test.bucket)
   121  		}
   122  	}
   123  }
   124  
   125  func TestAverage(t *testing.T) {
   126  	a := new(histogram)
   127  	average := a.average()
   128  	if average != 0 {
   129  		t.Errorf("Average of empty histogram was %v WANT: 0", average)
   130  	}
   131  
   132  	a.addMeasurement(1)
   133  	a.addMeasurement(1)
   134  	a.addMeasurement(3)
   135  	const expected = float64(5) / float64(3)
   136  	average = a.average()
   137  
   138  	if !isApproximate(average, expected) {
   139  		t.Errorf("Average = %g WANT: %v", average, expected)
   140  	}
   141  }
   142  
   143  func TestStandardDeviation(t *testing.T) {
   144  	a := new(histogram)
   145  	add(a, 10, 1<<4)
   146  	add(a, 10, 1<<5)
   147  	add(a, 10, 1<<6)
   148  	stdDev := a.standardDeviation()
   149  	const expected = 19.95
   150  
   151  	if !isApproximate(stdDev, expected) {
   152  		t.Errorf("StandardDeviation = %v WANT: %v", stdDev, expected)
   153  	}
   154  
   155  	// No values
   156  	a = new(histogram)
   157  	stdDev = a.standardDeviation()
   158  
   159  	if !isApproximate(stdDev, 0) {
   160  		t.Errorf("StandardDeviation = %v WANT: 0", stdDev)
   161  	}
   162  
   163  	add(a, 1, 1<<4)
   164  	if !isApproximate(stdDev, 0) {
   165  		t.Errorf("StandardDeviation = %v WANT: 0", stdDev)
   166  	}
   167  
   168  	add(a, 10, 1<<4)
   169  	if !isApproximate(stdDev, 0) {
   170  		t.Errorf("StandardDeviation = %v WANT: 0", stdDev)
   171  	}
   172  }
   173  
   174  func TestPercentileBoundary(t *testing.T) {
   175  	a := new(histogram)
   176  	add(a, 5, 1<<4)
   177  	add(a, 10, 1<<6)
   178  	add(a, 5, 1<<7)
   179  
   180  	for _, test := range percentileTests {
   181  		percentile := a.percentileBoundary(test.fraction)
   182  		if percentile != test.expected {
   183  			t.Errorf("h.PercentileBoundary (fraction=%v) = %v WANT: %v", test.fraction, percentile, test.expected)
   184  		}
   185  	}
   186  }
   187  
   188  func TestCopyFrom(t *testing.T) {
   189  	a := histogram{5, 25, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
   190  		19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}, 4, -1}
   191  	b := histogram{6, 36, []int64{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
   192  		20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}, 5, -1}
   193  
   194  	a.CopyFrom(&b)
   195  
   196  	if a.String() != b.String() {
   197  		t.Errorf("a.String = %s WANT: %s", a.String(), b.String())
   198  	}
   199  }
   200  
   201  func TestClear(t *testing.T) {
   202  	a := histogram{5, 25, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
   203  		19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}, 4, -1}
   204  
   205  	a.Clear()
   206  
   207  	expected := "0, 0.000000, 0, 0, []"
   208  	if a.String() != expected {
   209  		t.Errorf("a.String = %s WANT %s", a.String(), expected)
   210  	}
   211  }
   212  
   213  func TestNew(t *testing.T) {
   214  	a := histogram{5, 25, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
   215  		19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}, 4, -1}
   216  	b := a.New()
   217  
   218  	expected := "0, 0.000000, 0, 0, []"
   219  	if b.(*histogram).String() != expected {
   220  		t.Errorf("b.(*histogram).String = %s WANT: %s", b.(*histogram).String(), expected)
   221  	}
   222  }
   223  
   224  func TestAdd(t *testing.T) {
   225  	// The tests here depend on the associativity of addMeasurement and Add.
   226  	// Add empty observation
   227  	a := histogram{5, 25, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
   228  		19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}, 4, -1}
   229  	b := a.New()
   230  
   231  	expected := a.String()
   232  	a.Add(b)
   233  	if a.String() != expected {
   234  		t.Errorf("a.String = %s WANT: %s", a.String(), expected)
   235  	}
   236  
   237  	// Add same bucketed value, no new buckets
   238  	c := new(histogram)
   239  	d := new(histogram)
   240  	e := new(histogram)
   241  	c.addMeasurement(12)
   242  	d.addMeasurement(11)
   243  	e.addMeasurement(12)
   244  	e.addMeasurement(11)
   245  	c.Add(d)
   246  	if c.String() != e.String() {
   247  		t.Errorf("c.String = %s WANT: %s", c.String(), e.String())
   248  	}
   249  
   250  	// Add bucketed values
   251  	f := new(histogram)
   252  	g := new(histogram)
   253  	h := new(histogram)
   254  	f.addMeasurement(4)
   255  	f.addMeasurement(12)
   256  	f.addMeasurement(100)
   257  	g.addMeasurement(18)
   258  	g.addMeasurement(36)
   259  	g.addMeasurement(255)
   260  	h.addMeasurement(4)
   261  	h.addMeasurement(12)
   262  	h.addMeasurement(100)
   263  	h.addMeasurement(18)
   264  	h.addMeasurement(36)
   265  	h.addMeasurement(255)
   266  	f.Add(g)
   267  	if f.String() != h.String() {
   268  		t.Errorf("f.String = %q WANT: %q", f.String(), h.String())
   269  	}
   270  
   271  	// add buckets to no buckets
   272  	i := new(histogram)
   273  	j := new(histogram)
   274  	k := new(histogram)
   275  	j.addMeasurement(18)
   276  	j.addMeasurement(36)
   277  	j.addMeasurement(255)
   278  	k.addMeasurement(18)
   279  	k.addMeasurement(36)
   280  	k.addMeasurement(255)
   281  	i.Add(j)
   282  	if i.String() != k.String() {
   283  		t.Errorf("i.String = %q WANT: %q", i.String(), k.String())
   284  	}
   285  
   286  	// add buckets to single value (no overlap)
   287  	l := new(histogram)
   288  	m := new(histogram)
   289  	n := new(histogram)
   290  	l.addMeasurement(0)
   291  	m.addMeasurement(18)
   292  	m.addMeasurement(36)
   293  	m.addMeasurement(255)
   294  	n.addMeasurement(0)
   295  	n.addMeasurement(18)
   296  	n.addMeasurement(36)
   297  	n.addMeasurement(255)
   298  	l.Add(m)
   299  	if l.String() != n.String() {
   300  		t.Errorf("l.String = %q WANT: %q", l.String(), n.String())
   301  	}
   302  
   303  	// mixed order
   304  	o := new(histogram)
   305  	p := new(histogram)
   306  	o.addMeasurement(0)
   307  	o.addMeasurement(2)
   308  	o.addMeasurement(0)
   309  	p.addMeasurement(0)
   310  	p.addMeasurement(0)
   311  	p.addMeasurement(2)
   312  	if o.String() != p.String() {
   313  		t.Errorf("o.String = %q WANT: %q", o.String(), p.String())
   314  	}
   315  }
   316  
   317  func add(h *histogram, times int, val int64) {
   318  	for i := 0; i < times; i++ {
   319  		h.addMeasurement(val)
   320  	}
   321  }
   322  
   323  func isApproximate(x, y float64) bool {
   324  	return math.Abs(x-y) < 1e-2
   325  }