You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2017/12/26 20:40:33 UTC
svn commit: r1819293 - in /jmeter/trunk: bin/
src/components/org/apache/jmeter/timers/poissonarrivals/
src/core/org/apache/jmeter/save/
test/src/org/apache/jmeter/timers/poissonarrivals/ xdocs/ xdocs/usermanual/
Author: pmouawad
Date: Tue Dec 26 20:40:32 2017
New Revision: 1819293
URL: http://svn.apache.org/viewvc?rev=1819293&view=rev
Log:
Bug 61931 - Exponential Timer : timer that produces poisson arrivals with given constant throughput
This closes #231
Bugzilla Id: 61931
Added:
jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/
jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ConstantPoissonProcessGenerator.java (with props)
jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/DurationProvider.java (with props)
jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/EventProducer.java (with props)
jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimer.java (with props)
jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerBeanInfo.java (with props)
jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources.properties (with props)
jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources_fr.properties (with props)
jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ThroughputProvider.java (with props)
jmeter/trunk/test/src/org/apache/jmeter/timers/poissonarrivals/
jmeter/trunk/test/src/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerTest.java (with props)
Modified:
jmeter/trunk/bin/saveservice.properties
jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
jmeter/trunk/xdocs/changes.xml
jmeter/trunk/xdocs/usermanual/component_reference.xml
Modified: jmeter/trunk/bin/saveservice.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/saveservice.properties?rev=1819293&r1=1819292&r2=1819293&view=diff
==============================================================================
--- jmeter/trunk/bin/saveservice.properties (original)
+++ jmeter/trunk/bin/saveservice.properties Tue Dec 26 20:40:32 2017
@@ -65,7 +65,7 @@
# 3.1 = 3.1
# 3.2 = 3.2
# 3.4 = 3.4
-_version=3.4
+_version=4.0
#
#
# Character set encoding used to read and write JMeter XML files and CSV results
@@ -133,6 +133,7 @@ DNSCacheManager=org.apache.jmeter.protoc
DNSCachePanel=org.apache.jmeter.protocol.http.gui.DNSCachePanel
DurationAssertion=org.apache.jmeter.assertions.DurationAssertion
DurationAssertionGui=org.apache.jmeter.assertions.gui.DurationAssertionGui
+ExponentialTimer=org.apache.jmeter.timers.poissonarrivals.ExponentialTimer
# Should really have been defined as floatProp to agree with other properties
# No point changing this now
FloatProperty=org.apache.jmeter.testelement.property.FloatProperty
Added: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ConstantPoissonProcessGenerator.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ConstantPoissonProcessGenerator.java?rev=1819293&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ConstantPoissonProcessGenerator.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ConstantPoissonProcessGenerator.java Tue Dec 26 20:40:32 2017
@@ -0,0 +1,166 @@
+/*
+ * 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.jmeter.timers.poissonarrivals;
+
+import java.nio.DoubleBuffer;
+import java.util.Random;
+
+import org.apache.jmeter.testelement.AbstractTestElement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Generates events for poisson processes, ensuring throughput*duration events will be present in each "duration"
+ * @since 4.0
+ */
+public class ConstantPoissonProcessGenerator implements EventProducer {
+ private static final Logger log = LoggerFactory.getLogger(ConstantPoissonProcessGenerator.class);
+
+ private Random rnd = new Random();
+ public ThroughputProvider throughput;
+ private int batchSize;
+ private int batchThreadDelay;
+ public DurationProvider duration;
+ private double lastThroughput;
+ private int exactLimit;
+ private double allowedThroughputSurplus;
+ private DoubleBuffer events;
+ private double lastEvent;
+ private final boolean logFirstSamples;
+
+ public ConstantPoissonProcessGenerator(
+ ThroughputProvider throughput, int batchSize, int batchThreadDelay,
+ DurationProvider duration, int exactLimit, double allowedThroughputSurplus,
+ Long seed, boolean logFirstSamples) {
+ this.throughput = throughput;
+ this.batchSize = batchSize;
+ this.batchThreadDelay = batchThreadDelay;
+ this.duration = duration;
+ this.exactLimit = exactLimit;
+ this.allowedThroughputSurplus = allowedThroughputSurplus;
+ this.logFirstSamples = logFirstSamples;
+ if (seed != null && seed.intValue() != 0) {
+ rnd.setSeed(seed);
+ }
+ ensureCapacity();
+ }
+
+ private void ensureCapacity() {
+ int size = (int) Math.round((throughput.getThroughput() * duration.getDuration() + 1) * 3);
+ if (events != null && events.capacity() >= size) {
+ return;
+ }
+ events = DoubleBuffer.allocate(size);
+ }
+
+ public void generateNext() {
+ double throughput = this.throughput.getThroughput();
+ lastThroughput = throughput;
+ if (batchSize > 1) {
+ throughput /= batchSize;
+ }
+ long duration = this.duration.getDuration();
+ ensureCapacity();
+ int samples = (int) Math.ceil(throughput * duration);
+ double time;
+ int i = 0;
+ long t = System.currentTimeMillis();
+ int loops = 0;
+ double allowedThroughputSurplus = samples < exactLimit ? 0.0d : this.allowedThroughputSurplus / 100;
+ do {
+ time = 0;
+ events.clear();
+ if (throughput < 1e-5) {
+ log.info("Throughput should exceed zero");
+ break;
+ }
+ if (duration < 5) {
+ log.info("Duration should exceed 5 seconds");
+ break;
+ }
+ for (i = 0; time < duration; i++) {
+ double u = rnd.nextDouble();
+ // https://en.wikipedia.org/wiki/Exponential_distribution#Generating_exponential_variates
+ double delay = -Math.log(1 - u) / throughput;
+ time += delay;
+ events.put(time + lastEvent);
+ }
+ loops++;
+ } while (System.currentTimeMillis() - t < 5000 &&
+ (i < samples + 1 // not enough samples
+ || (i - 1 - samples) * 1.0f / samples > allowedThroughputSurplus));
+ t = System.currentTimeMillis() - t;
+ if (t > 1000) {
+ log.warn("Spent {} ms while generating sequence of delays for {} samples, {} throughput, {} duration",
+ t, samples, throughput, duration);
+ }
+ if (logFirstSamples) {
+ if (log.isDebugEnabled()) {
+ log.debug("Generated {} events ({} required, rate {}) in {} ms, restart was issued {} times",
+ events.position(), samples, throughput, t, loops);
+ }
+ if(log.isInfoEnabled()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Generated ").append(events.position()).append(" timings (");
+ if (this.duration instanceof AbstractTestElement) {
+ sb.append(((AbstractTestElement) this.duration).getName());
+ }
+ sb.append(" ").append(samples).append(" required, rate ").append(throughput).append(", duration ").append(duration);
+ sb.append(", exact lim ").append(exactLimit).append(", i").append(i);
+ sb.append(") in ").append(t).append(" ms, restart was issued ").append(loops).append(" times. ");
+ sb.append("First 15 events will be fired at: ");
+ double prev = 0;
+ for (i = 0; i < events.position() && i < 15; i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ double ev = events.get(i);
+ sb.append(ev);
+ sb.append(" (+").append(ev - prev).append(")");
+ prev = ev;
+ }
+ log.info(sb.toString());
+ }
+
+ }
+ events.flip();
+ if (batchSize > 1) {
+ // If required to generate "pairs" of events, then just duplicate events in the buffer
+ // TODO: for large batchSizes it makes sense to use counting instead
+ DoubleBuffer tmpBuffer = DoubleBuffer.allocate(batchSize * events.remaining());
+ while (events.hasRemaining()) {
+ double curTime = events.get();
+ for (int j = 0; j < batchSize; j++) {
+ tmpBuffer.put(curTime + j * batchThreadDelay);
+ }
+ }
+ tmpBuffer.flip();
+ events = tmpBuffer;
+ }
+ }
+
+ @Override
+ public double next() {
+ if (!events.hasRemaining() || throughput.getThroughput() != lastThroughput) {
+ generateNext();
+ }
+ lastEvent = events.get();
+ return lastEvent;
+ }
+}
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ConstantPoissonProcessGenerator.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ConstantPoissonProcessGenerator.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/DurationProvider.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/DurationProvider.java?rev=1819293&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/DurationProvider.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/DurationProvider.java Tue Dec 26 20:40:32 2017
@@ -0,0 +1,27 @@
+/*
+ * 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.jmeter.timers.poissonarrivals;
+
+/**
+ * @since 4.0
+ */
+@FunctionalInterface
+interface DurationProvider {
+ long getDuration();
+}
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/DurationProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/DurationProvider.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/EventProducer.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/EventProducer.java?rev=1819293&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/EventProducer.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/EventProducer.java Tue Dec 26 20:40:32 2017
@@ -0,0 +1,28 @@
+/*
+ * 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.jmeter.timers.poissonarrivals;
+
+/**
+ * @since 4.0
+ *
+ */
+@FunctionalInterface
+interface EventProducer {
+ double next();
+}
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/EventProducer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/EventProducer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimer.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimer.java?rev=1819293&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimer.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimer.java Tue Dec 26 20:40:32 2017
@@ -0,0 +1,215 @@
+/*
+ * 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.jmeter.timers.poissonarrivals;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.jmeter.testbeans.TestBean;
+import org.apache.jmeter.testelement.AbstractTestElement;
+import org.apache.jmeter.testelement.TestStateListener;
+import org.apache.jmeter.threads.AbstractThreadGroup;
+import org.apache.jmeter.timers.Timer;
+import org.apache.jorphan.util.JMeterStopThreadException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This timer generates poisson arrivals with constant throughput.
+ * On top of that, it tries to maintain the exact amount of arrivals for a given timeframe ({@link #throughputPeriod}.
+ * @since 4.0
+ */
+public class ExponentialTimer extends AbstractTestElement implements Cloneable, Timer, TestStateListener, TestBean, ThroughputProvider, DurationProvider {
+ private static final Logger log = LoggerFactory.getLogger(ExponentialTimer.class);
+
+ private static final long serialVersionUID = 3;
+ private static final ConcurrentMap<AbstractThreadGroup, EventProducer> groupEvents = new ConcurrentHashMap<>();
+
+ /**
+ * Desired throughput configured as {@code throughput/throughputPeriod} per second.
+ */
+ private double throughput;
+ private int throughputPeriod;
+
+ /**
+ * This is used to ensure you'll get {@code duration*throughput/throughputPeriod} samples during "test duration" timeframe.
+ * Even though arrivals are random, business users want to see round numbers in reports like "100 samples per hour",
+ * so the timer picks only those random arrivals that end up with round total numbers.
+ */
+ private long duration;
+
+ private long testStarted;
+
+ /**
+ * When number of required samples exceeds {@code exactLimit}, random generator would resort to approximate match of
+ * number of generated samples.
+ */
+ private int exactLimit;
+ private double allowedThroughputSurplus;
+
+ /**
+ * This enables to reproduce exactly the same sequence of delays by reusing the same seed.
+ */
+ private Long randomSeed;
+
+ /**
+ * This enables to generate events in batches (e.g. pairs of events with {@link #batchThreadDelay} sec in between)
+ * TODO: this should be either rewritten to double / ms, or dropped in favour of other approach
+ */
+ private int batchSize;
+ private int batchThreadDelay;
+
+ @Override
+ public Object clone() {
+ final ExponentialTimer newTimer = (ExponentialTimer) super.clone();
+ newTimer.testStarted = testStarted; // JMeter cloning does not clone fields
+ return newTimer;
+ }
+
+ @Override
+ public void testStarted() {
+ testStarted(null);
+ }
+
+ @Override
+ public void testStarted(String host) {
+ groupEvents.clear();
+ testStarted = System.currentTimeMillis();
+ }
+
+ @Override
+ public void testEnded() {
+ // NOOP
+ }
+
+ @Override
+ public void testEnded(String s) {
+ // NOOP
+ }
+
+ @Override
+ public long delay() {
+ double nextEvent;
+ EventProducer events = getEventProducer();
+ synchronized (events) {
+ nextEvent = events.next();
+ }
+ long delay = (long) (nextEvent * TimeUnit.SECONDS.toMillis(1) + testStarted - System.currentTimeMillis());
+ if (log.isDebugEnabled()) {
+ log.debug("Calculated delay is {}", delay);
+ }
+ delay = Math.max(0, delay);
+ long endTime = getThreadContext().getThread().getEndTime();
+ if (endTime > 0 && System.currentTimeMillis() + delay > endTime) {
+ throw new JMeterStopThreadException("The thread is scheduled to stop in " +
+ (System.currentTimeMillis() - endTime) + " ms" +
+ " and the throughput timer generates a delay of " + delay + "." +
+ " JMeter (as of 4.0) does not support interrupting of sleeping threads, thus terminating the thread manually."
+ );
+ }
+ return delay;
+ }
+
+ private EventProducer getEventProducer() {
+ AbstractThreadGroup tg = getThreadContext().getThreadGroup();
+ Long seed = randomSeed == null || randomSeed == 0 ? null : randomSeed;
+ return
+ groupEvents.computeIfAbsent(tg, x -> new ConstantPoissonProcessGenerator(
+ () -> ExponentialTimer.this.getThroughput() / throughputPeriod,
+ batchSize, batchThreadDelay, this, exactLimit, allowedThroughputSurplus, seed, true));
+ }
+
+ /**
+ * Returns number of generated samples per {@link #getThroughputPeriod}
+ * @return number of samples per {@link #getThroughputPeriod}
+ */
+ public double getThroughput() {
+ return throughput;
+ }
+
+ /**
+ * Sets number of generated samples per {@link #getThroughputPeriod}
+ * @param throughput number of samples per {@link #getThroughputPeriod}
+ */
+ public void setThroughput(double throughput) {
+ this.throughput = throughput;
+ }
+
+ /**
+ * Allows to use business values for throughput configuration.
+ * For instance, 100 samples per hour vs 100 samples per minute.
+ * @return
+ */
+ public int getThroughputPeriod() {
+ return throughputPeriod;
+ }
+
+ public void setThroughputPeriod(int throughputPeriod) {
+ this.throughputPeriod = throughputPeriod;
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+
+ public void setDuration(long duration) {
+ this.duration = duration;
+ }
+
+ public int getExactLimit() {
+ return exactLimit;
+ }
+
+ public void setExactLimit(int exactLimit) {
+ this.exactLimit = exactLimit;
+ }
+
+ public double getAllowedThroughputSurplus() {
+ return allowedThroughputSurplus;
+ }
+
+ public void setAllowedThroughputSurplus(double allowedThroughputSurplus) {
+ this.allowedThroughputSurplus = allowedThroughputSurplus;
+ }
+
+ public Long getRandomSeed() {
+ return randomSeed;
+ }
+
+ public void setRandomSeed(Long randomSeed) {
+ this.randomSeed = randomSeed;
+ }
+
+ public int getBatchSize() {
+ return batchSize;
+ }
+
+ public void setBatchSize(int batchSize) {
+ this.batchSize = batchSize;
+ }
+
+ public int getBatchThreadDelay() {
+ return batchThreadDelay;
+ }
+
+ public void setBatchThreadDelay(int batchThreadDelay) {
+ this.batchThreadDelay = batchThreadDelay;
+ }
+}
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerBeanInfo.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerBeanInfo.java?rev=1819293&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerBeanInfo.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerBeanInfo.java Tue Dec 26 20:40:32 2017
@@ -0,0 +1,97 @@
+/*
+ * 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.jmeter.timers.poissonarrivals;
+
+import java.beans.PropertyDescriptor;
+
+import org.apache.jmeter.testbeans.BeanInfoSupport;
+
+/**
+ * @since 4.0
+ */
+public class ExponentialTimerBeanInfo extends BeanInfoSupport {
+ public ExponentialTimerBeanInfo() {
+ super(ExponentialTimer.class);
+ createPropertyGroup(
+ "delay", //$NON-NLS-1$
+ new String[]{
+ "throughput", //$NON-NLS-1$
+ "throughputPeriod", //$NON-NLS-1$
+ "duration", //$NON-NLS-1$
+ }
+ );
+
+ PropertyDescriptor p;
+ p = property("throughput"); //$NON-NLS-1$
+ p.setValue(NOT_UNDEFINED, Boolean.TRUE);
+ p.setValue(DEFAULT, Double.valueOf(100));
+
+ p = property("throughputPeriod"); //$NON-NLS-1$
+ p.setValue(NOT_UNDEFINED, Boolean.TRUE);
+ p.setValue(DEFAULT, 3600);
+
+ p = property("duration"); //$NON-NLS-1$
+ p.setValue(NOT_UNDEFINED, Boolean.TRUE);
+ p.setValue(DEFAULT, Long.valueOf(3600));
+
+ createPropertyGroup(
+ "batching", //$NON-NLS-1$
+ new String[] {
+ "batchSize"
+ , "batchThreadDelay"
+ }
+ );
+
+ p = property("batchSize"); //$NON-NLS-1$
+ p.setValue(NOT_UNDEFINED, Boolean.TRUE);
+ p.setValue(DEFAULT, 1);
+
+ p = property("batchThreadDelay"); //$NON-NLS-1$
+ p.setValue(NOT_UNDEFINED, Boolean.TRUE);
+ p.setValue(DEFAULT, 0);
+
+
+ createPropertyGroup(
+ "accuracy", //$NON-NLS-1$
+ new String[]{
+ "exactLimit", //$NON-NLS-1$
+ "allowedThroughputSurplus" //$NON-NLS-1$
+ }
+ );
+
+ p = property("exactLimit"); //$NON-NLS-1$
+ p.setValue(NOT_UNDEFINED, Boolean.TRUE);
+ p.setValue(DEFAULT, Integer.valueOf(10000));
+
+ p = property("allowedThroughputSurplus"); //$NON-NLS-1$
+ p.setValue(NOT_UNDEFINED, Boolean.TRUE);
+ p.setValue(DEFAULT, Double.valueOf(1.0d));
+
+ createPropertyGroup(
+ "repeatability", //$NON-NLS-1$
+ new String[]{
+ "randomSeed" //$NON-NLS-1$
+ }
+ );
+
+ p = property("randomSeed"); //$NON-NLS-1$
+ p.setValue(NOT_UNDEFINED, Boolean.TRUE);
+ p.setValue(DEFAULT, Long.valueOf(0));
+ }
+}
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerBeanInfo.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerBeanInfo.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources.properties?rev=1819293&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources.properties (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources.properties Tue Dec 26 20:40:32 2017
@@ -0,0 +1,36 @@
+# 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.
+
+displayName=Exponential Timer
+delay.displayName=Delay threads to ensure target throughput
+throughput.displayName=Target throughput (in samples per "throughput period")
+throughput.shortDescription=Maximum number of samples you want to obtain per "throughput period", including all threads in group, from all affected samplers
+throughputPeriod.displayName=Throughput period (seconds)
+throughputPeriod.shortDescription=Throughput period. For example, if "throughput" is set to 42 and "throughput period" to 21 sec, then you'll get 2 samples per second.
+duration.displayName=Test duration (seconds)
+duration.shortDescription=This is used to ensure you'll get throughput*duration samples during "test duration" timeframe
+accuracy.displayName=Accuracy of generated delays
+exactLimit.displayName=Use approximate throughput when sequence length exceeds (samples)
+exactLimit.shortDescription=When the required number of samples is less than this limit, timer will generate exact number of samples
+allowedThroughputSurplus.displayName=Allowed throughput surplus (percents)
+allowedThroughputSurplus.shortDescription=When more than "max exact samples" samples is required, timer might generate slightly more events than specified by throughput
+repeatability.displayName=Setting to ensure repeatable sequence
+randomSeed.displayName=Random seed (change from 0 to random)
+randomSeed.shortDescription=Note: different timers should better have different seed values. Constant seed ensures timer generates the same delays each test start. The value of "0" means the timer is truly random (non-repeatable from one execution to another).
+batching.displayName=Batched departures
+batchSize.displayName=Number of threads in the batch (threads)
+batchSize.shortDescription=If the value exceeds 1, then multiple threads depart from the timer simultaneously. Average throughput still meets "throughput" value
+batchThreadDelay.displayName=Delay between threads in the batch (ms)
+batchThreadDelay.shortDescription=For instance, if set to 42, and the batch size is 3, then threads will depart at x, x+42ms, x+84ms
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources.properties
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources.properties
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources_fr.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources_fr.properties?rev=1819293&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources_fr.properties (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources_fr.properties Tue Dec 26 20:40:32 2017
@@ -0,0 +1,36 @@
+# 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.
+
+displayName=Exponential Timer
+delay.displayName=Delay threads to ensure target throughput
+throughput.displayName=Target throughput (in samples per "throughput period")
+throughput.shortDescription=Maximum number of samples you want to obtain per "throughput period", including all threads in group, from all affected samplers
+throughputPeriod.displayName=Throughput period (seconds)
+throughputPeriod.shortDescription=Throughput period. For example, if "throughput" is set to 42 and "throughput period" to 21 sec, then you'll get 2 samples per second.
+duration.displayName=Test duration (seconds)
+duration.shortDescription=This is used to ensure you'll get throughput*duration samples during "test duration" timeframe
+accuracy.displayName=Accuracy of generated delays
+exactLimit.displayName=Use approximate throughput when sequence length exceeds (samples)
+exactLimit.shortDescription=When the required number of samples is less than this limit, timer will generate exact number of samples
+allowedThroughputSurplus.displayName=Allowed throughput surplus (percents)
+allowedThroughputSurplus.shortDescription=When more than "max exact samples" samples is required, timer might generate slightly more events than specified by throughput
+repeatability.displayName=Setting to ensure repeatable sequence
+randomSeed.displayName=Random seed (change from 0 to random)
+randomSeed.shortDescription=Note: different timers should better have different seed values. Constant seed ensures timer generates the same delays each test start. The value of "0" means the timer is truly random (non-repeatable from one execution to another).
+batching.displayName=Batched departures
+batchSize.displayName=Number of threads in the batch (threads)
+batchSize.shortDescription=If the value exceeds 1, then multiple threads depart from the timer simultaneously. Average throughput still meets "throughput" value
+batchThreadDelay.displayName=Delay between threads in the batch (ms)
+batchThreadDelay.shortDescription=For instance, if set to 42, and the batch size is 3, then threads will depart at x, x+42ms, x+84ms
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources_fr.properties
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerResources_fr.properties
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ThroughputProvider.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ThroughputProvider.java?rev=1819293&view=auto
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ThroughputProvider.java (added)
+++ jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ThroughputProvider.java Tue Dec 26 20:40:32 2017
@@ -0,0 +1,28 @@
+/*
+ * 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.jmeter.timers.poissonarrivals;
+
+/**
+ * @since 4.0
+ *
+ */
+@FunctionalInterface
+interface ThroughputProvider {
+ double getThroughput();
+}
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ThroughputProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/components/org/apache/jmeter/timers/poissonarrivals/ThroughputProvider.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java?rev=1819293&r1=1819292&r2=1819293&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/save/SaveService.java Tue Dec 26 20:40:32 2017
@@ -149,13 +149,13 @@ public class SaveService {
// Must match _version property value in saveservice.properties
// used to ensure saveservice.properties and SaveService are updated simultaneously
- static final String PROPVERSION = "3.4";// Expected version $NON-NLS-1$
+ static final String PROPVERSION = "4.0";// Expected version $NON-NLS-1$
// Internal information only
private static String fileVersion = ""; // computed from saveservice.properties file// $NON-NLS-1$
// Must match the sha1 checksum of the file saveservice.properties (without newline character),
// used to ensure saveservice.properties and SaveService are updated simultaneously
- static final String FILEVERSION = "0acd8200bf252acf41d5eeca6aa56b0eaee06f0f"; // Expected value $NON-NLS-1$
+ static final String FILEVERSION = "c616712e26251d15588fbe615d1c31a34dbbf854"; // Expected value $NON-NLS-1$
private static String fileEncoding = ""; // read from properties file// $NON-NLS-1$
Added: jmeter/trunk/test/src/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerTest.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerTest.java?rev=1819293&view=auto
==============================================================================
--- jmeter/trunk/test/src/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerTest.java (added)
+++ jmeter/trunk/test/src/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerTest.java Tue Dec 26 20:40:32 2017
@@ -0,0 +1,92 @@
+/*
+ * 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.jmeter.timers.poissonarrivals;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ExponentialTimerTest {
+ private static final Logger LOG = LoggerFactory.getLogger(ExponentialTimerTest.class);
+
+ @Test
+ public void testTimer1() throws Exception {
+ ConstantPoissonProcessGenerator gen = getConstantPoissonProcessGenerator(2, 5, 42L);
+ gen.generateNext();
+ assertEquals(0.6501751901910952, gen.next(), 0.01);
+ assertEquals(1.2249545461599474, gen.next(), 0.01);
+ assertEquals(1.409559315928937, gen.next(), 0.01);
+ assertEquals(1.5717866281130652, gen.next(), 0.01);
+ assertEquals(2.1194190047658874, gen.next(), 0.01);
+ assertEquals(3.2878637366551384, gen.next(), 0.01);
+ assertEquals(3.517916456559849, gen.next(), 0.01);
+ assertEquals(3.679224444929692, gen.next(), 0.01);
+ assertEquals(3.9907119513763165, gen.next(), 0.01);
+ assertEquals(4.754414649148714, gen.next(), 0.01);
+ // ^^ 10 samples for 5 seconds
+ assertEquals(6.013095167372755, gen.next(), 0.01);
+ }
+
+ @Test
+ public void testExactNumberOfSamples() throws Exception {
+ java.util.Random rnd = new java.util.Random();
+ long seed = rnd.nextLong();
+ // Log seed, so the test can be reproduced in case of failure
+ LOG.info("testExactNumberOfSamples is using seed " + seed);
+ rnd.setSeed(seed);
+
+ int testDuration = 5;
+ for (int i = 0; i < 1000; i++) {
+ ConstantPoissonProcessGenerator gen = getConstantPoissonProcessGenerator(2, testDuration, rnd.nextLong());
+ gen.generateNext();
+ for (int j = 0; j < 10; j++) {
+ double next = gen.next();
+ assertTrue("Delay #" + j + " (0-based) exceeds " + testDuration + " seconds", next < 5.0);
+ }
+ }
+ }
+
+ protected ConstantPoissonProcessGenerator getConstantPoissonProcessGenerator(
+ final double throughput, final int duration, long seed) {
+ return new ConstantPoissonProcessGenerator(
+ new ThroughputProvider() {
+ @Override
+ public double getThroughput() {
+ return throughput; // samples per second
+ }
+ },
+ 1,
+ 0,
+ new DurationProvider() {
+ @Override
+ public long getDuration() {
+ return duration; // "expected" test duration: 3 seconds
+ }
+ },
+ 10000,
+ 0.1,
+ seed, // Seed
+ false
+ );
+ }
+
+}
Propchange: jmeter/trunk/test/src/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/test/src/org/apache/jmeter/timers/poissonarrivals/ExponentialTimerTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1819293&r1=1819292&r2=1819293&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml [utf-8] (original)
+++ jmeter/trunk/xdocs/changes.xml [utf-8] Tue Dec 26 20:40:32 2017
@@ -128,7 +128,8 @@ Summary
<h3>Timers, Assertions, Config, Pre- & Post-Processors</h3>
<ul>
- <li><bug>60213</bug>Boundary based extractor</li>
+ <li><bug>60213</bug>New component : Boundary based extractor</li>
+ <li><bug>61931</bug>New Component : Exponential Timer, timer that produces poisson arrivals with given constant throughput </li>
<li><bug>61644</bug>HTTP Cache Manager: "Use Cache-Control/Expires header when processing GET requests" should be checked by default</li>
<li><bug>61645</bug>Response Assertion: Add ability to assert on Request Data</li>
<li><bug>61534</bug>Convert AssertionError to a failed assertion in the JSR223Assertion allowing users to use assert in their code</li>
@@ -136,6 +137,7 @@ Summary
<li><bug>61758</bug><code>Apply to:</code> field in Extractors, Assertions : When entering a value in <code>JMeter Variable Name</code>, the radio box <code>JMeter Variable Name</code> should be selected by default. Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
<li><bug>61845</bug>New Component JSON Assertion based on AtlanBH JSON Path Assertion donated to JMeter-Plugins and migrated into JMeter core by Artem Fedorov (artem at blazemeter.com)</li>
<li><bug>61846</bug>Scoped Assertion should follow same order of evaluation as Post Processors</li>
+
</ul>
<h3>Functions</h3>
Modified: jmeter/trunk/xdocs/usermanual/component_reference.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/component_reference.xml?rev=1819293&r1=1819292&r2=1819293&view=diff
==============================================================================
--- jmeter/trunk/xdocs/usermanual/component_reference.xml (original)
+++ jmeter/trunk/xdocs/usermanual/component_reference.xml Tue Dec 26 20:40:32 2017
@@ -5310,6 +5310,39 @@ to the random delay.</property>
</component>
+<component name="Exponential Timer" index="§-num;.6.10" width="341" height="182" screenshot="timers/exponential_timer.png">
+<description><p>This timer produces poisson arrivals with given constant throughput. It provides the following features:
+<ul>
+ <li><i>Specific number of iterations per hour</i>.
+ The very basic requirement is to ensure you end up exactly 50
+ iterations per hour.</li>
+ <li><i>Bursty load</i> simulation. There is no easy way to test "50
+ iterations per hour as 10 bursts of 5 items".</li>
+ <li><i>Repeatable test profile</i>. All the random timers produce different
+ pattern on each test run. This is not good for low-level analysis
+ (e.g. compare of CPU% charts, etc).</li>
+ <li>
+ <li>Avoid all thread groups</li> to fire at 00:00:00. By default, all
+ thread groups would fire at 0, so there would be noticeable spike at
+ the start of the test.</li>
+</ul>
+</p></description>
+
+
+<properties>
+ <property name="Name" required="No">Descriptive name for this timer that is shown in the tree</property>
+ <property name="Target throughput (in samples per 'throughput period')" required="Yes">Maximum number of samples you want to obtain per "throughput period", including all threads in group, from all affected samplers.</property>
+ <property name="Throughput period (seconds)" required="Yes">Throughput period. For example, if "throughput" is set to 42 and "throughput period" to 21 sec, then you'll get 2 samples per second.</property>
+ <property name="Test duration (seconds)" required="Yes">This is used to ensure you'll get throughput*duration samples during "test duration" timeframe.</property>
+ <property name="Number of threads in the batch (threads)" required="Yes">If the value exceeds 1, then multiple threads depart from the timer simultaneously. Average throughput still meets "throughput" value.</property>
+ <property name="Delay between threads in the batch (ms)" required="Yes">For instance, if set to 42, and the batch size is 3, then threads will depart at x, x+42ms, x+84ms.</property>
+ <property name="Use approximate throughput when sequence length exceeds (samples)" required="Yes">When the required number of samples is less than this limit, timer will generate exact number of samples.</property>
+ <property name="Allowed throughput surplus (percents)" required="Yes">When more than "max exact samples" samples is required, timer might generate slightly more events than specified by throughput.</property>
+ <property name="Random seed (change from 0 to random)" required="Yes">Note: different timers should better have different seed values. Constant seed ensures timer generates the same delays each test start. The value of "0" means the timer is truly random (non-repeatable from one execution to another)..</property>
+</properties>
+
+</component>
+
<a href="#">^</a>
</section>