Skip to content

Commit 0c0b385

Browse files
vordimousdmathieuMrAlias
authored
Add method and benchmarks for pooling metric options (#6394)
This PR improves the `RecordMetrics()` allocations using a pool for the `metric.AddOption` slice. `benchstat main.txt pool.txt`: ``` goos: darwin goarch: arm64 pkg: go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv cpu: Apple M1 Max │ main.txt │ pool.txt │ │ sec/op │ sec/op vs base │ RecordMetrics/empty-10 4.513n ± 3% 4.620n ± 0% +2.38% (p=0.037 n=10) RecordMetrics/nil_meter-10 341.8n ± 1% 330.7n ± 4% -3.26% (p=0.022 n=10) RecordMetrics/with_Meter-10 341.1n ± 1% 330.0n ± 1% -3.27% (p=0.000 n=10) geomean 80.74n 79.59n -1.42% │ main.txt │ pool.txt │ │ B/op │ B/op vs base │ RecordMetrics/empty-10 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ RecordMetrics/nil_meter-10 696.0 ± 0% 680.0 ± 0% -2.30% (p=0.000 n=10) RecordMetrics/with_Meter-10 696.0 ± 0% 680.0 ± 0% -2.30% (p=0.000 n=10) geomean ² -1.54% ² ¹ all samples are equal ² summaries must be >0 to compute geomean │ main.txt │ pool.txt │ │ allocs/op │ allocs/op vs base │ RecordMetrics/empty-10 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ RecordMetrics/nil_meter-10 6.000 ± 0% 5.000 ± 0% -16.67% (p=0.000 n=10) RecordMetrics/with_Meter-10 6.000 ± 0% 5.000 ± 0% -16.67% (p=0.000 n=10) geomean ² -11.45% ² ¹ all samples are equal ² summaries must be >0 to compute geomean ``` Fixes #5968 --------- Co-authored-by: Damien Mathieu <[email protected]> Co-authored-by: Tyler Yahn <[email protected]>
1 parent 378d704 commit 0c0b385

File tree

3 files changed

+53
-3
lines changed

3 files changed

+53
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1515
- The `go.opentelemetry.io/contrib/bridges/otellogr` module.
1616
This module provides an OpenTelemetry logging bridge for `github.com/go-logr/logr`. (#6386)
1717
- Added SNS instrumentation in `go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws`. (#6388)
18+
- Use a `sync.Pool` for metric options in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp`. (#6394)
1819

1920
### Changed
2021

instrumentation/net/http/otelhttp/internal/semconv/env.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net/http"
1010
"os"
1111
"strings"
12+
"sync"
1213

1314
"go.opentelemetry.io/otel/attribute"
1415
"go.opentelemetry.io/otel/codes"
@@ -102,6 +103,12 @@ type MetricData struct {
102103
ElapsedTime float64
103104
}
104105

106+
var metricAddOptionPool = &sync.Pool{
107+
New: func() interface{} {
108+
return &[]metric.AddOption{}
109+
},
110+
}
111+
105112
func (s HTTPServer) RecordMetrics(ctx context.Context, md ServerMetricData) {
106113
if s.requestBytesCounter == nil || s.responseBytesCounter == nil || s.serverLatencyMeasure == nil {
107114
// This will happen if an HTTPServer{} is used instead of NewHTTPServer.
@@ -110,10 +117,13 @@ func (s HTTPServer) RecordMetrics(ctx context.Context, md ServerMetricData) {
110117

111118
attributes := OldHTTPServer{}.MetricAttributes(md.ServerName, md.Req, md.StatusCode, md.AdditionalAttributes)
112119
o := metric.WithAttributeSet(attribute.NewSet(attributes...))
113-
addOpts := []metric.AddOption{o}
114-
s.requestBytesCounter.Add(ctx, md.RequestSize, addOpts...)
115-
s.responseBytesCounter.Add(ctx, md.ResponseSize, addOpts...)
120+
addOpts := metricAddOptionPool.Get().(*[]metric.AddOption)
121+
*addOpts = append(*addOpts, o)
122+
s.requestBytesCounter.Add(ctx, md.RequestSize, *addOpts...)
123+
s.responseBytesCounter.Add(ctx, md.ResponseSize, *addOpts...)
116124
s.serverLatencyMeasure.Record(ctx, md.ElapsedTime, o)
125+
*addOpts = (*addOpts)[:0]
126+
metricAddOptionPool.Put(addOpts)
117127

118128
// TODO: Duplicate Metrics
119129
}

instrumentation/net/http/otelhttp/internal/semconv/env_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,42 @@ func TestHTTPClientDoesNotPanic(t *testing.T) {
9090
})
9191
}
9292
}
93+
94+
func BenchmarkRecordMetrics(b *testing.B) {
95+
benchmarks := []struct {
96+
name string
97+
server HTTPServer
98+
}{
99+
{
100+
name: "empty",
101+
server: HTTPServer{},
102+
},
103+
{
104+
name: "nil meter",
105+
server: NewHTTPServer(nil),
106+
},
107+
{
108+
name: "with Meter",
109+
server: NewHTTPServer(noop.Meter{}),
110+
},
111+
}
112+
113+
for _, bm := range benchmarks {
114+
b.Run(bm.name, func(b *testing.B) {
115+
req, _ := http.NewRequest("GET", "http://example.com", nil)
116+
_ = bm.server.RequestTraceAttrs("stuff", req)
117+
_ = bm.server.ResponseTraceAttrs(ResponseTelemetry{StatusCode: 200})
118+
ctx := context.Background()
119+
b.ReportAllocs()
120+
b.ResetTimer()
121+
for i := 0; i < b.N; i++ {
122+
bm.server.RecordMetrics(ctx, ServerMetricData{
123+
ServerName: bm.name,
124+
MetricAttributes: MetricAttributes{
125+
Req: req,
126+
},
127+
})
128+
}
129+
})
130+
}
131+
}

0 commit comments

Comments
 (0)