ILRuntime:ILRuntime寄存器模式详解
前言
- ILRunTime虽然有很多优点,其中有一点在以前经常被拿来与Lua进行比较,就是ILRunTime的数值计算性能
- 由于Lua采用了寄存器模式,而ILRunTime在过去是没有支持寄存器模式的,所以在比较时都会说ILRunTime的计算性能比起Lua要略微差一点
- 但是现在ILRunTime已经增加了寄存器模式,接下来我们就来看一看什么是ILRunTime的寄存器模式以及这种模式解决了哪些问题?有哪些优点?
ILRunTime寄存器介绍
- 上图是ILRunTime官网中关于寄存器模式的科普
- 寄存器模式是ILRunTime2.0版引入的专用于优化大规模数值计算的执行模式,该模式通过ILRunTime自己的JITCompiler将原始的DLL指令集转换成一个自定义的基于寄存器的指令集,再进行解译执行
- 由于该JIT编译的结果是ILRunTime自己设计的虚拟指令集,并不是真实硬件指令集,因此可以毫无问题的在IOS等平台上执行
- 寄存器模式的定义说的通俗一点,就是寄存器模式在原来的由VS生成的DLL程序集的基础上,在程序执行之前,利用JIT(即时编译)工具对指令集进行优化,可以把原来很多需要在内存里运算的东西放到寄存器里进行运算
- 寄存器说白了就是CPU里的一块缓存区域,要衡量一个CPU的性能指标,重点就是看它的缓存有多少,缓存的访问速度高于内存的访问速度又高于磁盘的访问速度,所以使用缓存(寄存器)方式的性能是高于在内存上进行数据读写的方式
寄存器模式的开启方法
// 第一种方式是在AppDomain的构造函数的参数中,指定全局希望使用的JIT模式
appdomain = new ILRuntime.Runtime.Enviorment.AppDomain(ILRuntimeJITFlags.JITOnDemand);//第二种方式为在指定的类或者方法上指定用于该类或者方法的JIT模式
[ILRuntimeJIT(ILRuntimeJITFlags.JITImmediately)]
class foo
{[ILRuntimeJIT(ILRuntimeJITFlags.NoJIT)]public void bar(){// 该方法的内容将不会开启寄存器模式}public void bar2(){// 该方法的内容将按照所在类指定的模式,也就是立即JIT模式运行}}
开启寄存器有两种方法
- 第一种方法:写一条语句(如下方代码)
// 第一种方式是在AppDomain的构造函数的参数中,指定全局希望使用的JIT模式 appdomain = new ILRuntime.Runtime.Enviorment.AppDomain(ILRuntimeJITFlags.JITOnDemand);
- 这条语句在你创建ILRunTIme的应用程序域时会指定一个JITOnDemand标志,这个标签能够使寄存器模式在热更程序及层面上整体生效,是一种全局模式
- 第二种方法是在一些特定的要经常进行高性能数学运算的类或方法上开启寄存器模式
//第二种方式为在指定的类或者方法上指定用于该类或者方法的JIT模式 [ILRuntimeJIT(ILRuntimeJITFlags.JITImmediately)] class foo {[ILRuntimeJIT(ILRuntimeJITFlags.NoJIT)]public void bar(){// 该方法的内容将不会开启寄存器模式}public void bar2(){// 该方法的内容将按照所在类指定的模式,也就是立即JIT模式运行}
- 比如在上面代码中的foo类上加上一个标志ILRunTimeJIT,就表示在这个类上采用JIT模式进行编译,编译后得到的代码就是基于寄存器模式的,这个类中的方法也都会采用JIT模式
- 如果想让这个类中的一些特定方法不使用JIT,可以给这个方法加上[ILRunTimeJIT(ILRunTimeJITFlags.NoJIT)]标志
LIRunTime的几种JIT模式
- JITOnDemand模式
- 按需JIT模式,使用该模式在默认的情况下会按照原始方式运行,当该方法被反复执行时,会被标记为需要被JIT,并在后台线程完成JIT编译后切换到寄存器模式运行
- 在ILRunTime解释器插件内部有一个计数器,用来统计方法被执行的频率和次数,如果频率比较高,它就会为这个方法开启寄存器模式
- JITImmediately模式
- 立即JIT模式,使用该模式时,当方法被调用的瞬间即会被执行JIT编译,在第一次执行时即使用寄存器模式运行。JIT会在当前线程发生,因此如果方法过于复杂在第一次执行时可能会有较大的初始化时间
- 为方法标记上JITImmediately后,就不会去对这个方法的执行频率进行分析,会立刻被编译成寄存器模式的代码
- 由于编码过程发生在当前执行方法的线程上,如果这个方法的内容很长,那么它的JIT编译是有时间开销的,所以如果使用了JITImmediately模式,那么在第一次执行这个方法时,编译开销会使程序在当前线程上卡一会儿,所以这里要想办法对经常要使用的一些方法进行预热
- NoJIT模式
- 禁用JIT模式,该方法在执行时会始终以传统方式执行
- ForceInIine模式
- 强制内联模式,该模式只对方法的Attribute生效,标注该模式的方法在被调用时将会无视方法体内容大小,强制被内联
寄存器模式的性能特点
- 当运行在寄存器模式时,主要会有以下性能特征:
- 数值计算性能会大幅提升,包括for循环等需要数值计算的控制流
- 由于小方法会被内联,所以getter/setter等的调用开销,for循环里调用其他热更内方法的性能也会有所提升
- 如果一个方法既没有数值计算,又没有频繁调用热更内小方法或者访问property,主要由调用系统或UnityAPI组成,则不会产生任何优化,一些情况下可能性能还低于传统模式
- 寄存器模式是为了提高数值计算的性能,也是为了提高类似于getter/setter访问器这样的小方法的调用开销,如果这两种都没有的话就不需要内联,因为内联有时优化不好会导致它的性能低于传统模式
ILRunTime寄存器模式的使用建议
- ILRunTime推荐的使用模式有二种:
- AppDomain构造函数时不指定JIT模式,即默认使用传统模式执行,在遇到就要优化的密集计算型方法时,对该方法指定JITImmediately模式
- 直接在AppDomain构造函数处指定JITDemand模式
- 第一种用法对现有实现影响最小,仅在需要优化处开启,可以比较精准的控制执行效果。如果并不知道在什么时候应该使用何种模式,也可以直接使用JITDemand模式,让ILRunTime自行决定运行模式,在大多数情况下是能达到不错的性能平衡的
- 比如在A寻路算法里有大量的距离计算,这里就可以对A寻路里的算法类开启JIT模式
- 如果不想那么复杂,想让它智能一点,可以·在进行大量数学计算的时候自动开启,就可以使用JITDemand
如何开启JITDemand
- 确保项目切换到ILRunTime模式
- 编译生成代码
- 要进行ILRunTime性能优化有这么几点
- 1,生成绑定代码
- 2,开启JIT模式
- 要开启ILRunTime的JIT模式需要在生成的代码中的创建appdomain语句中加入IlRuntimeJITFlags.JITDemand
- 回到Unity中按F7生成代码,然后启动游戏
- 游戏启动时会在Console面板中输出信息
- 将性能分析器打开,这里需要注意的是CPU的开销、Drawcall的批次数、以及帧率
- 下方是我们的《皇室战争》游戏项目,因为游戏原本是竖屏游戏,所以UI有些变形
- 可以看到性能分析器中的帧率在游戏战斗进行时保持在30帧左右,在游戏结束时帧率会恢复到150帧,这是采用了ILRunTime性能优化的结果
- 建立一个jitMode变量,并将JIT模式设置None,也就是不开启JIT模式
- 回到Unity按一下F7生成代码并启动游戏
- 可以看到游戏项目的帧率在游戏战斗进行时始终保持在20帧左右,而且游戏结束时帧率也只是在80帧左右
- 可以看出没有开启JIT模式的游戏性能比刚才低了将近一倍,所以开启JIT模式是很有意义的
开发心得
- 以上就是对于JIT模式的大致介绍,另外我在开发上有一点小小的心得建议
- 由于寄存器模式是经过了再编译,再简易执行的过程,所以它有的时候是不太稳定的,要解决这个问题就需要确保你的ILRunTime代码在不开启寄存器模式时能够正常运行
- 确保了这点以后再去开启JIT模式,这样就可以单独的测试JIT模式是否正常,这比把所有的问题搅在一起,然后去找问题要简单的多
ILRuntime:ILRuntime寄存器模式详解相关推荐
- 3.堆栈指针寄存器 SP 详解
堆栈指针寄存器 SP 详解 堆栈是一种具有"后进先出"(LIFO---Last In First Out)特殊访问属性的存储结构.堆栈一般使用RAM 物理资源作为存储体,再加上LI ...
- ST MCU_GPIO的八种工作模式详解
GPIO的八种工作模式详解 浮空输入_IN_FLOATING 带上拉输入_IPU 带下拉输入_IPD 模拟输入_AIN 开漏输出_OUT_OD 推挽输出_OUT_PP 开漏复用输出_AF_OD 推挽复 ...
- TI Cotex M3/4单片机关于寄存器操作详解
TI Cotex M3/4单片机关于寄存器操作详解 前备知识 寄存器与偏移量 位带操作.位带区 TI单片机寄存器操作详解 快速在TI的手册里面确认某外设某寄存器的确切地址 寄存器操作介绍 本文参考 前 ...
- HS6621 串口透传 模式 - [详解]
文章目录 HS6621串口透传模式详解 遇到的问题现象 UART发送源码 HS6621CG 内核的中断优先级 本人项目中的透传代码 UART0_Recv_IRQ UART1_Recv_IRQ 按照以上 ...
- getinstance方法详解_二、设计模式总览及工厂模式详解
二.架构师内功心法之设计模式 2.架构师内功心法之设计模式 2.1.课程目标 1.通过对本章内容的学习,了解设计模式的由来. 2.介绍设计模式能帮我们解决哪些问题. 3.剖析工厂模式的历史由来及应用场 ...
- Spotify敏捷模式详解三部曲第二篇:研发过程
本文转自:Scrum 中文网 引言 在本系列文章的第一篇,我们介绍了Spotify的敏捷研发团队,以及它独特的组织架构.Spotify的研发团队采用的是一种非常独特的组织架构,如下图所示: 整个研发组 ...
- Spotify敏捷模式详解三部曲第一篇:研发团队
本文转自:Scrum中文网 引言 2018年4月,来自北欧瑞典的音乐流媒体公司.百亿美元独角兽Spotify创造了历史,它成为了当代上市公司当中,第一家通过"直接上市"的方式在美国 ...
- Docker(十四):Docker:网络模式详解
Docker作为目前最火的轻量级容器技术,牛逼的功能,如Docker的镜像管理,不足的地方网络方面. Docker自身的4种网络工作方式,和一些自定义网络模式 安装Docker时,它会自动创建三个网络 ...
- linux apache两种工作模式详解
apache两种工作模式详解 刚接触这两个配置时很迷糊,全部开启或全部注释没有几多变化.今天搜索到这么一篇讲得还不错的文章,看了几篇,还是不能完全记住,做一个收藏. 空闲子进程:是指没有正在处理请求的 ...
最新文章
- java uv实例_Java注解的实际应用案例讲解
- Spring 2企业应用开发
- 以ActiveMQ为例JAVA消息中间件学习【4】——消息中间件实际应用场景
- java使用druid maven_SpringMVC+Spring+Mybatis整合,使用druid连接池,声明式事务,maven配置...
- 用VIPER构建iOS应用
- spock框架_Spock VW:编写自定义的Spock框架扩展
- 基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba的企业级微服务敏捷开发系统架构
- matlab用高斯消元法解线性方程组,用matlab利用高斯消元法求解线性方程组
- linux 进程线程限制,LINUX停每进程限制线程数量
- 【计算机网络笔记】数据链路层:点对点协议PPP
- ssh配置config文件,实现vscode免密登陆
- 工作中,掌握这四个说话技巧,再也不用担心自己不会说话
- java课设的总结和体会,JAVA设计培训心得体会【两篇】
- java多人聊天室与网络画板
- 南京大学比中科大计算机与科学专业,教育部直属:16所“软件工程”专业强校,浙大、南大、中科大上榜...
- 好的股票程序化交易api接口模型该怎么做?
- STM32系列 STM32F4xx SPI Flash-读写操作
- 信息重要性凸显,SSL证书为数据安全筑起高墙
- postman之什么是接口
- 还期待内存/闪存降价?三星/海力士们撑不住了