In my scenario, the methods in benchmark should run sequentially in one thread and modify the state in order.
For example, there is a List<Integer> called num in the benchmark class. What I want is: first, run add() to append a number into the list. Then, run remove() to remove the number from the list.
The calling sequence must be add() --> remove(). If remove() runs before add() or they run concurrently, they would raise exceptions because there's no element in the list.
That is, add() and remove() must be called sequentially and in one thread.
In Control the order of methods using JMH, I learned that the methods run in the lexicographical order. I tried the code below:
@State(Scope.Group)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.AverageTime)
@Fork(value = 10)
public class ListBenchmark {
private List<Integer> num;
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder()
.verbosity(VerboseMode.NORMAL)
.syncIterations(true)
.threads(1)
.include(".*" + ListBenchmark.class.getCanonicalName() + ".*")
.build();
new Runner(options).run();
}
@Setup(Level.Invocation)
public void setup() throws Exception {
num = new ArrayList<>();
}
@Benchmark
@BenchmarkMode(Mode.SingleShotTime)
@Group("num")
public void add() throws Exception {
num.add(1);
}
@Benchmark
@BenchmarkMode(Mode.SingleShotTime)
@Group("num")
public void remove() throws Exception {
num.remove(0);
}
}
But it doesn't work, because the add method and the remove method run concurrently. In some cases, the remove runs before add and raises IndexOutOfBoundsException.
How to run the methods in benchmarks sequentially with JMH?