Skip to content

Commit 82dced9

Browse files
committed
Optimize dpgSignature function in Prometheus receiver
This function is invoked very often, which leads to high CPU usage when collecting Prometheus metrics. Benchmark results on my machine show 3x less CPU and almost 4x less memory used. Since I'm also changing the format of returned values (dropping superfluous characters), it will reduce overall memory usage of the receiver, because they are used as map keys. Benchmark result before this change: Benchmark_dpgSignature-6 1284531 969.6 ns/op 120 B/op 7 allocs/op Benchmark result after this change: Benchmark_dpgSignature-6 3515179 313.9 ns/op 32 B/op 2 allocs/op
1 parent 90b2dec commit 82dced9

File tree

2 files changed

+31
-9
lines changed

2 files changed

+31
-9
lines changed

receiver/prometheusreceiver/internal/metricsbuilder.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,15 +179,27 @@ func isUsefulLabel(mType metricspb.MetricDescriptor_Type, labelKey string) bool
179179

180180
// dpgSignature is used to create a key for data complexValue belong to a same group of a metric family
181181
func dpgSignature(orderedKnownLabelKeys []string, ls labels.Labels) string {
182-
sign := make([]string, 0, len(orderedKnownLabelKeys))
182+
size := 0
183183
for _, k := range orderedKnownLabelKeys {
184184
v := ls.Get(k)
185185
if v == "" {
186186
continue
187187
}
188-
sign = append(sign, k+"="+v)
188+
// 2 enclosing quotes + 1 equality sign = 3 extra chars.
189+
// Note: if any character in the label value requires escaping,
190+
// we'll need more space than that, which will lead to some
191+
// extra allocation.
192+
size += 3 + len(k) + len(v)
189193
}
190-
return fmt.Sprintf("%#v", sign)
194+
sign := make([]byte, 0, size)
195+
for _, k := range orderedKnownLabelKeys {
196+
v := ls.Get(k)
197+
if v == "" {
198+
continue
199+
}
200+
sign = strconv.AppendQuote(sign, k+"="+v)
201+
}
202+
return string(sign)
191203
}
192204

193205
func normalizeMetricName(name string) string {

receiver/prometheusreceiver/internal/metricsbuilder_test.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package internal
1616

1717
import (
1818
"reflect"
19+
"runtime"
1920
"testing"
2021

2122
metricspb "github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1"
@@ -1291,6 +1292,15 @@ func Test_isUsefulLabel(t *testing.T) {
12911292
}
12921293
}
12931294

1295+
func Benchmark_dpgSignature(b *testing.B) {
1296+
knownLabelKeys := []string{"a", "b"}
1297+
labels := labels.FromStrings("a", "va", "b", "vb", "x", "xa")
1298+
b.ReportAllocs()
1299+
for i := 0; i < b.N; i++ {
1300+
runtime.KeepAlive(dpgSignature(knownLabelKeys, labels))
1301+
}
1302+
}
1303+
12941304
func Test_dpgSignature(t *testing.T) {
12951305
knownLabelKeys := []string{"a", "b"}
12961306

@@ -1299,16 +1309,16 @@ func Test_dpgSignature(t *testing.T) {
12991309
ls labels.Labels
13001310
want string
13011311
}{
1302-
{"1st label", labels.FromStrings("a", "va"), `[]string{"a=va"}`},
1303-
{"2nd label", labels.FromStrings("b", "vb"), `[]string{"b=vb"}`},
1304-
{"two labels", labels.FromStrings("a", "va", "b", "vb"), `[]string{"a=va", "b=vb"}`},
1305-
{"extra label", labels.FromStrings("a", "va", "b", "vb", "x", "xa"), `[]string{"a=va", "b=vb"}`},
1306-
{"different order", labels.FromStrings("b", "vb", "a", "va"), `[]string{"a=va", "b=vb"}`},
1312+
{"1st label", labels.FromStrings("a", "va"), `"a=va"`},
1313+
{"2nd label", labels.FromStrings("b", "vb"), `"b=vb"`},
1314+
{"two labels", labels.FromStrings("a", "va", "b", "vb"), `"a=va""b=vb"`},
1315+
{"extra label", labels.FromStrings("a", "va", "b", "vb", "x", "xa"), `"a=va""b=vb"`},
1316+
{"different order", labels.FromStrings("b", "vb", "a", "va"), `"a=va""b=vb"`},
13071317
}
13081318
for _, tt := range tests {
13091319
t.Run(tt.name, func(t *testing.T) {
13101320
if got := dpgSignature(knownLabelKeys, tt.ls); got != tt.want {
1311-
t.Errorf("dpgSignature() = %v, want %v", got, tt.want)
1321+
t.Errorf("dpgSignature() = %q, want %q", got, tt.want)
13121322
}
13131323
})
13141324
}

0 commit comments

Comments
 (0)