gpt4 book ai didi

java - 是否可以阻止 JIT 优化方法调用?

转载 作者:行者123 更新时间:2023-11-30 04:41:29 24 4
gpt4 key购买 nike

我们正在构建一个用于 Java 字节码程序的平均情况运行时分析的工具。其中一部分是测量实际运行时间。因此,我们将采用任意的、用户提供的方法,该方法可能有也可能没有结果,并且可能有也可能没有副作用(示例包括快速排序、阶乘、虚拟嵌套循环……)并执行它(使用反射),测量耗时。 (我们是否正确进行基准测试不是这里的重点。)

在基准测试代码中,我们显然没有对结果做任何事情(有些方法甚至没有结果)。因此,无法得知 JIT 可能会做什么,而且我们实际上观察到它有时似乎会优化整个基准测试方法调用。由于基准测试方法在现实中并不是孤立使用的,这使得基准测试毫无用处。

我们如何防止 JIT 这样做?我们不想完全关闭它,因为这样基准测试需要很长时间,而且我们无论如何都希望对“真实”运行时进行基准测试(因此我们希望 JIT 在方法内部处于 Activity 状态)。

我知道this question但给定的场景太狭窄;我们不知道结果类型(如果有的话),因此不能以 JIT 认为无用的某种方式使用结果。

最佳答案

简单的解决方案是编写一个更现实的基准测试,它可以做一些几乎有用的事情,这样它就不会被优化掉。

有很多技巧可以混淆 JIT,但这些不太可能对您有帮助。

这是一个基准示例,其中通过反射、MethodHandle 调用该方法并编译为空。

import java.lang.invoke.*;
import java.lang.reflect.*;

public class Main {
public static void main(String... args) throws Throwable {
for (int j = 0; j < 5; j++) {
testViaReflection();
testViaMethodHandle();
testWithoutReflection();
}
}

private static void testViaReflection() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Method nothing = Main.class.getDeclaredMethod("nothing");
int runs = 10000000; // triggers a warmup.
long start = System.nanoTime();
Object[] args = new Object[0];
for (int i = 0; i < runs; i++)
nothing.invoke(null, args);
long time = System.nanoTime() - start;
System.out.printf("A call to %s took an average of %.1f ns using reflection%n", nothing.getName(), 1.0 * time / runs);
}

private static void testViaMethodHandle() throws Throwable {
MethodHandle nothing = MethodHandles.lookup().unreflect(Main.class.getDeclaredMethod("nothing"));
int runs = 10000000; // triggers a warmup.
long start = System.nanoTime();
for (int i = 0; i < runs; i++) {
nothing.invokeExact();
}
long time = System.nanoTime() - start;
System.out.printf("A call to %s took an average of %.1f ns using MethodHandle%n", "nothing", 1.0 * time / runs);
}

private static void testWithoutReflection() {
int runs = 10000000; // triggers a warmup.
long start = System.nanoTime();
for (int i = 0; i < runs; i++)
nothing();
long time = System.nanoTime() - start;
System.out.printf("A call to %s took an average of %.1f ns without reflection%n", "nothing", 1.0 * time / runs);
}

public static void nothing() {
// does nothing.
}
}

打印

A call to nothing took an average of 6.6 ns using reflection
A call to nothing took an average of 10.7 ns using MethodHandle
A call to nothing took an average of 0.4 ns without reflection
A call to nothing took an average of 4.5 ns using reflection
A call to nothing took an average of 9.1 ns using MethodHandle
A call to nothing took an average of 0.0 ns without reflection
A call to nothing took an average of 4.3 ns using reflection
A call to nothing took an average of 8.8 ns using MethodHandle
A call to nothing took an average of 0.0 ns without reflection
A call to nothing took an average of 5.4 ns using reflection
A call to nothing took an average of 13.2 ns using MethodHandle
A call to nothing took an average of 0.0 ns without reflection
A call to nothing took an average of 4.9 ns using reflection
A call to nothing took an average of 8.7 ns using MethodHandle
A call to nothing took an average of 0.0 ns without reflection

我曾假设 MethodHandles 比反射更快,但事实并非如此。

关于java - 是否可以阻止 JIT 优化方法调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12176175/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com