理解cpu分支预测,提高代码效率(代码片段)

author author     2023-01-21     793

关键词:

摘要: 技术传播的价值,不仅仅体现在通过商业化产品和开源项目来缩短我们构建应用的路径,加速业务的上线速率,也会体现在优秀程序员在工作效率提升、产品性能优化和用户体验改善等小技巧方面的分享,以提高我们的工作能力。

技术分享图片

技术传播的价值,不仅仅体现在通过商业化产品和开源项目来缩短我们构建应用的路径,加速业务的上线速率,也会体现在优秀程序员在工作效率提升、产品性能优化和用户体验改善等小技巧方面的分享,以提高我们的工作能力。

从本期开始,我们将邀请来自阿里巴巴各个技术团队的程序员,涵盖中间件、前端、移动开发、大数据和人工智能等多个技术领域,分享他们在工作中的小技巧, 内容力求简短、实用和可操作。

第一期的分享嘉宾,是来自阿里巴巴中间件技术团队的程序员 - 断岭,他是阿里微服务开源项目 Dubbo 的项目组成员,也是Java线上诊断开源项目 Arthas 的负责人。

第一期:理解CPU分支预测,提高代码效率

一、基础概念:
Dubbo: 是一款高性能、轻量级的开源Java RPC框架,提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现;
ChannelEventRunnable: Dubbo 里所有网络事件的回调接口;
JMH:即Java Microbenchmark Harness,是专门用于代码微基准测试的工具套件。在性能优化的过程中,可以使用JMH对优化的结果进行量化的分析。
二、需求缘起:
在Stack Overflow上有一个非常著名的问题:为什么处理有序数组要比非有序数组快?从问题的结论来看,是分支预测对代码运行效率的提升起到了非常重要的作用。

现今的CPU是都支持分支预测(branch prediction)和指令流水线(instruction pipeline),这俩的结合可以极大的提高CPU的工作效率,从而提高代码执行效率。但这仅适用于简单的if跳转,但对于Switch跳转,CPU则没有太好的解决办法,因为Switch本质上是据索引,是从地址数组里取地址再跳转。

三、思考和方案假设:
要提高代码执行效率,一个重要的实现原则就是尽量避免CPU把流水线清空,从Stack Overflow上的讨论结果来看,通过提高分支预测的成功率,是可以降低CPU对流水线清空的概率。那么,除了在硬件层面,是否可以考虑代码层面帮CPU把判断提前,来提高代码执行效率呢?

四、方案验证:
在Dubbo的ChannelEventRunnable里有一个Switch来判断channel state。当一个channel建立起来之后,超过99.9%的情况,它的state都是ChannelState.RECEIVED,我们可以考虑,把这个判断提前。

以下通过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)br/>@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)br/>@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](assumes normal distribution)
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判断提高了近3倍的代码效率,这种技巧可以放在性能要求严格的地方。

五、总结:
Switch对于CPU来说难以做分支预测;
某些Switch条件如果概率比较高,可以在代码层设置提前if判断,充分利用CPU的分支预测机制;



cpu分支预测

...会按我们的代码的顺序一条一条去试,而是随机找出一个分支,执行,如果不对,再随机找到一个分支  当时由于种种原因,也没过多去想这个问题,最近查了下资料,发现里面的学问还挺大的  php解释器是由c编写的,是个... 查看详情

指令跳转与预测(代码片段)

...会跳转,以及不知道会跳转到哪里去。如果在TETCH有可以预测branch是否taken,或者知道taken之后的下一条指令,效率提高。怎么去做到branch。如何预测?1.该指令是否是branch指令? 查看详情

对于c51外部中断和程序调用的理解(代码片段)

对于c51外部中断和程序调用的理解四川师范大学工学院2018级徐浩宇首先介绍一下C51外部中断的基本概念中断的优点:1、实时处理。需要CPU立即做出相应或处理。2、异常处理。运行过程中,出现断电、程序出错等问题ÿ... 查看详情

利用cpu的分支预测(branchprediction)模型优化if-else(代码片段)

...博客下面将介绍另一种能“压榨”计算机性能的优化手段分支预测分支预测(BranchPrediction)是从Pentium5代开始的一种先进的,解决处理分支指令(if-then-else)导致流水线失败的数据处理方法,由CPU来判断程序分支的进行方... 查看详情

cpu亲和性绑定(代码片段)

