- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
每个尝试利用 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() 是一个本地方法。 native 调用下行到操作系统并执行相应的库。正确的?这使我们假设如果不使用本地调用的返回值并且不执行 io 操作,编译器可以消除本地调用。
我们想知道如果驻留在操作系统某处并处理来自 Java 世界的 native 调用的库会怎样不提供返回值,但执行 io 操作(例如日志记录)。那些指令会被彻底抹去吗?
为了证明我们的假设,我们通过简单的 JMH 测试和 native 调用重建了场景。我们编译了三个 c-native 库来执行:
正如我们在 JMH 测试(类似于 measureWrong() 测试)中对它们的称呼一样,它们都没有被消除,即使是那些不执行 io 操作的。由于测试结果,我们的假设无法得到证实。 native 调用无法优化,这意味着 Math.log() 和自定义 native 调用不具有相同的基础。他们不是本地人。也许我们在本地库代码中犯了一个错误,至少应该删除测试 1 的本地调用。如果这是真的,我们将与您分享我们的代码。
所以我们进一步搜索并找到了一个术语 Intrinsics ,其中 java 代码将被替换为对应架构非常优化的代码。 java.lang.Math.log() 具有这样的内在实现。本地人和内在人之间有什么关系吗?如果上述 Natives 和 Intrinsics 之间关系的假设成立,编译器是否会执行以下步骤来消除 native 调用?
最佳答案
As we looked closely to the test we note that Math.log() is a native method. And native calls go down to the OS and execute a corresponding lib. Right?
native 调用不会转到操作系统,它们会通过 JNI 转到 native 库。这可能最终进入操作系统,或者它可能进入某些用户提供的库。对于 JDK 中的 native 方法,我们还可以期望将一些 native 调用编译为内部函数。
This lead us to the assumption that native calls could be eliminated by the compiler if their return value is not used and they don't perform io operations.
JVM 不会查看任意 native 调用以确定它们可能具有或不具有何种副作用。这意味着 native 调用确实是作为方法调用进行的(在汇编级别,您跳转到某个地方的外部代码,堆栈上的另一个框架等)。这也意味着 JVM 无法消除它们或它们的依赖输入。
Native calls cannot be optimized out, meaning that Math.log() and custom native calls do not have the same basis.
是的。
Are there any relations between the Natives and Intrinsics?
一些 native JDK 方法是内部方法。但是普通的 JDK 方法也可以是内部函数。内部方法集也因一个 JVM 而异。
If the above assumption of the relationship between Natives and Intrinsics is valid will the compiler perform the following steps to eliminate the native call?
Math.log函数被转化为C2编译器IR(中间表示)中的一个特殊节点。这个节点可以被优化掉,因为它没有副作用,而且它的值从未被使用过。如果使用该值,JVM 就会知道为此节点发出专用机器代码。
总结:Intrinsics 是内置于 JVM 编译器中的优化方法替换。它们可用于替换任何方法( native 或其他):
关于java - Math.log() 的死代码消除如何在 JMH 示例中工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31751252/
我在网上找不到关于 here 的任何信息,谁能告诉我 ops/us, Cnt, Score, Error 是什么意思。 最佳答案 ops/us - 每微秒的操作(基准方法执行) Cnt - 试验总数(
我在网上找不到关于 here 的任何信息,谁能告诉我 ops/us, Cnt, Score, Error 是什么意思。 最佳答案 ops/us - 每微秒的操作(基准方法执行) Cnt - 试验总数(
在我的 jmh 课上,我正在使用 @BenchmarkMode(Mode.SampleTime) @Measurement(iterations = 10) @Threads(value = 10)
我已经将其视为微基准测试中的潜在陷阱之一。如果您指定@Measurement(或@Warmup)将运行固定的时间量,这意味着,当比较不同的运行(例如,不同的平台、不同版本的 VM 等)时,您将获得更少
想开始做我从现在开始写的方法的基准测试,有很长一段时间的动力,终于决定从昨天开始这样做。但我对我的设置过程感到震惊。 我已经正确安装了 JMH 插件。 所有导入工作正常。 甚至我的 POM 也没有显示
我正在使用 JMH,但发现有些难以理解:我有一种方法用 @Benchmark 注释。我设置了 measurementIterations(3) .该方法被调用了 3 次,但在每次迭代调用中,该函数运行
假设我有一个带有两个参数的 JMH 测试: @Param( { "1", "2", 4", "8", "16" } ) int param1; @Param( { "1", "2", 4", "8",
我正在使用tutorial学习JMH基准测试。 我注意到here中的功能benchMurmur3_128有2个与预热相关的东西。 因此,我对Fork注释中的热身属性和带有迭代属性的Warmup注释之间
我不明白 JMH 结果中的 score 属性?我也没有在网上找到任何关于它的信息。 谁能告诉我,它是关于什么的?据我所知,高分比低分好,但这究竟是什么意思,它是如何计算的? 最佳答案 JMH 支持以下
官方资源 官方Github样例 应用场景 对要使用的数据结构不确定,不知道谁的性能更好 对历史方法代码重构,要评判改造之后的性能提升多少 ( 我要做的场景 )
我用 JMH 测试我的程序性能。并且无法配置堆大小。我想知道为什么它不起作用。 问题: 为什么 JMH 不接受堆大小配置? JMH 是否在没有 jvmArgs 方法的情况下吸收 idea 堆大小设置?
我正在使用 JMH 对 DOM 解析器进行基准测试。我得到了非常奇怪的结果,因为第一次迭代实际上比后面的迭代运行得更快 谁能解释为什么会发生这种情况?另外,百分位数和所有数字是什么意思,为什么它在第三
我正在对 Spring Boot 应用程序启动时间进行基准测试。完整的项目是here ,这是 WIP,但相关类如下。 抽象基本状态: public abstract class BootAbstrac
我有:这样的方法: @GenerateMicroBenchmark public static void calculateArraySummary(String[] args) { // c
我读到了JMH并尝试了提供的示例。 我想做的是测量以下场景的统计数据, [ 1] client order -> [2] server -> [3] start processing the orde
我正在玩 Math.max 看看它是否受到分支预测的影响(不,至少在 x64 的 JDK 上不是,有一个 cmovl),如果按位实现可以与默认实现竞争。所有测试如下所示: @Threads(4) @S
我在 JMH 中看到一个常见问题 ConstantFold ,但是如果我有逆问题怎么办?我需要静态最终字段作为参数。例如,它可以是某些算法的某个常量变量。但在 java-doc 中我看到: {@lin
我正在尝试一个非常快的方法(~20 us/op),它似乎工作得很好,除了一些随机很长的迭代: Iteration 63: 14.319 us/op Iteration 64: 13.128 us/
我想看看是否有一种方法可以告诉 JMH 仅测量微基准调用的所有方法中的一个特定方法。 我想使用单元测试作为基础自动创建微基准,因此我不必手动构建微基准。在我的研究中,我有一个大型代码库,我在其中进行了
我正在运行 JMH 基准测试: Options opt = new OptionsBuilder() .output("C:/test/infinis
我是一名优秀的程序员,十分优秀!