You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2016/01/21 23:38:45 UTC

[08/50] [abbrv] calcite git commit: Add benchmark of Parser.create(sql).parseQuery()

Add benchmark of Parser.create(sql).parseQuery()

Closes #176


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/4a29b3cc
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/4a29b3cc
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/4a29b3cc

Branch: refs/heads/branch-release
Commit: 4a29b3ccf64e9a7d1534f540fd7f6d3d813605a0
Parents: b94a00e
Author: Vladimir Sitnikov <si...@gmail.com>
Authored: Sat Jan 9 13:36:33 2016 +0300
Committer: Julian Hyde <jh...@apache.org>
Committed: Sun Jan 10 00:46:49 2016 -0800

----------------------------------------------------------------------
 .../apache/calcite/sql/parser/SqlParser.java    |  25 +-
 pom.xml                                         |   4 +-
 ubenchmark/pom.xml                              |   5 +-
 .../java/org/apache/calcite/StatementTest.java  | 264 -------------------
 .../benchmarks/FlightRecorderProfiler.java      |  87 ++++++
 .../calcite/benchmarks/ParserBenchmark.java     | 121 +++++++++
 .../calcite/benchmarks/PreconditionTest.java    |  56 ++++
 .../calcite/benchmarks/StatementTest.java       | 264 +++++++++++++++++++
 .../apache/calcite/benchmarks/package-info.java |  26 ++
 9 files changed, 575 insertions(+), 277 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/4a29b3cc/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java b/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java
