blob: f5613a21b11141eadb42df0fba2df9320ba060dd [file] [log] [blame]
/*
* 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.parquet.benchmarks;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.BINARY;
import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.INT32;
import static org.apache.parquet.schema.Type.Repetition.OPTIONAL;
import static org.openjdk.jmh.annotations.Mode.SingleShotTime;
import static org.openjdk.jmh.annotations.Scope.Benchmark;
import java.io.IOException;
import java.util.Random;
import org.apache.parquet.example.data.Group;
import org.apache.parquet.example.data.GroupFactory;
import org.apache.parquet.example.data.simple.SimpleGroupFactory;
import org.apache.parquet.hadoop.ParquetFileWriter.Mode;
import org.apache.parquet.hadoop.ParquetWriter;
import org.apache.parquet.hadoop.example.ExampleParquetWriter;
import org.apache.parquet.io.OutputFile;
import org.apache.parquet.io.PositionOutputStream;
import org.apache.parquet.schema.MessageType;
import org.apache.parquet.schema.Types;
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.OutputTimeUnit;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
/**
* Benchmark to measure writing nested null values. (See PARQUET-343 for details.)
* <p>
* To execute this benchmark a jar file shall be created of this module. Then the jar file can be executed using the JMH
* framework.<br>
* The following one-liner (shall be executed in the parquet-benchmarks submodule) generates result statistics in the
* file {@code jmh-result.json}. This json might be visualized by using the tool at
* <a href="https://jmh.morethan.io">https://jmh.morethan.io</a>.
*
* <pre>
* mvn clean package &amp;&amp; java -jar target/parquet-benchmarks.jar org.apache.parquet.benchmarks.NestedNullWritingBenchmarks -rf json
* </pre>
*/
@BenchmarkMode(SingleShotTime)
@Fork(1)
@Warmup(iterations = 10, batchSize = 1)
@Measurement(iterations = 50, batchSize = 1)
@OutputTimeUnit(MILLISECONDS)
@State(Benchmark)
public class NestedNullWritingBenchmarks {
private static final MessageType SCHEMA = Types.buildMessage()
.optionalList()
.optionalElement(INT32)
.named("int_list")
.optionalList()
.optionalListElement()
.optionalElement(BINARY)
.named("dummy_list")
.optionalMap()
.key(BINARY)
.value(BINARY, OPTIONAL)
.named("dummy_map")
.optionalGroup()
.optional(BINARY).named("dummy_group_value1")
.optional(BINARY).named("dummy_group_value2")
.optional(BINARY).named("dummy_group_value3")
.named("dummy_group")
.named("msg");
private static final int RECORD_COUNT = 10_000_000;
private static final double NULL_RATIO = 0.99;
private static final OutputFile BLACK_HOLE = new OutputFile() {
@Override
public boolean supportsBlockSize() {
return false;
}
@Override
public long defaultBlockSize() {
return -1L;
}
@Override
public PositionOutputStream createOrOverwrite(long blockSizeHint) {
return create(blockSizeHint);
}
@Override
public PositionOutputStream create(long blockSizeHint) {
return new PositionOutputStream() {
private long pos;
@Override
public long getPos() throws IOException {
return pos;
}
@Override
public void write(int b) throws IOException {
++pos;
}
};
}
@Override
public String getPath() {
throw new UnsupportedOperationException();
}
};
private static class ValueGenerator {
private static final GroupFactory FACTORY = new SimpleGroupFactory(SCHEMA);
private static final Group NULL = FACTORY.newGroup();
private final Random random = new Random(42);
public Group nextValue() {
if (random.nextDouble() > NULL_RATIO) {
Group group = FACTORY.newGroup();
group.addGroup("int_list").addGroup("list").append("element", random.nextInt());
return group;
} else {
return NULL;
}
}
}
@Benchmark
public void benchmarkWriting() throws IOException {
ValueGenerator generator = new ValueGenerator();
try (ParquetWriter<Group> writer = ExampleParquetWriter.builder(BLACK_HOLE)
.withWriteMode(Mode.OVERWRITE)
.withType(SCHEMA)
.build()) {
for (int i = 0; i < RECORD_COUNT; ++i) {
writer.write(generator.nextValue());
}
}
}
}