.NET8极致性能优化Branch
前言
branch(分支)顾名思义:代码通过判断条件形成的执行情况,比如if/else这种判断分支。分支有用的代码是非常有意义的,它意味着是程序不可分割的部分。但是分支无意义的代码同样副作用巨大,比如一个永远不会执行的分支却一直被CLR加载,被JIT编译,被CPU识别,这种开销是巨大的。现代化的硬件,通过流水线技术,预测下一个指令执行的是谁,并且在上一个指令尚未执行完成,下一个指令已经被读取,解码,加载了。这也是一种巨大的开销,为了减少这种开销。目前的技术情况,编译器能做的是努力将分支最小化。本篇来看下。
原文:.NET8极致性能优化Branch ,作者:江湖评谈,欢迎关注。
概述
有一种简单的减少分支影响性能的方法就是完全的删除分支,但是这似乎不可能。比如多个分支通向同一个结果,我们可以通过一种方式找到冗余的分支,全部删掉,只留下一个分支。这是目前的一种优化方案。
public class Tests
{
private static readonly Random s_rand = new();
private readonly string _text = "hello world!";
[Params(1.0, 0.5)]
public double Probability { get; set; }
public ReadOnlySpan<char> TrySlice() => SliceOrDefault(_text.AsSpan(), s_rand.NextDouble() < Probability ? 3 : 20);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<char> SliceOrDefault(ReadOnlySpan<char> span, int i)
{
if ((uint)i < (uint)span.Length)
{
return span.Slice(i);
}
return default;
}
}
TrySlice在.NET7上的ASM如下:
; Tests.TrySlice()push rdi push rsi
push rbp
push rbx
sub rsp,28
vzeroupper
mov rdi,rcx
mov rsi,rdx
mov rcx,[rdi+8]
test rcx,rcx
je short M00_L01
lea rbx,[rcx+0C]
mov ebp,[rcx+8]
M00_L00:
mov rcx,1EBBFC01FA0
mov rcx,[rcx]
mov rcx,[rcx+8]
mov rax,[rcx]
mov rax,[rax+48]
call qword ptr [rax+20]
vmovsd xmm1,qword ptr [rdi+10]
vucomisd xmm1,xmm0
ja short M00_L02
mov eax,14
jmp short M00_L03
M00_L01:
xor ebx,ebx
xor ebp,ebp
jmp short M00_L00
M00_L02:
mov eax,3
M00_L03:
cmp eax,ebp
jae short M00_L04
cmp eax,ebp
ja short M00_L06
mov edx,eax
lea rdx,[rbx+rdx*2]
sub ebp,eax
jmp short M00_L05
M00_L04:
xor edx,edx
xor ebp,ebp
M00_L05:
mov [rsi],rdx
mov [rsi+8],ebp
mov rax,rsi
add rsp,28
pop rbx
pop rbp
pop rsi
pop rdi
ret
M00_L06:
call qword ptr [7FF999FEB498]
int 3
; Total bytes of code 136
看下M00_L03
M00_L03:cmp eax,ebp jae short M00_L04
cmp eax,ebp
ja short M00_L06
mov edx,eax
lea rdx,[rbx+rdx*2]
eax中已经被放置了3或者0x14,把它与dbp(也就是span.length)进行比较,这里有两个比较
cmp eax,ebp //看这个cmp
jae short M00_L04
cmp eax,ebp //以及这个cmp 它们完全一样 比较
两个一样的cmp指令,前者cmp是if条件判断,后者cmp是span.Slice内联的机器码。所以这可以进行优化。在.NET8里面一个cmp分支被消除掉了:
M00_L04:
cmp eax,ebp
jae short M00_L07
mov ecx,eax
lea rdx,[rdi+rcx*2]
另外一种优化方式是,可以用简单的位操作技术来避免分支。
public class Tests
{
[Arguments(42, 84)]
public bool BothGreaterThanOrEqualZero(int i, int j) => i >= 0 && j >= 0;
}
.NET7里面BothGreaterThanOrEqualZero的ASM如下:
; Tests.BothGreaterThanOrEqualZero(Int32, Int32)
test edx,edx
jl short M00_L00
mov eax,r8d
not eax
shr eax,1F
ret
M00_L00:
xor eax,eax
ret
; Total bytes of code 16
; Tests.BothGreaterThanOrEqualZero(Int32, Int32)
test edx,edx
jl short M00_L00
mov eax,r8d
not eax
shr eax,1F
ret
M00_L00:
xor eax,eax
ret
; Total bytes of code 16
以上代码的&&符号可以用位操作符号来替代,可以将他们重写为等效的(i | j) >= 0。现在.NET8如下:
; Tests.BothGreaterThanOrEqualZero(Int32, Int32)
or edx,r8d
mov eax,edx
not eax
shr eax,1F
ret
; Total bytes of code 11
如上所述,分支完全给避免掉了,不用判断,用位操作替代。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
渠成开源社区2023年工作总结
“道虽迩,不行不至;事虽小,不为不成。”2023年,对渠成开源社区来说,是不平凡的一年,更是值得回味的一年。 这一年,我们从零搭建了渠成开源社区,确定了工作组成员; 这一年,我们链接了开源作者/开源社区,为他们提供了服务; 这一年,我们举办了多场活动,为更多用户创建了彼此交流的机会; …… 回望2023年,渠成开源社区所经历的惊喜与感动,都离不开社区中每位伙伴的陪伴和努力。我们不断迭代、不断创新,我们共同走过的每一个瞬间都值得纪念与庆贺。 一、从0到1搭建社区 1成立社区工作组 2023年4月,我们确定了渠成开源社区的工作组团队,包括顾问专家、市场运营、产品规划、网站开发、设计以及财务几大角色。期间完善了社区相关运营机制,包括不限于确定社区23年的目标、完善社区的媒体账号、确定社区对外信息公开机制等。 社区的对外信息公开机制,真正让社区内每一次的会议、每一笔的支出都做到有迹可寻。在官网的“财务公开”版块,现已公开了2021年11月-2023年11月渠成开源社区的现金流水账。 2023年,工作组共开展了13场的会议,工作组成员在会上提出各项社区成员关注的问题,共同探讨以提供相应的解决方案...
- 下一篇
Snowy 2.5.0 已发布
此次升级主要体现在bug修复,功能优化,尤其是前端,整体对依赖进行了能升级的升级,语法全都升级为vue3的语法糖写法,去掉了出现的每一个this.xxx;其次开源版本接到部分小伙提供的优秀PR,本团队非常表示感谢;详细更新如下: 开源版更新 内容 【优化】日志列表修改为点击详情按钮时再请求详细数据 【优化】日志page查询中排除部分字段(提升查询速度) 【优化】jar制品包中移除冗余文件(_sql目录、md类型) 【优化】自定分页大小, 首次加载显示正常, 当输入条件点击查询之后, 分页大小又恢复成默认的 【优化】CommonEntity序列化时忽略deleteFlag字段(jackson) 【优化】user相关实体序列化时忽略password字段(jackson) 【修复】修复岗位接口无法依据名称关键词搜索数据bug 【修复】修复可通过UA设置长文本绕过日志记录的漏洞 【修复】修复修改个人信息接口水平越权漏洞 【修复】同步修复bug若干 【更新】默认将createUser跟updateUser进行翻译成用户名 【更新】在 vscode 中打开的 .vue 文件代码类型无法被推断的情况...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- 2048小游戏-低调大师作品
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS8编译安装MySQL8.0.19
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Red5直播服务器,属于Java语言的直播服务器