labels: optimize String method (#13673)

Use a stack buffer to reduce memory allocations.

`Write(AppendQuote(AvailableBuffer` does not allocate or copy when
the buffer has sufficient space.

Also add a benchmark, with some refactoring.

Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
This commit is contained in:
Bryan Boreham 2024-03-12 11:34:03 +00:00 committed by GitHub
parent d08f054950
commit 0bb5588386
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 24 additions and 27 deletions

View file

@ -39,7 +39,8 @@ type Label struct {
} }
func (ls Labels) String() string { func (ls Labels) String() string {
var b bytes.Buffer var bytea [1024]byte // On stack to avoid memory allocation while building the output.
b := bytes.NewBuffer(bytea[:0])
b.WriteByte('{') b.WriteByte('{')
i := 0 i := 0
@ -50,7 +51,7 @@ func (ls Labels) String() string {
} }
b.WriteString(l.Name) b.WriteString(l.Name)
b.WriteByte('=') b.WriteByte('=')
b.WriteString(strconv.Quote(l.Value)) b.Write(strconv.AppendQuote(b.AvailableBuffer(), l.Value))
i++ i++
}) })
b.WriteByte('}') b.WriteByte('}')

View file

@ -43,6 +43,13 @@ func TestLabels_String(t *testing.T) {
} }
} }
func BenchmarkString(b *testing.B) {
ls := New(benchmarkLabels...)
for i := 0; i < b.N; i++ {
_ = ls.String()
}
}
func TestLabels_MatchLabels(t *testing.T) { func TestLabels_MatchLabels(t *testing.T) {
labels := FromStrings( labels := FromStrings(
"__name__", "ALERTS", "__name__", "ALERTS",
@ -785,8 +792,7 @@ func BenchmarkLabels_Hash(b *testing.B) {
} }
} }
func BenchmarkBuilder(b *testing.B) { var benchmarkLabels = []Label{
m := []Label{
{"job", "node"}, {"job", "node"},
{"instance", "123.123.1.211:9090"}, {"instance", "123.123.1.211:9090"},
{"path", "/api/v1/namespaces/<namespace>/deployments/<name>"}, {"path", "/api/v1/namespaces/<namespace>/deployments/<name>"},
@ -798,11 +804,12 @@ func BenchmarkBuilder(b *testing.B) {
{"pod_name", "abcdef-99999-defee"}, {"pod_name", "abcdef-99999-defee"},
} }
func BenchmarkBuilder(b *testing.B) {
var l Labels var l Labels
builder := NewBuilder(EmptyLabels()) builder := NewBuilder(EmptyLabels())
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
builder.Reset(EmptyLabels()) builder.Reset(EmptyLabels())
for _, l := range m { for _, l := range benchmarkLabels {
builder.Set(l.Name, l.Value) builder.Set(l.Name, l.Value)
} }
l = builder.Labels() l = builder.Labels()
@ -811,18 +818,7 @@ func BenchmarkBuilder(b *testing.B) {
} }
func BenchmarkLabels_Copy(b *testing.B) { func BenchmarkLabels_Copy(b *testing.B) {
m := map[string]string{ l := New(benchmarkLabels...)
"job": "node",
"instance": "123.123.1.211:9090",
"path": "/api/v1/namespaces/<namespace>/deployments/<name>",
"method": "GET",
"namespace": "system",
"status": "500",
"prometheus": "prometheus-core-1",
"datacenter": "eu-west-1",
"pod_name": "abcdef-99999-defee",
}
l := FromMap(m)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
l = l.Copy() l = l.Copy()