Skip to content

Commit 4fc7ccd

Browse files
committed
Add unmarshal benchmark
Signed-off-by: György Krajcsovits <[email protected]>
1 parent 4a727c9 commit 4fc7ccd

File tree

3 files changed

+184
-21
lines changed

3 files changed

+184
-21
lines changed

integration/distributor_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
"github.com/stretchr/testify/require"
2323

2424
"github.com/grafana/mimir/integration/e2emimir"
25-
"github.com/grafana/mimir/pkg/distributor/rw2"
25+
rw2util "github.com/grafana/mimir/pkg/util/test"
2626
)
2727

2828
func TestDistributor(t *testing.T) {
@@ -385,7 +385,7 @@ func TestDistributorRemoteWrite2(t *testing.T) {
385385
}{
386386
"no special features": {
387387
inRemoteWrite: []*promRW2.Request{
388-
rw2.AddFloatSeries(
388+
rw2util.AddFloatSeries(
389389
nil,
390390
labels.FromStrings("__name__", "foobar"),
391391
[]promRW2.Sample{{Timestamp: queryStart.UnixMilli(), Value: 100}},

pkg/mimirpb/unmarshal_bench_test.go

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// SPDX-License-Identifier: AGPL-3.0-only
2+
3+
package mimirpb
4+
5+
import (
6+
"fmt"
7+
"strconv"
8+
"testing"
9+
10+
rw1 "github.com/prometheus/prometheus/prompb"
11+
rw2 "github.com/prometheus/prometheus/prompb/io/prometheus/write/v2"
12+
"github.com/stretchr/testify/require"
13+
14+
rw2util "github.com/grafana/mimir/pkg/util/test"
15+
)
16+
17+
// Measure unmarshal performance between Remote Write 1.0 and 2.0.
18+
// Testing with large data sets, use "-benchtime 5s" to get more accurate results.
19+
func BenchmarkUnMarshal(b *testing.B) {
20+
const numSeries = 10000
21+
22+
const numFamilies = 100 // Number of unique metric families.
23+
24+
// Some labels are common, like cluster/namespace, etc.
25+
// Some labels are unique, like pod_name, container_name, etc.
26+
const numCommonLabels = 30
27+
const numUniqueLabels = 30
28+
// Number of exemplars per series. This is not going to be true for native
29+
// histograms, but it's a good approximation.
30+
const numExemplars = 1
31+
const numExemplarLabels = 5
32+
33+
// Generate a random series in Remote Write 1.0 format.
34+
rw1Request := &rw1.WriteRequest{
35+
Timeseries: make([]rw1.TimeSeries, numSeries),
36+
Metadata: make([]rw1.MetricMetadata, numFamilies),
37+
}
38+
39+
for i := 0; i < numSeries; i++ {
40+
rw1Request.Timeseries[i].Labels = generateLabels("", i, numCommonLabels, numUniqueLabels)
41+
42+
rw1Request.Timeseries[i].Samples = make([]rw1.Sample, 1)
43+
// Histograms are the same in both formats so we skip them.
44+
rw1Request.Timeseries[i].Samples[0].Value = 1.0
45+
46+
rw1Request.Timeseries[i].Exemplars = make([]rw1.Exemplar, numExemplars)
47+
for j := 0; j < numExemplars; j++ {
48+
rw1Request.Timeseries[i].Exemplars[j].Labels = generateLabels("exemplar_", i, 0, numExemplarLabels)
49+
rw1Request.Timeseries[i].Exemplars[j].Value = 2.0
50+
}
51+
}
52+
for i := 0; i < numFamilies; i++ {
53+
rw1Request.Metadata[i].MetricFamilyName = fmt.Sprintf("metric_%d", i)
54+
rw1Request.Metadata[i].Help = fmt.Sprintf("help_%d", i)
55+
rw1Request.Metadata[i].Unit = fmt.Sprintf("unit_%d", i)
56+
rw1Request.Metadata[i].Type = rw1.MetricMetadata_COUNTER
57+
}
58+
59+
// Convert RW1 to RW2.
60+
rw2Request := &rw2.Request{}
61+
symBuilder := rw2util.NewSymbolTableBuilder(nil)
62+
63+
for i, ts := range rw1Request.Timeseries {
64+
rw2Ts := rw2.TimeSeries{}
65+
for _, label := range ts.Labels {
66+
rw2Ts.LabelsRefs = append(rw2Ts.LabelsRefs, symBuilder.GetSymbol(label.Name))
67+
rw2Ts.LabelsRefs = append(rw2Ts.LabelsRefs, symBuilder.GetSymbol(label.Value))
68+
}
69+
for _, sample := range ts.Samples {
70+
rw2Ts.Samples = append(rw2Ts.Samples, rw2.Sample{Value: sample.Value})
71+
}
72+
// Histograms are the same in both formats so we skip them.
73+
for _, exemplar := range ts.Exemplars {
74+
rw2Exemplar := rw2.Exemplar{
75+
Value: exemplar.Value,
76+
}
77+
for _, label := range exemplar.Labels {
78+
rw2Exemplar.LabelsRefs = append(rw2Exemplar.LabelsRefs, symBuilder.GetSymbol(label.Name))
79+
rw2Exemplar.LabelsRefs = append(rw2Exemplar.LabelsRefs, symBuilder.GetSymbol(label.Value))
80+
}
81+
rw2Ts.Exemplars = append(rw2Ts.Exemplars, rw2Exemplar)
82+
}
83+
rw2Ts.Metadata.Type = rw2.Metadata_METRIC_TYPE_COUNTER
84+
rw2Ts.Metadata.HelpRef = symBuilder.GetSymbol(rw1Request.Metadata[i%numFamilies].Help)
85+
rw2Ts.Metadata.UnitRef = symBuilder.GetSymbol(rw1Request.Metadata[i%numFamilies].Unit)
86+
87+
rw2Request.Timeseries = append(rw2Request.Timeseries, rw2Ts)
88+
}
89+
rw2Request.Symbols = symBuilder.GetSymbols()
90+
require.Len(b, rw2Request.Symbols, numCommonLabels*2+numSeries*numUniqueLabels*2+numFamilies*2+numExemplarLabels*numSeries*numExemplars*2)
91+
92+
rw1Data, err := rw1Request.Marshal()
93+
require.NoError(b, err)
94+
require.NotEmpty(b, rw1Data)
95+
96+
rw2Data, err := rw2Request.Marshal()
97+
require.NoError(b, err)
98+
require.NotEmpty(b, rw2Data)
99+
100+
for _, skipExemplars := range []bool{true, false} {
101+
b.Run(fmt.Sprintf("RW1/skipExemplars=%v", skipExemplars), func(b *testing.B) {
102+
b.ResetTimer()
103+
for i := 0; i < b.N; i++ {
104+
pw := PreallocWriteRequest{}
105+
pw.SkipUnmarshalingExemplars = skipExemplars
106+
err := pw.Unmarshal(rw1Data)
107+
require.NoError(b, err)
108+
}
109+
})
110+
111+
b.Run(fmt.Sprintf("RW2/skipExemplars=%v", skipExemplars), func(b *testing.B) {
112+
b.ResetTimer()
113+
for i := 0; i < b.N; i++ {
114+
pw := PreallocWriteRequest{}
115+
pw.SkipUnmarshalingExemplars = skipExemplars
116+
pw.UnmarshalFromRW2 = true
117+
err := pw.Unmarshal(rw2Data)
118+
require.NoError(b, err)
119+
}
120+
})
121+
}
122+
}
123+
124+
func generateLabels(prefix string, seriesNumber, numCommonLabels, numUniqueLabels int) []rw1.Label {
125+
labels := make([]rw1.Label, numCommonLabels+numUniqueLabels)
126+
for i := 0; i < numCommonLabels; i++ {
127+
labels[i].Name = prefix + "common_label_" + strconv.Itoa(i)
128+
labels[i].Value = prefix + "common_value_" + strconv.Itoa(i)
129+
}
130+
for i := 0; i < numUniqueLabels; i++ {
131+
idx := numCommonLabels + i
132+
uid := seriesNumber*(numUniqueLabels) + i
133+
labels[idx].Name = prefix + "unique_label_" + strconv.Itoa(uid)
134+
labels[idx].Value = prefix + "unique_value_" + strconv.Itoa(uid)
135+
}
136+
return labels
137+
}

pkg/distributor/rw2/utils.go renamed to pkg/util/test/rw2.go

+45-19
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
// SPDX-License-Identifier: AGPL-3.0-only
22

3-
package rw2
3+
package test
44

55
import (
6-
"fmt"
7-
86
"github.com/prometheus/prometheus/model/labels"
97
promRW2 "github.com/prometheus/prometheus/prompb/io/prometheus/write/v2"
108
)
@@ -29,25 +27,27 @@ func AddFloatSeries(
2927
req = NewWriteRequest()
3028
}
3129

30+
symBuilder := NewSymbolTableBuilder(req.Symbols)
31+
3232
var labelsRefs []uint32
3333
lbls.Range(func(l labels.Label) {
34-
labelsRefs = append(labelsRefs, getSymbol(l.Name, &req.Symbols))
35-
labelsRefs = append(labelsRefs, getSymbol(l.Value, &req.Symbols))
34+
labelsRefs = append(labelsRefs, symBuilder.GetSymbol(l.Name))
35+
labelsRefs = append(labelsRefs, symBuilder.GetSymbol(l.Value))
3636
})
3737

3838
ts := promRW2.TimeSeries{
3939
LabelsRefs: labelsRefs,
4040
Samples: floats,
4141
Metadata: promRW2.Metadata{
4242
Type: metricType,
43-
HelpRef: getSymbol(help, &req.Symbols),
44-
UnitRef: getSymbol(unit, &req.Symbols),
43+
HelpRef: symBuilder.GetSymbol(help),
44+
UnitRef: symBuilder.GetSymbol(unit),
4545
},
4646
Exemplars: exemplars,
4747
CreatedTimestamp: createdTimestamp,
4848
}
49-
fmt.Printf("KRAJO: AddFloatSeries: %v\n", ts.Metadata)
5049
req.Timeseries = append(req.Timeseries, ts)
50+
req.Symbols = symBuilder.GetSymbols()
5151

5252
return req
5353
}
@@ -66,10 +66,12 @@ func AddHistogramSeries(
6666
req = NewWriteRequest()
6767
}
6868

69+
symBuilder := NewSymbolTableBuilder(req.Symbols)
70+
6971
var labelsRefs []uint32
7072
lbls.Range(func(l labels.Label) {
71-
labelsRefs = append(labelsRefs, getSymbol(l.Name, &req.Symbols))
72-
labelsRefs = append(labelsRefs, getSymbol(l.Value, &req.Symbols))
73+
labelsRefs = append(labelsRefs, symBuilder.GetSymbol(l.Name))
74+
labelsRefs = append(labelsRefs, symBuilder.GetSymbol(l.Value))
7375
})
7476

7577
metricType := promRW2.Metadata_METRIC_TYPE_HISTOGRAM
@@ -82,23 +84,47 @@ func AddHistogramSeries(
8284
Histograms: histograms,
8385
Metadata: promRW2.Metadata{
8486
Type: metricType,
85-
HelpRef: getSymbol(help, &req.Symbols),
86-
UnitRef: getSymbol(unit, &req.Symbols),
87+
HelpRef: symBuilder.GetSymbol(help),
88+
UnitRef: symBuilder.GetSymbol(unit),
8789
},
8890
Exemplars: exemplars,
8991
CreatedTimestamp: createdTimestamp,
9092
}
9193
req.Timeseries = append(req.Timeseries, ts)
94+
req.Symbols = symBuilder.GetSymbols()
9295

9396
return req
9497
}
9598

96-
func getSymbol(sym string, symbols *[]string) uint32 {
97-
for i, s := range *symbols {
98-
if s == sym {
99-
return uint32(i)
100-
}
99+
type SymbolTableBuilder struct {
100+
count uint32
101+
symbols map[string]uint32
102+
}
103+
104+
func NewSymbolTableBuilder(symbols []string) *SymbolTableBuilder {
105+
symbolsMap := make(map[string]uint32)
106+
for i, sym := range symbols {
107+
symbolsMap[sym] = uint32(i)
108+
}
109+
return &SymbolTableBuilder{
110+
count: uint32(len(symbols)),
111+
symbols: symbolsMap,
112+
}
113+
}
114+
115+
func (symbols *SymbolTableBuilder) GetSymbol(sym string) uint32 {
116+
if i, ok := symbols.symbols[sym]; ok {
117+
return i
118+
}
119+
symbols.symbols[sym] = symbols.count
120+
symbols.count++
121+
return symbols.count - 1
122+
}
123+
124+
func (symbols *SymbolTableBuilder) GetSymbols() []string {
125+
res := make([]string, len(symbols.symbols))
126+
for sym, i := range symbols.symbols {
127+
res[i] = sym
101128
}
102-
*symbols = append(*symbols, sym)
103-
return uint32(len(*symbols) - 1)
129+
return res
104130
}

0 commit comments

Comments
 (0)