如何在JMH示例中

时间:2015-07-31 16:48:22

标签: java intrinsics microbenchmark jmh

每个试图利用JMH框架创建一些有意义的测试的人都会遇到JMH样本测试 (http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/)。 当我们经历它们时,我们坚持使用死代码(JMHSample_08_DeadCode.java)。

摘录:

private double x = Math.PI;

@Benchmark
public void baseline() {
 // do nothing, this is a baseline
}

@Benchmark
public void measureWrong() {
 // This is wrong: result is not used, and the entire computation is optimized out.
 Math.log(x);
}

measureWrong()的测量大约是 与基线测试相同。因为返回值了 从不使用Math.log()。因此HotSpot编译器 将消除死代码。好的,明白但是编译器如何确定可以消除Math.log()。

当我们仔细观察测试时,我们注意到Math.log()是一种本机方法。 本机调用转到操作系统并执行相应的lib。对? 这导致我们假设编译器可以消除本机调用,如果它们的返回值没有被使用并且它们不执行操作。

我们想知道如果lib驻留在OS中的某个地方并且处理来自java世界的本机调用 不提供返回值,但提供操作(例如日志记录)。 这些说明会完全消失吗?

为了证明我们的假设,我们使用简单的JMH测试和本机调用重建了场景。 我们编译了三个c-native libs来执行:

  1. 返回42
  2. 参数添加
  3. 空文件创建
  4. 正如我们在JMH测试中调用它们(类似于measureWrong()测试),它们都没有被消除,甚至没有消除执行io操作的那个。 由于测试结果,我们的假设无法确认。原生调用无法优化,这意味着Math.log()和自定义本机调用没有相同的基础。它们不是原生的。也许我们在我们的原生lib代码中犯了一个错误,至少测试1的本地调用应该已被删除。如果这是真的,我们将与您分享我们的代码。

    所以我们进一步搜索并找到了一个术语Intrinsics,其中java代码将被替换为 对应于架构非常优化的代码。 java.lang.Math.log()具有这样的内部实现。 Natives和Intrinsics之间有什么关系吗? 如果上述Natives和Intrinsics之间关系的假设有效,编译器会执行以下步骤来消除本机调用吗?

    • 在编译时,HotSpot会检查Math.log()是否存在内部实现(在jdk中?),并用该代码替换Math.log()。
    • 之后,第二次检查发生在HotSpot查看方法返回值的位置。在这个结果上,HotSpot决定彻底消除Math.log()调用。

1 个答案:

答案 0 :(得分:9)

  

当我们仔细观察测试时,我们注意到Math.log()是一种本机方法。本机调用转到操作系统并执行相应的lib。正确?

本机调用不会进入操作系统,而是通过JNI进入本机库。这可能最终会进入操作系统,或者它可能会进入一些用户提供的lib。对于JDK中的本机方法,我们还可以期望将一些本机调用编译为内在函数。

  

这导致我们假设编译器可以消除本机调用,如果它们的返回值没有被使用并且它们不执行操作。

JVM不会查看任意本机调用,以确定它们可能会或可能不会产生哪种副作用。这意味着本机调用确实是作为方法调用进行的(在程序集级别,你跳转到某个地方的foriegn代码,堆栈上的另一个框架等)。这也意味着JVM无法消除它们或它们的相关输入。

  

本机调用无法优化,这意味着Math.log()和自定义本机调用没有相同的基础。

  

Natives和Intrinsics之间是否有任何关系?

一些原生JDK方法是内在的。但普通的JDK方法也可以是内在函数。内部方法的集合也不同于一个JVM到下一个JVM。

  

如果上述Natives和Intrinsics之间关系的假设有效,编译器会执行以下步骤来消除本机调用吗?

Math.log函数转换为C2编译器IR(中间表示)中的特殊节点。这个节点可以被优化掉,因为它已知没有副作用,它的价值从未使用过。如果使用该值,则JVM知道为该节点发出专用机器代码。

总结: 内在函数是JVM编译器中内置的优化方法替换。它们可用于替换任何方法(本机或其他方法):

  1. 专业汇编代码
  2. 专业红外代码
  3. 内部JVM方法调用
  4. 上述
  5. 的组合
相关问题