From 9ada79acb6348b6b23469fbbb9ded6dbe52517d7 Mon Sep 17 00:00:00 2001 From: gtygo Date: Tue, 5 Nov 2019 12:03:21 +0800 Subject: [PATCH] expression: implement vectorized evaluation for `builtinCoalesceXXSig` (#13015) --- expression/builtin_compare_vec.go | 56 ----- expression/builtin_compare_vec_generated.go | 221 ++++++++++++++++++ .../builtin_compare_vec_generated_test.go | 72 ++++++ expression/generator/compare_vec.go | 116 +++++++++ 4 files changed, 409 insertions(+), 56 deletions(-) diff --git a/expression/builtin_compare_vec.go b/expression/builtin_compare_vec.go index d9259679e7c78..bd20496d9b27d 100644 --- a/expression/builtin_compare_vec.go +++ b/expression/builtin_compare_vec.go @@ -330,14 +330,6 @@ func (b *builtinGTIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) e return nil } -func (b *builtinCoalesceDurationSig) vectorized() bool { - return false -} - -func (b *builtinCoalesceDurationSig) vecEvalDuration(input *chunk.Chunk, result *chunk.Column) error { - return errors.Errorf("not implemented") -} - func (b *builtinNullEQIntSig) vectorized() bool { return false } @@ -346,22 +338,6 @@ func (b *builtinNullEQIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Colum return errors.Errorf("not implemented") } -func (b *builtinCoalesceRealSig) vectorized() bool { - return false -} - -func (b *builtinCoalesceRealSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error { - return errors.Errorf("not implemented") -} - -func (b *builtinCoalesceStringSig) vectorized() bool { - return false -} - -func (b *builtinCoalesceStringSig) vecEvalString(input *chunk.Chunk, result *chunk.Column) error { - return errors.Errorf("not implemented") -} - func (b *builtinIntervalIntSig) vectorized() bool { return true } @@ -453,14 +429,6 @@ func (b *builtinLEIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) e return nil } -func (b *builtinCoalesceDecimalSig) vectorized() bool { - return false -} - -func (b *builtinCoalesceDecimalSig) vecEvalDecimal(input *chunk.Chunk, result *chunk.Column) error { - return errors.Errorf("not implemented") -} - func (b *builtinLTIntSig) vectorized() bool { return true } @@ -551,14 +519,6 @@ func vecCompareInt(isUnsigned0, isUnsigned1 bool, largs, rargs, result *chunk.Co } } -func (b *builtinCoalesceIntSig) vectorized() bool { - return false -} - -func (b *builtinCoalesceIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error { - return errors.Errorf("not implemented") -} - func (b *builtinGreatestTimeSig) vectorized() bool { return false } @@ -567,22 +527,6 @@ func (b *builtinGreatestTimeSig) vecEvalString(input *chunk.Chunk, result *chunk return errors.Errorf("not implemented") } -func (b *builtinCoalesceTimeSig) vectorized() bool { - return false -} - -func (b *builtinCoalesceTimeSig) vecEvalTime(input *chunk.Chunk, result *chunk.Column) error { - return errors.Errorf("not implemented") -} - -func (b *builtinCoalesceJSONSig) vectorized() bool { - return false -} - -func (b *builtinCoalesceJSONSig) vecEvalJSON(input *chunk.Chunk, result *chunk.Column) error { - return errors.Errorf("not implemented") -} - func (b *builtinGreatestRealSig) vectorized() bool { return true } diff --git a/expression/builtin_compare_vec_generated.go b/expression/builtin_compare_vec_generated.go index 3e5dfbd658795..3a5799d9e7f9a 100644 --- a/expression/builtin_compare_vec_generated.go +++ b/expression/builtin_compare_vec_generated.go @@ -1756,3 +1756,224 @@ func (b *builtinNullEQJSONSig) vecEvalInt(input *chunk.Chunk, result *chunk.Colu func (b *builtinNullEQJSONSig) vectorized() bool { return true } + +func (b *builtinCoalesceIntSig) vecEvalInt(input *chunk.Chunk, result *chunk.Column) error { + n := input.NumRows() + result.ResizeInt64(n, true) + i64s := result.Int64s() + buf1, err := b.bufAllocator.get(types.ETInt, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf1) + for j := 0; j < len(b.args); j++ { + + if err := b.args[j].VecEvalInt(b.ctx, input, buf1); err != nil { + return err + } + args := buf1.Int64s() + for i := 0; i < n; i++ { + if !buf1.IsNull(i) && result.IsNull(i) { + i64s[i] = args[i] + result.SetNull(i, false) + } + } + } + return nil +} + +func (b *builtinCoalesceIntSig) vectorized() bool { + return true +} + +func (b *builtinCoalesceRealSig) vecEvalReal(input *chunk.Chunk, result *chunk.Column) error { + n := input.NumRows() + result.ResizeFloat64(n, true) + i64s := result.Float64s() + buf1, err := b.bufAllocator.get(types.ETReal, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf1) + for j := 0; j < len(b.args); j++ { + + if err := b.args[j].VecEvalReal(b.ctx, input, buf1); err != nil { + return err + } + args := buf1.Float64s() + for i := 0; i < n; i++ { + if !buf1.IsNull(i) && result.IsNull(i) { + i64s[i] = args[i] + result.SetNull(i, false) + } + } + } + return nil +} + +func (b *builtinCoalesceRealSig) vectorized() bool { + return true +} + +func (b *builtinCoalesceDecimalSig) vecEvalDecimal(input *chunk.Chunk, result *chunk.Column) error { + n := input.NumRows() + result.ResizeDecimal(n, true) + i64s := result.Decimals() + buf1, err := b.bufAllocator.get(types.ETDecimal, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf1) + for j := 0; j < len(b.args); j++ { + + if err := b.args[j].VecEvalDecimal(b.ctx, input, buf1); err != nil { + return err + } + args := buf1.Decimals() + for i := 0; i < n; i++ { + if !buf1.IsNull(i) && result.IsNull(i) { + i64s[i] = args[i] + result.SetNull(i, false) + } + } + } + return nil +} + +func (b *builtinCoalesceDecimalSig) vectorized() bool { + return true +} + +func (b *builtinCoalesceStringSig) vecEvalString(input *chunk.Chunk, result *chunk.Column) error { + n := input.NumRows() + argLen := len(b.args) + + bufs := make([]*chunk.Column, argLen) + + for i := 0; i < argLen; i++ { + buf, err := b.bufAllocator.get(types.ETInt, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf) + err = b.args[i].VecEvalString(b.ctx, input, buf) + if err != nil { + return err + } + bufs[i] = buf + } + result.ReserveString(n) + + for i := 0; i < n; i++ { + for j := 0; j < argLen; j++ { + if !bufs[j].IsNull(i) { + result.AppendString(bufs[j].GetString(i)) + break + } + if j == argLen-1 && bufs[j].IsNull(i) { + result.AppendNull() + } + } + } + return nil +} + +func (b *builtinCoalesceStringSig) vectorized() bool { + return true +} + +func (b *builtinCoalesceTimeSig) vecEvalTime(input *chunk.Chunk, result *chunk.Column) error { + n := input.NumRows() + result.ResizeTime(n, true) + i64s := result.Times() + buf1, err := b.bufAllocator.get(types.ETDatetime, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf1) + for j := 0; j < len(b.args); j++ { + + if err := b.args[j].VecEvalTime(b.ctx, input, buf1); err != nil { + return err + } + args := buf1.Times() + for i := 0; i < n; i++ { + if !buf1.IsNull(i) && result.IsNull(i) { + i64s[i] = args[i] + result.SetNull(i, false) + } + } + } + return nil +} + +func (b *builtinCoalesceTimeSig) vectorized() bool { + return true +} + +func (b *builtinCoalesceDurationSig) vecEvalDuration(input *chunk.Chunk, result *chunk.Column) error { + n := input.NumRows() + result.ResizeGoDuration(n, true) + i64s := result.GoDurations() + buf1, err := b.bufAllocator.get(types.ETDuration, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf1) + for j := 0; j < len(b.args); j++ { + + if err := b.args[j].VecEvalDuration(b.ctx, input, buf1); err != nil { + return err + } + args := buf1.GoDurations() + for i := 0; i < n; i++ { + if !buf1.IsNull(i) && result.IsNull(i) { + i64s[i] = args[i] + result.SetNull(i, false) + } + } + } + return nil +} + +func (b *builtinCoalesceDurationSig) vectorized() bool { + return true +} + +func (b *builtinCoalesceJSONSig) vecEvalJSON(input *chunk.Chunk, result *chunk.Column) error { + n := input.NumRows() + argLen := len(b.args) + + bufs := make([]*chunk.Column, argLen) + + for i := 0; i < argLen; i++ { + buf, err := b.bufAllocator.get(types.ETInt, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf) + err = b.args[i].VecEvalJSON(b.ctx, input, buf) + if err != nil { + return err + } + bufs[i] = buf + } + result.ReserveJSON(n) + + for i := 0; i < n; i++ { + for j := 0; j < argLen; j++ { + if !bufs[j].IsNull(i) { + result.AppendJSON(bufs[j].GetJSON(i)) + break + } + if j == argLen-1 && bufs[j].IsNull(i) { + result.AppendNull() + } + } + } + return nil +} + +func (b *builtinCoalesceJSONSig) vectorized() bool { + return true +} diff --git a/expression/builtin_compare_vec_generated_test.go b/expression/builtin_compare_vec_generated_test.go index 677dda5c35822..69bafe897979f 100644 --- a/expression/builtin_compare_vec_generated_test.go +++ b/expression/builtin_compare_vec_generated_test.go @@ -80,6 +80,78 @@ var vecGeneratedBuiltinCompareCases = map[string][]vecExprBenchCase{ {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETDuration, types.ETDuration}}, {retEvalType: types.ETInt, childrenTypes: []types.EvalType{types.ETJson, types.ETJson}}, }, + ast.Coalesce: { + + { + retEvalType: types.ETInt, + childrenTypes: []types.EvalType{types.ETInt, types.ETInt, types.ETInt}, + geners: []dataGenerator{ + gener{defaultGener{eType: types.ETInt, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETInt, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETInt, nullRation: 0.2}}, + }, + }, + + { + retEvalType: types.ETReal, + childrenTypes: []types.EvalType{types.ETReal, types.ETReal, types.ETReal}, + geners: []dataGenerator{ + gener{defaultGener{eType: types.ETReal, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETReal, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETReal, nullRation: 0.2}}, + }, + }, + + { + retEvalType: types.ETDecimal, + childrenTypes: []types.EvalType{types.ETDecimal, types.ETDecimal, types.ETDecimal}, + geners: []dataGenerator{ + gener{defaultGener{eType: types.ETDecimal, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETDecimal, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETDecimal, nullRation: 0.2}}, + }, + }, + + { + retEvalType: types.ETString, + childrenTypes: []types.EvalType{types.ETString, types.ETString, types.ETString}, + geners: []dataGenerator{ + gener{defaultGener{eType: types.ETString, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETString, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETString, nullRation: 0.2}}, + }, + }, + + { + retEvalType: types.ETDatetime, + childrenTypes: []types.EvalType{types.ETDatetime, types.ETDatetime, types.ETDatetime}, + geners: []dataGenerator{ + gener{defaultGener{eType: types.ETDatetime, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETDatetime, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETDatetime, nullRation: 0.2}}, + }, + }, + + { + retEvalType: types.ETDuration, + childrenTypes: []types.EvalType{types.ETDuration, types.ETDuration, types.ETDuration}, + geners: []dataGenerator{ + gener{defaultGener{eType: types.ETDuration, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETDuration, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETDuration, nullRation: 0.2}}, + }, + }, + + { + retEvalType: types.ETJson, + childrenTypes: []types.EvalType{types.ETJson, types.ETJson, types.ETJson}, + geners: []dataGenerator{ + gener{defaultGener{eType: types.ETJson, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETJson, nullRation: 0.2}}, + gener{defaultGener{eType: types.ETJson, nullRation: 0.2}}, + }, + }, + }, } func (s *testEvaluatorSuite) TestVectorizedGeneratedBuiltinCompareEvalOneVec(c *C) { diff --git a/expression/generator/compare_vec.go b/expression/generator/compare_vec.go index 4ea74bb30e210..9a712ecbdd64b 100644 --- a/expression/generator/compare_vec.go +++ b/expression/generator/compare_vec.go @@ -170,6 +170,76 @@ func (b *builtin{{ .compare.CompareName }}{{ .type.TypeName }}Sig) vectorized() } `)) +var builtinCoalesceCompareVecTpl = template.Must(template.New("").Parse(` + {{ if .type.Fixed }} +func (b *builtin{{ .compare.CompareName }}{{ .type.TypeName }}Sig) vecEval{{ .type.TypeName }}(input *chunk.Chunk, result *chunk.Column) error { + n := input.NumRows() + result.Resize{{ .type.TypeNameInColumn }}(n, true) + i64s := result.{{ .type.TypeNameInColumn }}s() + buf1, err := b.bufAllocator.get(types.ET{{ .type.ETName }}, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf1) + for j := 0; j < len(b.args); j++{ + + if err := b.args[j].VecEval{{ .type.TypeName }}(b.ctx, input, buf1); err != nil { + return err + } + args := buf1.{{ .type.TypeNameInColumn }}s() + for i := 0; i < n; i++ { + if !buf1.IsNull(i) && result.IsNull(i) { + i64s[i] = args[i] + result.SetNull(i, false) + } + } + } + return nil +} +{{ else }} +func (b *builtin{{ .compare.CompareName }}{{ .type.TypeName }}Sig) vecEval{{ .type.TypeName }}(input *chunk.Chunk, result *chunk.Column) error { + n := input.NumRows() + argLen := len(b.args) + + bufs := make([]*chunk.Column, argLen) + + for i := 0; i < argLen; i++ { + buf, err := b.bufAllocator.get(types.ETInt, n) + if err != nil { + return err + } + defer b.bufAllocator.put(buf) + err = b.args[i].VecEval{{ .type.TypeName }}(b.ctx, input, buf) + if err != nil { + return err + } + bufs[i]=buf + } + result.Reserve{{ .type.TypeName }}(n) + + for i := 0; i < n; i++ { + for j := 0; j < argLen; j++ { + if !bufs[j].IsNull(i) { + result.Append{{ .type.TypeName }}(bufs[j].Get{{ .type.TypeName }}(i)) + break + } + if j == argLen-1 && bufs[j].IsNull(i) { + result.AppendNull() + } + } + } + return nil +} + + +{{ end }} + +func (b *builtin{{ .compare.CompareName }}{{ .type.TypeName }}Sig) vectorized() bool { + return true +} + +`)) + const builtinCompareVecTestHeader = `import ( "testing" @@ -209,6 +279,20 @@ func BenchmarkVectorizedGeneratedBuiltinCompareFunc(b *testing.B) { } ` +var builtinCoalesceCompareVecTestFunc = template.Must(template.New("").Parse(` +{ + retEvalType: types.ET{{ .ETName }}, + childrenTypes: []types.EvalType{types.ET{{ .ETName }}, types.ET{{ .ETName }}, types.ET{{ .ETName }}}, + geners: []dataGenerator{ + gener{defaultGener{eType: types.ET{{ .ETName }}, nullRation: 0.2}}, + gener{defaultGener{eType: types.ET{{ .ETName }}, nullRation: 0.2}}, + gener{defaultGener{eType: types.ET{{ .ETName }}, nullRation: 0.2}}, + }, +}, + + +`)) + type CompareContext struct { // Describe the name of CompareContext(LT/LE/GT/GE/EQ/NE/NullEQ) CompareName string @@ -224,9 +308,11 @@ var comparesMap = []CompareContext{ {CompareName: "EQ", Operator: "=="}, {CompareName: "NE", Operator: "!="}, {CompareName: "NullEQ"}, + {CompareName: "Coalesce"}, } var typesMap = []TypeContext{ + TypeInt, TypeReal, TypeDecimal, TypeString, @@ -247,11 +333,24 @@ func generateDotGo(fileName string, compares []CompareContext, types []TypeConte ctx["compare"] = compareCtx ctx["type"] = typeCtx if compareCtx.CompareName == "NullEQ" { + if typeCtx.TypeName == TypeInt.TypeName { + continue + } err := builtinNullEQCompareVecTpl.Execute(w, ctx) if err != nil { return err } + } else if compareCtx.CompareName == "Coalesce" { + + err := builtinCoalesceCompareVecTpl.Execute(w, ctx) + if err != nil { + return err + } + } else { + if typeCtx.TypeName == TypeInt.TypeName { + continue + } err := builtinCompareVecTpl.Execute(w, ctx) if err != nil { return err @@ -273,11 +372,28 @@ func generateTestDotGo(fileName string, compares []CompareContext, types []TypeC w.WriteString(builtinCompareVecTestHeader) for _, compareCtx := range compares { + if compareCtx.CompareName == "Coalesce" { + err := builtinCompareVecTestFuncHeader.Execute(w, CompareContext{CompareName: "Coalesce"}) + if err != nil { + return err + } + for _, typeCtx := range types { + err := builtinCoalesceCompareVecTestFunc.Execute(w, typeCtx) + if err != nil { + return err + } + } + w.WriteString(builtinCompareVecTestFuncTail) + continue + } err := builtinCompareVecTestFuncHeader.Execute(w, compareCtx) if err != nil { return err } for _, typeCtx := range types { + if typeCtx.TypeName == TypeInt.TypeName { + continue + } err := builtinCompareVecTestCase.Execute(w, typeCtx) if err != nil { return err