前言

.NET8在.NET7的基础上进行了进一步的优化,比如CHRL(全称:CORINFO_HELP_RNGCHKFAIL)优化技术,CORINFO_HELP_RNGCHKFAIL是边界检查,在.NET7里面它已经进行了部分优化,但是.NET8里面它继续优化,类似人工智能,.NET8能意识到某些性能问题,从而进行优化。本篇来看下

概述

JIT会对数组,字符串的范围边界进行检查。比如数组的索引是否在数组长度范围内,不能超过。所以JIT就会产生边界检查的步骤。

  1. public class Tests
  2. {
  3. private byte[] _array = new byte[8];
  4. private int _index = 4;
  5. public void Get() => Get(_array, _index);
  6. [MethodImpl(MethodImplOptions.NoInlining)]
  7. private static byte Get(byte[] array, int index) => array[index];
  8. }

Get函数.NET7的ASM如下:

  1. ; Tests.Get(Byte[], Int32)
  2. sub rsp,28
  3. cmp edx,[rcx+8]
  4. jae short M01_L00
  5. mov eax,edx
  6. movzx eax,byte ptr [rcx+rax+10]
  7. add rsp,28
  8. ret
  9. M01_L00:
  10. call CORINFO_HELP_RNGCHKFAIL
  11. int 3

cmp指令把数组的MT(方法表)偏移8位置的数组长度与当前的数组索引对比,两者如果索引大于(后者)或等于(jae)数组长度(前者)的时候。就会跳转到CORINFO_HELP_RNGCHKFAIL进行边界检查,可能会引发超出引范围的异常IndexOutOfRangeException。但是实际上这段这段代码的访问只需要两个mov,一个是数组的索引,一个是(MT(方法表)+0x10+索引)取其值返回即可。所以这个地方有清晰可见的优化的地方。

.NET8学习了一些范围边界的智能化优化,也就说,有的地方不需要边界检查,从而把边界检查优化掉,用以提高代码的性能。下面例子:

  1. private readonly int[] _array = new int[7];
  2. public int GetBucket() => GetBucket(_array, 42);
  3. private static int GetBucket(int[] buckets, int hashcode) =>
  4. buckets[(uint)hashcode % buckets.Length];

.NET7它的ASM如下:

  1. ; Tests.GetBucket()
  2. sub rsp,28
  3. mov rcx,[rcx+8]
  4. mov eax,2A
  5. mov edx,[rcx+8]
  6. mov r8d,edx
  7. xor edx,edx
  8. idiv r8
  9. cmp rdx,r8
  10. jae short M00_L00
  11. mov eax,[rcx+rdx*4+10]
  12. add rsp,28
  13. ret
  14. M00_L00:
  15. call CORINFO_HELP_RNGCHKFAIL
  16. int 3

它依然进行了边界检查,然.NET8的JIT能自动识别到(uint)hashcode%buckets.Length这个索引不可能超过数组的长度也就是buckets.Length。所以.NET8可以省略掉边界检查,如下.NET8 ASM

  1. ; Tests.GetBucket()
  2. mov rcx,[rcx+8]
  3. mov eax,2A
  4. mov r8d,[rcx+8]
  5. xor edx,edx
  6. div r8
  7. mov eax,[rcx+rdx*4+10]
  8. ret

再看下另外一个例子:

  1. public class Tests
  2. {
  3. private readonly string _s = "\"Hello, World!\"";
  4. public bool IsQuoted() => IsQuoted(_s);
  5. private static bool IsQuoted(string s) =>
  6. s.Length >= 2 && s[0] == '"' && s[^1] == '"';
  7. }

