/* * Licensed 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 com.facebook.presto.sql.gen; import com.facebook.presto.SequencePageBuilder; import com.facebook.presto.Session; import com.facebook.presto.metadata.Metadata; import com.facebook.presto.operator.CursorProcessor; import com.facebook.presto.operator.index.PageRecordSet; import com.facebook.presto.operator.project.PageProcessor; import com.facebook.presto.spi.Page; import com.facebook.presto.spi.PageBuilder; import com.facebook.presto.spi.RecordSet; import com.facebook.presto.spi.type.Type; import com.facebook.presto.sql.parser.SqlParser; import com.facebook.presto.sql.planner.Symbol; import com.facebook.presto.sql.planner.SymbolToInputRewriter; import com.facebook.presto.sql.relational.RowExpression; import com.facebook.presto.sql.relational.SqlToRowExpressionTranslator; import com.facebook.presto.sql.tree.Expression; import com.facebook.presto.testing.TestingSession; import com.facebook.presto.util.maps.IdentityLinkedHashMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; 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.Warmup; 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 org.openjdk.jmh.runner.options.VerboseMode; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; import static com.facebook.presto.metadata.FunctionKind.SCALAR; import static com.facebook.presto.metadata.MetadataManager.createTestMetadataManager; import static com.facebook.presto.operator.scalar.FunctionAssertions.createExpression; import static com.facebook.presto.spi.type.BigintType.BIGINT; import static com.facebook.presto.spi.type.VarcharType.VARCHAR; import static com.facebook.presto.sql.analyzer.ExpressionAnalyzer.getExpressionTypesFromInput; import static java.util.Collections.emptyList; import static java.util.Locale.ENGLISH; import static java.util.stream.Collectors.toList; @SuppressWarnings({"PackageVisibleField", "FieldCanBeLocal"}) @State(Scope.Thread) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Fork(10) @Warmup(iterations = 10) @Measurement(iterations = 10) @BenchmarkMode(Mode.AverageTime) public class PageProcessorBenchmark { private static final Map<String, Type> TYPE_MAP = ImmutableMap.of("bigint", BIGINT, "varchar", VARCHAR); private static final SqlParser SQL_PARSER = new SqlParser(); private static final Metadata METADATA = createTestMetadataManager(); private static final Session TEST_SESSION = TestingSession.testSessionBuilder().build(); private static final int POSITIONS = 1024; private final Map<Symbol, Type> symbolTypes = new HashMap<>(); private final Map<Symbol, Integer> sourceLayout = new HashMap<>(); private CursorProcessor cursorProcessor; private PageProcessor pageProcessor; private Page inputPage; private RecordSet recordSet; private List<Type> types; @Param({ "2", "4", "8", "16", "32" }) int columnCount; @Param({ "varchar", "bigint" }) String type; @Param({ "false", "true" }) boolean dictionaryBlocks; @Setup public void setup() { Type type = TYPE_MAP.get(this.type); for (int i = 0; i < columnCount; i++) { Symbol symbol = new Symbol(type.getDisplayName().toLowerCase(ENGLISH) + i); symbolTypes.put(symbol, type); sourceLayout.put(symbol, i); } List<RowExpression> projections = getProjections(type); types = projections.stream().map(RowExpression::getType).collect(toList()); inputPage = createPage(types, dictionaryBlocks); pageProcessor = new ExpressionCompiler(createTestMetadataManager()).compilePageProcessor(Optional.of(getFilter(type)), projections).get(); recordSet = new PageRecordSet(types, inputPage); cursorProcessor = new ExpressionCompiler(createTestMetadataManager()).compileCursorProcessor(Optional.of(getFilter(type)), projections, "key").get(); } @Benchmark public Page rowOriented() { PageBuilder pageBuilder = new PageBuilder(types); cursorProcessor.process(null, recordSet.cursor(), inputPage.getPositionCount(), pageBuilder); return pageBuilder.build(); } @Benchmark public List<Page> columnOriented() { return ImmutableList.copyOf(pageProcessor.process(null, inputPage)); } private RowExpression getFilter(Type type) { if (type == VARCHAR) { return rowExpression("cast(varchar0 as bigint) % 2 = 0", VARCHAR); } if (type == BIGINT) { return rowExpression("bigint0 % 2 = 0", BIGINT); } throw new IllegalArgumentException("filter not supported for type : " + type); } private List<RowExpression> getProjections(Type type) { ImmutableList.Builder<RowExpression> builder = ImmutableList.builder(); if (type == BIGINT) { for (int i = 0; i < columnCount; i++) { builder.add(rowExpression("bigint" + i + " + 5", type)); } } else if (type == VARCHAR) { for (int i = 0; i < columnCount; i++) { // alternatively use identity expression rowExpression("varchar" + i, type) or // rowExpression("substr(varchar" + i + ", 1, 1)", type) builder.add(rowExpression("concat(varchar" + i + ", 'foo')", type)); } } return builder.build(); } private RowExpression rowExpression(String expression, Type type) { SymbolToInputRewriter symbolToInputRewriter = new SymbolToInputRewriter(sourceLayout); Expression inputReferenceExpression = symbolToInputRewriter.rewrite(createExpression(expression, METADATA, symbolTypes)); ImmutableMap.Builder<Integer, Type> builder = ImmutableMap.builder(); for (int i = 0; i < columnCount; i++) { builder.put(i, type); } Map<Integer, Type> types = builder.build(); IdentityLinkedHashMap<Expression, Type> expressionTypes = getExpressionTypesFromInput(TEST_SESSION, METADATA, SQL_PARSER, types, inputReferenceExpression, emptyList()); return SqlToRowExpressionTranslator.translate(inputReferenceExpression, SCALAR, expressionTypes, METADATA.getFunctionRegistry(), METADATA.getTypeManager(), TEST_SESSION, true); } private static Page createPage(List<? extends Type> types, boolean dictionary) { if (dictionary) { return SequencePageBuilder.createSequencePageWithDictionaryBlocks(types, POSITIONS); } else { return SequencePageBuilder.createSequencePage(types, POSITIONS); } } public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .verbosity(VerboseMode.NORMAL) .include(".*" + PageProcessorBenchmark.class.getSimpleName() + ".*") .build(); new Runner(options).run(); } }