From c4296b65fd467cac4df36021059c53865ef1ca05 Mon Sep 17 00:00:00 2001 From: Vilius Pranckaitis Date: Mon, 18 Jan 2021 15:35:04 +0200 Subject: [PATCH] benchmark TagValueFromEncodedTagsFast --- .../convert/decoder_fast_benchmark_test.go | 74 +++++++++++++++++++ src/x/serialize/decoder_fast.go | 50 +++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 src/dbnode/storage/index/convert/decoder_fast_benchmark_test.go diff --git a/src/dbnode/storage/index/convert/decoder_fast_benchmark_test.go b/src/dbnode/storage/index/convert/decoder_fast_benchmark_test.go new file mode 100644 index 0000000000..88efae2d7d --- /dev/null +++ b/src/dbnode/storage/index/convert/decoder_fast_benchmark_test.go @@ -0,0 +1,74 @@ +package convert + +import ( + "github.com/m3db/m3/src/x/checked" + "github.com/m3db/m3/src/x/pool" + "github.com/m3db/m3/src/x/serialize" + "github.com/stretchr/testify/require" + "math/rand" + "testing" +) + +type encodedTagsWithTagName struct { + encodedTags, tagName []byte +} + +func BenchmarkTagValueFromEncodedTagsFast(b *testing.B) { + testData, err := prepareData(b) + require.NoError(b, err) + + b.ResetTimer() + for i := range testData { + _, _, err := serialize.TagValueFromEncodedTagsFast(testData[i].encodedTags, + testData[i].tagName) + require.NoError(b, err) + } +} + +func BenchmarkTagValueFromEncodedTagsFast2(b *testing.B) { + testData, err := prepareData(b) + require.NoError(b, err) + + b.ResetTimer() + for i := range testData { + _, _, err := serialize.TagValueFromEncodedTagsFast2(testData[i].encodedTags, + testData[i].tagName) + require.NoError(b, err) + } +} + +func prepareData(b *testing.B) ([]encodedTagsWithTagName, error) { + data, err := prepareIDAndEncodedTags(b) + if err != nil { + return nil, err + } + + decoderPool := serialize.NewTagDecoderPool( + serialize.NewTagDecoderOptions(serialize.TagDecoderOptionsConfig{}), + pool.NewObjectPoolOptions(), + ) + decoderPool.Init() + decoder := decoderPool.Get() + defer decoder.Close() + + var tagNames [][]byte + decoder.Reset(checked.NewBytes(data[0].encodedTags, nil)) + for decoder.Next() { + tagNames = append(tagNames, clone(decoder.Current().Name.Bytes())) + } + tagNames = append(tagNames, []byte("not_exist")) + + var ( + result = make([]encodedTagsWithTagName, 0, b.N) + rnd = rand.New(rand.NewSource(42)) + ) + + for i := 0; i < b.N; i++ { + result = append(result, encodedTagsWithTagName{ + encodedTags: data[i].encodedTags, + tagName: tagNames[rnd.Intn(len(tagNames))], + }) + } + + return result, nil +} diff --git a/src/x/serialize/decoder_fast.go b/src/x/serialize/decoder_fast.go index f73cf9c131..60d8bb053d 100644 --- a/src/x/serialize/decoder_fast.go +++ b/src/x/serialize/decoder_fast.go @@ -30,6 +30,56 @@ import ( func TagValueFromEncodedTagsFast( encodedTags []byte, tagName []byte, +) ([]byte, bool, error) { + total := len(encodedTags) + if total < 4 { + return nil, false, fmt.Errorf( + "encoded tags too short: size=%d, need=%d", total, 4) + } + + header := byteOrder.Uint16(encodedTags[:2]) + encodedTags = encodedTags[2:] + if header != headerMagicNumber { + return nil, false, errIncorrectHeader + } + + length := int(byteOrder.Uint16(encodedTags[:2])) + encodedTags = encodedTags[2:] + + for i := 0; i < length; i++ { + if len(encodedTags) < 2 { + return nil, false, fmt.Errorf("missing size for tag name: index=%d", i) + } + numBytesName := int(byteOrder.Uint16(encodedTags[:2])) + if numBytesName == 0 { + return nil, false, errEmptyTagNameLiteral + } + encodedTags = encodedTags[2:] + + bytesName := encodedTags[:numBytesName] + encodedTags = encodedTags[numBytesName:] + + if len(encodedTags) < 2 { + return nil, false, fmt.Errorf("missing size for tag value: index=%d", i) + } + + numBytesValue := int(byteOrder.Uint16(encodedTags[:2])) + encodedTags = encodedTags[2:] + + bytesValue := encodedTags[:numBytesValue] + encodedTags = encodedTags[numBytesValue:] + + if bytes.Equal(bytesName, tagName) { + return bytesValue, true, nil + } + } + + return nil, false, nil +} + +func TagValueFromEncodedTagsFast2( + encodedTags []byte, + tagName []byte, ) ([]byte, bool, error) { var ( length int