ILRuntime:用寄存器模式吊打Lua

前言
ILRunTime雖然有很多優(yōu)點(diǎn),其中有一點(diǎn)在以前經(jīng)常被拿來(lái)與Lua進(jìn)行比較,就是ILRunTime的數(shù)值計(jì)算性能
由于Lua采用了寄存器模式,而ILRunTime在過(guò)去是沒(méi)有支持寄存器模式的,所以在比較時(shí)都會(huì)說(shuō)ILRunTime的計(jì)算性能比起Lua要略微差一點(diǎn)
但是現(xiàn)在ILRunTime已經(jīng)增加了寄存器模式,接下來(lái)我們就來(lái)看一看什么是ILRunTime的寄存器模式以及這種模式解決了哪些問(wèn)題?有哪些優(yōu)點(diǎn)?
版權(quán)聲明
本文為“優(yōu)夢(mèng)創(chuàng)客”原創(chuàng)文章,您可以自由轉(zhuǎn)載,但必須加入完整的版權(quán)聲明
更多學(xué)習(xí)資源請(qǐng)加QQ:1517069595或WX:alice17173獲?。ㄆ髽I(yè)級(jí)性能優(yōu)化/熱更新/Shader特效/服務(wù)器/商業(yè)項(xiàng)目實(shí)戰(zhàn)/每周直播/一對(duì)一指導(dǎo))
點(diǎn)贊、關(guān)注、分享可免費(fèi)獲得配套學(xué)習(xí)資源
詳細(xì)內(nèi)容可觀看文末完整視頻
ILRunTime寄存器介紹

上圖是ILRunTime官網(wǎng)中關(guān)于寄存器模式的科普
寄存器模式是ILRunTime2.0版引入的專用于優(yōu)化大規(guī)模數(shù)值計(jì)算的執(zhí)行模式,該模式通過(guò)ILRunTime自己的JITCompiler將原始的DLL指令集轉(zhuǎn)換成一個(gè)自定義的基于寄存器的指令集,再進(jìn)行解譯執(zhí)行
由于該JIT編譯的結(jié)果是ILRunTime自己設(shè)計(jì)的虛擬指令集,并不是真實(shí)硬件指令集,因此可以毫無(wú)問(wèn)題的在IOS等平臺(tái)上執(zhí)行
寄存器模式的定義說(shuō)的通俗一點(diǎn),就是寄存器模式在原來(lái)的由VS生成的DLL程序集的基礎(chǔ)上,在程序執(zhí)行之前,利用JIT(即時(shí)編譯)工具對(duì)指令集進(jìn)行優(yōu)化,可以把原來(lái)很多需要在內(nèi)存里運(yùn)算的東西放到寄存器里進(jìn)行運(yùn)算
寄存器說(shuō)白了就是CPU里的一塊緩存區(qū)域,要衡量一個(gè)CPU的性能指標(biāo),重點(diǎn)就是看它的緩存有多少,緩存的訪問(wèn)速度高于內(nèi)存的訪問(wèn)速度又高于磁盤的訪問(wèn)速度,所以使用緩存(寄存器)方式的性能是高于在內(nèi)存上進(jìn)行數(shù)據(jù)讀寫的方式
寄存器模式的開(kāi)啟方法
開(kāi)啟寄存器有兩種方法
第一種方法:寫一條語(yǔ)句(如下方代碼)
這條語(yǔ)句在你創(chuàng)建ILRunTIme的應(yīng)用程序域時(shí)會(huì)指定一個(gè)JITOnDemand標(biāo)志,這個(gè)標(biāo)簽?zāi)軌蚴辜拇嫫髂J皆跓岣绦蚣皩用嫔险w生效,是一種全局模式
第二種方法是在一些特定的要經(jīng)常進(jìn)行高性能數(shù)學(xué)運(yùn)算的類或方法上開(kāi)啟寄存器模式
比如在上面代碼中的foo類上加上一個(gè)標(biāo)志ILRunTimeJIT,就表示在這個(gè)類上采用JIT模式進(jìn)行編譯,編譯后得到的代碼就是基于寄存器模式的,這個(gè)類中的方法也都會(huì)采用JIT模式
如果想讓這個(gè)類中的一些特定方法不使用JIT,可以給這個(gè)方法加上[ILRunTimeJIT(ILRunTimeJITFlags.NoJIT)]標(biāo)志
LIRunTime的幾種JIT模式

