Faster JMeter If Controllers

When load testing to a large scale, it’s just as important for your test scripts to be optimized as it is for your servers. Your tests will often need to simulate thousands of users on a single physical box running JMeter and so you need to be running as efficiently as possible. If you are using the standard If Controller in your test with their default configuration, then it’s likely that you’re burning CPU cycles and resources just to check if two variables are the same.

By default, the If Controller will use JavaScript to evaluate the condition you’ve specified. This means that JMeter will create a brand new JavaScript execution context each time an If Controller is processed. This happens for every controller in every thread. That will give your garbage collector a good work out as well as your servers!

Fortunately, the JMeter team knew this could be a problem and so added the option evaluate the condition as a variable expression. This allows you to create a JMeter function to check your condition that returns either true or false. This is tens to hundreds of times faster.

Creating custom functions is even easier than creating a test component. You just need to add the class file to your plugin project and JMeter will automatically find it and do the rest. Here’s another article that goes into the specifics of JMeter functions a bit more and you can also read my original guide on creating custom components.

Common Checks

The most common checks I perform in my scripts are to test if a variable is equal to some value. Using a JavaScript condition, you would specify something like ${value} == 1. However, for my tests, I’ve created my own __eq() function for quickly comparing two values:

package org.adesquared.jmeter.functions;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.jmeter.engine.util.CompoundVariable;
import org.apache.jmeter.functions.AbstractFunction;
import org.apache.jmeter.functions.InvalidVariableException;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.Sampler;

public class EqFunction extends AbstractFunction {

	private final static String NAME = "__eq";
	private final static ArrayList<String> DESC = new ArrayList<String>(2);

	private CompoundVariable a;
	private CompoundVariable b;

	static {
		DESC.add("a");
		DESC.add("b");
	}

	@Override
	public String getReferenceKey() {
		return NAME;
	}

	public List<String> getArgumentDesc() {
		return DESC;
	}

	@Override
	public String execute(SampleResult previousResult, Sampler currentSampler) throws InvalidVariableException {

		String a = this.a.execute();
		String b = this.b.execute();

		return a.equals(b) ? "true" : "false";

	}

	@Override
	public void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException {

		if (parameters.size() < 2) throw new InvalidVariableException("Not enough parameters for " + NAME);

		Iterator<CompoundVariable> it = parameters.iterator();
		this.a = it.next();
		this.b = it.next();

	}

}

Using that, I can enable the Interpret Condition as Variable Expression option in the If Controller and change the condition to ${__eq(${value},1)}. That will give me exactly the same functionality as before but without JMeter creating a new JavaScript context each time.

How much faster?

To test how much faster, I put together a small script that had a 100,000 iteration Loop Controller that contained an If Controller that contained a Test Action Sampler (a sampler that will do nothing in this case). I defined the variable value to have the value 1 in the test. You can download the test script from here.

When the test is executed using JavaScript to interpret the condition, it takes 78 seconds to complete the test. Changing the condition to a variable expression using my new __eq() function, the test took less than 2 seconds. Both tests ran using the server VM.

I know which one I’m going to continue to use in the future!

Bonus Not Equals Function

Of course I also often need to check if two values aren’t equal, for those, I use this function:

package org.adesquared.jmeter.functions;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.jmeter.engine.util.CompoundVariable;
import org.apache.jmeter.functions.AbstractFunction;
import org.apache.jmeter.functions.InvalidVariableException;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.Sampler;

public class NeqFunction extends AbstractFunction {

	private final static String NAME = "__neq";
	private final static ArrayList<String> DESC = new ArrayList<String>(2);

	private CompoundVariable a;
	private CompoundVariable b;

	static {
		DESC.add("a");
		DESC.add("b");
	}

	@Override
	public String getReferenceKey() {
		return NAME;
	}

	public List<String> getArgumentDesc() {
		return DESC;
	}

	@Override
	public String execute(SampleResult previousResult, Sampler currentSampler) throws InvalidVariableException {

		String a = this.a.execute();
		String b = this.b.execute();

		return a.equals(b) ? "false" : "true";

	}

	@Override
	public void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException {

		if (parameters.size() < 2) throw new InvalidVariableException("Not enough parameters for " + NAME);

		Iterator<CompoundVariable> it = parameters.iterator();
		this.a = it.next();
		this.b = it.next();

	}

}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: