You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@drill.apache.org by ja...@apache.org on 2014/06/16 23:31:40 UTC

[31/32] git commit: DRILL-937: Optimize boolean and/or operator with short circuit evaluation in run-time generated code.

DRILL-937: Optimize boolean and/or operator with short circuit  evaluation in run-time generated code.


Project: http://git-wip-us.apache.org/repos/asf/incubator-drill/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-drill/commit/38dde9e9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-drill/tree/38dde9e9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-drill/diff/38dde9e9

Branch: refs/heads/master
Commit: 38dde9e9d780aa3dba6faa1c44d6669e7f4bb202
Parents: 1568fc6
Author: Jinfeng Ni <jn...@maprtech.com>
Authored: Sun Jun 15 14:28:12 2014 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Mon Jun 16 13:50:49 2014 -0700

----------------------------------------------------------------------
 .../apache/drill/exec/expr/ClassGenerator.java  |  16 +++
 .../drill/exec/expr/EvaluationVisitor.java      | 136 +++++++++++++++++++
 .../exec/expr/annotations/FunctionTemplate.java |   3 +-
 .../exec/expr/fn/DrillSCBooleanOPHolder.java    |  35 +++++
 .../drill/exec/expr/fn/FunctionConverter.java   |   6 +
 .../drill/exec/expr/fn/impl/BitFunctions.java   |   4 +-
 6 files changed, 197 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/38dde9e9/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ClassGenerator.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ClassGenerator.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ClassGenerator.java
index ab3c307..7b1832c 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ClassGenerator.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ClassGenerator.java
@@ -49,6 +49,7 @@ import com.sun.codemodel.JExpr;
 import com.sun.codemodel.JExpression;
 import com.sun.codemodel.JFieldRef;
 import com.sun.codemodel.JInvocation;
+import com.sun.codemodel.JLabel;
 import com.sun.codemodel.JMethod;
 import com.sun.codemodel.JMod;
 import com.sun.codemodel.JType;
