| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | package metrix |
| 4 | |
| 5 | import "testing" |
| 6 | |
| 7 | func BenchmarkSummaryStatefulWindowCycle(b *testing.B) { |
| 8 | tests := map[string]struct { |
| 9 | samples int |
| 10 | quantiles []float64 |
| 11 | }{ |
| 12 | "100_samples_3q": { |
| 13 | samples: 100, |
| 14 | quantiles: []float64{0.5, 0.9, 0.99}, |
| 15 | }, |
| 16 | "1000_samples_3q": { |
| 17 | samples: 1000, |
| 18 | quantiles: []float64{0.5, 0.9, 0.99}, |
| 19 | }, |
| 20 | "5000_samples_3q": { |
| 21 | samples: 5000, |
| 22 | quantiles: []float64{0.5, 0.9, 0.99}, |
| 23 | }, |
| 24 | } |
| 25 | |
| 26 | for name, tc := range tests { |
| 27 | b.Run(name, func(b *testing.B) { |
| 28 | s := NewCollectorStore() |
| 29 | cc := benchmarkCycleController(b, s) |
| 30 | sum := s.Write().StatefulMeter("bench").Summary( |
| 31 | "latency_seconds", |
| 32 | WithSummaryQuantiles(tc.quantiles...), |
| 33 | WithWindow(WindowCycle), |
| 34 | ) |
| 35 | values := benchmarkSummaryValues(tc.samples) |
| 36 | |
| 37 | b.ReportAllocs() |
| 38 | b.ResetTimer() |
| 39 | for i := 0; i < b.N; i++ { |
| 40 | cc.BeginCycle() |
| 41 | for _, v := range values { |
| 42 | sum.Observe(v) |
| 43 | } |
| 44 | cc.CommitCycleSuccess() |
| 45 | } |
| 46 | }) |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | func BenchmarkSummaryStatefulCumulativeWithPreload(b *testing.B) { |
| 51 | tests := map[string]struct { |
| 52 | preload int |
| 53 | add int |
| 54 | quantiles []float64 |
| 55 | }{ |
| 56 | "preload_1000_add_100_3q": { |
| 57 | preload: 1000, |
| 58 | add: 100, |
| 59 | quantiles: []float64{0.5, 0.9, 0.99}, |
| 60 | }, |
| 61 | "preload_10000_add_100_3q": { |
| 62 | preload: 10000, |
| 63 | add: 100, |
| 64 | quantiles: []float64{0.5, 0.9, 0.99}, |
| 65 | }, |
| 66 | } |
| 67 | |
| 68 | for name, tc := range tests { |
| 69 | b.Run(name, func(b *testing.B) { |
| 70 | preloadValues := benchmarkSummaryValues(tc.preload) |
| 71 | addValues := benchmarkSummaryValues(tc.add) |
| 72 | |
| 73 | b.ReportAllocs() |
| 74 | b.ResetTimer() |
| 75 | for i := 0; i < b.N; i++ { |
| 76 | b.StopTimer() |
| 77 | s := NewCollectorStore() |
| 78 | cc := benchmarkCycleController(b, s) |
| 79 | sum := s.Write().StatefulMeter("bench").Summary( |
| 80 | "latency_seconds", |
| 81 | WithSummaryQuantiles(tc.quantiles...), |
| 82 | WithWindow(WindowCumulative), |
| 83 | ) |
| 84 | cc.BeginCycle() |
| 85 | for _, v := range preloadValues { |
| 86 | sum.Observe(v) |
| 87 | } |
| 88 | cc.CommitCycleSuccess() |
| 89 | b.StartTimer() |
| 90 | |
| 91 | cc.BeginCycle() |
| 92 | for _, v := range addValues { |
| 93 | sum.Observe(v) |
| 94 | } |
| 95 | cc.CommitCycleSuccess() |
| 96 | } |
| 97 | }) |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | func BenchmarkSummarySnapshotObservePoint(b *testing.B) { |
| 102 | tests := map[string]struct { |
| 103 | quantiles []float64 |
| 104 | }{ |
| 105 | "count_sum_only": { |
| 106 | quantiles: nil, |
| 107 | }, |
| 108 | "with_3q": { |
| 109 | quantiles: []float64{0.5, 0.9, 0.99}, |
| 110 | }, |
| 111 | } |
| 112 | |
| 113 | for name, tc := range tests { |
| 114 | b.Run(name, func(b *testing.B) { |
| 115 | s := NewCollectorStore() |
| 116 | cc := benchmarkCycleController(b, s) |
| 117 | sum := s.Write().SnapshotMeter("bench").Summary("latency_seconds", WithSummaryQuantiles(tc.quantiles...)) |
| 118 | |
| 119 | point := SummaryPoint{ |
| 120 | Count: 100, |
| 121 | Sum: 12.34, |
| 122 | } |
| 123 | if len(tc.quantiles) > 0 { |
| 124 | point.Quantiles = []QuantilePoint{ |
| 125 | {Quantile: 0.5, Value: 0.12}, |
| 126 | {Quantile: 0.9, Value: 0.88}, |
| 127 | {Quantile: 0.99, Value: 1.2}, |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | b.ReportAllocs() |
| 132 | b.ResetTimer() |
| 133 | for i := 0; i < b.N; i++ { |
| 134 | cc.BeginCycle() |
| 135 | sum.ObservePoint(point) |
| 136 | cc.CommitCycleSuccess() |
| 137 | } |
| 138 | }) |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | func benchmarkCycleController(b *testing.B, s CollectorStore) CycleController { |
| 143 | b.Helper() |
| 144 | managed, ok := AsCycleManagedStore(s) |
| 145 | if !ok { |
| 146 | b.Fatalf("store does not expose cycle control") |
| 147 | } |
| 148 | return managed.CycleController() |
| 149 | } |
| 150 | |
| 151 | func benchmarkSummaryValues(n int) []SampleValue { |
| 152 | vals := make([]SampleValue, n) |
| 153 | var x uint64 = 0x9e3779b97f4a7c15 |
| 154 | for i := range n { |
| 155 | // Deterministic pseudo-random in [0,1). |
| 156 | x ^= x >> 12 |
| 157 | x ^= x << 25 |
| 158 | x ^= x >> 27 |
| 159 | y := x * 2685821657736338717 |
| 160 | vals[i] = SampleValue(float64(y&0xffffffff) / float64(1<<32)) |
| 161 | } |
| 162 | return vals |
| 163 | } |