`
猫耳呀
  • 浏览: 170681 次
社区版块
存档分类
最新评论

优化技巧:提前if判断帮助CPU分支预测

 
阅读更多

摘要: 在stackoverflow上有一个非常有名的问题:为什么处理有序数组要比非有序数组快?,可见分支预测对代码运行效率有非常大的影响。要提高代码执行效率,一个重要的原则就是尽量避免CPU把流水线清空,那么提高分支预测的成功率就非常重要。

分支预测

在stackoverflow上有一个非常有名的问题:为什么处理有序数组要比非有序数组快?,可见分支预测对代码运行效率有非常大的影响。

现代CPU都支持分支预测(branch prediction)和指令流水线(instruction pipeline),这两个结合可以极大提高CPU效率。对于像简单的if跳转,CPU是可以比较好地做分支预测的。但是对于switch跳转,CPU则没有太多的办法。switch本质上是据索引,从地址数组里取地址再跳转。

要提高代码执行效率,一个重要的原则就是尽量避免CPU把流水线清空,那么提高分支预测的成功率就非常重要。

那么对于代码里,如果某个switch分支概率很高,是否可以考虑代码层面帮CPU把判断提前,来提高代码执行效率呢?

Dubbo里ChannelEventRunnable的switch判断

ChannelEventRunnable里有一个switch来判断channel state,然后做对应的逻辑:查看

一个channel建立起来之后,超过99.9%情况它的state都是ChannelState.RECEIVED,那么可以考虑把这个判断提前。

benchmark验证

下面通过jmh来验证下:

public class TestBenchMarks {

 

public enum ChannelState {
    CONNECTED, DISCONNECTED, SENT, RECEIVED, CAUGHT
}

@State(Scope.Benchmark)
public static class ExecutionPlan {
    @Param({ "1000000" })
    public int size;
    public ChannelState[] states = null;

    @Setup
    public void setUp() {
        ChannelState[] values = ChannelState.values();
        states = new ChannelState[size];
        Random random = new Random(new Date().getTime());
        for (int i = 0; i < size; i++) {
            int nextInt = random.nextInt(1000000);
            if (nextInt > 100) {
                states[i] = ChannelState.RECEIVED;
            } else {
                states[i] = values[nextInt % values.length];
            }
        }
    }
}

@Fork(value = 5)
@Benchmark
@BenchmarkMode(Mode.Throughput)
public void benchSiwtch(ExecutionPlan plan, Blackhole bh) {
    int result = 0;
    for (int i = 0; i < plan.size; ++i) {
        switch (plan.states[i]) {
        case CONNECTED:
            result += ChannelState.CONNECTED.ordinal();
            break;
        case DISCONNECTED:
            result += ChannelState.DISCONNECTED.ordinal();
            break;
        case SENT:
            result += ChannelState.SENT.ordinal();
            break;
        case RECEIVED:
            result += ChannelState.RECEIVED.ordinal();
            break;
        case CAUGHT:
            result += ChannelState.CAUGHT.ordinal();
            break;
        }
    }
    bh.consume(result);
}

@Fork(value = 5)
@Benchmark
@BenchmarkMode(Mode.Throughput)
public void benchIfAndSwitch(ExecutionPlan plan, Blackhole bh) {
    int result = 0;
    for (int i = 0; i < plan.size; ++i) {
        ChannelState state = plan.states[i];
        if (state == ChannelState.RECEIVED) {
            result += ChannelState.RECEIVED.ordinal();
        } else {
            switch (state) {
            case CONNECTED:
                result += ChannelState.CONNECTED.ordinal();
                break;
            case SENT:
                result += ChannelState.SENT.ordinal();
                break;
            case DISCONNECTED:
                result += ChannelState.DISCONNECTED.ordinal();
                break;
            case CAUGHT:
                result += ChannelState.CAUGHT.ordinal();
                break;
            }
        }
    }
    bh.consume(result);
}

}

  • benchSiwtch里是纯switch判断
  • benchIfAndSwitch 里用一个if提前判断state是否ChannelState.RECEIVED

benchmark结果是:

 

Result "io.github.hengyunabc.jmh.TestBenchMarks.benchSiwtch":
  576.745 ±(99.9%) 6.806 ops/s [Average]
  (min, avg, max) = (490.348, 576.745, 618.360), stdev = 20.066
  CI (99.9%): 569.939, 583.550

Run complete. Total time: 00:06:48

Benchmark (size) Mode Cnt Score Error Units
TestBenchMarks.benchIfAndSwitch 1000000 thrpt 100 1535.867 ± 61.212 ops/s
TestBenchMarks.benchSiwtch 1000000 thrpt 100 576.745 ± 6.806 ops/s

可以看到提前if判断的确提高了代码效率,这种技巧可以放在性能要求严格的地方。
Benchmark代码:https://github.com/hengyunabc/jmh-demo

总结

  • switch对于CPU来说难以做分支预测
  • 某些switch条件如果概率比较高,可以考虑单独提前if判断,充分利用CPU的分支预测机制

原文链接

分享到:
评论

相关推荐

    分支预测器实验。。。。

    总的来说,这个实验提供了实践经验,帮助我们理解现代处理器如何通过分支预测技术提升性能,这对于理解和优化计算机系统性能至关重要。通过深入研究并实践这些知识,你将能够更好地应对复杂的硬件优化问题。

    branchdemo:CPU 分支预测器演示

    func CountInt ( search int , ints [] int ) int {count := 0for _ , num := range ints {if num == search {count ++}}return count} 当提供的整数未排序时,CPU 的分支预测器无法可靠地预测每次迭代时是否遵循...

    代码优化-之-优化条件分支[定义].pdf

    4.优化第一次执行的条件分支:当CPU第一次执行到一个条件分支的时候,默认的预测分支规则是不跳转的那个分支(也就是紧接着条件跳转指令之后的那些指令)。 5.使用条件状态值生成掩码来移除条件分支:例如:if ...

    Lab4-分支预测-实验指导1

    当IF(指令 fetch)阶段的PC在BTB中命中时,如果BTB记录的跳转标志位表示最近一次执行时跳转了,那么处理器会预测当前分支也会跳转,并使用预测的PC作为下一条指令的地址。反之,若BTB预测不跳转,则不进行跳转。...

    动态分支预测实验1

    它预测程序中的分支指令(如if-then-else结构)的结果,以便处理器可以提前执行可能的路径,从而减少因等待分支结果而引起的延迟。动态分支预测与静态分支预测不同,它基于程序的运行时行为进行预测,而不是依赖于...

    Nginx中if语句的判断条件与多条件判断详解

    一、if语句中的判断条件(nginx)介绍 1、正则表达式匹配:  ==:等值比较;  ~:与指定正则表达式模式匹配时返回“真”,判断匹配与否时区分字符大小写;  ~*:与指定正则表达式模式匹配时返回“真”,判断匹配...

    shell判断cpu架构

    shell判断cpu架构

    c++入门内容(if语句)经典例题:(闰年判断.cpp)

    输入年份,输出是否是闰年

    Python基础教程之if判断,while循环,循环嵌套

    if判断 判断的定义  如果条件满足,就做一件事;条件不满足,就做另一件事;  判断语句又被称为分支语句,有判断,才有分支; if判断语句基本语法 if语句格式: if 判断的条件:  条件成立后做的事  … … 代码...

    PYTHON学习教程:条件判断(if、elif.、else代码练习print Run).docx

    PYTHON学习教程:条件判断(if、elif、else代码练习print Run) PYTHON学习教程中,条件判断是自动化任务的基础。在Python程序中,用if语句实现条件判断。if语句的基本结构是:if &lt;条件判断&gt;:&lt;执行语句&gt;,如果条件...

    MIPS.rar_pipeline_pipeline mips_superscaler verilog_分支预测_流水线MIPS

    常见的分支预测技术有:静态预测(如二进制预测器、计数器预测器)和动态预测(如最近未使用预测、双向预测、全局历史预测器等)。 **超标量(Superscalar)**: 超标量技术允许一个处理器在一个时钟周期内执行多条...

    05.if判断_Pythonif判断_If..._

    总之,Python的`if`判断是控制流程的关键工具,通过它可以实现灵活的条件分支,满足各种编程需求。从简单的单条件判断到复杂的逻辑结构,`if`语句始终扮演着重要的角色。理解并熟练运用`if`判断,能帮助我们编写出...

    代码中大量的 if else如何优化.doc

    代码中大量的 if else 如何优化 在编程中,我们常常会遇到大量的 if else 语句,这些语句会使得代码变得难以维护和阅读。那么,如何优化这些 if else 语句呢?下面我们来讨论一些常见的优化方法。 首先,让我们看...

    javascript教程:关于if简写语句优化的方法

    下面我们将探讨几种通过UglifyJS或直接在编写代码时采用的if语句优化技巧。 1. **使用三元操作符** 三元操作符是JavaScript中的一种简洁表达方式,它可以替代简单的if-else结构。例如: ```javascript if (foo) ...

    嵌入式开发优化方法嵌入式开发优化方法.doc

    - 条件分支语句:优化分支结构,提高执行效率。 6. **代码大小优化** - 紧凑数据类型:不一定总能减小代码大小,需综合考虑。 - 减少参数数量:减少调用开销。 - 全局数据堆指针:高效访问全局变量。 - 初始化...

    linux shell编程if语句内判断参数详解

    Linux Shell 编程 if 语句内判断参数详解 Linux Shell 编程中,if 语句是一种基本的控制结构,用于根据条件执行不同的操作。if 语句可以与各种参数结合使用,以判断文件、目录、字符串、数字等的状态,从而执行相应...

    计组头歌实验:MIPS单周期CPU设计(24条指令)(HUST)1-4关源码

    在本实验中,我们关注的是MIPS(Microprocessor without Interlocked Pipeline Stages)单周期CPU的设计,这是一种基于RISC(Reduced Instruction Set Computer)架构的处理器。MIPS架构以其简单高效而闻名,常用于...

    策略模式消除if-else分支判断.zip

    "策略模式消除if-else分支判断"的主题旨在通过引入策略模式和工厂模式来解决这一问题,提高代码的灵活性和可复用性。 策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。在策略模式中,一个类的行为或...

    C语言if语句PPT课件.pptx

    介绍了if语句的基本概念、功能模型、代码模型和各种类型的if语句,包括基本的if语句、if-else语句和if-else if-else语句,并提供了多个实例来帮助学习者更好地理解和掌握if语句的使用。 第一部分:if语句的基本概念...

Global site tag (gtag.js) - Google Analytics