...u绑定,最直观的好处就是减少cpu之间的cache同步和切换,提高了cpucache的命中率,提高代码的效率。从cpu架构上,NUMA拥有独立的本地内存,节点之间可以通过互换模块做连接和信息交互,因此每个CPU可以访问整个系统的内存,但... 查看详情

如何提高scrapy的爬取效率(代码片段)

提高scrapy的爬取效率增加并发:默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改CONCURRENT_REQUESTS=100值为100,并发设置成了为100。降低日志级别:在运行scrapy时,会有大量日志信息的输出,为了减少CPU... 查看详情

使用django-debug-toolbar优化query提高代码效率(代码片段)

...用Django-debug-toolbar能够快速找出哪些地方的SQL可以优化,提高程序执行效率 1.安装 Django-debug-toolbar:pipinstalldjango-debug-toolbar 2.在Django项目中创建APP用于toolbar测试: 查看详情

并行计算程序设计(cudac)(代码片段)

...CPU快10倍以上异构并行计算中的可移植性和可扩展性目标理解并行编程中可扩展性和可移植性的重要性和本质可扩展性相同的应用程序在新一代内核上可以高效运行相同的应用程序在更多相同的内核上可以高效运行可移植性同一... 查看详情

深入理解协程(代码片段)

目录深入理解python协程概述生成器变形yield/sendyieldsendyieldfromasyncio.coroutine和yieldfromasync和await深入理解python协程概述由于cpu和磁盘读写的效率有很大的差距,往往cpu执行代码,然后遇到需要从磁盘中读写文件的操作,此时主线程... 查看详情

提高工作效率的命令(代码片段)

...号,有背景介绍,有输入,有输出,以及适量的文字辅助理解,这样方便能一眼看懂 查看详情

可怕!cpu竟成了黑客的帮凶!(代码片段)

...!CPU一味求快出事儿了!自从我们车间用上了乱序执行和分支预测后,生产效率那是大大提升,领导不仅在全厂的员工大会表扬了我们,还把这两项技术向全厂推广,在我们8个CPU核心车间都铺开了,性能甩开竞争对手CPU几条街... 查看详情

并发编程之多线程(代码片段)

...之间的资源是不共享的。为什么要使用多线程?  为了提高程序效率。  可是多进程也可以提高程序效率啊,为什么不使用多进程,那是因为进程对操作系统的资源耗费非常高。多线程是如何提高程序的开发效率?  多线... 查看详情

mysql调优之-索引指南(代码片段)

...目的就在于提高查询效率,可以类比字典3、你可以简单理解为排好序的快速查找的数据结构索引约等于查得快+?排序索引的优势和劣势?优势1、创建了索引,提高了检索效率,降低的数据库的IO成本2、通过索引列对数据进行排... 查看详情

linux性能学习(1.2):cpu_如何提高cpu缓存命中率(代码片段)

...们编写的程序尽可能的被CPU缓存命中,从而尽可能的提高运行效率?1数组访问测试代码测试如下:#include<stdio.h>#include<sys/time.h>#def 查看详情

linux性能学习(1.2):cpu_如何提高cpu缓存命中率(代码片段)

...们编写的程序尽可能的被CPU缓存命中,从而尽可能的提高运行效率?1数组访问测试代码测试如下:#include<stdio.h>#include<sys/time.h>#def 查看详情

进程和计划任务管理(想提高工作效率吗?从计划工作任务开始)(代码片段)

进程和计划任务管理一、进程1.1、程序和进程的关系程序1、保存在硬盘、光盘等介质中的可执行代码和数据2、文件中静态保存的代码进程:1、在CPU及内存中运行的程序代码2、动态执行的代码3、父、子进程4、每个程序可以... 查看详情

进程和计划任务管理(想提高工作效率吗?从计划工作任务开始)(代码片段)

进程和计划任务管理一、进程1.1、程序和进程的关系程序1、保存在硬盘、光盘等介质中的可执行代码和数据2、文件中静态保存的代码进程:1、在CPU及内存中运行的程序代码2、动态执行的代码3、父、子进程4、每个程序可以... 查看详情

对于c51外部中断和程序调用的理解(代码片段)

对于c51外部中断和程序调用的理解四川师范大学工学院2018级徐浩宇首先介绍一下C51外部中断的基本概念中断的优点:1、实时处理。需要CPU立即做出相应或处理。2、异常处理。运行过程中,出现断电、程序出错等问题ÿ... 查看详情