Source file src/runtime/histogram_test.go

     1  // Copyright 2020 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 runtime_test
     6  
     7  import (
     8  	"math"
     9  	. "runtime"
    10  	"testing"
    11  )
    12  
    13  var dummyTimeHistogram TimeHistogram
    14  
    15  func TestTimeHistogram(t *testing.T) {
    16  	// We need to use a global dummy because this
    17  	// could get stack-allocated with a non-8-byte alignment.
    18  	// The result of this bad alignment is a segfault on
    19  	// 32-bit platforms when calling Record.
    20  	h := &dummyTimeHistogram
    21  
    22  	// Record exactly one sample in each bucket.
    23  	for j := 0; j < TimeHistNumSubBuckets; j++ {
    24  		v := int64(j) << (TimeHistMinBucketBits - 1 - TimeHistSubBucketBits)
    25  		for k := 0; k < j; k++ {
    26  			// Record a number of times equal to the bucket index.
    27  			h.Record(v)
    28  		}
    29  	}
    30  	for i := TimeHistMinBucketBits; i < TimeHistMaxBucketBits; i++ {
    31  		base := int64(1) << (i - 1)
    32  		for j := 0; j < TimeHistNumSubBuckets; j++ {
    33  			v := int64(j) << (i - 1 - TimeHistSubBucketBits)
    34  			for k := 0; k < (i+1-TimeHistMinBucketBits)*TimeHistNumSubBuckets+j; k++ {
    35  				// Record a number of times equal to the bucket index.
    36  				h.Record(base + v)
    37  			}
    38  		}
    39  	}
    40  	// Hit the underflow and overflow buckets.
    41  	h.Record(int64(-1))
    42  	h.Record(math.MaxInt64)
    43  	h.Record(math.MaxInt64)
    44  
    45  	// Check to make sure there's exactly one count in each
    46  	// bucket.
    47  	for i := 0; i < TimeHistNumBuckets; i++ {
    48  		for j := 0; j < TimeHistNumSubBuckets; j++ {
    49  			c, ok := h.Count(i, j)
    50  			if !ok {
    51  				t.Errorf("unexpected invalid bucket: (%d, %d)", i, j)
    52  			} else if idx := uint64(i*TimeHistNumSubBuckets + j); c != idx {
    53  				t.Errorf("bucket (%d, %d) has count that is not %d: %d", i, j, idx, c)
    54  			}
    55  		}
    56  	}
    57  	c, ok := h.Count(-1, 0)
    58  	if ok {
    59  		t.Errorf("expected to hit underflow bucket: (%d, %d)", -1, 0)
    60  	}
    61  	if c != 1 {
    62  		t.Errorf("overflow bucket has count that is not 1: %d", c)
    63  	}
    64  
    65  	c, ok = h.Count(TimeHistNumBuckets+1, 0)
    66  	if ok {
    67  		t.Errorf("expected to hit overflow bucket: (%d, %d)", TimeHistNumBuckets+1, 0)
    68  	}
    69  	if c != 2 {
    70  		t.Errorf("overflow bucket has count that is not 2: %d", c)
    71  	}
    72  
    73  	dummyTimeHistogram = TimeHistogram{}
    74  }
    75  
    76  func TestTimeHistogramMetricsBuckets(t *testing.T) {
    77  	buckets := TimeHistogramMetricsBuckets()
    78  
    79  	nonInfBucketsLen := TimeHistNumSubBuckets * TimeHistNumBuckets
    80  	expBucketsLen := nonInfBucketsLen + 3 // Count -Inf, the edge for the overflow bucket, and +Inf.
    81  	if len(buckets) != expBucketsLen {
    82  		t.Fatalf("unexpected length of buckets: got %d, want %d", len(buckets), expBucketsLen)
    83  	}
    84  	// Check some values.
    85  	idxToBucket := map[int]float64{
    86  		0:                 math.Inf(-1),
    87  		1:                 0.0,
    88  		2:                 float64(0x040) / 1e9,
    89  		3:                 float64(0x080) / 1e9,
    90  		4:                 float64(0x0c0) / 1e9,
    91  		5:                 float64(0x100) / 1e9,
    92  		6:                 float64(0x140) / 1e9,
    93  		7:                 float64(0x180) / 1e9,
    94  		8:                 float64(0x1c0) / 1e9,
    95  		9:                 float64(0x200) / 1e9,
    96  		10:                float64(0x280) / 1e9,
    97  		11:                float64(0x300) / 1e9,
    98  		12:                float64(0x380) / 1e9,
    99  		13:                float64(0x400) / 1e9,
   100  		15:                float64(0x600) / 1e9,
   101  		81:                float64(0x8000000) / 1e9,
   102  		82:                float64(0xa000000) / 1e9,
   103  		108:               float64(0x380000000) / 1e9,
   104  		expBucketsLen - 2: float64(0x1<<47) / 1e9,
   105  		expBucketsLen - 1: math.Inf(1),
   106  	}
   107  	for idx, bucket := range idxToBucket {
   108  		if got, want := buckets[idx], bucket; got != want {
   109  			t.Errorf("expected bucket %d to have value %e, got %e", idx, want, got)
   110  		}
   111  	}
   112  }
   113  

View as plain text