加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – JIT – 微优化 – if语句消除

发布时间:2020-12-15 08:28:00 所属栏目:Java 来源:网络整理
导读:我们假设我们有以下代码: public static void check() { if (Config.initialized) { ... }} Config.initialized在开头是假的,只有在方法已经编译JIT之后的某个时刻才变为true.价值永远不会回归假. 我“知道”有很多非常复杂的优化正在进行(循环展开,分支预
我们假设我们有以下代码:

public static void check() {   
    if (Config.initialized) {
           ...
    }
}

Config.initialized在开头是假的,只有在方法已经编译JIT之后的某个时刻才变为true.价值永远不会回归假.

我“知道”有很多非常复杂的优化正在进行(循环展开,分支预测,内联,逃逸分析等),虽然我远远没有详细了解它们,但我主要对以下内容感兴趣目前:

> JIT编译器是否有办法在某个时间点之后检测到if将始终为true,以便可以完全跳过检查?完全我的意思是没有变量访问,没有条件检查/ jne等…
>如果JIT没有办法摆脱(从某一点开始)不必要的样本检查(我不知道它怎么可能)有什么我可以做的来支持它?我唯一的想法是重新创建类,并在初始化事件发生后从字节代码中删除不必要的代码.

我知道这是完全微观优化,即使使用像JMH这样的工具也可能很难保证,但我仍然想知道和理解.

最后但并非最不重要的:

>我的理解是正确的,如果上面的方法内联所有这些方法将被重新编译(假设它们很热),以防某些东西发生变化,以便检查方法需要重新编译?

如果我正确理解我的JitWatch测试结果,上述问题的答案应该是:

>不,没办法.总会有条件检查.
>真的只能通过转型
>是的

解决方法

  1. Does the JIT compiler have a way to detect that the if will always be true after a certain point

是的,如果该字段是静态final,并且它的holder类已在JIT编译器启动时初始化.显然这不适用于您的情况,因为Config.initialized不能成为静态final.

  1. is there anything I could do to support that?

java.lang.invoke.MutableCallSite来救援.

本课程专为您提出的要求而设计.其setTarget方法支持在运行时重新绑定调用站点.它引起了当前编译方法的优化,并有可能在以后用新目标重新编译它.

可以使用dynamicInvoker方法获得用于调用MutableCallSite目标的MethodHandle.请注意,MethodHandle应该是静态final,以允许内联.

  1. if the above method got inlined somewhere that all those methods would be recompiled

是.

这是一个基准,证明mutableCallSite方法在开始时和alwaysFalse一样快,并且在切换切换后也和alwaysTrue一样快.我还在@Holger建议中包含了一个静态字段切换以进行比较.

package bench;

import org.openjdk.jmh.annotations.*;
import java.lang.invoke.*;
import java.util.concurrent.*;

@State(Scope.Benchmark)
public class Toggle {
    static boolean toggleField = false;

    static final MutableCallSite toggleCallSite =
            new MutableCallSite(MethodHandles.constant(boolean.class,false));

    static final MethodHandle toggleMH = toggleCallSite.dynamicInvoker();

    public void switchToggle() {
        toggleField = true;
        toggleCallSite.setTarget(MethodHandles.constant(boolean.class,true));
        MutableCallSite.syncAll(new MutableCallSite[]{toggleCallSite});
        System.out.print("*** Toggle switched *** ");
    }

    @Setup
    public void init() {
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
        executor.schedule(this::switchToggle,10100,TimeUnit.MILLISECONDS);
        executor.shutdown();
    }

    @Benchmark
    public int alwaysFalse() {
        return 0;
    }

    @Benchmark
    public int alwaysTrue() {
        return ThreadLocalRandom.current().nextInt();
    }

    @Benchmark
    public int field() {
        if (toggleField) {
            return ThreadLocalRandom.current().nextInt();
        } else {
            return 0;
        }
    }

    @Benchmark
    public int mutableCallSite() throws Throwable {
        if ((boolean) toggleMH.invokeExact()) {
            return ThreadLocalRandom.current().nextInt();
        } else {
            return 0;
        }
    }
}

通过5次预热迭代和10次测量迭代运行基准测试,我得到以下结果:

# JMH version: 1.20
# VM version: JDK 1.8.0_192,VM 25.192-b12

# Benchmark: bench.Toggle.alwaysFalse

# Run progress: 0,00% complete,ETA 00:01:00
# Fork: 1 of 1
# Warmup Iteration   1: 3,875 ns/op
# Warmup Iteration   2: 3,369 ns/op
# Warmup Iteration   3: 2,699 ns/op
# Warmup Iteration   4: 2,696 ns/op
# Warmup Iteration   5: 2,703 ns/op
Iteration   1: 2,697 ns/op
Iteration   2: 2,696 ns/op
Iteration   3: 2,696 ns/op
Iteration   4: 2,706 ns/op
Iteration   5: *** Toggle switched *** 2,698 ns/op
Iteration   6: 2,698 ns/op
Iteration   7: 2,692 ns/op
Iteration   8: 2,707 ns/op
Iteration   9: 2,712 ns/op
Iteration  10: 2,702 ns/op


# Benchmark: bench.Toggle.alwaysTrue

# Run progress: 25,ETA 00:00:48
# Fork: 1 of 1
# Warmup Iteration   1: 5,159 ns/op
# Warmup Iteration   2: 5,198 ns/op
# Warmup Iteration   3: 4,314 ns/op
# Warmup Iteration   4: 4,321 ns/op
# Warmup Iteration   5: 4,306 ns/op
Iteration   1: 4,306 ns/op
Iteration   2: 4,310 ns/op
Iteration   3: 4,297 ns/op
Iteration   4: 4,324 ns/op
Iteration   5: *** Toggle switched *** 4,356 ns/op
Iteration   6: 4,300 ns/op
Iteration   7: 4,310 ns/op
Iteration   8: 4,290 ns/op
Iteration   9: 4,297 ns/op
Iteration  10: 4,294 ns/op


# Benchmark: bench.Toggle.field

# Run progress: 50,ETA 00:00:32
# Fork: 1 of 1
# Warmup Iteration   1: 3,596 ns/op
# Warmup Iteration   2: 3,429 ns/op
# Warmup Iteration   3: 2,973 ns/op
# Warmup Iteration   4: 2,937 ns/op
# Warmup Iteration   5: 2,934 ns/op
Iteration   1: 2,927 ns/op
Iteration   2: 2,928 ns/op
Iteration   3: 2,932 ns/op
Iteration   4: 2,929 ns/op
Iteration   5: *** Toggle switched *** 3,002 ns/op
Iteration   6: 4,887 ns/op
Iteration   7: 4,866 ns/op
Iteration   8: 4,877 ns/op
Iteration   9: 4,867 ns/op
Iteration  10: 4,877 ns/op


# Benchmark: bench.Toggle.mutableCallSite

# Run progress: 75,ETA 00:00:16
# Fork: 1 of 1
# Warmup Iteration   1: 3,474 ns/op
# Warmup Iteration   2: 3,332 ns/op
# Warmup Iteration   3: 2,750 ns/op
# Warmup Iteration   4: 2,701 ns/op
# Warmup Iteration   5: 2,701 ns/op
Iteration   1: 2,699 ns/op
Iteration   4: 2,771 ns/op
Iteration   6: 4,310 ns/op
Iteration   7: 4,306 ns/op
Iteration   8: 4,312 ns/op
Iteration   9: 4,317 ns/op
Iteration  10: 4,301 ns/op

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读