前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.NET9 PreView6 RyuJIT代码布局改进(HIR)

.NET9 PreView6 RyuJIT代码布局改进(HIR)

作者头像
江湖评谈
发布2024-07-15 12:27:59
540
发布2024-07-15 12:27:59
举报
文章被收录于专栏:天下风云

前言

7月9日微软发布了.NET9 PreView6,本篇看下这个版本的CLR(JIT)第一个改进:代码布局改进。

问题

代码的布局改进,是在RyuJIT的HIR(Hight IR)部分,它实际上是对BB(Basick Block)块的顺序改进。

微软早在.NET6就引入了动态PGO的实验,后续的7,8等版本也进行了BB块的顺序改进,但是BB块的顺序如同顽疾始终受限于代码流程图的的控制,这点一直没变。为了改变这个现状,在过去的几个月围绕重构了 RyuJIT 的流程图数据结构,以消除围绕区块排序的各种限制。

非官方解决

一般来说,代码的流水线指令按照顺序执行。比如执行完前一行代码,后一行继续执行。这样会产生两个概念前任(preds)和继任(succs)。但是有的代码,比如if分支这种类型的代码,它的后一行代码不一定是它需要执行的代码,通过if判断跳转,可能跳转到很多行之后去执行。而优化的地点就在这里。

看一个例子(注意这个例子取自官网,但是多了一行代码:Console.ReadLine()所以分析过程会不太一样。

代码语言:javascript
复制
var random = new Random();
int number = random.Next(100);

if (number < 99)
{
   Console.WriteLine("We're in BB02");
}
else
{
   Console.WriteLine("We're in BB03");
}
Console.WriteLine("We're in BB04 -- the successor of BB02 and BB03");
Console.ReadLine();

.NET9 RyuJIT HIR会把以上代码生成五个BB块。C#伪代码如下:

代码语言:javascript
复制
// bb01 JIT植入的调试代码:CORINFO_HELP_DBG_IS_JUST_MY_CODE
// bb02
var random = new Random();
int number = random.Next(100);
// bb03
if (number < 99)
{
   Console.WriteLine("We're in BB02");
}
// bb04
else
{
   Console.WriteLine("We're in BB03");
}
// bb05
Console.WriteLine("We're in BB04 -- the successor of BB02 and BB03");
Console.ReadLine();

BB01是JIT植入的调试代码,它的preds和succs如下,这里可以忽略。

代码语言:javascript
复制
------------ BB01 [0000] [???..???) -> BB02(1) (always), preds={} succs={BB02}

BB02即是初始化随机数,可以看到它有两个分支。

代码语言:javascript
复制
------------ BB02 [0001] [000..019) -> BB04(0.5),BB03(0.5) (cond), preds={BB01} succs={BB03,BB04}

‍BB03

代码语言:javascript
复制
------------ BB03 [0002] [019..028) -> BB05(1) (always), preds={BB02} succs={BB05}

BB04

代码语言:javascript
复制
------------ BB04 [0003] [028..035) -> BB05(1) (always), preds={BB02} succs={BB05}

BB05

代码语言:javascript
复制
------------ BB05 [0004] [035..047) (return), preds={BB03,BB04} succs={}

没有优化的代码的流水线执行路径如下:

代码语言:javascript
复制
BB01->BB02->BB03-BB04->BB05

但加入了if分支,则变成了如下,其中变化的BB03/4是if判断里面的内容

代码语言:javascript
复制
BB01->BB02->BB03->BB05
BB01->BB02->BB04->BB05

优化点就在这里,JIT会对执行的热点(执行次数较多的代码块)进行排序,假如BB03的热点大于BB04,则可以如下流水执行。注意它这里BB04移动到BB05后面去了,是因为4根本没有执行,所以它的热点在某时刻基本为零。

代码语言:javascript
复制
BB01->BB02->BB03->BB05->-BB04

反之呢?因为是随机数,如果BB04的热度超过了BB03,则可如下动态优化

代码语言:javascript
复制
BB01->BB02->BB04->BB05->-BB03

BB块

看下热点BB块3/4的实际情况

1.BB03

代码语言:javascript
复制
------------ BB03 [0002] [019..028) -> BB05(1) (always), preds={BB02} succs={BB05}

***** BB03 [0002]
STMT00018 ( 0x019[E-] ... 0x019 )
               [000036] -----+-----                         *  NO_OP     void

***** BB03 [0002]
STMT00019 ( 0x01A[E-] ... 0x024 )
               [000038] --CXG+-----                         *  CALL      void   System.Console:WriteLine(System.String)
               [000058] H----+----- arg0 in rcx             \--*  CNS_INT(h) ref     'We're in BB02'

***** BB03 [0002]
STMT00020 ( 0x024[E-] ... ??? )
               [000039] -----+-----                         *  NO_OP     void

***** BB03 [0002]
STMT00021 ( 0x025[E-] ... 0x025 )
               [000040] -----+-----                         *  NO_OP     void

***** BB03 [0002]
STMT00022 ( 0x026[E-] ... 0x026 )
               [000041] -----+-----                         *  NOP       void

2.BB04

代码语言:javascript
复制
------------ BB04 [0003] [028..035) -> BB05(1) (always), preds={BB02} succs={BB05}

***** BB04 [0003]
STMT00009 ( 0x028[E-] ... 0x028 )
               [000023] -----+-----                         *  NO_OP     void

***** BB04 [0003]
STMT00010 ( 0x029[E-] ... 0x033 )
               [000025] --CXG+-----                         *  CALL      void   System.Console:WriteLine(System.String)
               [000059] H----+----- arg0 in rcx             \--*  CNS_INT(h) ref     'We're in BB03'

***** BB04 [0003]
STMT00011 ( 0x033[E-] ... ??? )
               [000026] -----+-----                         *  NO_OP     void

***** BB04 [0003]
STMT00012 ( 0x034[E-] ... 0x034 )
               [000027] -----+-----                         *  NO_OP     void

结尾

.NET9 PreView6的这次优化,实际上是对一些优化方方面的硬骨头进行了敲碎,然后重新组织,配合PGO则是性能的另一大提升。当然它的优化远不止于此,其它的诸如,ARM64 代码生成,代码布局,循环优化,减少地址暴露,AVX10v1 支持,硬件内部代码生成,用于浮点和 SIMD 运算的恒定折叠等,后续继续关注下。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-07-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 江湖评谈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题
  • 非官方解决
  • BB块
  • 结尾
相关产品与服务
图数据库 KonisGraph
图数据库 KonisGraph(TencentDB for KonisGraph)是一种云端图数据库服务,基于腾讯在海量图数据上的实践经验,提供一站式海量图数据存储、管理、实时查询、计算、可视化分析能力;KonisGraph 支持属性图模型和 TinkerPop Gremlin 查询语言,能够帮助用户快速完成对图数据的建模、查询和可视化分析。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档