@@ -76,6 +77,7 @@ public class ClassGenerator<T>{
   private final JCodeModel model;
 
   private int index = 0;
+  private int labelIndex = 0;
   private MappingSet mappings;
 
   public static MappingSet getDefaultMapping(){
@@ -149,6 +151,20 @@ public class ClassGenerator<T>{
     return getBlock(getCurrentMapping().getMethodName(BlockType.CLEANUP));
   }
 
+  public void nestEvalBlock(JBlock block) {
+    String methodName = getCurrentMapping().getMethodName(BlockType.EVAL);
+    this.blocks[sig.get(methodName)].addLast(block);
+  }
+  
+  public void unNestEvalBlock() {
+    String methodName = getCurrentMapping().getMethodName(BlockType.EVAL);
+    this.blocks[sig.get(methodName)].removeLast();
+  }
+  
+  public JLabel getEvalBlockLabel (String prefix) {
+    return getEvalBlock().label(prefix + labelIndex ++);
+  }
+  
   public JVar declareVectorValueSetupAndMember(String batchName, TypedFieldId fieldId){
     return declareVectorValueSetupAndMember( DirectExpression.direct(batchName), fieldId);
   }

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/38dde9e9/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java
index 31cc563..efc7259 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java
@@ -55,6 +55,7 @@ import org.apache.drill.exec.compile.sig.ConstantExpressionIdentifier;
 import org.apache.drill.exec.expr.ClassGenerator.BlockType;
 import org.apache.drill.exec.expr.ClassGenerator.HoldingContainer;
 import org.apache.drill.exec.expr.fn.DrillFuncHolder;
+import org.apache.drill.exec.expr.fn.DrillSCBooleanOPHolder;
 import org.apache.drill.exec.expr.fn.FunctionImplementationRegistry;
 import org.apache.drill.exec.expr.fn.HiveFuncHolder;
 import org.apache.drill.exec.physical.impl.filter.ReturnValueExpression;
@@ -104,6 +105,15 @@ public class EvaluationVisitor {
 
       if (holderExpr instanceof DrillFuncHolderExpr) {
         DrillFuncHolder holder = ((DrillFuncHolderExpr) holderExpr).getHolder();
+        
+        if (holder instanceof DrillSCBooleanOPHolder && holderExpr.getName().equals("booleanAnd")) {
+          return visitBooleanAnd(holderExpr, generator);
+        }
+
+        if (holder instanceof DrillSCBooleanOPHolder && holderExpr.getName().equals("booleanOr")) {
+          return visitBooleanOr(holderExpr, generator);
+        }
+
         JVar[] workspaceVars = holder.renderStart(generator, null);
 
         if (holder.isNested())
@@ -592,6 +602,132 @@ public class EvaluationVisitor {
       FunctionCall fc = new FunctionCall(convertFunctionName, newArgs, e.getPosition());
       return fc.accept(this, value);
     }
+    
+    private HoldingContainer visitBooleanAnd(FunctionHolderExpression holderExpr,
+        ClassGenerator<?> generator) {
+      
+      HoldingContainer out = generator.declare(holderExpr.getMajorType());
+      
+      JLabel label = generator.getEvalBlockLabel("AndOP");
+      JBlock eval = generator.getEvalBlock().block();  // enter into nested block
+      generator.nestEvalBlock(eval);
+
+      HoldingContainer arg = null;
+      
+      JExpression e = null;
+      
+      //  value of boolean "and" when one side is null
+      //    p       q     p and q
+      //    true    null     null
+      //    false   null     false
+      //    null    true     null
+      //    null    false    false
+      //    null    null     null
+      for (int i = 0; i < holderExpr.args.size(); i++) {
+        arg = holderExpr.args.get(i).accept(this, generator);
+        
+        JBlock earlyExit = null;
+        if (arg.isOptional()) {
+          earlyExit = eval._if(arg.getIsSet().eq(JExpr.lit(1)).cand(arg.getValue().ne(JExpr.lit(1))))._then();          
+          if(e == null){
+            e = arg.getIsSet();
+          }else{
+            e = e.mul(arg.getIsSet());
+          }            
+        } else {
+          earlyExit = eval._if(arg.getValue().ne(JExpr.lit(1)))._then();               
+        }
+        
+        if (out.isOptional()) {
+          earlyExit.assign(out.getIsSet(), JExpr.lit(1));
+        } 
+        
+        earlyExit.assign(out.getValue(),  JExpr.lit(0));             
+        earlyExit._break(label);            
+      }
+      
+      if (out.isOptional()) {
+        assert (e != null);
+        
+        JConditional notSetJC = eval._if(e.eq(JExpr.lit(0)));
+        notSetJC._then().assign(out.getIsSet(), JExpr.lit(0));
+        
+        JBlock setBlock = notSetJC._else().block();
+        setBlock.assign(out.getIsSet(), JExpr.lit(1));
+        setBlock.assign(out.getValue(), JExpr.lit(1));
+      } else {
+        assert (e == null);            
+        eval.assign(out.getValue(), JExpr.lit(1)) ;
+      }
+      
+      generator.unNestEvalBlock();     // exit from nested block 
+      
+      return out;
+    }
+    
+    private HoldingContainer visitBooleanOr(FunctionHolderExpression holderExpr,
+        ClassGenerator<?> generator) {
+      
+      HoldingContainer out = generator.declare(holderExpr.getMajorType());
+      
+      JLabel label = generator.getEvalBlockLabel("OrOP");
+      JBlock eval = generator.getEvalBlock().block();
+      generator.nestEvalBlock(eval);   // enter into nested block. 
+
+      HoldingContainer arg = null;
+      
+      JExpression e = null;
+
+      //  value of boolean "or" when one side is null
+      //    p       q       p and q
+      //    true    null     true
+      //    false   null     null
+      //    null    true     true
+      //    null    false    null
+      //    null    null     null
+      
+      for (int i = 0; i < holderExpr.args.size(); i++) {
+        arg = holderExpr.args.get(i).accept(this, generator);
+        
+        JBlock earlyExit = null;
+        if (arg.isOptional()) {
+          earlyExit = eval._if(arg.getIsSet().eq(JExpr.lit(1)).cand(arg.getValue().eq(JExpr.lit(1))))._then();          
+          if(e == null){
+            e = arg.getIsSet();
+          }else{
+            e = e.mul(arg.getIsSet());
+          }            
+        } else {
+          earlyExit = eval._if(arg.getValue().eq(JExpr.lit(1)))._then();               
+        }
+        
+        if (out.isOptional()) {
+          earlyExit.assign(out.getIsSet(), JExpr.lit(1));
+        } 
+        
+        earlyExit.assign(out.getValue(),  JExpr.lit(1));             
+        earlyExit._break(label);            
+      }
+      
+      if (out.isOptional()) {
+        assert (e != null);
+        
+        JConditional notSetJC = eval._if(e.eq(JExpr.lit(0)));
+        notSetJC._then().assign(out.getIsSet(), JExpr.lit(0));
+        
+        JBlock setBlock = notSetJC._else().block();
+        setBlock.assign(out.getIsSet(), JExpr.lit(1));
+        setBlock.assign(out.getValue(), JExpr.lit(0));
+      } else {
+        assert (e == null);            
+        eval.assign(out.getValue(), JExpr.lit(0)) ;
+      }
+      
+      generator.unNestEvalBlock();   // exit from nested block. 
+      
+      return out;
+    }
+    
   }
 
   private class ConstantFilter extends EvalVisitor {

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/38dde9e9/exec/java-exec/src/main/java/org/apache/drill/exec/expr/annotations/FunctionTemplate.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/annotations/FunctionTemplate.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/annotations/FunctionTemplate.java
index 9d7091d..b364a4a 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/annotations/FunctionTemplate.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/annotations/FunctionTemplate.java
@@ -61,6 +61,7 @@ public @interface FunctionTemplate {
     DECIMAL_CAST,
     DECIMAL_DIV_SCALE,
     DECIMAL_SET_SCALE,
-    DECIMAL_ZERO_SCALE;
+    DECIMAL_ZERO_SCALE,
+    SC_BOOLEAN_OPERATOR
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/38dde9e9/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillSCBooleanOPHolder.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillSCBooleanOPHolder.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillSCBooleanOPHolder.java
new file mode 100644
index 0000000..d6d7037
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillSCBooleanOPHolder.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.drill.exec.expr.fn;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.drill.exec.expr.annotations.FunctionTemplate.FunctionScope;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate.NullHandling;
+
+public class DrillSCBooleanOPHolder extends DrillSimpleFuncHolder{
+
+  public DrillSCBooleanOPHolder(FunctionScope scope, NullHandling nullHandling, boolean isBinaryCommutative, boolean isRandom,
+      String[] registeredNames, ValueReference[] parameters, ValueReference returnValue, WorkspaceReference[] workspaceVars,
+      Map<String, String> methods, List<String> imports) {
+    super(scope, nullHandling, isBinaryCommutative, isRandom, registeredNames, parameters, returnValue, workspaceVars, methods, imports);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/38dde9e9/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java
index 75c3cbb..2107421 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java
@@ -235,6 +235,12 @@ public class FunctionConverter {
                                            template.isBinaryCommutative(),
                                            template.isRandom(), registeredNames, 
                                            ps, outputField, works, methods, imports);
+      case SC_BOOLEAN_OPERATOR:
+        return new DrillSCBooleanOPHolder(template.scope(), template.nulls(), 
+            template.isBinaryCommutative(),
+            template.isRandom(), registeredNames, 
+            ps, outputField, works, methods, imports);
+        
       case DECIMAL_MAX_SCALE:
           return new DrillDecimalMaxScaleFuncHolder(template.scope(), template.nulls(), template.isBinaryCommutative(),
                   template.isRandom(), registeredNames, ps, outputField, works, methods, imports);

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/38dde9e9/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/BitFunctions.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/BitFunctions.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/BitFunctions.java
index 1ea4988..3ffc682 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/BitFunctions.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/BitFunctions.java
@@ -29,7 +29,7 @@ import org.apache.drill.exec.record.RecordBatch;
 
 public class BitFunctions {
   
-  @FunctionTemplate(names = {"booleanOr", "or", "||"}, scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+  @FunctionTemplate(names = {"booleanOr", "or", "||"}, scope = FunctionScope.SC_BOOLEAN_OPERATOR, nulls = NullHandling.NULL_IF_NULL)
   public static class BitOr implements DrillSimpleFunc {
 
     @Param BitHolder left;
@@ -43,7 +43,7 @@ public class BitFunctions {
     }
   }  
 
-  @FunctionTemplate(names = {"booleanAnd", "and", "&&"}, scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+  @FunctionTemplate(names = {"booleanAnd", "and", "&&"}, scope = FunctionScope.SC_BOOLEAN_OPERATOR, nulls = NullHandling.NULL_IF_NULL)
   public static class BitAnd implements DrillSimpleFunc {
 
     @Param BitHolder left;