Author: psteitz Date: Sat Jul 28 16:24:33 2007 New Revision: 560643 URL: http://svn.apache.org/viewvc?view=rev&rev=560643 Log: Added pom for maven build Added some tests Fixed some errors and cleaned up state transition / delay computation code in ClientThread.
Added: jakarta/commons/sandbox/performance/trunk/LICENSE.txt (with props) jakarta/commons/sandbox/performance/trunk/NOTICE.txt (with props) jakarta/commons/sandbox/performance/trunk/pom.xml (with props) jakarta/commons/sandbox/performance/trunk/src/test/ jakarta/commons/sandbox/performance/trunk/src/test/org/ jakarta/commons/sandbox/performance/trunk/src/test/org/apache/ jakarta/commons/sandbox/performance/trunk/src/test/org/apache/commons/ jakarta/commons/sandbox/performance/trunk/src/test/org/apache/commons/performance/ jakarta/commons/sandbox/performance/trunk/src/test/org/apache/commons/performance/ClientThreadTest.java (with props) Modified: jakarta/commons/sandbox/performance/trunk/README.txt jakarta/commons/sandbox/performance/trunk/src/java/org/apache/commons/performance/ClientThread.java Added: jakarta/commons/sandbox/performance/trunk/LICENSE.txt URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/trunk/LICENSE.txt?view=auto&rev=560643 ============================================================================== --- jakarta/commons/sandbox/performance/trunk/LICENSE.txt (added) +++ jakarta/commons/sandbox/performance/trunk/LICENSE.txt Sat Jul 28 16:24:33 2007 @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. Propchange: jakarta/commons/sandbox/performance/trunk/LICENSE.txt ------------------------------------------------------------------------------ svn:eol-style = native Added: jakarta/commons/sandbox/performance/trunk/NOTICE.txt URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/trunk/NOTICE.txt?view=auto&rev=560643 ============================================================================== --- jakarta/commons/sandbox/performance/trunk/NOTICE.txt (added) +++ jakarta/commons/sandbox/performance/trunk/NOTICE.txt Sat Jul 28 16:24:33 2007 @@ -0,0 +1,5 @@ +Apache Commons Performance +Copyright 2007 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). Propchange: jakarta/commons/sandbox/performance/trunk/NOTICE.txt ------------------------------------------------------------------------------ svn:eol-style = native Modified: jakarta/commons/sandbox/performance/trunk/README.txt URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/trunk/README.txt?view=diff&rev=560643&r1=560642&r2=560643 ============================================================================== --- jakarta/commons/sandbox/performance/trunk/README.txt (original) +++ jakarta/commons/sandbox/performance/trunk/README.txt Sat Jul 28 16:24:33 2007 @@ -55,5 +55,5 @@ similar to ClientThread.nextDelay. Probably nextDelay belongs in a separate latency generation class. -* TESTS!!! There are no Junit tests. wtf? +* TESTS!!! Need more tests. Added: jakarta/commons/sandbox/performance/trunk/pom.xml URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/trunk/pom.xml?view=auto&rev=560643 ============================================================================== --- jakarta/commons/sandbox/performance/trunk/pom.xml (added) +++ jakarta/commons/sandbox/performance/trunk/pom.xml Sat Jul 28 16:24:33 2007 @@ -0,0 +1,119 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.commons</groupId> + <artifactId>commons-sandbox-parent</artifactId> + <version>1</version> + </parent> + + <artifactId>commons-performance</artifactId> + <version>0.1-SNAPSHOT</version> + <name>Commons Performance</name> + <inceptionYear>2007</inceptionYear> + <description>Performance and load tests for commons components</description> + <url>http://commons.apache.org/commons/sandbox/performance/</url> + + <scm> + <connection>scm:svn:http://svn.apache.org/repos/asf/commons/sandbox/performance/trunk/</connection> + <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/sandbox/js2j/trunk/</developerConnection> + <url>http://svn.apache.org/viewcvs.cgi/commons/sandbox/performance/trunk/</url> + </scm> + + <developers> + <developer> + <id>psteitz</id> + <name>Phil Steitz</name> + <email>psteitz AT apache.org</email> + </developer> + </developers> + + <dependencies> + <dependency> + <groupId>commons-digester</groupId> + <artifactId>commons-digester</artifactId> + <version>1.4.1</version> + </dependency> + <dependency> + <groupId>commons-dbcp</groupId> + <artifactId>commons-dbcp</artifactId> + <version>1.2.2</version> + </dependency> + <dependency> + <groupId>commons-pool</groupId> + <artifactId>commons-pool</artifactId> + <version>1.3</version> + </dependency> + <dependency> + <groupId>commons-math</groupId> + <artifactId>commons-math</artifactId> + <version>1.1</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>3.8.1</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <sourceDirectory>src/java</sourceDirectory> + <testSourceDirectory>src/test</testSourceDirectory> + <resources> + <resource> + <directory>.</directory> + <targetPath>META-INF</targetPath> + <includes> + <include>NOTICE.txt</include> + <include>LICENSE.txt</include> + </includes> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.3</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <archive> + <manifestEntries> + <mode>development</mode> + <url>${pom.url}</url> + </manifestEntries> + </archive> + </configuration> + </plugin> + </plugins> + <defaultGoal>install</defaultGoal> + </build> + + <!-- Compiler source and target JVM --> + <properties> + <maven.compile.source>1.5</maven.compile.source> + <maven.compile.target>1.5</maven.compile.target> + </properties> +</project> Propchange: jakarta/commons/sandbox/performance/trunk/pom.xml ------------------------------------------------------------------------------ svn:eol-style = native Modified: jakarta/commons/sandbox/performance/trunk/src/java/org/apache/commons/performance/ClientThread.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/trunk/src/java/org/apache/commons/performance/ClientThread.java?view=diff&rev=560643&r1=560642&r2=560643 ============================================================================== --- jakarta/commons/sandbox/performance/trunk/src/java/org/apache/commons/performance/ClientThread.java (original) +++ jakarta/commons/sandbox/performance/trunk/src/java/org/apache/commons/performance/ClientThread.java Sat Jul 28 16:24:33 2007 @@ -65,7 +65,8 @@ /** Last mean delay */ protected double lastMean; /** Random data generator */ - protected RandomData randomData; + protected RandomData randomData = new RandomDataImpl(); + protected SummaryStatistics stats = new SummaryStatisticsImpl(); /** Cycle state constants */ protected static final int RAMPING_UP = 0; @@ -73,7 +74,7 @@ protected static final int PEAK_LOAD = 2; protected static final int TROUGH_LOAD = 3; /** Cycle state */ - protected int cycleState = 0; + protected int cycleState = RAMPING_UP; /** * Create a client thread. @@ -121,8 +122,6 @@ long lastStart = startTime; long numMisses = 0; long numErrors = 0; - SummaryStatistics stats = new SummaryStatisticsImpl(); - randomData = new RandomDataImpl(); periodStart = System.currentTimeMillis(); lastMean = (double) maxDelay; // Ramp up, if any, starts here for (int i = 0; i < iterations; i++) { @@ -189,18 +188,48 @@ * Poisson and Gaussian distributed random time delays, linear and random * ramps, and oscillating / non-oscillating cycle types. * </p> - * <p>If delayType = "constant" the configured minDelay is always returned. - * If delayType is "gaussian" or "poisson" and cycleType is "none", - * random deviates with the configured parameters are returned. + * <p>loadType determines whether returned times are deterministic + * or random. If loadType is not "constant", a random value with the + * specified distribution and mean determined by the other parameters + * is returned. For "gaussian" loadType, sigma is used as used as the + * standard deviation. * </p> - * <p>If delayType is not "constant" and cycleType is "oscillating", means - * of random deviates ramp up and down between minDelay and maxDelay. Ramp - * type is controlled by rampType. Linear rampType means the means + * <p>cycleType determines how the returned times vary over time. + * "oscillating", means times ramp up and down between minDelay and maxDelay. + * Ramp type is controlled by rampType. Linear rampType means the means * increase or decrease linearly over the time of the period. Random * makes random jumps up or down toward the next peak or trough. "None" for * rampType under oscillating cycleType makes the means alternate between * peak (minDelay) and trough (maxDelay) with no ramp between. * </p> + * <p>Oscillating loads cycle through RAMPING_UP, PEAK_LOAD, RAMPING_DOWN + * and TROUGH_LOAD states, with the amount of time spent in each state + * determined by rampPeriod (time spent increasing on the way up and + * decreasing on the way down), peakPeriod (time spent at peak load, i.e., + * minDelay) and troughPeriod (time spent at minimum load, i.e., maxDelay). + * All times are specified in milliseconds. + * </p> + * <p> For example, given <pre> + * delayType = "constant" + * minDelay = 250 + * maxDelay = 500 + * cycleState = "oscillating" + * rampType = "linear" + * rampPeriod = 10000 + * peakPeriod = 20000 + * troughPeriod = 30000 + * </pre> + * load will start at one request every 500 ms, which is "trough load." + * Load then ramps up linearly over the next 10 seconds unil it reaches + * one request per 250 milliseconds, which is "peak load." Peak load is + * sustained for 20 seconds and then load ramps back down, again taking + * 10 seconds to get down to "trough load," which is sustained for 30 + * seconds. The cycle then repeats. If delayType is "gaussian", things + * work the same way, but the computed delay value is fed into a gaussian + * random number generator as the mean - i.e., nextDelay returns + * random, gaussian distributed values with means moving according to the + * algorithm above (and standard deviation constantly = sigma). + * </p> * <p>For non-oscillating, non-constant runs, linear and random rampTypes * work similarly, but over just one ramp up period at the beginning of * the run. @@ -209,95 +238,51 @@ * @param currentTime current time * @return next value for delay */ - protected long nextDelay() { + protected long nextDelay() throws ConfigurationException { + double targetDelay = 0; + double dMinDelay = (double) minDelay; + double dMaxDelay = (double) maxDelay; + double delayDifference = dMaxDelay - dMinDelay; long currentTime = System.currentTimeMillis(); - double mean = 0; - if (delayType.equals("constant")) { - //TODO: should support single ramp up to constant - return minDelay; - } else { // delay not constant, use random variate - // Determine mean to use - double dMinDelay = (double) minDelay; - double dMaxDelay = (double) maxDelay; - double delayDifference = dMaxDelay - dMinDelay; - if (cycleType.equals("none")) { - if (rampType.equals("none") || - (currentTime - startTime) > rampPeriod) { // ramped up - mean = dMinDelay; - } else if (rampType.equals("linear")) { // single period linear - double prop = - (double) (currentTime - startTime) / (double) rampPeriod; - mean = dMaxDelay - delayDifference * prop; - } else { // Random jumps down to delay - single period - // TODO: govern size of jumps as in oscillating - // Where we last were as proportion of way down to minDelay - double lastProp = - (dMaxDelay - lastMean) / delayDifference; - // Make a random jump toward 1 (1 = all the way down) - double prop = randomData.nextUniform(lastProp, 1); - mean = dMaxDelay - delayDifference * prop; - } - } else if (cycleType.equals("oscillating")) { - // First change cycle state if we need to - adjustState(currentTime); - if (cycleState == PEAK_LOAD) { - mean = dMinDelay; - } else if (cycleState == TROUGH_LOAD) { - mean = dMaxDelay; - } else if (rampType.equals("none")) { // minDelay or maxDelay, no ramp - if (cycleState == RAMPING_UP) { - mean = dMaxDelay; - } else { - mean = dMinDelay; - } - } else if (rampType.equals("linear")) { // ramp down, then up - double prop = - (double)(currentTime - periodStart) / (double) rampPeriod; - if (cycleState == RAMPING_UP) { - mean = dMaxDelay - delayDifference * prop; - } else { - mean = dMinDelay + delayDifference * prop; - } - } else { // random jumps down, then back up - // Where we last were as proportion of way down to minDelay - double lastProp = - (dMaxDelay - lastMean) / delayDifference; - // Where we would be if this were a linear ramp - double linearProp = - (double)(currentTime - periodStart) / (double) rampPeriod; - // Need to govern size of jumps, otherwise "convergence" - // can be too fast - use linear ramp as governor - if ((cycleState == RAMPING_UP && (lastProp > linearProp)) || - (cycleState == RAMPING_DOWN && - ((1 - lastProp) > linearProp))) - lastProp = (cycleState == RAMPING_UP) ? linearProp : - (1 - linearProp); - double prop = 0; - if (cycleState == RAMPING_UP) { // Random jump toward 1 - prop = randomData.nextUniform(lastProp, 1); - } else { // Random jump toward 0 - prop = randomData.nextUniform(0, lastProp); - } - // Make sure sequence is monotone - if (cycleState == RAMPING_UP) { - mean = Math.min(lastMean, - maxDelay - delayDifference * prop); - } else { - mean = Math.max(lastMean, - minDelay + delayDifference * prop); - } - } + if (cycleType.equals("none")) { + if (rampType.equals("none") || + (currentTime - startTime) > rampPeriod) { // ramped up + targetDelay = dMinDelay; + } else if (rampType.equals("linear")) { // single period linear + double prop = + (double) (currentTime - startTime) / (double) rampPeriod; + targetDelay = dMaxDelay - delayDifference * prop; + } else { // Random jumps down to delay - single period + // TODO: govern size of jumps as in oscillating + // Where we last were as proportion of way down to minDelay + double lastProp = + (dMaxDelay - lastMean) / delayDifference; + // Make a random jump toward 1 (1 = all the way down) + double prop = randomData.nextUniform(lastProp, 1); + targetDelay = dMaxDelay - delayDifference * prop; } + } else if (cycleType.equals("oscillating")) { + // First change cycle state if we need to + adjustState(currentTime); + targetDelay = computeCyclicDelay( + currentTime, dMinDelay, dMaxDelay); + } else { + throw new ConfigurationException( + "Cycle type not supported: " + cycleType); + } - // Remember last mean for ramp up / down - lastMean = mean; + // Remember last mean for ramp up / down + lastMean = targetDelay; - // Generate and return random deviate - if (delayType.equals("gaussian")) { - return Math.round(randomData.nextGaussian(mean, sigma)); - } else { // must be Poisson - return Math.round(randomData.nextPoisson(mean)); - } + if (delayType.equals("constant")) { + return Math.round(targetDelay); + } + + // Generate and return random deviate + if (delayType.equals("gaussian")) { + return Math.round(randomData.nextGaussian(targetDelay, sigma)); + } else { // must be Poisson + return Math.round(randomData.nextPoisson(targetDelay)); } } @@ -308,60 +293,117 @@ * @param currentTime current time */ protected void adjustState(long currentTime) { + long timeInPeriod = currentTime - periodStart; + if ( ((cycleState == RAMPING_UP || cycleState == RAMPING_DOWN) && + timeInPeriod < rampPeriod) || + (cycleState == PEAK_LOAD && timeInPeriod < peakPeriod) || + (cycleState == TROUGH_LOAD && timeInPeriod < troughPeriod)) { + return; // No state change + } switch (cycleState) { - case RAMPING_UP: { - if ((currentTime - periodStart) >= rampPeriod) { - if (peakPeriod > 0) { - cycleState = PEAK_LOAD; - } else { - cycleState = RAMPING_DOWN; - } - lastMean = (double) minDelay; - periodStart = currentTime; + case RAMPING_UP: + if (peakPeriod > 0) { + cycleState = PEAK_LOAD; + } else { + cycleState = RAMPING_DOWN; } + lastMean = (double) minDelay; + periodStart = currentTime; break; - } - case RAMPING_DOWN: { - if ((currentTime - periodStart) >= rampPeriod) { - if (troughPeriod > 0) { - cycleState = TROUGH_LOAD; - } else { - cycleState = RAMPING_UP; - } - lastMean = (double) maxDelay; - periodStart = currentTime; + + case RAMPING_DOWN: + if (troughPeriod > 0) { + cycleState = TROUGH_LOAD; + } else { + cycleState = RAMPING_UP; } + lastMean = (double) maxDelay; + periodStart = currentTime; break; - } - case PEAK_LOAD: { - if ((currentTime - periodStart) >= peakPeriod) { - if (rampPeriod > 0) { - cycleState = RAMPING_DOWN; - lastMean = (double) minDelay; - } else { - cycleState = TROUGH_LOAD; - lastMean = (double) maxDelay; - } - periodStart = currentTime; + + case PEAK_LOAD: + if (rampPeriod > 0) { + cycleState = RAMPING_DOWN; + lastMean = (double) minDelay; + } else { + cycleState = TROUGH_LOAD; + lastMean = (double) maxDelay; } + periodStart = currentTime; break; - } - case TROUGH_LOAD: { - if ((currentTime - periodStart) >= peakPeriod) { - if (rampPeriod > 0) { - cycleState = RAMPING_UP; - lastMean = (double) maxDelay; - } else { - cycleState = PEAK_LOAD; - lastMean = (double) minDelay; - } - periodStart = currentTime; + + case TROUGH_LOAD: + if (rampPeriod > 0) { + cycleState = RAMPING_UP; + lastMean = (double) maxDelay; + } else { + cycleState = PEAK_LOAD; + lastMean = (double) minDelay; } + periodStart = currentTime; break; - } - default: { + + default: throw new IllegalStateException( "Illegal cycle state: " + cycleState); + } + } + + protected double computeCyclicDelay( + long currentTime, double min, double max) { + + // Constant load states + if (cycleState == PEAK_LOAD) { + return min; + } + if (cycleState == TROUGH_LOAD) { + return max; + } + + // No ramp - stay at min or max load during ramp + if (rampType.equals("none")) { // min or max, no ramp + if (cycleState == RAMPING_UP) { + return max; + } else { + return min; + } + } + + // Linear ramp type and ramping up or down + double diff = max - min; + if (rampType.equals("linear")) { + double prop = + (double)(currentTime - periodStart) / (double) rampPeriod; + if (cycleState == RAMPING_UP) { + return max - diff * prop; + } else { + return min + diff * prop; + } + } else { // random jumps down, then back up + // Where we last were as proportion of way down to minDelay + double lastProp = + (max - lastMean) / diff; + // Where we would be if this were a linear ramp + double linearProp = + (double)(currentTime - periodStart) / (double) rampPeriod; + // Need to govern size of jumps, otherwise "convergence" + // can be too fast - use linear ramp as governor + if ((cycleState == RAMPING_UP && (lastProp > linearProp)) || + (cycleState == RAMPING_DOWN && + ((1 - lastProp) > linearProp))) + lastProp = (cycleState == RAMPING_UP) ? linearProp : + (1 - linearProp); + double prop = 0; + if (cycleState == RAMPING_UP) { // Random jump toward 1 + prop = randomData.nextUniform(lastProp, 1); + } else { // Random jump toward 0 + prop = randomData.nextUniform(0, lastProp); + } + // Make sure sequence is monotone + if (cycleState == RAMPING_UP) { + return Math.min(lastMean, max - diff * prop); + } else { + return Math.max(lastMean, min + diff * prop); } } } Added: jakarta/commons/sandbox/performance/trunk/src/test/org/apache/commons/performance/ClientThreadTest.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/performance/trunk/src/test/org/apache/commons/performance/ClientThreadTest.java?view=auto&rev=560643 ============================================================================== --- jakarta/commons/sandbox/performance/trunk/src/test/org/apache/commons/performance/ClientThreadTest.java (added) +++ jakarta/commons/sandbox/performance/trunk/src/test/org/apache/commons/performance/ClientThreadTest.java Sat Jul 28 16:24:33 2007 @@ -0,0 +1,174 @@ +/* + * 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.commons.performance; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; +import org.apache.commons.math.stat.descriptive.SummaryStatistics; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class ClientThreadTest extends TestCase { + + protected ClientThread clientThread = null; + protected static Logger logger = Logger.getLogger(LoadGenerator.class.getName()); + protected static List <SummaryStatistics> statsList = + new ArrayList <SummaryStatistics>(); + + // Dummy ClientThread concrete class to instantiate in tests + class nullClientThread extends ClientThread { + public nullClientThread(long iterations, long minDelay, long maxDelay, + double sigma, String delayType, long rampPeriod, + long peakPeriod, long troughPeriod, String cycleType, + String rampType, Logger logger, + List <SummaryStatistics> statsList) { + super(iterations, minDelay, maxDelay, sigma, delayType, rampPeriod, + peakPeriod, troughPeriod, cycleType, rampType, logger, + statsList); + } + public void execute() {} + } + + + public ClientThreadTest(String name) { + super(name); + } + + + public static Test suite() { + return new TestSuite(ClientThreadTest.class); + } + + public void setUp() throws Exception { + clientThread = new nullClientThread( + 1000, // iterations + 100, // minDelay + 1000, // maxDelay + 100, // sigma + "constant", // delayType + 1000, // ramp period + 2000, // peak period + 3000, // trough period + "oscillating", // cycle type + "linear", // ramp type + logger, statsList); + } + + // ====================================================== + // computCyclicDelay tests + // ====================================================== + + public void testComputeCyclicDelayRamp() throws Exception { + clientThread.cycleState = ClientThread.RAMPING_UP; + clientThread.periodStart = 1000; + assertEquals(150, clientThread.computeCyclicDelay(1500, 100, 200), 10E-12); + assertEquals(110, clientThread.computeCyclicDelay(1900, 100, 200), 10E-12); + clientThread.cycleState = ClientThread.RAMPING_DOWN; + assertEquals(150, clientThread.computeCyclicDelay(1500, 100, 200), 10E-12); + assertEquals(190, clientThread.computeCyclicDelay(1900, 100, 200), 10E-12); + } + + public void testComputeCyclicDelayConst() throws Exception { + clientThread.cycleState = ClientThread.PEAK_LOAD; + clientThread.periodStart = 1000; + assertEquals(100, clientThread.computeCyclicDelay(1500, 100, 200), 10E-12); + assertEquals(100, clientThread.computeCyclicDelay(1900, 100, 200), 10E-12); + clientThread.cycleState = ClientThread.TROUGH_LOAD; + assertEquals(200, clientThread.computeCyclicDelay(1500, 100, 200), 10E-12); + assertEquals(200, clientThread.computeCyclicDelay(1900, 100, 200), 10E-12); + } + + public void testCyclicDelayRandom() throws Exception { + clientThread.rampType = "random"; + clientThread.cycleState = ClientThread.RAMPING_UP; + clientThread.periodStart = 1000; + clientThread.lastMean = 200; + for (int i = 1; i < 10; i++) { + double nextMean = clientThread.computeCyclicDelay(1500, 100, 200); + assertTrue(nextMean <= 200 && nextMean >= 100 && + nextMean <= clientThread.lastMean); + clientThread.lastMean = nextMean; + } + clientThread.cycleState = ClientThread.RAMPING_DOWN; + clientThread.periodStart = 1000; + clientThread.lastMean = 100; + for (int i = 1; i < 10; i++) { + double nextMean = clientThread.computeCyclicDelay(1500, 100, 200); + assertTrue(nextMean <= 200 && nextMean >= 100 && + nextMean >= clientThread.lastMean); + clientThread.lastMean = nextMean; + } + } + + + // ====================================================== + // adjustState tests + // ====================================================== + public void testAdjustStateNoChange() throws Exception { + clientThread.periodStart = 1000; + clientThread.cycleState = ClientThread.RAMPING_UP; + clientThread.rampPeriod = 1000; + clientThread.adjustState(1100); + assertEquals(ClientThread.RAMPING_UP, clientThread.cycleState); + clientThread.cycleState = ClientThread.RAMPING_DOWN; + clientThread.adjustState(1100); + assertEquals(ClientThread.RAMPING_DOWN, clientThread.cycleState); + clientThread.cycleState = ClientThread.PEAK_LOAD; + clientThread.peakPeriod = 1000; + clientThread.adjustState(1100); + assertEquals(ClientThread.PEAK_LOAD, clientThread.cycleState); + clientThread.cycleState = ClientThread.TROUGH_LOAD; + clientThread.peakPeriod = 1000; + clientThread.adjustState(1100); + assertEquals(ClientThread.TROUGH_LOAD, clientThread.cycleState); + } + + public void testStateTransitions() throws Exception { + clientThread.peakPeriod = 1500; + clientThread.rampPeriod = 1000; + clientThread.troughPeriod = 2000; + + // Ramping up to peak + clientThread.periodStart = 1000; + clientThread.cycleState = ClientThread.RAMPING_UP; + clientThread.adjustState(2100); + assertEquals(ClientThread.PEAK_LOAD, clientThread.cycleState); + assertEquals(2100, clientThread.periodStart); + assertEquals((double) clientThread.minDelay, clientThread.lastMean); + + // Peak to ramping down + clientThread.adjustState(3700); + assertEquals(ClientThread.RAMPING_DOWN, clientThread.cycleState); + assertEquals(3700, clientThread.periodStart); + assertEquals((double) clientThread.minDelay, clientThread.lastMean); + + // Ramping down to trough + clientThread.adjustState(4800); + assertEquals(ClientThread.TROUGH_LOAD, clientThread.cycleState); + assertEquals(4800, clientThread.periodStart); + assertEquals((double) clientThread.maxDelay, clientThread.lastMean); + + // Trough to ramping up + clientThread.adjustState(6900); + assertEquals(ClientThread.RAMPING_UP, clientThread.cycleState); + assertEquals(6900, clientThread.periodStart); + assertEquals((double) clientThread.maxDelay, clientThread.lastMean); + } + +} Propchange: jakarta/commons/sandbox/performance/trunk/src/test/org/apache/commons/performance/ClientThreadTest.java ------------------------------------------------------------------------------ svn:eol-style = native --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]