JITOnDemand模式
按需JIT模式,使用該模式在默認(rèn)的情況下會(huì)按照原始方式運(yùn)行,當(dāng)該方法被反復(fù)執(zhí)行時(shí),會(huì)被標(biāo)記為需要被JIT,并在后臺(tái)線程完成JIT編譯后切換到寄存器模式運(yùn)行
在ILRunTime解釋器插件內(nèi)部有一個(gè)計(jì)數(shù)器,用來(lái)統(tǒng)計(jì)方法被執(zhí)行的頻率和次數(shù),如果頻率比較高,它就會(huì)為這個(gè)方法開(kāi)啟寄存器模式
JITImmediately模式
立即JIT模式,使用該模式時(shí),當(dāng)方法被調(diào)用的瞬間即會(huì)被執(zhí)行JIT編譯,在第一次執(zhí)行時(shí)即使用寄存器模式運(yùn)行。JIT會(huì)在當(dāng)前線程發(fā)生,因此如果方法過(guò)于復(fù)雜在第一次執(zhí)行時(shí)可能會(huì)有較大的初始化時(shí)間
為方法標(biāo)記上JITImmediately后,就不會(huì)去對(duì)這個(gè)方法的執(zhí)行頻率進(jìn)行分析,會(huì)立刻被編譯成寄存器模式的代碼
由于編碼過(guò)程發(fā)生在當(dāng)前執(zhí)行方法的線程上,如果這個(gè)方法的內(nèi)容很長(zhǎng),那么它的JIT編譯是有時(shí)間開(kāi)銷的,所以如果使用了JITImmediately模式,那么在第一次執(zhí)行這個(gè)方法時(shí),編譯開(kāi)銷會(huì)使程序在當(dāng)前線程上卡一會(huì)兒,所以這里要想辦法對(duì)經(jīng)常要使用的一些方法進(jìn)行預(yù)熱
NoJIT模式
禁用JIT模式,該方法在執(zhí)行時(shí)會(huì)始終以傳統(tǒng)方式執(zhí)行
ForceInIine模式
強(qiáng)制內(nèi)聯(lián)模式,該模式只對(duì)方法的Attribute生效,標(biāo)注該模式的方法在被調(diào)用時(shí)將會(huì)無(wú)視方法體內(nèi)容大小,強(qiáng)制被內(nèi)聯(lián)
寄存器模式的性能特點(diǎn)

當(dāng)運(yùn)行在寄存器模式時(shí),主要會(huì)有以下性能特征:
數(shù)值計(jì)算性能會(huì)大幅提升,包括for循環(huán)等需要數(shù)值計(jì)算的控制流
由于小方法會(huì)被內(nèi)聯(lián),所以getter/setter等的調(diào)用開(kāi)銷,for循環(huán)里調(diào)用其他熱更內(nèi)方法的性能也會(huì)有所提升
如果一個(gè)方法既沒(méi)有數(shù)值計(jì)算,又沒(méi)有頻繁調(diào)用熱更內(nèi)小方法或者訪問(wèn)property,主要由調(diào)用系統(tǒng)或UnityAPI組成,則不會(huì)產(chǎn)生任何優(yōu)化,一些情況下可能性能還低于傳統(tǒng)模式
寄存器模式是為了提高數(shù)值計(jì)算的性能,也是為了提高類似于getter/setter訪問(wèn)器這樣的小方法的調(diào)用開(kāi)銷,如果這兩種都沒(méi)有的話就不需要內(nèi)聯(lián),因?yàn)閮?nèi)聯(lián)有時(shí)優(yōu)化不好會(huì)導(dǎo)致它的性能低于傳統(tǒng)模式
ILRunTime寄存器模式的使用建議

