lib/promscrape: reduce memory allocations in promLabelsString() function

This should help with reducing memory usage in https://github.com/VictoriaMetrics/VictoriaMetrics/issues/878
This commit is contained in:
Aliaksandr Valialkin 2020-11-04 10:38:09 +02:00
parent c0bd208c77
commit c046735571
2 changed files with 44 additions and 3 deletions

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"math" "math"
"math/bits" "math/bits"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -121,11 +122,24 @@ func (sw *ScrapeWork) LabelsString() string {
} }
func promLabelsString(labels []prompbmarshal.Label) string { func promLabelsString(labels []prompbmarshal.Label) string {
a := make([]string, 0, len(labels)) // Calculate the required memory for storing serialized labels.
n := 2 // for `{...}`
for _, label := range labels { for _, label := range labels {
a = append(a, fmt.Sprintf("%s=%q", label.Name, label.Value)) n += len(label.Name) + len(label.Value)
n += 4 // for `="...",`
} }
return "{" + strings.Join(a, ", ") + "}" b := make([]byte, 0, n)
b = append(b, '{')
for i, label := range labels {
b = append(b, label.Name...)
b = append(b, '=')
b = strconv.AppendQuote(b, label.Value)
if i+1 < len(labels) {
b = append(b, ',')
}
}
b = append(b, '}')
return bytesutil.ToUnsafeString(b)
} }
type scrapeWork struct { type scrapeWork struct {

View file

@ -11,6 +11,33 @@ import (
parser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus" parser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus"
) )
func TestPromLabelsString(t *testing.T) {
f := func(labels []prompbmarshal.Label, resultExpected string) {
t.Helper()
result := promLabelsString(labels)
if result != resultExpected {
t.Fatalf("unexpected result; got\n%s\nwant\n%s", result, resultExpected)
}
}
f([]prompbmarshal.Label{}, "{}")
f([]prompbmarshal.Label{
{
Name: "foo",
Value: "bar",
},
}, `{foo="bar"}`)
f([]prompbmarshal.Label{
{
Name: "foo",
Value: "bar",
},
{
Name: "a",
Value: `"b"`,
},
}, `{foo="bar",a="\"b\""}`)
}
func TestScrapeWorkScrapeInternalFailure(t *testing.T) { func TestScrapeWorkScrapeInternalFailure(t *testing.T) {
dataExpected := ` dataExpected := `
up 0 123 up 0 123