From 9768d7c9e4a5bf8b475fc911ea404db08813a325 Mon Sep 17 00:00:00 2001 From: pingyu Date: Wed, 20 Nov 2019 23:32:29 +0800 Subject: [PATCH 1/6] vectorize `builtinBenchmarkSig` --- expression/builtin_info.go | 12 +++++- expression/builtin_info_vec.go | 58 ++++++++++++++++++++++++++++- expression/builtin_info_vec_test.go | 4 ++ 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/expression/builtin_info.go b/expression/builtin_info.go index cca418881e85a..828da1b7cfb9f 100644 --- a/expression/builtin_info.go +++ b/expression/builtin_info.go @@ -455,13 +455,23 @@ func (c *benchmarkFunctionClass) getFunction(ctx sessionctx.Context, args []Expr // Syntax: BENCHMARK(loop_count, expression) // Define with same eval type of input arg to avoid unnecessary cast function. sameEvalType := args[1].GetType().EvalType() + // constLoopCount is used by VecEvalInt + // since non-constant loop count would be different between rows, and cannot be vectorized. + var constLoopCount int64 + con, ok := args[0].(*Constant) + if ok && con.Value.Kind() == types.KindInt64 { + if lc, isNull, err := con.EvalInt(ctx, chunk.Row{}); err == nil && !isNull { + constLoopCount = lc + } + } bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt, sameEvalType) - sig := &builtinBenchmarkSig{bf} + sig := &builtinBenchmarkSig{bf, constLoopCount} return sig, nil } type builtinBenchmarkSig struct { baseBuiltinFunc + constLoopCount int64 } func (b *builtinBenchmarkSig) Clone() builtinFunc { diff --git a/expression/builtin_info_vec.go b/expression/builtin_info_vec.go index 7b26f448ba023..3cc9256f449cd 100644 --- a/expression/builtin_info_vec.go +++ b/expression/builtin_info_vec.go @@ -210,11 +210,65 @@ func (b *builtinFoundRowsSig) vecEvalInt(input *chunk.Chunk, result *chunk.Colum } func (b *builtinBenchmarkSig) vectorized() bool { - return false + return b.constLoopCount > 0 } func (b *builtinBenchmarkSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error { - return errors.Errorf("not implemented") + n := input.NumRows() + loopCount := b.constLoopCount + arg, ctx := b.args[1], b.ctx + evalType := arg.GetType().EvalType() + buf, err := b.bufAllocator.get(evalType, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf) + + var k int64 + for ; k < loopCount; k++ { + switch evalType { + case types.ETInt: + if err = arg.VecEvalInt(ctx, input, buf); err != nil { + return err + } + case types.ETReal: + if err = arg.VecEvalReal(ctx, input, buf); err != nil { + return err + } + case types.ETDecimal: + if err = arg.VecEvalDecimal(ctx, input, buf); err != nil { + return err + } + case types.ETString: + if err = arg.VecEvalString(ctx, input, buf); err != nil { + return err + } + case types.ETDatetime, types.ETTimestamp: + if err = arg.VecEvalTime(ctx, input, buf); err != nil { + return err + } + case types.ETDuration: + if err = arg.VecEvalDuration(ctx, input, buf); err != nil { + return err + } + case types.ETJson: + if err = arg.VecEvalJSON(ctx, input, buf); err != nil { + return err + } + default: // Should never go into here. + return errors.Errorf("EvalType %v not implemented for builtin BENCHMARK()", evalType) + } + } + + result.ResizeInt64(n, false) + i64s := result.Int64s() + for i := range i64s { + // Return value of BENCHMARK() is always 0. + // even if buf.IsNull + i64s[i] = 0 + } + + return nil } func (b *builtinLastInsertIDSig) vectorized() bool { diff --git a/expression/builtin_info_vec_test.go b/expression/builtin_info_vec_test.go index bd3d43a8d365c..e20d693a8100b 100644 --- a/expression/builtin_info_vec_test.go +++ b/expression/builtin_info_vec_test.go @@ -90,6 +90,10 @@ var vecBuiltinInfoCases = map[string][]vecExprBenchCase{ {retEvalType: types.ETInt, childrenTypes: []types.EvalType{}}, {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETInt}}, }, + ast.Benchmark: { + {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETInt, types.ETInt}, + geners: []dataGenerator{&rangeInt64Gener{10, 11}, nil}}, + }, } func (s *testEvaluatorSuite) TestVectorizedBuiltinInfoFunc(c *C) { From 3e8459671a9ea231261287b9e9bd04bf9cb8cef1 Mon Sep 17 00:00:00 2001 From: pingyu Date: Wed, 20 Nov 2019 23:47:24 +0800 Subject: [PATCH 2/6] update test case --- expression/builtin_info_vec_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/expression/builtin_info_vec_test.go b/expression/builtin_info_vec_test.go index e20d693a8100b..6342a8868a3f9 100644 --- a/expression/builtin_info_vec_test.go +++ b/expression/builtin_info_vec_test.go @@ -20,6 +20,7 @@ import ( . "github.com/pingcap/check" "github.com/pingcap/parser/ast" + "github.com/pingcap/parser/mysql" "github.com/pingcap/tidb/tablecodec" "github.com/pingcap/tidb/types" ) @@ -92,7 +93,7 @@ var vecBuiltinInfoCases = map[string][]vecExprBenchCase{ }, ast.Benchmark: { {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETInt, types.ETInt}, - geners: []dataGenerator{&rangeInt64Gener{10, 11}, nil}}, + constants: []*Constant{{Value: types.NewIntDatum(10), RetType: types.NewFieldType(mysql.TypeLonglong)}, nil}}, }, } From 8a5a4cfdb4f7f6d8bc554b98474b12fd20cea124 Mon Sep 17 00:00:00 2001 From: pingyu Date: Wed, 20 Nov 2019 23:55:42 +0800 Subject: [PATCH 3/6] improve comment --- expression/builtin_info_vec.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expression/builtin_info_vec.go b/expression/builtin_info_vec.go index 3cc9256f449cd..ef670f3b5cf72 100644 --- a/expression/builtin_info_vec.go +++ b/expression/builtin_info_vec.go @@ -264,7 +264,7 @@ func (b *builtinBenchmarkSig) vecEvalInt(input *chunk.Chunk, result *chunk.Colum i64s := result.Int64s() for i := range i64s { // Return value of BENCHMARK() is always 0. - // even if buf.IsNull + // even if args[1].IsNull(i) i64s[i] = 0 } From 448c7fb1fdb3b574c8f4284a22e4926c589b1d28 Mon Sep 17 00:00:00 2001 From: pingyu Date: Wed, 27 Nov 2019 23:28:42 +0800 Subject: [PATCH 4/6] update --- expression/builtin_info.go | 13 ++++++++++--- expression/builtin_info_vec.go | 34 +++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/expression/builtin_info.go b/expression/builtin_info.go index 828da1b7cfb9f..125ffbd6377ec 100644 --- a/expression/builtin_info.go +++ b/expression/builtin_info.go @@ -484,9 +484,16 @@ func (b *builtinBenchmarkSig) Clone() builtinFunc { // See https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_benchmark func (b *builtinBenchmarkSig) evalInt(row chunk.Row) (int64, bool, error) { // Get loop count. - loopCount, isNull, err := b.args[0].EvalInt(b.ctx, row) - if isNull || err != nil { - return 0, isNull, err + var loopCount int64 + var isNull bool + var err error + if b.constLoopCount > 0 { + loopCount = b.constLoopCount + } else { + loopCount, isNull, err = b.args[0].EvalInt(b.ctx, row) + if isNull || err != nil { + return 0, isNull, err + } } // BENCHMARK() will return NULL if loop count < 0, diff --git a/expression/builtin_info_vec.go b/expression/builtin_info_vec.go index ef670f3b5cf72..e2415f4d93e16 100644 --- a/expression/builtin_info_vec.go +++ b/expression/builtin_info_vec.go @@ -225,39 +225,51 @@ func (b *builtinBenchmarkSig) vecEvalInt(input *chunk.Chunk, result *chunk.Colum defer b.bufAllocator.put(buf) var k int64 - for ; k < loopCount; k++ { - switch evalType { - case types.ETInt: + switch evalType { + case types.ETInt: + for ; k < loopCount; k++ { if err = arg.VecEvalInt(ctx, input, buf); err != nil { return err } - case types.ETReal: + } + case types.ETReal: + for ; k < loopCount; k++ { if err = arg.VecEvalReal(ctx, input, buf); err != nil { return err } - case types.ETDecimal: + } + case types.ETDecimal: + for ; k < loopCount; k++ { if err = arg.VecEvalDecimal(ctx, input, buf); err != nil { return err } - case types.ETString: + } + case types.ETString: + for ; k < loopCount; k++ { if err = arg.VecEvalString(ctx, input, buf); err != nil { return err } - case types.ETDatetime, types.ETTimestamp: + } + case types.ETDatetime, types.ETTimestamp: + for ; k < loopCount; k++ { if err = arg.VecEvalTime(ctx, input, buf); err != nil { return err } - case types.ETDuration: + } + case types.ETDuration: + for ; k < loopCount; k++ { if err = arg.VecEvalDuration(ctx, input, buf); err != nil { return err } - case types.ETJson: + } + case types.ETJson: + for ; k < loopCount; k++ { if err = arg.VecEvalJSON(ctx, input, buf); err != nil { return err } - default: // Should never go into here. - return errors.Errorf("EvalType %v not implemented for builtin BENCHMARK()", evalType) } + default: // Should never go into here. + return errors.Errorf("EvalType %v not implemented for builtin BENCHMARK()", evalType) } result.ResizeInt64(n, false) From 0c594d3b0197c1a22b3b1ab4fece0be0e1c8ed52 Mon Sep 17 00:00:00 2001 From: pingyu Date: Mon, 2 Dec 2019 23:12:13 +0800 Subject: [PATCH 5/6] add more tests --- expression/builtin_info_vec_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/expression/builtin_info_vec_test.go b/expression/builtin_info_vec_test.go index 6342a8868a3f9..19f3c52edc0a4 100644 --- a/expression/builtin_info_vec_test.go +++ b/expression/builtin_info_vec_test.go @@ -94,6 +94,20 @@ var vecBuiltinInfoCases = map[string][]vecExprBenchCase{ ast.Benchmark: { {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETInt, types.ETInt}, constants: []*Constant{{Value: types.NewIntDatum(10), RetType: types.NewFieldType(mysql.TypeLonglong)}, nil}}, + {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETInt, types.ETReal}, + constants: []*Constant{{Value: types.NewIntDatum(11), RetType: types.NewFieldType(mysql.TypeLonglong)}, nil}}, + {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETInt, types.ETDecimal}, + constants: []*Constant{{Value: types.NewIntDatum(12), RetType: types.NewFieldType(mysql.TypeLonglong)}, nil}}, + {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETInt, types.ETString}, + constants: []*Constant{{Value: types.NewIntDatum(13), RetType: types.NewFieldType(mysql.TypeLonglong)}, nil}}, + {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETInt, types.ETDatetime}, + constants: []*Constant{{Value: types.NewIntDatum(14), RetType: types.NewFieldType(mysql.TypeLonglong)}, nil}}, + {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETInt, types.ETTimestamp}, + constants: []*Constant{{Value: types.NewIntDatum(15), RetType: types.NewFieldType(mysql.TypeLonglong)}, nil}}, + {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETInt, types.ETDuration}, + constants: []*Constant{{Value: types.NewIntDatum(16), RetType: types.NewFieldType(mysql.TypeLonglong)}, nil}}, + {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETInt, types.ETJson}, + constants: []*Constant{{Value: types.NewIntDatum(17), RetType: types.NewFieldType(mysql.TypeLonglong)}, nil}}, }, } From 85cbed39c34f2c8a71d71e0d05162666fd918b05 Mon Sep 17 00:00:00 2001 From: pingyu Date: Tue, 10 Dec 2019 01:52:15 +0800 Subject: [PATCH 6/6] address comment --- expression/builtin_info.go | 2 +- expression/builtin_info_test.go | 4 ++++ expression/builtin_info_vec.go | 8 ++------ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/expression/builtin_info.go b/expression/builtin_info.go index 125ffbd6377ec..bfb062255391f 100644 --- a/expression/builtin_info.go +++ b/expression/builtin_info.go @@ -475,7 +475,7 @@ type builtinBenchmarkSig struct { } func (b *builtinBenchmarkSig) Clone() builtinFunc { - newSig := &builtinBenchmarkSig{} + newSig := &builtinBenchmarkSig{constLoopCount: b.constLoopCount} newSig.cloneFrom(&b.baseBuiltinFunc) return newSig } diff --git a/expression/builtin_info_test.go b/expression/builtin_info_test.go index cdb1489efb54f..9d450d5f33ee1 100644 --- a/expression/builtin_info_test.go +++ b/expression/builtin_info_test.go @@ -167,6 +167,10 @@ func (s *testEvaluatorSuite) TestBenchMark(c *C) { } else { c.Assert(d.GetInt64(), Equals, t.Expected) } + + // test clone + b1 := f.Clone().(*ScalarFunction).Function.(*builtinBenchmarkSig) + c.Assert(b1.constLoopCount, Equals, int64(t.LoopCount)) } } diff --git a/expression/builtin_info_vec.go b/expression/builtin_info_vec.go index e2415f4d93e16..690f2f47ca6ab 100644 --- a/expression/builtin_info_vec.go +++ b/expression/builtin_info_vec.go @@ -272,13 +272,9 @@ func (b *builtinBenchmarkSig) vecEvalInt(input *chunk.Chunk, result *chunk.Colum return errors.Errorf("EvalType %v not implemented for builtin BENCHMARK()", evalType) } + // Return value of BENCHMARK() is always 0. + // even if args[1].IsNull(i) result.ResizeInt64(n, false) - i64s := result.Int64s() - for i := range i64s { - // Return value of BENCHMARK() is always 0. - // even if args[1].IsNull(i) - i64s[i] = 0 - } return nil }