ILRunTime推薦的使用模式有二種:
AppDomain構(gòu)造函數(shù)時(shí)不指定JIT模式,即默認(rèn)使用傳統(tǒng)模式執(zhí)行,在遇到就要優(yōu)化的密集計(jì)算型方法時(shí),對(duì)該方法指定JITImmediately模式
直接在AppDomain構(gòu)造函數(shù)處指定JITDemand模式
第一種用法對(duì)現(xiàn)有實(shí)現(xiàn)影響最小,僅在需要優(yōu)化處開(kāi)啟,可以比較精準(zhǔn)的控制執(zhí)行效果。如果并不知道在什么時(shí)候應(yīng)該使用何種模式,也可以直接使用JITDemand模式,讓ILRunTime自行決定運(yùn)行模式,在大多數(shù)情況下是能達(dá)到不錯(cuò)的性能平衡的
比如在A尋路算法里有大量的距離計(jì)算,這里就可以對(duì)A尋路里的算法類開(kāi)啟JIT模式
如果不想那么復(fù)雜,想讓它智能一點(diǎn),可以·在進(jìn)行大量數(shù)學(xué)計(jì)算的時(shí)候自動(dòng)開(kāi)啟,就可以使用JITDemand
如何開(kāi)啟JITDemand

確保項(xiàng)目切換到ILRunTime模式

編譯生成代碼
要進(jìn)行ILRunTime性能優(yōu)化有這么幾點(diǎn)
1,生成綁定代碼
2,開(kāi)啟JIT模式
要開(kāi)啟ILRunTime的JIT模式需要在生成的代碼中的創(chuàng)建appdomain語(yǔ)句中加入IlRuntimeJITFlags.JITDemand

回到Unity中按F7生成代碼,然后啟動(dòng)游戲
游戲啟動(dòng)時(shí)會(huì)在Console面板中輸出信息

將性能分析器打開(kāi),這里需要注意的是CPU的開(kāi)銷、Drawcall的批次數(shù)、以及幀率

下方是我們的《皇室戰(zhàn)爭(zhēng)》游戲項(xiàng)目,因?yàn)橛螒蛟臼秦Q屏游戲,所以UI有些變形
可以看到性能分析器中的幀率在游戲戰(zhàn)斗進(jìn)行時(shí)保持在30幀左右,在游戲結(jié)束時(shí)幀率會(huì)恢復(fù)到150幀,這是采用了ILRunTime性能優(yōu)化的結(jié)果

建立一個(gè)jitMode變量,并將JIT模式設(shè)置None,也就是不開(kāi)啟JIT模式

回到Unity按一下F7生成代碼并啟動(dòng)游戲

可以看到游戲項(xiàng)目的幀率在游戲戰(zhàn)斗進(jìn)行時(shí)始終保持在20幀左右,而且游戲結(jié)束時(shí)幀率也只是在80幀左右
可以看出沒(méi)有開(kāi)啟JIT模式的游戲性能比剛才低了將近一倍,所以開(kāi)啟JIT模式是很有意義的
開(kāi)發(fā)心得
以上就是對(duì)于JIT模式的大致介紹,另外我在開(kāi)發(fā)上有一點(diǎn)小小的心得建議
由于寄存器模式是經(jīng)過(guò)了再編譯,再簡(jiǎn)易執(zhí)行的過(guò)程,所以它有的時(shí)候是不太穩(wěn)定的,要解決這個(gè)問(wèn)題就需要確保你的ILRunTime代碼在不開(kāi)啟寄存器模式時(shí)能夠正常運(yùn)行
確保了這點(diǎn)以后再去開(kāi)啟JIT模式,這樣就可以單獨(dú)的測(cè)試JIT模式是否正常,這比把所有的問(wèn)題攪在一起,然后去找問(wèn)題要簡(jiǎn)單的多
寫在最后
更多學(xué)習(xí)資源請(qǐng)加QQ:1517069595或WX:alice17173獲?。ㄆ髽I(yè)級(jí)性能優(yōu)化/熱更新/Shader特效/服務(wù)器/商業(yè)項(xiàng)目實(shí)戰(zhàn)/每周直播/一對(duì)一指導(dǎo))
點(diǎn)贊、關(guān)注、分享可免費(fèi)獲得配套學(xué)習(xí)資源
詳細(xì)內(nèi)容可觀看下方完整視頻
