Coverage Report - org.apache.commons.performance.LoadGenerator
 
Classes in this File Line Coverage Branch Coverage Complexity
LoadGenerator
0%
0/54
0%
0/6
1.273
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  * 
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  * 
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 package org.apache.commons.performance;
 19  
 
 20  
 import java.io.File;
 21  
 import java.util.Iterator;
 22  
 import java.util.concurrent.ExecutorService;
 23  
 import java.util.concurrent.Executors;
 24  
 import java.util.concurrent.TimeUnit;
 25  
 import java.util.logging.Logger;
 26  
 import org.apache.commons.digester.Digester;
 27  
  
 28  
 /**
 29  
  * <p>Base class for load / peformance test runners.
 30  
  * Uses Commons Digester to parse and load configuration and spawns
 31  
  * {@link ClientThread} instances to generate load and gather statistics.</p>
 32  
  * 
 33  
  * <p>Subclasses <code>must</code> implement <code>makeClientThread</code> to
 34  
  * create client thread instances to be kicked off by <code>execute.</code>
 35  
  * Subclasses will also in general override <code>configure</code> to load
 36  
  * additional configuration parameters and pass them on to the client in 
 37  
  * <code>makeClientThread.</code>  Implementations of <code>configure</code>
 38  
  * should start with a <code>super()</code> call so that the base configuration
 39  
  * parameters are loaded. This method should also set the <code>configFile</code>
 40  
  * property to a valid URI or filespec (suitable argument for Digester's parse
 41  
  * method). Setup code that needs to be executed before any client threads are
 42  
  * spawned should be put in <code>init</code></p>
 43  
  * 
 44  
  * <p>See 
 45  
  * <a href="http://svn.apache.org/viewvc/commons/sandbox/performance/trunk/src/java/org/apache/commons/performance/dbcp/DBCPSoak.java?view=markup">
 46  
  * DBCPSoak</a> and its 
 47  
  * <a href="http://svn.apache.org/viewvc/commons/sandbox/performance/trunk/config-dbcp.xml?view=markup">
 48  
  * sample configuration file</a> for an example.  As in that example, additional
 49  
  * sections of the config file should be parsed and loaded in the overridden
 50  
  * <code>configure</code> method. The "run" section is required by the base
 51  
  * implementation. That example also illustrates how <code>init</code>
 52  
  * can be used to set up resources or data structures required by the client
 53  
  * threads.</p>
 54  
  *
 55  
  */
 56  0
 public abstract class LoadGenerator {
 57  
     
 58  
     /** logger */
 59  0
     protected static final Logger logger = 
 60  
         Logger.getLogger(LoadGenerator.class.getName());
 61  
     
 62  
     /** Statistics aggregator */
 63  0
     private static Statistics stats = new Statistics();
 64  
     
 65  
     // Client thread properties
 66  
     protected long minDelay;
 67  
     protected long maxDelay;
 68  
     protected double sigma;
 69  
     protected String delayType;
 70  
     protected String rampType;
 71  
     protected long rampPeriod;
 72  
     protected long peakPeriod;
 73  
     protected long troughPeriod;
 74  
     protected String cycleType;
 75  
     
 76  
     // Run properties
 77  
     private long numClients;
 78  
     private long iterations;
 79  
     
 80  0
     protected Digester digester = new Digester();
 81  0
     protected String configFile = null;
 82  
     
 83  
     /**
 84  
      * <p>Invokes {@link #configure()} to load digester rules, then digster.parse,
 85  
      * then {@link #init} to initialize configuration members. Then spawns and
 86  
      * executes {@link #numClients} ClientThreads using {@link #makeClientThread}
 87  
      * to create the ClientThread instances. Waits for all spawned threads to
 88  
      * terminate and then logs accumulated statistics, using 
 89  
      * {@link Statistics#displayOverallSummary}</p>
 90  
      * 
 91  
      * <p>Subclasses should not need to override this method, but must implement
 92  
      * {@link #makeClientThread} and may override {@link #configure} and
 93  
      * {@link #init} to prepare data to pass to <code>makeClientThread</code>, 
 94  
      * and {@link #cleanUp} to clean up after all threads terminate.
 95  
      * </p>
 96  
      * 
 97  
      * @throws Exception
 98  
      */
 99  
     public void execute() throws Exception {
 100  0
         configure();
 101  0
         parseConfigFile();
 102  0
         init();
 103  
         // Spawn and execute client threads
 104  0
                 ExecutorService ex = Executors.newFixedThreadPool((int)numClients);
 105  0
                 for (int i = 0; i < numClients; i++) {
 106  0
             ClientThread clientThread = makeClientThread(iterations, minDelay,
 107  
                     maxDelay, sigma, delayType, rampPeriod, peakPeriod,
 108  
                     troughPeriod, cycleType, rampType, logger, stats);
 109  0
                         ex.execute(clientThread);
 110  
                 } 
 111  0
         ex.shutdown();
 112  
         // hard time limit of one day for now 
 113  
         // TODO: make this configurable
 114  0
         ex.awaitTermination(60 * 60 * 24, TimeUnit.SECONDS);
 115  
         
 116  
         // Log summary statistics for accumulated metrics
 117  0
         logger.info(stats.displayOverallSummary());
 118  
         
 119  
         // clean up
 120  0
         cleanUp();
 121  0
         }
 122  
     
 123  
     protected abstract ClientThread makeClientThread(
 124  
             long iterations, long minDelay, long maxDelay, double sigma,
 125  
             String delayType, long rampPeriod, long peakPeriod,
 126  
             long troughPeriod, String cycleType, String rampType,
 127  
             Logger logger, Statistics stats);
 128  
     
 129  
     /**
 130  
      * This method is invoked by {@link #execute()} after {@link #configure()}
 131  
      * and digester parse, just before client threads are created. Objects that
 132  
      * need to be created and passed to client threads using configuration info
 133  
      * parsed from the config file should be created in this method.
 134  
      * 
 135  
      * @throws Exception
 136  
      */
 137  0
     protected void init() throws Exception {}
 138  
     
 139  
     
 140  
     /**
 141  
      * This method is invoked by {@link #execute()} after all spawned threads
 142  
      * have terminated. Override to clean up any resources allocated in 
 143  
      * {@link #init()}.
 144  
      * 
 145  
      * @throws Exception
 146  
      */
 147  0
     protected void cleanUp() throws Exception {}
 148  
     
 149  
     
 150  
     /**
 151  
      * Configures basic run parameters. Invoked by Digester via a rule defined
 152  
      * in {@link #configure()}.
 153  
      * 
 154  
      * @param iterations number of iterations
 155  
      * @param clients number of client threads
 156  
      * @param minDelay minimum delay between client thread requests (ms)
 157  
      * @param maxDelay maximum delay between client thread requests (ms)
 158  
      * @param sigma standard deviation of delay
 159  
      * @param delayType type of delay (constant, gaussian, poisson)
 160  
      * @param rampType type of ramp (none, linear, random)
 161  
      * @param rampPeriod rampup/rampdown time
 162  
      * @param peakPeriod peak period
 163  
      * @param troughPeriod trough period
 164  
      * @param cycleType cycle type (none, oscillating)
 165  
      * @throws ConfigurationException
 166  
      */
 167  
     
 168  
     public void configureRun(String iterations, String clients,
 169  
             String minDelay, String maxDelay, String sigma,
 170  
             String delayType, String rampType, String rampPeriod,
 171  
             String peakPeriod, String troughPeriod, String cycleType) 
 172  
             throws ConfigurationException {
 173  
      
 174  0
         this.iterations = Long.parseLong(iterations);
 175  0
         this.numClients = Long.parseLong(clients);
 176  0
         this.minDelay = Long.parseLong(minDelay);
 177  0
         this.maxDelay = Long.parseLong(maxDelay);
 178  0
         this.sigma = Double.parseDouble(sigma);
 179  0
         this.delayType = delayType;
 180  0
         this.rampType = rampType;
 181  0
         this.rampPeriod = Long.parseLong(rampPeriod);
 182  0
         this.peakPeriod = Long.parseLong(peakPeriod);
 183  0
         this.troughPeriod = Long.parseLong(troughPeriod);
 184  0
         this.cycleType = cycleType;
 185  0
         if (cycleType.equals("oscillating") && this.rampPeriod <= 0) {
 186  0
             throw new ConfigurationException(
 187  
               "Ramp period must be positive for oscillating cycle type");
 188  
         }
 189  0
     }
 190  
     
 191  
     /**
 192  
      * <p>Starts preparing Digester to parse the configuration file, pushing
 193  
      * *this onto the stack and loading rules to configure basic "run" 
 194  
      * parameters.
 195  
      * </p>
 196  
      * <p>Subclasses can override this, using <code>super()</code> to load base
 197  
      * parameters and then adding additional </code>addCallMethod</code>
 198  
      * sequences for additional parameters.
 199  
      * </p>
 200  
      * 
 201  
      * @throws Exception
 202  
      */
 203  
     protected void configure() throws Exception {
 204  0
         digester.push(this);
 205  
         
 206  0
         digester.addCallMethod("configuration/run", 
 207  
                 "configureRun", 11);
 208  0
         digester.addCallParam(
 209  
                 "configuration/run/iterations", 0);
 210  0
         digester.addCallParam(
 211  
                 "configuration/run/clients", 1);
 212  0
         digester.addCallParam(
 213  
                 "configuration/run/delay-min", 2);
 214  0
         digester.addCallParam(
 215  
                 "configuration/run/delay-max", 3);
 216  0
         digester.addCallParam(
 217  
                 "configuration/run/delay-sigma", 4);
 218  0
         digester.addCallParam(
 219  
                 "configuration/run/delay-type", 5);
 220  0
         digester.addCallParam(
 221  
                 "configuration/run/ramp-type", 6);
 222  0
         digester.addCallParam(
 223  
                 "configuration/run/ramp-period", 7);
 224  0
         digester.addCallParam(
 225  
                 "configuration/run/peak-period", 8);
 226  0
         digester.addCallParam(
 227  
                 "configuration/run/trough-period", 9);
 228  0
         digester.addCallParam(
 229  
                 "configuration/run/cycle-type", 10);    
 230  0
     }
 231  
     
 232  
     protected void parseConfigFile() throws Exception {
 233  
         // TODO: get rid of File spec
 234  0
         digester.parse(new File(configFile));
 235  0
     }
 236  
 
 237  
     /**
 238  
      * @return the configFile
 239  
      */
 240  
     public String getConfigFile() {
 241  0
         return configFile;
 242  
     }
 243  
 
 244  
     /**
 245  
      * @param configFile the configFile to set
 246  
      */
 247  
     public void setConfigFile(String configFile) {
 248  0
         this.configFile = configFile;
 249  0
     }
 250  
 
 251  
     /**
 252  
      * @return the digester
 253  
      */
 254  
     public Digester getDigester() {
 255  0
         return digester;
 256  
     }
 257  
     
 258  
     /**
 259  
      * @return statistics
 260  
      */
 261  
     public Statistics getStatistics() {
 262  0
         return stats;
 263  
     }
 264  
 }