I'm trying to prove algorithm complexity by using benchmark data. My algorithm to test is the binary search algorithm (stated complexity is O(log n)
) and I want to use JMH library for benchmarking.
Here is test example:
public class BinarySearchTest {
private static SearchAlgorithm binaryIterative = new BinarySearchIterative();
private static SearchAlgorithm binaryRecursive = new BinarySearchRecursive();
@Test
public void runBenchmarks() throws Exception {
Options options = new OptionsBuilder()
.include(this.getClass().getName() + ".*")
.mode(Mode.Throughput)
.forks(1)
.threads(1)
.warmupIterations(0)
.measurementIterations(1)
.shouldFailOnError(true)
.shouldDoGC(true)
.build();
new Runner(options).run();
}
@Benchmark
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public void binarySearchIterativeBenchmark(ExecutionPlan plan) {
//given
int size = randomPositiveIntLessThan(plan.arraySize);
int[] array = generateUninterrupted(0, size);
int target = randomPositiveIntLessThan(size);
//when
var result = binaryIterative.find(array, 0, array.length, target);
//then
assertTrue(result != -1);
}
This is class with algorithm implementation:
public class BinarySearchIterative implements SearchAlgorithm {
@Override
public int find(int[] array, int start, int end, int target) {
if (end > array.length) {
return -1;
}
int left = start;
int right = end;
while (left <= right) {
int median = left + (right - left) / 2;
if (array[median] == target) {
return median;
}
if (array[median] > target) {
right = median - 1;
}
if (array[median] < target) {
left = median + 1;
}
}
return -1;
}
I use a class annotated with @State
to get size for arrays:
@State(Scope.Benchmark)
public class ExecutionPlan {
@Param({"100000", "200000", "300000", "400000", "500000",
"1000000", "2000000", "3000000", "4000000", "5000000",
"10000000", "20000000", "30000000", "40000000", "50000000"})
public int arraySize;
So I have next results:
BinarySearchTest.binarySearchIterativeBenchmark 100000 thrpt
31.602 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 200000 thrpt 14.520 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 300000 thrpt
9.004 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 400000 thrpt 6.896 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 500000 thrpt
5.333 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 1000000 thrpt 2.304 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 2000000 thrpt
0.790 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 3000000 thrpt 0.451 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 4000000 thrpt
0.330 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 5000000 thrpt 0.232 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 10000000 thrpt
0.135 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 20000000 thrpt 0.061 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 30000000 thrpt
0.039 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 40000000 thrpt 0.033 ops/ms BinarySearchTest.binarySearchIterativeBenchmark 50000000 thrpt
0.025 ops/ms
But if I plot the graph score/arraysize I get not log(n) but rather 1/x graph. If I use Mode.AverageTime
the graph is rather x^2.
Here is my graph for data provide above, y[ms/ops], x[arraysize]:
How can I get Operation units from JMH or tune my test?