com.blazemeter.jmeter.threads.arrivals.ArrivalsThreadStarter Maven / Gradle / Ivy
package com.blazemeter.jmeter.threads.arrivals;
import com.blazemeter.jmeter.threads.AbstractThreadStarter;
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.threads.ListenerNotifier;
import org.apache.jorphan.collections.ListedHashTree;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
public class ArrivalsThreadStarter extends AbstractThreadStarter {
private static final Logger log = LoggerFactory.getLogger(ArrivalsThreadStarter.class);
private ArrivalsThreadGroup arrivalsTG;
protected long scheduledCount = 0;
protected double rollingTime = 0;
public ArrivalsThreadStarter(int groupIndex, ListenerNotifier listenerNotifier, ListedHashTree listedHashTree, StandardJMeterEngine standardJMeterEngine, ArrivalsThreadGroup owner) {
super(groupIndex, owner, listedHashTree, listenerNotifier, standardJMeterEngine);
arrivalsTG = owner;
}
protected void supplyActiveThreads() throws InterruptedException {
while (needMoreArrivals()) {
if (!arrivalsTG.releasedPoolThread()) {
if (arrivalsTG.canCreateMoreThreads()) {
addActiveThread();
} else {
log.debug("Not creating thread because of concurrency limit");
}
}
}
}
public synchronized boolean needMoreArrivals() throws InterruptedException {
if (rollingTime > 0) { // a case for very first thread
while (rollingTime >= System.currentTimeMillis()) {
long maxWait = (long) (rollingTime - System.currentTimeMillis());
if (maxWait > 0) {
log.debug("Waiting " + maxWait);
wait(maxWait);
}
}
} else {
rollingTime = System.currentTimeMillis();
startTime = rollingTime / 1000.0;
}
double currentRate;
do {
currentRate = getCurrentRate();
if (currentRate == 0) {
log.debug("Zero arrivals rate, waiting a bit");
rollingTime += 200; // FIXME: magic constant
Thread.sleep(200);
}
} while (currentRate == 0);
if (currentRate < 0) {
log.info("Duration limit reached, no more arrivals needed, had arrivals: " + scheduledCount);
((ArrivalsThreadGroup) owner).setArrivalsLimit(String.valueOf(scheduledCount));
return false;
}
tickRollingTime(currentRate);
return !owner.isLimitReached();
}
// ported from Taurus PBench module
protected double getCurrentRate() {
long rampUp = owner.getRampUpSeconds();
long hold = owner.getHoldSeconds();
long steps = owner.getStepsAsLong();
double throughput = owner.getTargetLevelFactored();
double timeOffset = rollingTime / 1000.0 - startTime;
if (timeOffset >= rampUp + hold) {
return -1; // means no more requests
}
if (rampUp == 0 || timeOffset > rampUp) {
return throughput;
} else if (steps > 0) {
double stepSize = throughput / (double) steps;
double stepLen = rampUp / (double) steps;
return stepSize * (Math.floor(timeOffset / stepLen) + 1);
} else {
double slope = throughput / rampUp;
return slope * Math.sqrt(2 * scheduledCount / slope);
}
}
protected void tickRollingTime(double currentRate) {
if (currentRate > 0) {
double delay = currentRate > 0 ? (1000.0 / currentRate) : 0;
rollingTime += delay;
scheduledCount++;
} else {
log.debug("Negative arrivals rate, ignoring");
}
}
}