blob: 860a5ed30d0e291ca3a1c29c63be52f295bba440 [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2005-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* more patents listed at http://www.pivotal.io/patents.
*========================================================================
*/
package com.gemstone.gemfire.cache.query;
import it.unimi.dsi.fastutil.floats.FloatArrayList;
import java.text.DateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import com.gemstone.gemfire.cache.AttributesFactory;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheException;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionAttributes;
import com.gemstone.gemfire.cache.execute.RegionFunctionContext;
import com.gemstone.gemfire.cache.query.data.Portfolio;
import com.gemstone.gemfire.cache.query.internal.ResultsSet;
import com.gemstone.gemfire.distributed.DistributedSystem;
import com.gemstone.gemfire.internal.NanoTimer;
/**
*
* @author Eric Zoerner
*/
public class PerfQuery {
private static int NUM_ITERATIONS = 20000;
// exec types
private static final int HAND_CODED = 0;
private static final int BRUTE_FORCE = 1;
private static final int INDEXED = 2;
private static final int INDEX_CREATE = 3;
private static final String[] execTypeStrings =
new String[] {"hand-coded", "brute force", "indexed", "index-create"};
private static final int[] DATA_SET_SIZES = new int[] {100, 1000, 10000 , 20000};
private DistributedSystem ds;
private Region region = null;
private RegionAttributes regionAttributes;
private QueryService qs;
protected Cache cache;
// RESULTS
private final FloatArrayList[] results;
/** Creates a new instance of PerfQuery */
public PerfQuery() {
results = new FloatArrayList[4];
results[BRUTE_FORCE] = new FloatArrayList();
results[HAND_CODED] = new FloatArrayList();
results[INDEXED] = new FloatArrayList();
results[INDEX_CREATE] = new FloatArrayList();
}
public void run() throws Exception {
Date startTime = new Date();
setUp();
DateFormat formatter = DateFormat.getDateTimeInstance();
System.out.println("Test started at: " + formatter.format(startTime));
runQueries();
printSummary();
tearDown();
Date endTime = new Date();
System.out.println("Test ended at: " + formatter.format(endTime));
long durationMs = endTime.getTime() - startTime.getTime();
long durationS = durationMs / 1000;
long durationM = durationS / 60;
long durationMM = durationM % 60;
long durationH = durationM / 60;
System.out.println("Test took " + durationH + "hrs, " + durationMM + "min.");
}
private void printSummary() {
System.out.println("Query Execution Performance Results Summary");
System.out.println("num iterations = " + NUM_ITERATIONS);
System.out.println();
System.out.println("Average query execution time in ms");
System.out.println();
String[] setNames = new String[] {"33% Retrieval", "0% Retrieval"};
for (int setI = 0; setI < setNames.length; setI++) {
String setName = setNames[setI];
System.out.println(setName + ":");
System.out.println("dataset size,hand-coded,brute-force,indexed,[index-create-time]");
for (int szi = 0; szi < DATA_SET_SIZES.length; szi++) {
System.out.print(DATA_SET_SIZES[szi]);
System.out.print(',');
for (int ti = HAND_CODED; ti <= INDEX_CREATE; ti++) {
// skip over first set of each type, which was warm up
int ix = ((setI + 1) * DATA_SET_SIZES.length) + szi;
System.out.print(results[ti].get(ix));
if (ti < INDEX_CREATE) {
System.out.print(',');
}
}
System.out.println();
}
System.out.println();
}
}
private void runQueries() throws Exception {
String queryString;
Query query;
// WARM-UP
System.out.println("WARMING UP...");
queryString = "select distinct * from /portfolios where type = 'type1'";
query = this.qs.newQuery(queryString);
runQuery(getType1HandQuery(queryString), HAND_CODED);
runQuery(query, BRUTE_FORCE);
runQuery(query, INDEXED);
warmUpIndexCreation();
System.out.println("END WARM UP");
// 1/3 DATASET
queryString = "select distinct * from /portfolios where type = 'type1'";
query = this.qs.newQuery(queryString);
runQuery(getType1HandQuery(queryString), HAND_CODED);
runQuery(query, BRUTE_FORCE);
runQuery(query, INDEXED);
// MISS QUERY
queryString = "select distinct * from /portfolios where type = 'miss'";
query = this.qs.newQuery(queryString);
runQuery(getMissHandQuery(queryString), HAND_CODED);
runQuery(query, BRUTE_FORCE);
runQuery(query, INDEXED);
}
private void runQuery(Query query, int execType)
throws Exception {
System.out.println("Executing Query: " + query.getQueryString());
System.out.println("Num iterations=" + NUM_ITERATIONS);
System.out.println();
boolean indexed = execType == INDEXED;
for (int i = 0; i < DATA_SET_SIZES.length; i++) {
int num = DATA_SET_SIZES[i];
populate(num, indexed);
System.out.println("Executing (" + execTypeStrings[execType] + ")...");
long startTime = NanoTimer.getTime();
SelectResults results = null;
for (int j = 0; j < NUM_ITERATIONS; j++) {
results = (SelectResults)query.execute();
}
long totalTime = NanoTimer.getTime() - startTime;
System.out.println("results size =" + results.size());
float aveTime = totalTime / NUM_ITERATIONS / 1e6f;
System.out.println("ave execution time=" + aveTime + " ms");
this.results[execType].add(aveTime);
System.out.println();
}
System.out.println("--------------------------------------------");
}
//--------------------------------------------------------
// Hand-Coded Queries
private Query getType1HandQuery(String queryString) {
return new HandQuery(queryString) {
public Object execute() {
Region region = PerfQuery.this.cache.getRegion("/portfolios");
SelectResults results = new ResultsSet();
for (Iterator itr = region.values().iterator(); itr.hasNext(); ) {
Portfolio ptflo = (Portfolio)itr.next();
if ("type1".equals(ptflo.getType())) {
results.add(ptflo);
}
}
return results;
}
};
}
private Query getMissHandQuery(String queryString) {
return new HandQuery(queryString) {
public Object execute() {
Region region = PerfQuery.this.cache.getRegion("/portfolios");
SelectResults results = new ResultsSet();
for (Iterator itr = region.values().iterator(); itr.hasNext(); ) {
Portfolio ptflo = (Portfolio)itr.next();
if ("miss".equals(ptflo.getType())) {
results.add(ptflo);
}
}
return results;
}
};
}
//--------------------------------------------------------
private void setUp() throws CacheException {
this.ds = DistributedSystem.connect(new Properties());
this.cache = CacheFactory.create(ds);
AttributesFactory attributesFactory = new AttributesFactory();
attributesFactory.setValueConstraint(Portfolio.class);
this.regionAttributes = attributesFactory.create();
this.qs = this.cache.getQueryService();
}
private void tearDown() {
this.ds.disconnect();
}
private void populate(int numPortfolios, boolean indexed)
throws CacheException, QueryException {
System.out.println("Populating Cache with " + numPortfolios + " Portfolios");
if (this.region != null) {
this.region.localDestroyRegion();
}
this.region = cache.createRegion("portfolios", this.regionAttributes);
for (int i = 0; i < numPortfolios; i++) {
this.region.put(String.valueOf(i), new Portfolio(i));
}
if (indexed) {
System.out.println("Creating index...");
long startNanos = NanoTimer.getTime();
this.qs.createIndex("portfolios", IndexType.FUNCTIONAL, "type", "/portfolios");
float createTime = (NanoTimer.getTime() - startNanos) / 1e6f;
System.out.println("Index created in " + createTime + " ms.");
this.results[INDEX_CREATE].add(createTime);
}
}
private void warmUpIndexCreation() throws CacheException, QueryException {
System.out.println("Populating Cache with 1000 Portfolios");
if (this.region != null) {
this.region.localDestroyRegion();
}
this.region = cache.createRegion("portfolios", this.regionAttributes);
for (int i = 0; i < 1000; i++) {
this.region.put(String.valueOf(i), new Portfolio(i));
}
System.out.println("Warming up index creation...");
for (int i = 0; i < 20000; i++) {
Index index = this.qs.createIndex("portfolios", IndexType.FUNCTIONAL, "type", "/portfolios");
this.qs.removeIndex(index);
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws Exception {
new PerfQuery().run();
}
abstract class HandQuery implements Query {
private final String queryString;
HandQuery(String queryString) {
this.queryString = queryString;
}
public abstract Object execute()
throws FunctionDomainException, TypeMismatchException, NameResolutionException,
QueryInvocationTargetException;
public void compile()
throws TypeMismatchException, NameResolutionException {
// already compiled
}
public boolean isCompiled() {
return true;
}
public String getQueryString() {
return this.queryString;
}
public Object execute(Object[] params)
throws FunctionDomainException, TypeMismatchException, NameResolutionException,
QueryInvocationTargetException {
throw new UnsupportedOperationException();
}
public QueryStatistics getStatistics() {
throw new UnsupportedOperationException();
}
public Set getRegionsInQuery() {
throw new UnsupportedOperationException();
}
@Override
public Object execute(RegionFunctionContext context)
throws FunctionDomainException, TypeMismatchException,
NameResolutionException, QueryInvocationTargetException {
throw new UnsupportedOperationException();
}
@Override
public Object execute(RegionFunctionContext context, Object[] params)
throws FunctionDomainException, TypeMismatchException,
NameResolutionException, QueryInvocationTargetException {
throw new UnsupportedOperationException();
}
}
}