IsQuoted检查字符串是否至少有两个字符,并且字符串开头和结尾均以引号结束,s[^1]表示s[s.Length - 1]也就是字符串的长度。.NET7 ASM如下:

  1. ; Tests.IsQuoted(System.String)
  2. sub rsp,28
  3. mov eax,[rcx+8]
  4. cmp eax,2
  5. jl short M01_L00
  6. cmp word ptr [rcx+0C],22
  7. jne short M01_L00
  8. lea edx,[rax-1]
  9. cmp edx,eax
  10. jae short M01_L01
  11. mov eax,edx
  12. cmp word ptr [rcx+rax*2+0C],22
  13. sete al
  14. movzx eax,al
  15. add rsp,28
  16. ret
  17. M01_L00:
  18. xor eax,eax
  19. add rsp,28
  20. ret
  21. M01_L01:
  22. call CORINFO_HELP_RNGCHKFAIL
  23. int 3

注意看.NET7的骚操,它实际上进行了边界检查,但是只检查了一个,因为它只有一个jae指令跳转。这是为什么呢?JIT已经知道不需要对s[0]进行边界检查,因为s.Length >= 2已经检查过了,只要是小于2的索引(因为索引是无符号,没有负数)都不需要检查。但是依然对s[s.Length - 1]进行了边界检查,所以.NET7虽然也是骚操,但是它这个骚操不够彻底。

我们来看下彻底骚操的.NET8

  1. ; Tests.IsQuoted(System.String)
  2. mov eax,[rcx+8]
  3. cmp eax,2
  4. jl short M01_L00
  5. cmp word ptr [rcx+0C],22
  6. jne short M01_L00
  7. dec eax
  8. cmp word ptr [rcx+rax*2+0C],22
  9. sete al
  10. movzx eax,al
  11. ret
  12. M01_L00:
  13. xor eax,eax
  14. ret

完全没有了边界检查,JIT不仅意识到s[0]是安全的,因为检查过了s.Length >= 2。因为检查过了s.Length >= 2,还意识到s.length> s.Length-1 >=1。所以不需要边界检查,全给它优化掉了。

可以看到.NET8的性能优化的极致有多厉害,它基本上榨干了JIT的引擎,让其进行最大智能化程度的优化。


点击下加入技术讨论群:

欢迎加入.NET技术交流群

结尾

作者:江湖评谈

欢迎关注公众号:jianghupt,文章首发,以及更多高阶内容分享。

