/* * 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.geode.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 org.apache.geode.cache.AttributesFactory; import org.apache.geode.cache.Cache; import org.apache.geode.cache.CacheException; import org.apache.geode.cache.CacheFactory; import org.apache.geode.cache.Region; import org.apache.geode.cache.RegionAttributes; import org.apache.geode.cache.execute.RegionFunctionContext; import org.apache.geode.cache.query.data.Portfolio; import org.apache.geode.cache.query.internal.ResultsSet; import org.apache.geode.distributed.DistributedSystem; import org.apache.geode.internal.NanoTimer; /** * */ 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(); } } }