/**
* Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com)
*
* 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.linkedin.pinot.perf;
import com.google.common.util.concurrent.Uninterruptibles;
import com.linkedin.pinot.broker.requesthandler.OptimizationFlags;
import com.linkedin.pinot.common.request.BrokerRequest;
import com.linkedin.pinot.core.segment.index.SegmentMetadataImpl;
import com.linkedin.pinot.tools.perf.PerfBenchmarkDriver;
import com.linkedin.pinot.tools.perf.PerfBenchmarkDriverConf;
import java.io.File;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.I0Itec.zkclient.ZkClient;
import org.apache.helix.ZNRecord;
import org.apache.helix.manager.zk.ZNRecordSerializer;
import org.json.JSONObject;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
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.profile.StackProfiler;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;
@State(Scope.Benchmark)
@Fork(value = 1, jvmArgs = {"-server", "-Xmx8G", "-XX:MaxDirectMemorySize=16G"})
public class BenchmarkQueryEngine {
/** List of query patterns used in the benchmark */
private static final String[] QUERY_PATTERNS = new String[] {
"SELECT count(*) from myTable"
};
/** List of optimization flags to test,
* see {@link OptimizationFlags#getOptimizationFlags(BrokerRequest)} for the syntax
* used here. */
@Param({"", "-multipleOrEqualitiesToInClause"})
public String optimizationFlags;
/** List of query patterns indices to run */
@Param({"0"})
public int queryPattern;
/** The table name which contains the offline data, for example "myTable_OFFLINE." */
private static final String TABLE_NAME = "myTable_OFFLINE";
/** The directory that contains the unpacked data, for example "/data"
*
* In that directory, there should be a "myTable_OFFLINE" directory which contains unpacked segments, so the
* directory for "/data" should look like "/data/myTable_OFFLINE/mySegment_0/metadata.properties"
*/
private static final String DATA_DIRECTORY = "/home/someuser/data";
/**
* Whether or not to enable profiling information
*/
private static final boolean ENABLE_PROFILING = false;
PerfBenchmarkDriver _perfBenchmarkDriver;
boolean ranOnce = false;
@Setup
public void startPinot() throws Exception {
System.out.println("Using table name " + TABLE_NAME);
System.out.println("Using data directory " + DATA_DIRECTORY);
System.out.println("Starting pinot");
PerfBenchmarkDriverConf conf = new PerfBenchmarkDriverConf();
conf.setStartBroker(true);
conf.setStartController(true);
conf.setStartServer(true);
conf.setStartZookeeper(true);
conf.setUploadIndexes(false);
conf.setRunQueries(false);
conf.setServerInstanceSegmentTarDir(null);
conf.setServerInstanceDataDir(DATA_DIRECTORY);
conf.setConfigureResources(false);
_perfBenchmarkDriver = new PerfBenchmarkDriver(conf);
_perfBenchmarkDriver.run();
Set<String> tables = new HashSet<String>();
File[] segments = new File(DATA_DIRECTORY, TABLE_NAME).listFiles();
for (File segmentDir : segments) {
SegmentMetadataImpl segmentMetadata = new SegmentMetadataImpl(segmentDir);
if (!tables.contains(segmentMetadata.getTableName())) {
_perfBenchmarkDriver.configureTable(segmentMetadata.getTableName());
tables.add(segmentMetadata.getTableName());
}
System.out.println("Adding segment " + segmentDir.getAbsolutePath());
_perfBenchmarkDriver.addSegment(segmentMetadata);
}
ZkClient client = new ZkClient("localhost:2191", 10000, 10000, new ZNRecordSerializer());
ZNRecord record = client.readData("/PinotPerfTestCluster/EXTERNALVIEW/" + TABLE_NAME);
while (true) {
System.out.println("record = " + record);
Uninterruptibles.sleepUninterruptibly(10, TimeUnit.SECONDS);
int onlineSegmentCount = 0;
for (Map<String, String> instancesAndStates : record.getMapFields().values()) {
for (String state : instancesAndStates.values()) {
if (state.equals("ONLINE")) {
onlineSegmentCount++;
break;
}
}
}
System.out.println(onlineSegmentCount + " segments online out of " + segments.length);
if (onlineSegmentCount == segments.length) {
break;
}
record = client.readData("/PinotPerfTestCluster/EXTERNALVIEW/" + TABLE_NAME);
}
ranOnce = false;
System.out.println(
_perfBenchmarkDriver.postQuery(QUERY_PATTERNS[queryPattern], optimizationFlags).toString(2)
);
}
@Benchmark
@BenchmarkMode({Mode.SampleTime})
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public int sendQueryToPinot() throws Exception {
JSONObject returnValue = _perfBenchmarkDriver.postQuery(QUERY_PATTERNS[queryPattern], optimizationFlags);
return returnValue.getInt("totalDocs");
}
public static void main(String[] args) throws Exception {
ChainedOptionsBuilder opt = new OptionsBuilder()
.include(BenchmarkQueryEngine.class.getSimpleName())
.warmupTime(TimeValue.seconds(30))
.warmupIterations(4)
.measurementTime(TimeValue.seconds(30))
.measurementIterations(20);
if (ENABLE_PROFILING) {
opt = opt.addProfiler(StackProfiler.class,
"excludePackages=true;excludePackageNames=sun.,java.net.,io.netty.,org.apache.zookeeper.,org.eclipse.jetty.;lines=5;period=1;top=20");
}
new Runner(opt.build()).run();
}
}