From 251b8d2cc6155d58fcd85dbde9c658b4f28ea7e1 Mon Sep 17 00:00:00 2001 From: uzer_007 Date: Wed, 8 Jul 2026 02:01:51 +0300 Subject: [PATCH] Add Go hot path benchmarks --- bindings/cproto/cproto_test.go | 2 +- bindings/cproto/encdec_bench_test.go | 29 ++-- cjson/base64_bench_test.go | 193 +++++++++++++++++++++++++++ cjson/encoder_bench_test.go | 2 - cjson/serializer_bench_test.go | 53 +++++++- cjson/serializer_micro_bench_test.go | 31 +---- query_builder_bench_test.go | 123 +++++++++++++++++ test/reindexer_bench_test.go | 87 +++++++++--- 8 files changed, 455 insertions(+), 65 deletions(-) create mode 100644 cjson/base64_bench_test.go create mode 100644 query_builder_bench_test.go diff --git a/bindings/cproto/cproto_test.go b/bindings/cproto/cproto_test.go index 33d2b7ec4..0d892b7d3 100644 --- a/bindings/cproto/cproto_test.go +++ b/bindings/cproto/cproto_test.go @@ -76,7 +76,7 @@ func BenchmarkGetConn(b *testing.B) { b.Run("getConn", func(b *testing.B) { var conn connection ctx := context.Background() - for i := 0; i < b.N; i++ { + for b.Loop() { conn, err = binding.getConnection(ctx) if err != nil { panic(err) diff --git a/bindings/cproto/encdec_bench_test.go b/bindings/cproto/encdec_bench_test.go index 80ec8cf07..66ba149d2 100644 --- a/bindings/cproto/encdec_bench_test.go +++ b/bindings/cproto/encdec_bench_test.go @@ -17,12 +17,13 @@ func BenchmarkRPCEncoderInt32ArrArg(b *testing.B) { } b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - enc := newRPCEncoder(cmdSelect, uint32(i), false, false) + var seq uint32 + for b.Loop() { + enc := newRPCEncoder(cmdSelect, seq, false, false) enc.int32ArrArg(values) _ = enc.bytes() enc.ser.Close() + seq++ } } @@ -34,12 +35,13 @@ func BenchmarkRPCEncoderSnappyBytes(b *testing.B) { b.ReportAllocs() b.SetBytes(int64(len(payload))) - b.ResetTimer() - for i := 0; i < b.N; i++ { - enc := newRPCEncoder(cmdSelect, uint32(i), true, false) + var seq uint32 + for b.Loop() { + enc := newRPCEncoder(cmdSelect, seq, true, false) enc.bytesArg(payload) _ = enc.bytes() enc.ser.Close() + seq++ } } @@ -48,8 +50,7 @@ func BenchmarkRPCEncoderStartArgsChunck(b *testing.B) { defer enc.ser.Close() b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { enc.ser.Truncate(cprotoHdrLen) enc.startArgsChunck() } @@ -65,8 +66,7 @@ func BenchmarkRPCEncoderUpdate(b *testing.B) { enc.ser.PutVarInt(1) b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { enc.update() } } @@ -98,8 +98,7 @@ func BenchmarkRPCDecoderIntfArgs(b *testing.B) { b.ReportAllocs() b.SetBytes(int64(len(reply))) - b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { dec := newRPCDecoder(reply) err := dec.errCode() require.NoError(b, err) @@ -141,8 +140,7 @@ func BenchmarkNetBufferParseArgs(b *testing.B) { b.ReportAllocs() b.SetBytes(int64(len(reply))) - b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { err := nb.parseArgs() require.NoError(b, err) if len(nb.args) != 5 { @@ -159,8 +157,7 @@ func BenchmarkNetBufferParseArgsTimeout(b *testing.B) { b.ReportAllocs() b.SetBytes(int64(len(reply))) - b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { err := nb.parseArgs() if err != context.DeadlineExceeded { b.Fatalf("expected context.DeadlineExceeded, got %v", err) diff --git a/cjson/base64_bench_test.go b/cjson/base64_bench_test.go new file mode 100644 index 000000000..67b4713d4 --- /dev/null +++ b/cjson/base64_bench_test.go @@ -0,0 +1,193 @@ +package cjson + +import ( + "fmt" + "sort" + "testing" +) + +type benchBase64BytesDoc struct { + ID int `json:"id"` + Data []byte `json:"data"` +} + +var cjsonBase64PayloadSizes = []int{0, 1, 2, 3, 8, 16, 24, 32, 64, 128, 192, 512, 1024, 4096} + +func makeCJSONBase64Payload(size int) []byte { + payload := make([]byte, size) + for i := range payload { + payload[i] = byte(i*31 + 17) + } + return payload +} + +func makeCJSONBase64RealShapePayloads() [][]byte { + words := []string{ + "able_ant", "balanced_bear", "direct_dane", "enabled_emu", + "faithful_fish", "great_goat", "humane_hare", "logical_lark", + "modern_mole", "optimal_orca", "rapid_ray", "welcome_wren", + } + payloads := make([][]byte, len(words)) + for i, word := range words { + payloads[i] = []byte(word) + } + return payloads +} + +func BenchmarkCJSONBase64Encode(b *testing.B) { + state := NewState() + enc := state.NewEncoder() + + for _, size := range cjsonBase64PayloadSizes { + payload := makeCJSONBase64Payload(size) + doc := benchBase64BytesDoc{ID: size, Data: payload} + + ser := NewPoolSerializer() + if err := enc.EncodeRaw(doc, ser); err != nil { + b.Fatalf("warm encode size %d: %v", size, err) + } + ser.Close() + + b.Run(fmt.Sprintf("size=%d", size), func(b *testing.B) { + b.ReportAllocs() + b.SetBytes(int64(size)) + for b.Loop() { + ser := NewPoolSerializer() + if err := enc.EncodeRaw(doc, ser); err != nil { + b.Fatalf("encode size %d: %v", size, err) + } + benchBytesSink = ser.Bytes() + ser.Close() + } + }) + } +} + +func BenchmarkCJSONBase64Decode(b *testing.B) { + state := NewState() + enc := state.NewEncoder() + dec := state.NewDecoder(benchBase64BytesDoc{}, nil) + defer dec.Finalize() + + for _, size := range cjsonBase64PayloadSizes { + payload := makeCJSONBase64Payload(size) + doc := benchBase64BytesDoc{ID: size, Data: payload} + ser := NewPoolSerializer() + if err := enc.EncodeRaw(doc, ser); err != nil { + b.Fatalf("prepare decode size %d: %v", size, err) + } + wire := append([]byte(nil), ser.Bytes()...) + ser.Close() + + b.Run(fmt.Sprintf("size=%d", size), func(b *testing.B) { + b.ReportAllocs() + b.SetBytes(int64(size)) + for b.Loop() { + var out benchBase64BytesDoc + if err := dec.Decode(wire, &out); err != nil { + b.Fatalf("decode size %d: %v", size, err) + } + benchBytesSink = out.Data + } + }) + } +} + +func BenchmarkCJSONBase64RealShape(b *testing.B) { + payloads := makeCJSONBase64RealShapePayloads() + state := NewState() + enc := state.NewEncoder() + dec := state.NewDecoder(benchBase64BytesDoc{}, nil) + defer dec.Finalize() + + wires := make([][]byte, len(payloads)) + for i, payload := range payloads { + ser := NewPoolSerializer() + if err := enc.EncodeRaw(benchBase64BytesDoc{ID: i, Data: payload}, ser); err != nil { + b.Fatalf("prepare real-shape %d: %v", i, err) + } + wires[i] = append([]byte(nil), ser.Bytes()...) + ser.Close() + } + + b.Run("encode", func(b *testing.B) { + b.ReportAllocs() + for b.Loop() { + for i, payload := range payloads { + ser := NewPoolSerializer() + if err := enc.EncodeRaw(benchBase64BytesDoc{ID: i, Data: payload}, ser); err != nil { + b.Fatalf("encode real-shape %d: %v", i, err) + } + benchBytesSink = ser.Bytes() + ser.Close() + } + } + }) + + b.Run("decode", func(b *testing.B) { + b.ReportAllocs() + for b.Loop() { + for i, wire := range wires { + var out benchBase64BytesDoc + if err := dec.Decode(wire, &out); err != nil { + b.Fatalf("decode real-shape %d: %v", i, err) + } + benchBytesSink = out.Data + } + } + }) +} + +func BenchmarkCJSONBase64PayloadReport(b *testing.B) { + payloads := append([][]byte(nil), makeCJSONBase64RealShapePayloads()...) + for _, size := range cjsonBase64PayloadSizes { + payloads = append(payloads, makeCJSONBase64Payload(size)) + } + + lengths := make([]int, len(payloads)) + encodedLengths := make([]int, len(payloads)) + modCounts := [3]int{} + buckets := [4]int{} + for i, payload := range payloads { + l := len(payload) + lengths[i] = l + encodedLengths[i] = ((l + 2) / 3) * 4 + modCounts[l%3]++ + switch { + case l < 16: + buckets[0]++ + case l <= 128: + buckets[1]++ + case l <= 191: + buckets[2]++ + default: + buckets[3]++ + } + } + sort.Ints(lengths) + sort.Ints(encodedLengths) + + count := float64(len(payloads)) + b.ReportAllocs() + for b.Loop() { + for _, payload := range payloads { + benchBytesSink = payload + } + } + + b.ReportMetric(count, "payloads") + b.ReportMetric(float64(lengths[0]), "raw_min") + b.ReportMetric(float64(lengths[len(lengths)/2]), "raw_p50") + b.ReportMetric(float64(lengths[(len(lengths)*90)/100]), "raw_p90") + b.ReportMetric(float64(lengths[(len(lengths)*99)/100]), "raw_p99") + b.ReportMetric(float64(lengths[len(lengths)-1]), "raw_max") + b.ReportMetric(float64(encodedLengths[len(encodedLengths)/2]), "enc_p50") + b.ReportMetric(float64(encodedLengths[len(encodedLengths)-1]), "enc_max") + b.ReportMetric(float64(modCounts[0])*100/count, "mod0_pct") + b.ReportMetric(float64(modCounts[1])*100/count, "mod1_pct") + b.ReportMetric(float64(modCounts[2])*100/count, "mod2_pct") + b.ReportMetric(float64(buckets[0])*100/count, "lt16_pct") + b.ReportMetric(float64(buckets[1])*100/count, "16_128_pct") + b.ReportMetric(float64(buckets[2])*100/count, "129_191_pct") + b.ReportMetric(float64(buckets[3])*100/count, "ge192_pct") +} diff --git a/cjson/encoder_bench_test.go b/cjson/encoder_bench_test.go index 42d615214..4ef210193 100644 --- a/cjson/encoder_bench_test.go +++ b/cjson/encoder_bench_test.go @@ -79,7 +79,6 @@ func benchmarkCJSONEncodeRaw(b *testing.B, doc any) { ser.Close() b.ReportAllocs() - b.ResetTimer() for b.Loop() { ser := NewPoolSerializer() if err := enc.EncodeRaw(doc, ser); err != nil { @@ -103,7 +102,6 @@ func BenchmarkGobEncoderTypicalDocument(b *testing.B) { } b.ReportAllocs() - b.ResetTimer() for b.Loop() { buf.Reset() if err := enc.Encode(doc); err != nil { diff --git a/cjson/serializer_bench_test.go b/cjson/serializer_bench_test.go index 3e42a780c..d31f99adc 100644 --- a/cjson/serializer_bench_test.go +++ b/cjson/serializer_bench_test.go @@ -1,11 +1,14 @@ package cjson import ( + "reflect" "testing" "github.com/stretchr/testify/require" ) +var benchSerializerLen int + func BenchmarkSerializerEncodeTypicalDocument(b *testing.B) { tags := []string{"books", "science", "math", "history"} scores := []int{10, 42, 17, 5, 99, 100, 77, 54} @@ -15,7 +18,7 @@ func BenchmarkSerializerEncodeTypicalDocument(b *testing.B) { } b.ReportAllocs() - + for b.Loop() { ser := NewPoolSerializer() ser.WriteString("doc-2026-04-12") @@ -44,7 +47,7 @@ func BenchmarkSerializerWriteIntsBatch(b *testing.B) { b.ReportAllocs() b.SetBytes(int64(len(values) * 8)) - + for b.Loop() { ser := NewPoolSerializer() _, err := ser.WriteInts(values) @@ -61,7 +64,7 @@ func BenchmarkSerializerWriteInts16Batch(b *testing.B) { b.ReportAllocs() b.SetBytes(int64(len(values) * 2)) - + for b.Loop() { ser := NewPoolSerializer() _, err := ser.WriteInts16(values) @@ -78,10 +81,52 @@ func BenchmarkSerializerPutFloatVectorBatch(b *testing.B) { b.ReportAllocs() b.SetBytes(int64(len(vec) * 4)) - + for b.Loop() { ser := NewPoolSerializer() ser.PutFloatVector(vec) ser.Close() } } + +func BenchmarkSerializerPutValueInt(b *testing.B) { + v := reflect.ValueOf(123) + var buf [32]byte + + b.ReportAllocs() + for b.Loop() { + ser := NewSerializer(buf[:0]) + if err := ser.PutValue(v); err != nil { + b.Fatal(err) + } + benchSerializerLen = len(ser.Bytes()) + } +} + +func BenchmarkSerializerPutValueString(b *testing.B) { + v := reflect.ValueOf("benchmark") + var buf [64]byte + + b.ReportAllocs() + for b.Loop() { + ser := NewSerializer(buf[:0]) + if err := ser.PutValue(v); err != nil { + b.Fatal(err) + } + benchSerializerLen = len(ser.Bytes()) + } +} + +func BenchmarkSerializerPutValueSlice(b *testing.B) { + v := reflect.ValueOf([]int{1, 2, 3, 4}) + var buf [128]byte + + b.ReportAllocs() + for b.Loop() { + ser := NewSerializer(buf[:0]) + if err := ser.PutValue(v); err != nil { + b.Fatal(err) + } + benchSerializerLen = len(ser.Bytes()) + } +} diff --git a/cjson/serializer_micro_bench_test.go b/cjson/serializer_micro_bench_test.go index 3b96b4342..d7e9d330f 100644 --- a/cjson/serializer_micro_bench_test.go +++ b/cjson/serializer_micro_bench_test.go @@ -24,7 +24,6 @@ func benchmarkSerializerBytesOp(b *testing.B, op func(*Serializer, []byte), head ser := NewSerializer(make([]byte, 0, size+headerReserve)) b.ReportAllocs() b.SetBytes(int64(size)) - b.ResetTimer() for b.Loop() { ser.Reset() op(&ser, payload) @@ -38,12 +37,16 @@ func BenchmarkSerializerWriteIntBits(b *testing.B) { sizes := []uintptr{1, 2, 4, 8} for _, sz := range sizes { b.Run(fmt.Sprintf("size=%d", sz), func(b *testing.B) { - ser := NewSerializer(make([]byte, 0, b.N*int(sz))) + ser := NewSerializer(make([]byte, 0, 64<<10)) b.ReportAllocs() b.SetBytes(int64(sz)) - b.ResetTimer() - for i := 0; i < b.N; i++ { + var i int64 + for b.Loop() { + if len(ser.buf)+int(sz) > cap(ser.buf) { + ser.Reset() + } ser.writeIntBits(int64(i), sz) + i++ } benchBytesSink = ser.buf }) @@ -59,7 +62,6 @@ func BenchmarkSerializerPutFloatVector(b *testing.B) { ser := NewSerializer(make([]byte, 0, len(vec)*4+binary.MaxVarintLen64)) b.ReportAllocs() b.SetBytes(int64(len(vec) * 4)) - b.ResetTimer() for b.Loop() { ser.Reset() ser.PutFloatVector(vec) @@ -72,7 +74,6 @@ func BenchmarkSerializerWriteString(b *testing.B) { ser := NewSerializer(make([]byte, 0, len(payload))) b.ReportAllocs() b.SetBytes(int64(len(payload))) - b.ResetTimer() for b.Loop() { ser.Reset() ser.WriteString(payload) @@ -93,7 +94,6 @@ func BenchmarkSerializerWriteInts(b *testing.B) { ser := NewSerializer(make([]byte, 0, len(values)*8)) b.ReportAllocs() b.SetBytes(int64(len(values) * 8)) - b.ResetTimer() for b.Loop() { ser.Reset() _, _ = ser.WriteInts(values) @@ -129,7 +129,6 @@ func BenchmarkSerializerAppend(b *testing.B) { b.ReportAllocs() b.SetBytes(int64(len(src.Bytes()))) - b.ResetTimer() for b.Loop() { dst.Reset() dst.Append(src) @@ -141,7 +140,6 @@ func BenchmarkSerializerGrow(b *testing.B) { b.Run("reuse-capacity", func(b *testing.B) { ser := NewSerializer(make([]byte, 0, 64)) b.ReportAllocs() - b.ResetTimer() for b.Loop() { ser.Reset() ser.grow(16) @@ -152,7 +150,6 @@ func BenchmarkSerializerGrow(b *testing.B) { b.Run("nil-buffer", func(b *testing.B) { var ser Serializer b.ReportAllocs() - b.ResetTimer() for b.Loop() { ser.buf = nil ser.grow(16) @@ -164,7 +161,6 @@ func BenchmarkSerializerGrow(b *testing.B) { base := make([]byte, 16, 16) ser := NewSerializer(base) b.ReportAllocs() - b.ResetTimer() for b.Loop() { ser.buf = base ser.grow(1) @@ -179,7 +175,6 @@ func BenchmarkSerializerPutUuid(b *testing.B) { b.ReportAllocs() b.SetBytes(16) - b.ResetTimer() for b.Loop() { ser.Reset() @@ -197,7 +192,6 @@ func BenchmarkSerializerGetUuid(b *testing.B) { b.ReportAllocs() b.SetBytes(16) - b.ResetTimer() for b.Loop() { if rd.pos >= len(rd.buf) { rd.pos = 0 @@ -215,7 +209,6 @@ func BenchmarkSerializerGetUInt16(b *testing.B) { b.ReportAllocs() b.SetBytes(2) - b.ResetTimer() for b.Loop() { if rd.pos+2 > len(rd.buf) { rd.pos = 0 @@ -233,7 +226,6 @@ func BenchmarkSerializerGetUInt32(b *testing.B) { b.ReportAllocs() b.SetBytes(4) - b.ResetTimer() for b.Loop() { if rd.pos+4 > len(rd.buf) { rd.pos = 0 @@ -251,7 +243,6 @@ func BenchmarkSerializerGetUInt64(b *testing.B) { b.ReportAllocs() b.SetBytes(8) - b.ResetTimer() for b.Loop() { if rd.pos+8 > len(rd.buf) { rd.pos = 0 @@ -291,7 +282,6 @@ func BenchmarkSerializerWriteInts16(b *testing.B) { ser := NewSerializer(make([]byte, 0, len(values)*2)) b.ReportAllocs() b.SetBytes(int64(len(values) * 2)) - b.ResetTimer() for b.Loop() { ser.Reset() _, _ = ser.WriteInts16(values) @@ -304,7 +294,6 @@ func BenchmarkSerializerPutVString(b *testing.B) { ser := NewSerializer(make([]byte, 0, len(payload)+binary.MaxVarintLen64)) b.ReportAllocs() b.SetBytes(int64(len(payload))) - b.ResetTimer() for b.Loop() { ser.Reset() ser.PutVString(payload) @@ -317,7 +306,6 @@ func BenchmarkSerializerPutVarInt(b *testing.B) { b.Run(fmt.Sprintf("value=%d", value), func(b *testing.B) { ser := NewSerializer(make([]byte, 0, binary.MaxVarintLen64)) b.ReportAllocs() - b.ResetTimer() for b.Loop() { ser.Reset() ser.PutVarInt(value) @@ -331,7 +319,6 @@ func BenchmarkSerializerPutVarIntSequence(b *testing.B) { values := [...]int64{0, 42, -42, 8192, -8192} ser := NewSerializer(make([]byte, 0, len(values)*binary.MaxVarintLen64)) b.ReportAllocs() - b.ResetTimer() for b.Loop() { ser.Reset() for _, value := range values { @@ -346,7 +333,6 @@ func BenchmarkSerializerPutVarUInt(b *testing.B) { b.Run(fmt.Sprintf("value=%d", value), func(b *testing.B) { ser := NewSerializer(make([]byte, 0, binary.MaxVarintLen64)) b.ReportAllocs() - b.ResetTimer() for b.Loop() { ser.Reset() ser.PutVarUInt(value) @@ -360,7 +346,6 @@ func BenchmarkSerializerPutVarUIntSequence(b *testing.B) { values := [...]uint64{0, 42, 8192, 1 << 28} ser := NewSerializer(make([]byte, 0, len(values)*binary.MaxVarintLen64)) b.ReportAllocs() - b.ResetTimer() for b.Loop() { ser.Reset() for _, value := range values { @@ -375,7 +360,6 @@ func BenchmarkSerializerPutVarCUInt(b *testing.B) { b.Run(fmt.Sprintf("value=%d", value), func(b *testing.B) { ser := NewSerializer(make([]byte, 0, binary.MaxVarintLen64)) b.ReportAllocs() - b.ResetTimer() for b.Loop() { ser.Reset() ser.PutVarCUInt(value) @@ -393,7 +377,6 @@ func BenchmarkSerializerGetVarInt(b *testing.B) { payload := wr.Bytes() rd := NewSerializer(payload) b.ReportAllocs() - b.ResetTimer() for b.Loop() { if rd.pos >= len(rd.buf) { rd.pos = 0 diff --git a/query_builder_bench_test.go b/query_builder_bench_test.go new file mode 100644 index 000000000..602cfd64f --- /dev/null +++ b/query_builder_bench_test.go @@ -0,0 +1,123 @@ +package reindexer + +import ( + "reflect" + "testing" +) + +var benchQueryLen int + +func BenchmarkQueryWhereExpressionsFieldValues(b *testing.B) { + left := Field{Name: "id"} + right := Values{Values: []any{1}} + + b.ReportAllocs() + for b.Loop() { + q := newQuery(nil, "bench", nil) + q.WhereExpressions(left, EQ, right) + benchQueryLen = len(q.ser.Bytes()) + q.close() + } +} + +func BenchmarkQueryWhereExpressionsFunctions(b *testing.B) { + left := FlatArrayLen{Field: "tags"} + right := Now{TimeUnit: Sec} + + b.ReportAllocs() + for b.Loop() { + q := newQuery(nil, "bench", nil) + q.WhereExpressions(left, EQ, right) + benchQueryLen = len(q.ser.Bytes()) + q.close() + } +} + +func BenchmarkQueryWhereExpressionsFunctionsLegacySlices(b *testing.B) { + left := legacyFlatArrayLen{Field: "tags"} + right := legacyNow{TimeUnit: Sec} + + b.ReportAllocs() + for b.Loop() { + q := newQuery(nil, "bench", nil) + legacyWhereExpressionsFunctions(q, left, EQ, right) + benchQueryLen = len(q.ser.Bytes()) + q.close() + } +} + +func legacyWhereExpressionsFunctions(q *Query, left legacyFlatArrayLen, condition int, right legacyNow) { + q.ser.PutVarCUInt(queryExpressions) + legacySerializeFunctionExpression(q, left) + q.ser.PutVarCUInt(q.nextOp) + q.ser.PutVarCUInt(condition) + legacySerializeFunctionExpression(q, right) + q.whereEntriesCount++ + q.nextOp = opAND +} + +type legacyFlatArrayLen struct { + Field string +} + +func (f legacyFlatArrayLen) Type() int { + return expressionTypeExpression +} + +func (f legacyFlatArrayLen) FunctionType() int { + return functionFlatArrayLen +} + +func (f legacyFlatArrayLen) Fields() []string { + return []string{f.Field} +} + +func (f legacyFlatArrayLen) Args() []any { + return []any{} +} + +type legacyNow struct { + TimeUnit TimeUnit +} + +func (n legacyNow) Type() int { + return expressionTypeExpression +} + +func (n legacyNow) FunctionType() int { + return functionNow +} + +func (n legacyNow) Fields() []string { + return []string{} +} + +func (n legacyNow) Args() []any { + return []any{n.TimeUnit} +} + +type legacyFunctionExpression interface { + Type() int + FunctionType() int + Fields() []string + Args() []any +} + +func legacySerializeFunctionExpression(q *Query, fn legacyFunctionExpression) { + q.ser.PutVarCUInt(fn.Type()) + legacySerializeFunction(q, fn) +} + +func legacySerializeFunction(q *Query, fn legacyFunctionExpression) { + q.ser.PutVarCUInt(len(fn.Fields())) + for _, field := range fn.Fields() { + q.ser.PutVString(field) + } + q.ser.PutVarCUInt(len(fn.Args())) + for _, arg := range fn.Args() { + if err := q.ser.PutValue(reflect.ValueOf(arg)); err != nil { + panic(err) + } + } + q.ser.PutVarCUInt(fn.FunctionType()) +} diff --git a/test/reindexer_bench_test.go b/test/reindexer_bench_test.go index 4754c4cb1..0586076d7 100644 --- a/test/reindexer_bench_test.go +++ b/test/reindexer_bench_test.go @@ -244,70 +244,92 @@ func BenchmarkPrepare(b *testing.B) { func BenchmarkSimpleInsert(b *testing.B) { rand.Seed(*benchmarkSeed) tx := DBD.MustBeginTx(testBenchItemsSimpleNs) - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { if err := tx.Upsert(TestItemSimple{ID: mkID(i), Year: rand.Int()%1000 + 10, Name: randString(), Phone: randString()}); err != nil { panic(err) } + i++ } + b.StartTimer() tx.MustCommit() + b.StopTimer() } func BenchmarkSimpleUpdate(b *testing.B) { rand.Seed(*benchmarkSeed) tx := DBD.MustBeginTx(testBenchItemsSimpleNs) - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { if err := tx.Upsert(TestItemSimple{ID: mkID(i), Year: rand.Int()%1000 + 10, Name: randString()}); err != nil { panic(err) } + i++ } + b.StartTimer() tx.MustCommit() + b.StopTimer() } func BenchmarkSimpleUpdateAsync(b *testing.B) { rand.Seed(*benchmarkSeed) tx := DBD.MustBeginTx(testBenchItemsSimpleNs) - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { tx.UpsertAsync(TestItemSimple{ID: mkID(i), Year: rand.Int()%1000 + 10, Name: randString()}, func(err error) { if err != nil { panic(err) } }) + i++ } + b.StartTimer() tx.MustCommit() + b.StopTimer() } func BenchmarkSimpleCmplxPKUpsert(b *testing.B) { rand.Seed(*benchmarkSeed) tx := DBD.MustBeginTx(testBenchItemsSimpleComplexPkNs) - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { if err := tx.Upsert(TestItemCmplxPK{ID: int32(i), Year: int32(rand.Int()%1000 + 10), Name: randString(), SubID: randString()}); err != nil { panic(err) } + i++ } + b.StartTimer() tx.MustCommit() + b.StopTimer() } func BenchmarkInsert(b *testing.B) { tx := DBD.MustBeginTx(testBenchItemsInsertNs) - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { if err := tx.Upsert(testItemsSeed[i%len(testItemsSeed)]); err != nil { panic(err) } + i++ } + b.StartTimer() tx.MustCommit() + b.StopTimer() } func BenchmarkCJsonEncode(b *testing.B) { enc := cjsonState.NewEncoder() - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { ser := cjson.NewPoolSerializer() enc.Encode(testItemsSeed[i%len(testItemsSeed)], ser) ser.Close() + i++ } } @@ -315,9 +337,11 @@ func BenchmarkCJsonDecode(b *testing.B) { dec := cjsonState.NewDecoder(TestItem{}, nil) defer dec.Finalize() - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { ti := TestItem{} dec.Decode(testItemsCJsonSeed[i%len(testItemsCJsonSeed)], &ti) + i++ } } @@ -326,9 +350,11 @@ func BenchmarkGobEncode(b *testing.B) { buf := &bytes.Buffer{} enc := gob.NewEncoder(buf) - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { enc.Encode(testItemsSeed[i%len(testItemsSeed)]) buf.Reset() + i++ } } @@ -337,66 +363,85 @@ func BenchmarkGobDecode(b *testing.B) { buf := &bytes.Buffer{} dec := gob.NewDecoder(buf) buf.Write(testItemsGobSeed[0]) - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { ti := TestItem{} if err := dec.Decode(&ti); err != nil { panic(err) } buf.Reset() buf.Write(testItemsGobSeed[(i%(len(testItemsGobSeed)-1))+1]) + i++ } } func BenchmarkJsonEncode(b *testing.B) { // Just for the reference timings - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { ser := cjson.NewPoolSerializer() enc := json.NewEncoder(ser) enc.Encode(testItemsSeed[i%len(testItemsSeed)]) ser.Close() + i++ } } func BenchmarkJsonDecode(b *testing.B) { // Just for the reference timings - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { ti := TestItem{} json.Unmarshal(testItemsJsonSeed[i%len(testItemsJsonSeed)], &ti) + i++ } } func BenchmarkInsertJson(b *testing.B) { tx := DBD.MustBeginTx(testBenchItemsInsertJsonNs) - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { if err := tx.UpsertJSON(testItemsJsonSeed[i%len(testItemsJsonSeed)]); err != nil { panic(err) } + i++ } + b.StartTimer() tx.MustCommit() + b.StopTimer() } func BenchmarkUpdate(b *testing.B) { tx := DBD.MustBeginTx(testBenchItemsInsertNs) - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { if err := tx.Upsert(testItemsSeed[i%len(testItemsSeed)]); err != nil { panic(err) } + i++ } + b.StartTimer() tx.MustCommit() + b.StopTimer() } func BenchmarkDeleteAndUpdate(b *testing.B) { rand.Seed(*benchmarkSeed) tx := DBD.MustBeginTx(testBenchItemsInsertNs) - for i := 0; i < b.N; i++ { - tx.Delete(TestItem{ID: mkID(rand.Int() % b.N)}) + i := 0 + deleteIDRange := len(testItemsSeed) + for b.Loop() { + tx.Delete(TestItem{ID: mkID(rand.Int() % deleteIDRange)}) if err := tx.Upsert(testItemsSeed[i%len(testItemsSeed)]); err != nil { panic(err) } + i++ } + b.StartTimer() tx.Commit() + b.StopTimer() } func BenchmarkWarmup(b *testing.B) { @@ -813,16 +858,20 @@ func BenchmarkFullScan(b *testing.B) { func BenchmarkSelectByPKAndUpdate(b *testing.B) { rand.Seed(*benchmarkSeed) - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { FillTestItemsBench(i, 1, 10) DBD.Query(testBenchItemsNs).WhereInt("id", reindexer.EQ, mkID(rand.Int()%100000)).Limit(1).GetJson() + i++ } } func BenchmarkSelectByIdxAndUpdate(b *testing.B) { - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { FillTestItemsBench(i, 1, 10) DBD.Query(testBenchItemsNs).WhereInt("year", reindexer.EQ, 2010).Limit(1).GetJson() + i++ } } @@ -918,11 +967,13 @@ func BenchmarkKnnIvfL2WithVectors(b *testing.B) { func benchmarkFloatVectorInsert(b *testing.B, indexType string, metric string) { ns := knnBenchNsName(indexType, metric) - for i := 0; i < b.N; i++ { + i := 0 + for b.Loop() { _, err := DBD.Insert(ns, newKnnItem(i+kBenchKnnNsSize)) if err != nil { panic(err) } + i++ } }