Index: bin/jmeter.properties =================================================================== --- bin/jmeter.properties (revision 1759038) +++ bin/jmeter.properties (working copy) @@ -1242,3 +1242,7 @@ # Number of iterations to use to validate a Thread Group #testplan_validation.number_iterations=1 + +# Timer factor that can be applied to Timer except for Constant ThroughputTimer and SynchronizingTimer +# as long as any timer return false in org.apache.jmeter.timers.Timer#isModifiable +#timer.factor=1.0 \ No newline at end of file Index: src/components/org/apache/jmeter/timers/BSFTimer.java =================================================================== --- src/components/org/apache/jmeter/timers/BSFTimer.java (revision 1754657) +++ src/components/org/apache/jmeter/timers/BSFTimer.java (working copy) @@ -52,4 +52,9 @@ } return delay; } + + @Override + public boolean isModifiable() { + return true; + } } Index: src/components/org/apache/jmeter/timers/BeanShellTimer.java =================================================================== --- src/components/org/apache/jmeter/timers/BeanShellTimer.java (revision 1754657) +++ src/components/org/apache/jmeter/timers/BeanShellTimer.java (working copy) @@ -62,4 +62,9 @@ return 0; } } + + @Override + public boolean isModifiable() { + return true; + } } Index: src/components/org/apache/jmeter/timers/ConstantThroughputTimer.java =================================================================== --- src/components/org/apache/jmeter/timers/ConstantThroughputTimer.java (revision 1754657) +++ src/components/org/apache/jmeter/timers/ConstantThroughputTimer.java (working copy) @@ -217,8 +217,8 @@ //Synchronize on the info object's MUTEX to ensure //Multiple threads don't update the scheduled time simultaneously synchronized (info.MUTEX) { - final long nextRequstTime = info.lastScheduledTime + milliSecPerRequest; - info.lastScheduledTime = Math.max(now, nextRequstTime); + final long nextRequestTime = info.lastScheduledTime + milliSecPerRequest; + info.lastScheduledTime = Math.max(now, nextRequestTime); calculatedDelay = info.lastScheduledTime - now; } @@ -329,5 +329,9 @@ void setMode(Mode newMode) { mode = newMode; } - + + @Override + public boolean isModifiable() { + return false; + } } Index: src/components/org/apache/jmeter/timers/ConstantTimer.java =================================================================== --- src/components/org/apache/jmeter/timers/ConstantTimer.java (revision 1754657) +++ src/components/org/apache/jmeter/timers/ConstantTimer.java (working copy) @@ -109,4 +109,9 @@ delay = getPropertyAsLong(DELAY); } + + @Override + public boolean isModifiable() { + return true; + } } Index: src/components/org/apache/jmeter/timers/JSR223Timer.java =================================================================== --- src/components/org/apache/jmeter/timers/JSR223Timer.java (revision 1754657) +++ src/components/org/apache/jmeter/timers/JSR223Timer.java (working copy) @@ -50,4 +50,9 @@ } return delay; } + + @Override + public boolean isModifiable() { + return true; + } } Index: src/components/org/apache/jmeter/timers/SyncTimer.java =================================================================== --- src/components/org/apache/jmeter/timers/SyncTimer.java (revision 1754657) +++ src/components/org/apache/jmeter/timers/SyncTimer.java (working copy) @@ -275,4 +275,9 @@ public void setTimeoutInMs(long timeoutInMs) { this.timeoutInMs = timeoutInMs; } + + @Override + public boolean isModifiable() { + return false; + } } Index: src/components/org/apache/jmeter/timers/UniformRandomTimer.java =================================================================== --- src/components/org/apache/jmeter/timers/UniformRandomTimer.java (revision 1754657) +++ src/components/org/apache/jmeter/timers/UniformRandomTimer.java (working copy) @@ -20,7 +20,7 @@ import java.io.Serializable; -import org.apache.jmeter.util.JMeterUtils; +import org.apache.commons.lang3.builder.ToStringBuilder; /** * This class implements those methods needed by RandomTimer to be instantiable @@ -38,7 +38,7 @@ @Override public String toString() { - return JMeterUtils.getResString("uniform_timer_memo"); //$NON-NLS-1$ + //return JMeterUtils.getResString("uniform_timer_memo"); //$NON-NLS-1$ + return ToStringBuilder.reflectionToString(this); } - } Index: src/core/org/apache/jmeter/threads/JMeterThread.java =================================================================== --- src/core/org/apache/jmeter/threads/JMeterThread.java (revision 1758348) +++ src/core/org/apache/jmeter/threads/JMeterThread.java (working copy) @@ -75,6 +75,8 @@ private static final int RAMPUP_GRANULARITY = JMeterUtils.getPropDefault("jmeterthread.rampup.granularity", 1000); // $NON-NLS-1$ + private static final double TIMER_FACTOR = JMeterUtils.getPropDefault("timer.factor", 1.0d); + private final Controller threadGroupLoopController; private final HashTree testTree; @@ -795,7 +797,17 @@ long totalDelay = 0; for (Timer timer : timers) { TestBeanHelper.prepare((TestElement) timer); - totalDelay += timer.delay(); + long delay = timer.delay(); + if(TIMER_FACTOR != 1.0d && timer.isModifiable()) { + if(log.isDebugEnabled()) { + log.debug("Applying TIMER_FACTOR:" + +TIMER_FACTOR + " on timer:" + +((TestElement)timer).getName() + + " for thread:"+getThreadName()); + } + delay = Math.round(delay * TIMER_FACTOR); + } + totalDelay += delay; } if (totalDelay > 0) { try { Index: src/core/org/apache/jmeter/timers/Timer.java =================================================================== --- src/core/org/apache/jmeter/timers/Timer.java (revision 1754657) +++ src/core/org/apache/jmeter/timers/Timer.java (working copy) @@ -33,4 +33,9 @@ * @return the computed delay value. */ long delay(); + + /** + * @return true if factor can be applied to it + */ + boolean isModifiable(); } Index: src/core/org/apache/jmeter/util/JMeterUtils.java =================================================================== --- src/core/org/apache/jmeter/util/JMeterUtils.java (revision 1756527) +++ src/core/org/apache/jmeter/util/JMeterUtils.java (working copy) @@ -856,6 +856,26 @@ } return ans; } + + /** + * Get a double value with default if not present. + * + * @param propName + * the name of the property. + * @param defaultVal + * the default value. + * @return The PropDefault value + */ + public static double getPropDefault(String propName, double defaultVal) { + double ans; + try { + ans = Double.parseDouble(appProperties.getProperty(propName, Double.toString(defaultVal)).trim()); + } catch (Exception e) { + log.warn("Exception '"+ e.getMessage()+ "' occurred when fetching double property:'"+propName+"', defaulting to:"+defaultVal); + ans = defaultVal; + } + return ans; + } /** * Get a String value with default if not present.