Simple micro-benchmark with JMH

2019-04-12 09:36发布

问题:

Inspired by another question on Stack Overflow, I have written a micro-benchmark to check, what is more efficient:

  • conditionally checking for zero divisor or
  • catching and handling an ArithmeticException

Below is my code:

@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MyBenchmark {

    private int a = 10;
    // a little bit less obvious than int b = 0;
    private int b = (int) Math.floor(Math.random());

    @Benchmark
    public float conditional() {
        if (b == 0) {
            return 0;
        } else {
            return a / b;
        }
    }

    @Benchmark
    public float exceptional() {
        try {
            return a / b;
        } catch (ArithmeticException aex) {
            return 0;
        }
    }
}

I am totally new to JMH and not sure if the code is allright.

Is my benchmark correct? Do you see any mistakes?

Side not: please don't suggest asking on https://codereview.stackexchange.com. For Codereview code must already work as intended. I am not sure this benchmark works as intended.

回答1:

The big thing I see missing is any sort of randomness. That will make it easier for the branch prediction to do its work, which will make both methods faster than they probably would be in practice for division by 0.

I would do three variations of each method:

  1. with a random array with zeros intermixed, and have the benchmark be parameterized with an index into that array.
  2. with a random array of non-zero numbers
  3. with all 0s

That should give you a good idea of the overall performance, including branch prediction. For point (1), it may also be interesting to play with the ratio of 0s to non-0s.

I forget if JMH lets you parameterize directly on individual values of an array. If it does, then I'd use that. Otherwise, you'll have to parameterize on the index to that array. In that case, I would also put the all-0s in an array so that the stay access is part of all tests. I would also probably create a "control" that just accesses the array and returns its value, so that you can find out that overhead more directly.

Also, a minor nit: I don't think you need to return floats, since they'll just be converted from the ints that the division actually produces.