index 4c14395..e1bda73 100644
--- a/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java
+++ b/core/src/main/java/org/apache/calcite/sql/parser/SqlParser.java
@@ -133,22 +133,27 @@ public class SqlParser {
   }
 
   /**
+   * Parses a <code>SELECT</code> statement and reuses parser.
+   *
+   * @param sql sql to parse
+   * @return A {@link org.apache.calcite.sql.SqlSelect} for a regular <code>
+   * SELECT</code> statement; a {@link org.apache.calcite.sql.SqlBinaryOperator}
+   * for a <code>UNION</code>, <code>INTERSECT</code>, or <code>EXCEPT</code>.
+   * @throws SqlParseException if there is a parse error
+   */
+  public SqlNode parseQuery(String sql) throws SqlParseException {
+    parser.ReInit(new StringReader(sql));
+    return parseQuery();
+  }
+
+  /**
    * Parses an SQL statement.
    *
    * @return top-level SqlNode representing stmt
    * @throws SqlParseException if there is a parse error
    */
   public SqlNode parseStmt() throws SqlParseException {
-    try {
-      return parser.parseSqlStmtEof();
-    } catch (Throwable ex) {
-      if ((ex instanceof CalciteContextException)
-          && (originalInput != null)) {
-        ((CalciteContextException) ex).setOriginalStatement(
-            originalInput);
-      }
-      throw parser.normalizeException(ex);
-    }
+    return parseQuery();
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/4a29b3cc/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 9ac5596..3253f25 100644
--- a/pom.xml
+++ b/pom.xml
@@ -295,12 +295,12 @@ limitations under the License.
       <dependency>
         <groupId>org.openjdk.jmh</groupId>
         <artifactId>jmh-core</artifactId>
-        <version>0.7.1</version>
+        <version>1.11.2</version>
       </dependency>
       <dependency>
         <groupId>org.openjdk.jmh</groupId>
         <artifactId>jmh-generator-annprocess</artifactId>
-        <version>0.7.1</version>
+        <version>1.11.2</version>
       </dependency>
       <dependency>
         <groupId>sqlline</groupId>

http://git-wip-us.apache.org/repos/asf/calcite/blob/4a29b3cc/ubenchmark/pom.xml
----------------------------------------------------------------------
diff --git a/ubenchmark/pom.xml b/ubenchmark/pom.xml
index 1f1752c..e50d4dd 100644
--- a/ubenchmark/pom.xml
+++ b/ubenchmark/pom.xml
@@ -55,6 +55,10 @@ limitations under the License.
       <artifactId>jmh-generator-annprocess</artifactId>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
   </dependencies>
 
   <build>
@@ -64,7 +68,6 @@ limitations under the License.
         <configuration>
           <source>1.6</source>
           <target>1.6</target>
-          <compilerArgument>-proc:none</compilerArgument>
         </configuration>
       </plugin>
       <plugin>

http://git-wip-us.apache.org/repos/asf/calcite/blob/4a29b3cc/ubenchmark/src/main/java/org/apache/calcite/StatementTest.java
----------------------------------------------------------------------
diff --git a/ubenchmark/src/main/java/org/apache/calcite/StatementTest.java b/ubenchmark/src/main/java/org/apache/calcite/StatementTest.java
deleted file mode 100644
index b8a7d2f..0000000
--- a/ubenchmark/src/main/java/org/apache/calcite/StatementTest.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * 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.calcite;
-
-import org.apache.calcite.adapter.java.ReflectiveSchema;
-import org.apache.calcite.jdbc.CalciteConnection;
-import org.apache.calcite.schema.SchemaPlus;
-
-import org.openjdk.jmh.annotations.BenchmarkMode;
-import org.openjdk.jmh.annotations.GenerateMicroBenchmark;
-import org.openjdk.jmh.annotations.Level;
-import org.openjdk.jmh.annotations.Mode;
-import org.openjdk.jmh.annotations.Scope;
-import org.openjdk.jmh.annotations.Setup;
-import org.openjdk.jmh.annotations.State;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Properties;
-import java.util.Random;
-
-/**
- * Compares {@link java.sql.Statement} vs {@link java.sql.PreparedStatement}.
- *
- * <p>This package contains micro-benchmarks to test calcite performance.
- *
- * <p>To run this and other benchmarks:
- *
- * <blockquote>
- *   <code>mvn package &amp;&amp;
- *   java -jar ./target/ubenchmarks.jar -wi 5 -i 5 -f 1</code>
- * </blockquote>
- *
- * <p>To run with profiling:
- *
- * <blockquote>
- *   <code>java -Djmh.stack.lines=10 -jar ./target/ubenchmarks.jar
- *     -prof hs_comp,hs_gc,stack -f 1 -wi 5</code>
- * </blockquote>
- */
-public class StatementTest {
-
-  /**
-   * Connection to be used during tests.
-   */
-  @State(Scope.Thread)
-  @BenchmarkMode(Mode.AverageTime)
-  public static class HrConnection {
-    Connection con;
-    int id;
-    HrSchema hr = new HrSchema();
-    Random rnd = new Random();
-    {
-      try {
-        Class.forName("org.apache.calcite.jdbc.Driver");
-      } catch (ClassNotFoundException e) {
-        throw new IllegalStateException(e);
-      }
-      Connection connection;
-
-      try {
-        Properties info = new Properties();
-        info.put("lex", "JAVA");
-        info.put("quoting", "DOUBLE_QUOTE");
-        connection = DriverManager.getConnection("jdbc:calcite:", info);
-      } catch (SQLException e) {
-        throw new IllegalStateException(e);
-      }
-      CalciteConnection calciteConnection;
-      try {
-        calciteConnection = connection.unwrap(CalciteConnection.class);
-      } catch (SQLException e) {
-        throw new IllegalStateException(e);
-      }
-      final SchemaPlus rootSchema = calciteConnection.getRootSchema();
-      rootSchema.add("hr", new ReflectiveSchema(new HrSchema()));
-      try {
-        calciteConnection.setSchema("hr");
-      } catch (SQLException e) {
-        throw new IllegalStateException(e);
-      }
-      con = connection;
-    }
-
-    @Setup(Level.Iteration)
-    public void pickEmployee() {
-      id = hr.emps[rnd.nextInt(4)].empid;
-    }
-  }
-
-  /**
-   * Tests performance of reused execution of prepared statement.
-   */
-  public static class HrPreparedStatement extends HrConnection {
-    PreparedStatement ps;
-    {
-      try {
-        ps = con.prepareStatement("select name from emps where empid = ?");
-      } catch (SQLException e) {
-        throw new IllegalStateException(e);
-      }
-    }
-  }
-
-  @GenerateMicroBenchmark
-  public String prepareBindExecute(HrConnection state) throws SQLException {
-    Connection con = state.con;
-    Statement st = null;
-    ResultSet rs = null;
-    String ename = null;
-    try {
-      final PreparedStatement ps =
-          con.prepareStatement("select name from emps where empid = ?");
-      st = ps;
-      ps.setInt(1, state.id);
-      rs = ps.executeQuery();
-      rs.next();
-      ename = rs.getString(1);
-    } finally {
-      close(rs, st);
-    }
-    return ename;
-  }
-
-  @GenerateMicroBenchmark
-  public String bindExecute(HrPreparedStatement state)
-      throws SQLException {
-    PreparedStatement st = state.ps;
-    ResultSet rs = null;
-    String ename = null;
-    try {
-      st.setInt(1, state.id);
-      rs = st.executeQuery();
-      rs.next();
-      ename = rs.getString(1);
-    } finally {
-      close(rs, null); // Statement is not closed
-    }
-    return ename;
-  }
-
-  @GenerateMicroBenchmark
-  public String executeQuery(HrConnection state) throws SQLException {
-    Connection con = state.con;
-    Statement st = null;
-    ResultSet rs = null;
-    String ename = null;
-    try {
-      st = con.createStatement();
-      rs = st.executeQuery("select name from emps where empid = " + state.id);
-      rs.next();
-      ename = rs.getString(1);
-    } finally {
-      close(rs, st);
-    }
-    return ename;
-  }
-
-  @GenerateMicroBenchmark
-  public String forEach(HrConnection state) throws SQLException {
-    final Employee[] emps = state.hr.emps;
-    for (Employee emp : emps) {
-      if (emp.empid == state.id) {
-        return emp.name;
-      }
-    }
-    return null;
-  }
-
-  private static void close(ResultSet rs, Statement st) {
-    if (rs != null) {
-      try { rs.close(); } catch (SQLException e) { /**/ }
-    }
-    if (st != null) {
-      try { st.close(); } catch (SQLException e) { /**/ }
-    }
-  }
-
-  /** Pojo schema containing "emps" and "depts" tables. */
-  public static class HrSchema {
-    @Override public String toString() {
-      return "HrSchema";
-    }
-
-    public final Employee[] emps = {
-      new Employee(100, 10, "Bill", 10000, 1000),
-      new Employee(200, 20, "Eric", 8000, 500),
-      new Employee(150, 10, "Sebastian", 7000, null),
-      new Employee(110, 10, "Theodore", 11500, 250),
-    };
-    public final Department[] depts = {
-      new Department(10, "Sales", Arrays.asList(emps[0], emps[2])),
-      new Department(30, "Marketing", Collections.<Employee>emptyList()),
-      new Department(40, "HR", Collections.singletonList(emps[1])),
-    };
-  }
-
-  /** Employee record. */
-  public static class Employee {
-    public final int empid;
-    public final int deptno;
-    public final String name;
-    public final float salary;
-    public final Integer commission;
-
-    public Employee(int empid, int deptno, String name, float salary,
-        Integer commission) {
-      this.empid = empid;
-      this.deptno = deptno;
-      this.name = name;
-      this.salary = salary;
-      this.commission = commission;
-    }
-
-    public String toString() {
-      return "Employee [empid: " + empid + ", deptno: " + deptno
-          + ", name: " + name + "]";
-    }
-  }
-
-  /** Department record. */
-  public static class Department {
-    public final int deptno;
-    public final String name;
-    public final List<Employee> employees;
-
-    public Department(
-        int deptno, String name, List<Employee> employees) {
-      this.deptno = deptno;
-      this.name = name;
-      this.employees = employees;
-    }
-
-
-    public String toString() {
-      return "Department [deptno: " + deptno + ", name: " + name
-          + ", employees: " + employees + "]";
-    }
-  }
-
-}
-
-// End StatementTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/4a29b3cc/ubenchmark/src/main/java/org/apache/calcite/benchmarks/FlightRecorderProfiler.java
----------------------------------------------------------------------
diff --git a/ubenchmark/src/main/java/org/apache/calcite/benchmarks/FlightRecorderProfiler.java b/ubenchmark/src/main/java/org/apache/calcite/benchmarks/FlightRecorderProfiler.java
new file mode 100644
index 0000000..451c004
--- /dev/null
+++ b/ubenchmark/src/main/java/org/apache/calcite/benchmarks/FlightRecorderProfiler.java
@@ -0,0 +1,87 @@
+/*
+ * 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.calcite.benchmarks;
+
+import org.openjdk.jmh.infra.BenchmarkParams;
+import org.openjdk.jmh.infra.IterationParams;
+import org.openjdk.jmh.profile.ExternalProfiler;
+import org.openjdk.jmh.results.BenchmarkResult;
+import org.openjdk.jmh.results.Result;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Captures Flight Recorder log.
+ * Note: Flight Recorder is available in OracleJDK only.
+ * Usage of Flight Recorder in production requires a LICENSE FEE, however Flight Recorder is free
+ * for use in test systems.
+ * It is assumed you would not use Calcite benchmarks for running a production system, thus it is
+ * believed to be safe.
+ */
+public class FlightRecorderProfiler implements ExternalProfiler {
+  @Override public Collection<String> addJVMInvokeOptions(BenchmarkParams params) {
+    return Collections.emptyList();
+  }
+
+  @Override public Collection<String> addJVMOptions(BenchmarkParams params) {
+    StringBuilder sb = new StringBuilder();
+    for (String param : params.getParamsKeys()) {
+      if (sb.length() != 0) {
+        sb.append('-');
+      }
+      sb.append(param).append('-').append(params.getParam(param));
+    }
+
+    long duration =
+        getDurationSeconds(params.getWarmup()) + getDurationSeconds(params.getMeasurement());
+    return Arrays.asList(
+        "-XX:+UnlockCommercialFeatures", "-XX:+FlightRecorder",
+        "-XX:StartFlightRecording=settings=profile,duration=" + duration + "s,filename="
+            + params.getBenchmark() + "_" + sb + ".jfr");
+  }
+
+  private long getDurationSeconds(IterationParams warmup) {
+    return warmup.getTime().convertTo(TimeUnit.SECONDS) * warmup.getCount();
+  }
+
+  @Override public void beforeTrial(BenchmarkParams benchmarkParams) {
+
+  }
+
+  @Override public Collection<? extends Result> afterTrial(BenchmarkResult br, long pid,
+      File stdOut, File stdErr) {
+    return Collections.emptyList();
+  }
+
+  @Override public boolean allowPrintOut() {
+    return true;
+  }
+
+  @Override public boolean allowPrintErr() {
+    return true;
+  }
+
+  @Override public String getDescription() {
+    return "Collects Java Flight Recorder profile";
+  }
+}
+
+// End FlightRecorderProfiler.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/4a29b3cc/ubenchmark/src/main/java/org/apache/calcite/benchmarks/ParserBenchmark.java
----------------------------------------------------------------------
diff --git a/ubenchmark/src/main/java/org/apache/calcite/benchmarks/ParserBenchmark.java b/ubenchmark/src/main/java/org/apache/calcite/benchmarks/ParserBenchmark.java
new file mode 100644
index 0000000..90e4e8a
--- /dev/null
+++ b/ubenchmark/src/main/java/org/apache/calcite/benchmarks/ParserBenchmark.java
@@ -0,0 +1,121 @@
+/*
+ * 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.calcite.benchmarks;
+
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.parser.SqlParseException;
+import org.apache.calcite.sql.parser.SqlParser;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.profile.GCProfiler;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Benchmarks JavaCC-generated SQL parser
+ */
+@Fork(value = 1, jvmArgsPrepend = "-Xmx128m")
+@Measurement(iterations = 7, time = 1, timeUnit = TimeUnit.SECONDS)
+@Warmup(iterations = 7, time = 1, timeUnit = TimeUnit.SECONDS)
+@State(Scope.Thread)
+@Threads(1)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+public class ParserBenchmark {
+
+  @Param({ "1000" })
+  int length;
+
+  @Param({ "true" })
+  boolean comments;
+
+  String sql;
+  SqlParser parser;
+
+  @Setup
+  public void setup() throws SqlParseException {
+    StringBuilder sb = new StringBuilder((int) (length * 1.2));
+    sb.append("select 1");
+    Random rnd = new Random();
+    rnd.setSeed(424242);
+    for (; sb.length() < length;) {
+      for (int i = 0; i < 7 && sb.length() < length; i++) {
+        sb.append(", ");
+        switch (rnd.nextInt(3)) {
+        case 0:
+          sb.append("?");
+          break;
+        case 1:
+          sb.append(rnd.nextInt());
+          break;
+        case 2:
+          sb.append('\'').append(rnd.nextLong()).append(rnd.nextLong())
+              .append('\'');
+          break;
+        }
+      }
+      if (comments && sb.length() < length) {
+        sb.append("// sb.append('\\'').append(rnd.nextLong()).append(rnd.nextLong()).append(rnd"
+            + ".nextLong())");
+      }
+      sb.append('\n');
+    }
+    sb.append(" from dual");
+    parser = SqlParser.create("values(1)");
+    sql = sb.toString();
+  }
+
+  @Benchmark
+  public SqlNode parseCached() throws SqlParseException {
+    return parser.parseQuery(sql);
+  }
+
+  @Benchmark
+  public SqlNode parseNonCached() throws SqlParseException {
+    return SqlParser.create(sql).parseQuery();
+  }
+
+  public static void main(String[] args) throws RunnerException {
+    Options opt = new OptionsBuilder()
+        .include(ParserBenchmark.class.getSimpleName())
+        .addProfiler(GCProfiler.class)
+        .addProfiler(FlightRecorderProfiler.class)
+        .detectJvmArgs()
+        .build();
+
+    new Runner(opt).run();
+  }
+
+}
+
+// End ParserBenchmark.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/4a29b3cc/ubenchmark/src/main/java/org/apache/calcite/benchmarks/PreconditionTest.java
----------------------------------------------------------------------
diff --git a/ubenchmark/src/main/java/org/apache/calcite/benchmarks/PreconditionTest.java b/ubenchmark/src/main/java/org/apache/calcite/benchmarks/PreconditionTest.java
new file mode 100644
index 0000000..c150a49
--- /dev/null
+++ b/ubenchmark/src/main/java/org/apache/calcite/benchmarks/PreconditionTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.calcite.benchmarks;
+
+import com.google.common.base.Preconditions;
+
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.profile.GCProfiler;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+/**
+ * Checks if silent precondition has noticeable overhead
+ */
+@BenchmarkMode(Mode.AverageTime)
+@State(Scope.Benchmark)
+public class PreconditionTest {
+  boolean fire = false;
+  String param = "world";
+
+  public void testPrecondition() {
+    Preconditions.checkState(fire, "Hello %s", param);
+  }
+
+  public static void main(String[] args) throws RunnerException {
+    Options opt = new OptionsBuilder()
+        .include(PreconditionTest.class.getSimpleName())
+        .addProfiler(GCProfiler.class)
+        .detectJvmArgs()
+        .build();
+
+    new Runner(opt).run();
+  }
+
+}
+
+// End PreconditionTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/4a29b3cc/ubenchmark/src/main/java/org/apache/calcite/benchmarks/StatementTest.java
----------------------------------------------------------------------
diff --git a/ubenchmark/src/main/java/org/apache/calcite/benchmarks/StatementTest.java b/ubenchmark/src/main/java/org/apache/calcite/benchmarks/StatementTest.java
new file mode 100644
index 0000000..d716fdf
--- /dev/null
+++ b/ubenchmark/src/main/java/org/apache/calcite/benchmarks/StatementTest.java
@@ -0,0 +1,264 @@
+/*
+ * 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.calcite.benchmarks;
+
+import org.apache.calcite.adapter.java.ReflectiveSchema;
+import org.apache.calcite.jdbc.CalciteConnection;
+import org.apache.calcite.schema.SchemaPlus;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import java.util.Random;
+
+/**
+ * Compares {@link java.sql.Statement} vs {@link java.sql.PreparedStatement}.
+ *
+ * <p>This package contains micro-benchmarks to test calcite performance.
+ *
+ * <p>To run this and other benchmarks:
+ *
+ * <blockquote>
+ *   <code>mvn package &amp;&amp;
+ *   java -jar ./target/ubenchmarks.jar -wi 5 -i 5 -f 1</code>
+ * </blockquote>
+ *
+ * <p>To run with profiling:
+ *
+ * <blockquote>
+ *   <code>java -Djmh.stack.lines=10 -jar ./target/ubenchmarks.jar
+ *     -prof hs_comp,hs_gc,stack -f 1 -wi 5</code>
+ * </blockquote>
+ */
+public class StatementTest {
+
+  /**
+   * Connection to be used during tests.
+   */
+  @State(Scope.Thread)
+  @BenchmarkMode(Mode.AverageTime)
+  public static class HrConnection {
+    Connection con;
+    int id;
+    HrSchema hr = new HrSchema();
+    Random rnd = new Random();
+    {
+      try {
+        Class.forName("org.apache.calcite.jdbc.Driver");
+      } catch (ClassNotFoundException e) {
+        throw new IllegalStateException(e);
+      }
+      Connection connection;
+
+      try {
+        Properties info = new Properties();
+        info.put("lex", "JAVA");
+        info.put("quoting", "DOUBLE_QUOTE");
+        connection = DriverManager.getConnection("jdbc:calcite:", info);
+      } catch (SQLException e) {
+        throw new IllegalStateException(e);
+      }
+      CalciteConnection calciteConnection;
+      try {
+        calciteConnection = connection.unwrap(CalciteConnection.class);
+      } catch (SQLException e) {
+        throw new IllegalStateException(e);
+      }
+      final SchemaPlus rootSchema = calciteConnection.getRootSchema();
+      rootSchema.add("hr", new ReflectiveSchema(new HrSchema()));
+      try {
+        calciteConnection.setSchema("hr");
+      } catch (SQLException e) {
+        throw new IllegalStateException(e);
+      }
+      con = connection;
+    }
+
+    @Setup(Level.Iteration)
+    public void pickEmployee() {
+      id = hr.emps[rnd.nextInt(4)].empid;
+    }
+  }
+
+  /**
+   * Tests performance of reused execution of prepared statement.
+   */
+  public static class HrPreparedStatement extends HrConnection {
+    PreparedStatement ps;
+    {
+      try {
+        ps = con.prepareStatement("select name from emps where empid = ?");
+      } catch (SQLException e) {
+        throw new IllegalStateException(e);
+      }
+    }
+  }
+
+  @Benchmark
+  public String prepareBindExecute(HrConnection state) throws SQLException {
+    Connection con = state.con;
+    Statement st = null;
+    ResultSet rs = null;
+    String ename = null;
+    try {
+      final PreparedStatement ps =
+          con.prepareStatement("select name from emps where empid = ?");
+      st = ps;
+      ps.setInt(1, state.id);
+      rs = ps.executeQuery();
+      rs.next();
+      ename = rs.getString(1);
+    } finally {
+      close(rs, st);
+    }
+    return ename;
+  }
+
+  @Benchmark
+  public String bindExecute(HrPreparedStatement state)
+      throws SQLException {
+    PreparedStatement st = state.ps;
+    ResultSet rs = null;
+    String ename = null;
+    try {
+      st.setInt(1, state.id);
+      rs = st.executeQuery();
+      rs.next();
+      ename = rs.getString(1);
+    } finally {
+      close(rs, null); // Statement is not closed
+    }
+    return ename;
+  }
+
+  @Benchmark
+  public String executeQuery(HrConnection state) throws SQLException {
+    Connection con = state.con;
+    Statement st = null;
+    ResultSet rs = null;
+    String ename = null;
+    try {
+      st = con.createStatement();
+      rs = st.executeQuery("select name from emps where empid = " + state.id);
+      rs.next();
+      ename = rs.getString(1);
+    } finally {
+      close(rs, st);
+    }
+    return ename;
+  }
+
+  @Benchmark
+  public String forEach(HrConnection state) throws SQLException {
+    final Employee[] emps = state.hr.emps;
+    for (Employee emp : emps) {
+      if (emp.empid == state.id) {
+        return emp.name;
+      }
+    }
+    return null;
+  }
+
+  private static void close(ResultSet rs, Statement st) {
+    if (rs != null) {
+      try { rs.close(); } catch (SQLException e) { /**/ }
+    }
+    if (st != null) {
+      try { st.close(); } catch (SQLException e) { /**/ }
+    }
+  }
+
+  /** Pojo schema containing "emps" and "depts" tables. */
+  public static class HrSchema {
+    @Override public String toString() {
+      return "HrSchema";
+    }
+
+    public final Employee[] emps = {
+      new Employee(100, 10, "Bill", 10000, 1000),
+      new Employee(200, 20, "Eric", 8000, 500),
+      new Employee(150, 10, "Sebastian", 7000, null),
+      new Employee(110, 10, "Theodore", 11500, 250),
+    };
+    public final Department[] depts = {
+      new Department(10, "Sales", Arrays.asList(emps[0], emps[2])),
+      new Department(30, "Marketing", Collections.<Employee>emptyList()),
+      new Department(40, "HR", Collections.singletonList(emps[1])),
+    };
+  }
+
+  /** Employee record. */
+  public static class Employee {
+    public final int empid;
+    public final int deptno;
+    public final String name;
+    public final float salary;
+    public final Integer commission;
+
+    public Employee(int empid, int deptno, String name, float salary,
+        Integer commission) {
+      this.empid = empid;
+      this.deptno = deptno;
+      this.name = name;
+      this.salary = salary;
+      this.commission = commission;
+    }
+
+    public String toString() {
+      return "Employee [empid: " + empid + ", deptno: " + deptno
+          + ", name: " + name + "]";
+    }
+  }
+
+  /** Department record. */
+  public static class Department {
+    public final int deptno;
+    public final String name;
+    public final List<Employee> employees;
+
+    public Department(
+        int deptno, String name, List<Employee> employees) {
+      this.deptno = deptno;
+      this.name = name;
+      this.employees = employees;
+    }
+
+
+    public String toString() {
+      return "Department [deptno: " + deptno + ", name: " + name
+          + ", employees: " + employees + "]";
+    }
+  }
+
+}
+
+// End StatementTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/4a29b3cc/ubenchmark/src/main/java/org/apache/calcite/benchmarks/package-info.java
----------------------------------------------------------------------
diff --git a/ubenchmark/src/main/java/org/apache/calcite/benchmarks/package-info.java b/ubenchmark/src/main/java/org/apache/calcite/benchmarks/package-info.java
new file mode 100644
index 0000000..3146cae
--- /dev/null
+++ b/ubenchmark/src/main/java/org/apache/calcite/benchmarks/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * JMH benchmarks for Calcite
+ */
+@PackageMarker
+package org.apache.calcite.benchmarks;
+
+import org.apache.calcite.avatica.util.PackageMarker;
+
+// End package-info.java