【问题标题】:Simple micro-benchmark with JMH使用 JMH 进行简单的微基准测试
【发布时间】:2018-04-16 05:57:45
【问题描述】:

another question on Stack Overflow的启发,我写了一个微基准来检查,什么效率更高:

  • 有条件地检查零除数或
  • 捕获和处理ArithmeticException

下面是我的代码:

@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;
        }
    }
}

我对 JMH 完全陌生,不确定代码是否正常。

我的基准测试是否正确?你发现有什么错误吗?

旁白:请不要建议在https://codereview.stackexchange.com 上提问。对于 Codereview 代码必须已经按预期工作。我不确定这个基准是否能按预期工作。

【问题讨论】:

    标签: java microbenchmark jmh


    【解决方案1】:

    我发现缺少的最重要的事情是任何形式的随机性。这将使分支预测更容易完成其工作,这将使这两种方法都比它们在实践中除以 0 时可能更快。

    我会对每种方法做三种变体:

    1. 包含一个混合了零的随机数组,并使用该数组的索引对基准进行参数化。
    2. 具有非零数字的随机数组
    3. 全为 0

    这应该让您对整体性能有一个很好的了解,包括分支预测。对于第 (1) 点,使用 0 与非 0 的比率可能也很有趣。

    我忘记了 JMH 是否允许您直接对数组的单个值进行参数化。如果是这样,那么我会使用它。否则,您必须参数化该数组的索引。在这种情况下,我还将全 0 放入一个数组中,以便保持访问是所有测试的一部分。我也可能会创建一个“控件”,它只访问数组并返回其值,这样您就可以更直接地找出开销。

    另外,一个小问题:我认为您不需要返回浮点数,因为它们只是从除法实际产生的整数转换而来。

    【讨论】:

    • 关于参数化,我猜,正确的方法是使用int 参数确定百分比,相应地填充数组并在设置中对其进行洗牌。在基准测试中,我要么遍历数组,要么在每一步计算index = (index+1) & array.length-1(使用两个数组长度的幂)。您将放置点 2 和 3 放在特殊情况下。
    • @maaartinus 这可能是一个很好的简化。不过,最后我检查了一下,JMH 强烈建议不要在基准方法中循环。我对其中的微妙之处并不肯定。
    • 我知道;这就是我提出替代方案的原因。但是,我想,那里的开销比循环要高(尽管我希望边界检查现在已经消失了(见底部的this question)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多