master
go 117 lines 3.27 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package metrix
4
5 import (
6 "strconv"
7 "testing"
8 )
9
10 // Baseline results (2026-02-13, darwin/arm64, Apple M4 Pro):
11 // Command:
12 //
13 // go test ./pkg/metrix -run '^$' -bench 'CollectStyleSnapshot' -benchmem
14 //
15 // BenchmarkCollectStyleSnapshot/lazy_declare_3_metrics-14 764806 1544 ns/op 3912 B/op 57 allocs/op
16 // BenchmarkCollectStyleSnapshot/cached_handles_3_metrics-14 940884 1286 ns/op 3208 B/op 44 allocs/op
17 // BenchmarkCollectStyleSnapshot/lazy_declare_20_metrics-14 138122 8734 ns/op 20792 B/op 291 allocs/op
18 // BenchmarkCollectStyleSnapshot/cached_handles_20_metrics-14 167974 7197 ns/op 16960 B/op 227 allocs/op
19 //
20 // Keep this block updated when changing metrix write/declaration paths.
21 func BenchmarkCollectStyleSnapshot(b *testing.B) {
22 tests := map[string]struct {
23 totalMetrics int
24 lazyDeclare bool
25 }{
26 "lazy_declare_3_metrics": {
27 totalMetrics: 3,
28 lazyDeclare: true,
29 },
30 "cached_handles_3_metrics": {
31 totalMetrics: 3,
32 lazyDeclare: false,
33 },
34 "lazy_declare_20_metrics": {
35 totalMetrics: 20,
36 lazyDeclare: true,
37 },
38 "cached_handles_20_metrics": {
39 totalMetrics: 20,
40 lazyDeclare: false,
41 },
42 }
43
44 for name, tc := range tests {
45 b.Run(name, func(b *testing.B) {
46 s := NewCollectorStore()
47 cc := benchmarkCycleController(b, s)
48 base := s.Write().SnapshotMeter("bench.collect")
49 instanceLS := base.LabelSet(Label{Key: "instance", Value: "collector-A"})
50
51 gaugeNames, counterNames := benchmarkMetricNames(tc.totalMetrics)
52 var cachedGauges []SnapshotGauge
53 var cachedCounters []SnapshotCounter
54
55 if !tc.lazyDeclare {
56 sm := s.Write().SnapshotMeter("bench.collect").WithLabelSet(instanceLS)
57 cachedGauges = make([]SnapshotGauge, 0, len(gaugeNames))
58 cachedCounters = make([]SnapshotCounter, 0, len(counterNames))
59 for _, n := range gaugeNames {
60 cachedGauges = append(cachedGauges, sm.Gauge(n))
61 }
62 for _, n := range counterNames {
63 cachedCounters = append(cachedCounters, sm.Counter(n))
64 }
65 }
66
67 b.ReportAllocs()
68 b.ResetTimer()
69 for i := 0; i < b.N; i++ {
70 cc.BeginCycle()
71 if tc.lazyDeclare {
72 sm := s.Write().SnapshotMeter("bench.collect").WithLabelSet(instanceLS)
73 for j, n := range gaugeNames {
74 sm.Gauge(n).Observe(SampleValue(j + i))
75 }
76 for j, n := range counterNames {
77 sm.Counter(n).ObserveTotal(SampleValue(1000 + j + i))
78 }
79 } else {
80 for j := range cachedGauges {
81 cachedGauges[j].Observe(SampleValue(j + i))
82 }
83 for j := range cachedCounters {
84 cachedCounters[j].ObserveTotal(SampleValue(1000 + j + i))
85 }
86 }
87 cc.CommitCycleSuccess()
88 }
89 })
90 }
91 }
92
93 func benchmarkMetricNames(total int) (gauges []string, counters []string) {
94 if total < 1 {
95 return []string{"gauge0"}, nil
96 }
97 gaugeCount := total / 2
98 counterCount := total - gaugeCount
99 if gaugeCount == 0 {
100 gaugeCount = 1
101 counterCount = total - gaugeCount
102 }
103 if counterCount == 0 {
104 counterCount = 1
105 gaugeCount = total - counterCount
106 }
107
108 gauges = make([]string, 0, gaugeCount)
109 counters = make([]string, 0, counterCount)
110 for i := 0; i < gaugeCount; i++ {
111 gauges = append(gauges, "gauge_"+strconv.Itoa(i))
112 }
113 for i := 0; i < counterCount; i++ {
114 counters = append(counters, "counter_"+strconv.Itoa(i))
115 }
116 return gauges, counters
117 }