.NET8极致性能优化CHRL的更多相关文章

  1. MIS性能优化常见问题与方案(辅助项目组性能优化的总结贴)

    最近帮忙公司的几个项目组进行了不同方面的性能优化,发现几个项目都出现了一些共性的问题.这里写一篇文章,总结一下这几类问题,以及其对应的解决方案.方便其它项目组参考.   常见问题一:打开页面非常慢,有 ...

  2. 【前端构建】WebPack实例与前端性能优化

    计划把微信的文章也搬一份上来. 这篇主要介绍一下我在玩Webpack过程中的心得.通过实例介绍WebPack的安装,插件使用及加载策略.感受构建工具给前端优化工作带来的便利. 壹 | Fisrt 曾几 ...

  3. Android应用性能优化(转)

    人类大脑与眼睛对一个画面的连贯性感知其实是有一个界限的,譬如我们看电影会觉得画面很自然连贯(帧率为24fps),用手机当然也需要感知屏幕操作的连贯性(尤其是动画过度),所以Android索性就把达到这 ...

  4. Web前端性能优化教程09:图像和Cookie优化

    本文是Web前端性能优化系列文章中的第九篇,主要讲述内容:图像和Cookie优化.完整教程可查看:  一. 图像优化 图像基础知识 gif: 适用于动画效果,例如提示的滚动条图案 jpg: 是一种使用 ...

  5. Web前端性能优化教程07:精简JS 移除重复脚本

    本文是Web前端性能优化系列文章中的第七篇,主要讲述内容:精简Javascript代码,以及移出重复脚本.完整教程可查看:  一.精简javascript 基础知识 精简:从javascript代码中 ...

  6. web前端性能优化

    性能优化对于用户体验无疑是非常重要的,下面介绍一些性能优化的方法. 1.减少HTTP请求 http请求越多,那么消耗的时间越多,如果在加上网络很糟糕,那么问题就更多了.且如果网页中的图片.css文件. ...

  7. 一些新的web性能优化技术

    1.IconFont:图标字体,这是近年来新流行的一种以字体代替图片的技术.它可以适应任何分辨率而不会出现图片模糊问题,与图片相比它具有更小的容量,更高的灵活性(像字体一样可以设置图标大小.颜色.透明 ...

  8. Web 前端性能优化准则

    准则01:尽量减少http请求 “只有10%-20%的最终用户响应时间花在接收请求的HTML文档上,剩下的80%-90%时间花在HTML文档所引用的所有组件(图片,script,css,flash等等 ...

  9. 【原/转】UITableview性能优化总结

    UITableView作为ios中使用最频繁的控件之一,其性能优化也是常常要面对的,尤其是当数据量偏大并且设备性能不足时.本文旨在总结tableview的几个性能优化tips,并且随着认识的深入,本文 ...

  10. mysql数据库性能优化(包括SQL,表结构,索引,缓存)

    优化目标减少 IO 次数IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作所占用的,减少 IO 次数是 SQL 优化中需要第一优先考虑,当 ...

随机推荐

  1. linux 查找目录中的大文件

    find是Linux系统中常用的文件查找命令.它可以在文件系统中查找指定条件的文件,并执行相应的操作.语法格式如下: find [pathname] [options] pathname: 指定查找的 ...

  2. 通过AOP拦截Spring Boot日志并将其存入数据库

    本文分享自华为云社区<Spring Boot入门(23):[实战]通过AOP拦截Spring Boot日志并将其存入数据库>,作者:bug菌. 前言 在软件开发中,常常需要记录系统运行时的 ...

  3. 白话领域驱动设计DDD

    容我找个借口先,日常工作太忙,写作略有荒废.一直想聊下领域驱动设计,以下简称DDD,之前也看过一些教程,公司今年两个项目--银行核心和信用卡核心,都深度运用DDD成功落地,有人说DDD挺难理解,在此讲 ...

  4. 使用API数据接口获取商品详情数据的流程

    API数据接口是开发者获取第三方平台数据的一种方式,使用API接口可以快速地获取海量的商品详情数据,相比其他方式更加高效.实时.下面将介绍使用API数据接口获取商品详情数据的主要流程和步骤: 申请AP ...

  5. 聊透 GPU 通信技术——GPU Direct、NVLink、RDMA 审核中

    最近人工智能大火,AI 应用所涉及的技术能力包括语音.图像.视频.NLP 等多方面,而这些都需要强大的计算资源支持.AI 技术对算力的需求是非常庞大的,虽然 GPU 的计算能力在持续提升,但是对于 A ...

  6. Elasticsearch之常用术语

    一. 数据库和ES简单类比 关系型数据库 表(Table) 行(Row) 列(Cloumn) Schema SQL Elasticsearch 索引(Index) 文档(Document) 字段(Fi ...

  7. 开源.NetCore通用工具库Xmtool使用连载 - 图形验证码篇

    [Github源码] <上一篇> 介绍了Xmtool工具库中的Web操作类库,今天我们继续为大家介绍其中的图形验证码类库. 图形验证码是为了抵御恶意攻击出现的一种设计:例如用户登录.修改密 ...

  8. 【WPF】后台代码实现绑定ComboBox的SelectedItem功能

    WPF 开发程序目前最好的用的设计模式为MVVM模式,实现了前后端的分离,前端页面的更改不需要后台代码逻辑发生变化,同理,后台逻辑发生变化时基本上也不需要修改前台的页面布局等信息. 由于某些原因,可能 ...

  9. Solution Set -「ARC 111」

    「ARC 111A」Simple Math 2 Link. \(\lfloor \frac{10^N - kM^2}{M} \rfloor \equiv \lfloor \frac{10^N}{M} ...

  10. 探秘公有IP地址与私有IP地址的区别及其在路由控制中的作用

    引言 IP地址是互联网通信中至关重要的组成部分.虽然在前一章节我们讲解了IP一些基础知识,但在我们日常生活中,我们经常听到公有IP地址和私有IP地址这两个术语.那么,公有IP地址和私有IP地址有何区别 ...