From 56b070617ed873702099f62dfac133a129fc4918 Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Wed, 23 Mar 2022 14:10:48 +0200 Subject: [PATCH] Remove generateFromTimeSeries and cleanup after that MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This does have some performance improvements due to having to not support some cases. name old time/op new time/op delta CompileTemplatesSimple-8 1.05µs ±10% 0.98µs ±10% -5.92% (p=0.015 n=10+10) CompileTemplatesComplex-8 1.54µs ± 7% 1.41µs ± 6% -8.35% (p=0.001 n=9+10) EvaluateTemplatesSimple-8 230ns ± 7% 25ns ± 8% -89.30% (p=0.000 n=10+10) EvaluateTemplatesComplex-8 6.88ns ± 6% 6.98ns ±10% ~ (p=0.796 n=10+10) StoreFromPrecompiledTemplates-8 155ms ±13% 153ms ± 7% ~ (p=1.000 n=10+10) StoreFromTemplates-8 153ms ± 7% 158ms ±10% ~ (p=0.243 n=10+9) GenerateFromPrecompiledTemplates-8 31.6ms ±19% 27.4ms ±20% -13.42% (p=0.005 n=10+10) WriteFor-8 1.08µs ±10% 1.05µs ±11% ~ (p=0.280 n=10+10) name old alloc/op new alloc/op delta StoreFromPrecompiledTemplates-8 117MB ± 0% 117MB ± 0% ~ (p=1.000 n=10+9) StoreFromTemplates-8 117MB ± 0% 117MB ± 0% ~ (p=0.143 n=10+10) GenerateFromPrecompiledTemplates-8 79.2MB ± 0% 79.2MB ± 0% -0.00% (p=0.000 n=10+9) WriteFor-8 640B ± 5% 739B ±43% ~ (p=0.795 n=7+10) name old allocs/op new allocs/op delta StoreFromPrecompiledTemplates-8 175 ± 2% 175 ± 1% ~ (p=0.643 n=10+10) StoreFromTemplates-8 309 ± 1% 281 ± 1% -9.22% (p=0.000 n=10+10) GenerateFromPrecompiledTemplates-8 39.0 ±21% 28.3 ±13% -27.44% (p=0.000 n=10+10) WriteFor-8 0.00 0.00 ~ (all equal) --- bench_test.go | 40 ++++--------------------------- remote_write.go | 56 -------------------------------------------- remote_write_test.go | 9 +++++-- 3 files changed, 11 insertions(+), 94 deletions(-) diff --git a/bench_test.go b/bench_test.go index 8258075..86a9855 100644 --- a/bench_test.go +++ b/bench_test.go @@ -10,9 +10,7 @@ import ( "testing" "time" - "github.com/golang/protobuf/proto" "github.com/oxtoacart/bpool" - "github.com/prometheus/prometheus/prompb" "github.com/stretchr/testify/require" "go.k6.io/k6/js/modulestest" "go.k6.io/k6/lib" @@ -38,8 +36,9 @@ func BenchmarkEvaluateTemplatesSimple(b *testing.B) { t, err := compileTemplate("something ${series_id} else") require.NoError(b, err) b.ResetTimer() + var buf []byte for i := 0; i < b.N; i++ { - _ = t.ToString(i) + buf = t.AppendByte(buf[:0], i) } } @@ -47,8 +46,9 @@ func BenchmarkEvaluateTemplatesComplex(b *testing.B) { t, err := compileTemplate("something ${series_id/1000} else") require.NoError(b, err) b.ResetTimer() + var buf []byte for i := 0; i < b.N; i++ { - _ = t.ToString(i) + buf = t.AppendByte(buf[:0], i) } } @@ -158,35 +158,3 @@ func BenchmarkGenerateFromPrecompiledTemplates(b *testing.B) { } }) } - -func BenchmarkGenerateFromTemplates(b *testing.B) { - b.ReportAllocs() - b.RunParallel(func(pb *testing.PB) { - r := rand.New(rand.NewSource(time.Now().Unix())) - i := 0 - for pb.Next() { - i++ - _, err := generateFromTemplates(r, i, i+10, int64(i), 0, 100000, benchmarkLabels) - require.NoError(b, err) - } - }) -} - -func BenchmarkGenerateFromTemplatesAndMarshal(b *testing.B) { - b.ReportAllocs() - b.RunParallel(func(pb *testing.PB) { - r := rand.New(rand.NewSource(time.Now().Unix())) - i := 0 - for pb.Next() { - i++ - batch, err := generateFromTemplates(r, i, i+10, int64(i), 0, 100000, benchmarkLabels) - require.NoError(b, err) - - req := prompb.WriteRequest{ - Timeseries: batch, - } - _, err = proto.Marshal(&req) - require.NoError(b, err) - } - }) -} diff --git a/remote_write.go b/remote_write.go index 3114548..d207013 100644 --- a/remote_write.go +++ b/remote_write.go @@ -329,9 +329,6 @@ func compileTemplate(template string) (*labelGenerator, error) { switch template[i+len("${series_id")] { case '}': return &labelGenerator{ - ToString: func(seriesID int) string { - return template[:i] + strconv.Itoa(seriesID) + template[i+len("${series_id}"):] - }, AppendByte: func(b []byte, seriesID int) []byte { b = append(b, template[:i]...) b = strconv.AppendInt(b, int64(seriesID), 10) @@ -356,15 +353,7 @@ func compileTemplate(template string) (*labelGenerator, error) { b = strconv.AppendInt(b, int64(j), 10) possibleValues[j] = append(b, template[i+end+1:]...) } - possibleValuesS := make([]string, d) - // TODO have an upper limit - for j := 0; j < d; j++ { - possibleValuesS[j] = template[:i] + strconv.Itoa((j)) + template[i+end+1:] - } return &labelGenerator{ - ToString: func(seriesID int) string { - return possibleValuesS[seriesID%d] - }, AppendByte: func(b []byte, seriesID int) []byte { return append(b, possibleValues[seriesID%d]...) }, @@ -378,20 +367,9 @@ func compileTemplate(template string) (*labelGenerator, error) { if err != nil { return nil, err } - var memoizeS string - var memoizeSValue int - var memoize []byte var memoizeValue int64 return &labelGenerator{ - ToString: func(seriesID int) string { - value := (seriesID / d) - if memoizeS == "" || value != memoizeSValue { - memoizeSValue = value - memoizeS = template[:i] + strconv.Itoa(value) + template[i+end+1:] - } - return memoizeS - }, AppendByte: func(b []byte, seriesID int) []byte { value := int64(seriesID / d) if memoize == nil || value != memoizeValue { @@ -409,49 +387,15 @@ func compileTemplate(template string) (*labelGenerator, error) { } type labelGenerator struct { - ToString func(int) string AppendByte func([]byte, int) []byte } func newIdentityLabelGenerator(t string) *labelGenerator { return &labelGenerator{ - ToString: func(int) string { return t }, AppendByte: func(b []byte, _ int) []byte { return append(b, t...) }, } } -func generateFromTemplates(r *rand.Rand, minValue, maxValue int, - timestamp int64, minSeriesID, maxSeriesID int, - labelsTemplate map[string]string, -) ([]prompb.TimeSeries, error) { - batchSize := maxSeriesID - minSeriesID - series := make([]prompb.TimeSeries, batchSize) - - compiledTemplates, err := compileLabelTemplates(labelsTemplate) - if err != nil { - return nil, err - } - for seriesID := minSeriesID; seriesID < maxSeriesID; seriesID++ { - labels := make([]prompb.Label, len(labelsTemplate)) - // TODO optimize - for i, template := range compiledTemplates.compiledTemplates { - labels[i] = prompb.Label{Name: template.name, Value: template.generator.ToString(seriesID)} - } - - series[seriesID-minSeriesID] = prompb.TimeSeries{ - Labels: labels, - Samples: []prompb.Sample{ - { - Value: valueBetween(r, minValue, maxValue), - Timestamp: timestamp, - }, - }, - } - } - - return series, nil -} - // this is opaque on purpose so that it can't be done anything to from the js side type labelTemplates struct { compiledTemplates []compiledTemplate diff --git a/remote_write_test.go b/remote_write_test.go index 94ce65f..7dd1ff4 100644 --- a/remote_write_test.go +++ b/remote_write_test.go @@ -39,7 +39,7 @@ func TestEvaluateTemplate(t *testing.T) { return } require.NoError(t, err) - result := compiled.ToString(testcase.value) + result := string(compiled.AppendByte(nil, testcase.value)) require.Equal(t, testcase.result, result) }) } @@ -143,7 +143,12 @@ func TestGenerateFromTemplates(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := rand.New(rand.NewSource(time.Now().Unix())) - got, err := generateFromTemplates(r, tt.args.minValue, tt.args.maxValue, tt.args.timestamp, tt.args.minSeriesID, tt.args.maxSeriesID, tt.args.labelsTemplate) + compiled, err := compileLabelTemplates(tt.args.labelsTemplate) + require.NoError(t, err) + buf := generateFromPrecompiledTemplates(r, tt.args.minValue, tt.args.maxValue, tt.args.timestamp, tt.args.minSeriesID, tt.args.maxSeriesID, compiled) + req := new(prompb.WriteRequest) + require.NoError(t, proto.Unmarshal(buf.Bytes(), req)) + got := req.Timeseries require.NoError(t, err) if len(got) != len(tt.want.series) { t.Errorf("Differing length, want: %d, got: %d", len(tt.want.series), len(got))