Skip to content

Commit 751c050

Browse files
authored
chore: add benchmark for prometheusmetrics.MetricsAggregator (#8066)
* add benchmark for prom metrics aggregator * fixup! add benchmark for prom metrics aggregator * make fmt
1 parent 3ec2e96 commit 751c050

File tree

1 file changed

+85
-0
lines changed

1 file changed

+85
-0
lines changed

coderd/prometheusmetrics/aggregator_test.go

+85
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package prometheusmetrics_test
22

33
import (
44
"context"
5+
"sync/atomic"
56
"testing"
67
"time"
78

@@ -13,6 +14,7 @@ import (
1314
"cdr.dev/slog/sloggers/slogtest"
1415
"github.com/coder/coder/coderd/prometheusmetrics"
1516
"github.com/coder/coder/codersdk/agentsdk"
17+
"github.com/coder/coder/cryptorand"
1618
"github.com/coder/coder/testutil"
1719
)
1820

@@ -175,3 +177,86 @@ func TestUpdateMetrics_MetricsExpire(t *testing.T) {
175177
return len(actual) == 0
176178
}, testutil.WaitShort, testutil.IntervalFast)
177179
}
180+
181+
func Benchmark_MetricsAggregator_Run(b *testing.B) {
182+
// Number of metrics to generate and send in each iteration.
183+
// Hard-coded to 1024 to avoid overflowing the queue in the metrics aggregator.
184+
numMetrics := 1024
185+
186+
// given
187+
registry := prometheus.NewRegistry()
188+
metricsAggregator := must(prometheusmetrics.NewMetricsAggregator(
189+
slogtest.Make(b, &slogtest.Options{IgnoreErrors: true}),
190+
registry,
191+
time.Hour,
192+
))
193+
194+
ctx, cancelFunc := context.WithCancel(context.Background())
195+
b.Cleanup(cancelFunc)
196+
197+
closeFunc := metricsAggregator.Run(ctx)
198+
b.Cleanup(closeFunc)
199+
200+
ch := make(chan prometheus.Metric)
201+
go func() {
202+
for {
203+
select {
204+
case <-ctx.Done():
205+
return
206+
default:
207+
metricsAggregator.Collect(ch)
208+
}
209+
}
210+
}()
211+
212+
for i := 0; i < b.N; i++ {
213+
b.StopTimer()
214+
b.Logf("N=%d generating %d metrics", b.N, numMetrics)
215+
metrics := make([]agentsdk.AgentMetric, 0, numMetrics)
216+
for i := 0; i < numMetrics; i++ {
217+
metrics = append(metrics, genAgentMetric(b))
218+
}
219+
220+
b.Logf("N=%d sending %d metrics", b.N, numMetrics)
221+
var nGot atomic.Int64
222+
b.StartTimer()
223+
metricsAggregator.Update(ctx, testUsername, testWorkspaceName, testAgentName, metrics)
224+
for i := 0; i < numMetrics; i++ {
225+
select {
226+
case <-ctx.Done():
227+
b.FailNow()
228+
case <-ch:
229+
nGot.Add(1)
230+
}
231+
}
232+
b.StopTimer()
233+
b.Logf("N=%d got %d metrics", b.N, nGot.Load())
234+
}
235+
}
236+
237+
func genAgentMetric(t testing.TB) agentsdk.AgentMetric {
238+
t.Helper()
239+
240+
var metricType agentsdk.AgentMetricType
241+
if must(cryptorand.Float64()) >= 0.5 {
242+
metricType = agentsdk.AgentMetricTypeCounter
243+
} else {
244+
metricType = agentsdk.AgentMetricTypeGauge
245+
}
246+
247+
// Ensure that metric name does not start or end with underscore, as it is not allowed by Prometheus.
248+
metricName := "metric_" + must(cryptorand.StringCharset(cryptorand.Alpha, 80)) + "_gen"
249+
// Generate random metric value between 0 and 1000.
250+
metricValue := must(cryptorand.Float64()) * float64(must(cryptorand.Intn(1000)))
251+
252+
return agentsdk.AgentMetric{
253+
Name: metricName, Type: metricType, Value: metricValue, Labels: []agentsdk.AgentMetricLabel{},
254+
}
255+
}
256+
257+
func must[T any](t T, err error) T {
258+
if err != nil {
259+
panic(err)
260+
}
261+
return t
262+
}

0 commit comments

Comments
 (0)