導航:首頁 > 源碼編譯 > 做編譯器優化有前途嗎

做編譯器優化有前途嗎

發布時間:2025-02-17 02:50:34

❶ 淺談vue3的編譯優化

編譯優化:編譯器將模版編譯為渲染函數的過程中,盡可能地提取關鍵信息,並以此指導生成最優代碼的過程。

優化的方向:盡可能地區分動態內容和靜態內容,並針對不同的內容採用不同的優化策略

1.動態節點收集與補丁標志1.1傳統diff演算法的問題

比對新舊兩棵虛擬DOM樹的時候,總是要按照虛擬DOM的層級結構「一層一層」地遍歷

<divid="foo"><pclass="bar">{{text}}</p></div>

上面這段代碼中,當響應式數據text值發生變化的時候,最高效的更新方式是直接設置p標簽的文本內容

傳統Diff演算法做不到如此高效,當text值發生變化的時候,會產生一顆新的虛擬DOM樹,對比新舊虛擬DOM過程如下:

對比div節點,以及該節點的屬性和子節點

對比p節點,以及該節點的屬性和子節點

對比p節點的文本子節點,如果文本子節點的內容變了,則更新,否則什麼都不做

可以發現,有很多無意義的對比操作。

總結:

傳統diff演算法的問題:無法利用編譯時提取到的任何關鍵信息,導致渲染器在運行時不會去做相關的優化。

vue3的編譯器會將編譯得到的關鍵信息「附著」在它生成的虛擬DOM上,傳遞給渲染器,執行「快捷路徑」。

1.2Block與PatchFlags

傳統Diff演算法無法避免新舊虛擬DOM樹間無用的比較操作,是因為運行時得不到足夠的關鍵信息,從而無法區分動態內容和靜態內容。換句話說,只要運行時能夠區分動態內容和靜態內容,就可以實現極簡的優化策略

舉個例子:

<div><div>foo</div><p>{{bar}}</p></div>

只有{{bar}}是動態的內容。理想情況下,當數據bar的值變化時,只需要更新p標簽的文本節點即可。為了實現這個目標,需要提供信息給運行時

//傳統虛擬DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}//編譯優化後constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//這是動態節點]}

可以發現,虛擬節點多了一個額外的屬性,即patchFlag(補丁標志),存在該屬性,就認為是動態節點

patchFlag(補丁標志)可以理解為一系列的數字標記,含義如下

constPatchFlags={TEXT:1,//代表節點有動態的textContentCLASS:2,//代表元素有動態的class綁定STYLE:3//其他。。。}

可以在虛擬節點的創建階段,把它的動態子節點提取出來,並存儲到該虛擬節點的dynamicChildren數組中

constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//這是動態節點],//將children中的動態節點提取到dynamicChildren數組中dynamicChildren:[{tag:'p',children:ctx.bar,patchFlag:PatchFlags.TEXT}]}

Block定義:帶有dynamicChildren屬性的虛擬節點稱為「塊」,即(Block)

一個Block本質上也是一個虛擬DOM,比普通的虛擬節點多處一個用來存儲動態節點的dynamicChildren屬性。(能夠收集所有的動態子代節點)

渲染器的更新操作會以Block為維度。當渲染器在更新一個Block時,會忽略虛擬節點的children數組,直接找到dynamicChildren數組,並只更新該數組中的動態節點。跳過了靜態內容,只更新動態內容。同時,由於存在對應的補丁標志,也能夠做到靶向更新。

Block節點有哪些:模版根節點、帶有v-for、v-if/v-else-if/v-else等指令的節點

1.3收集動態節點

編譯器生成的渲染函數代碼中,不會直接包含用來描述虛擬節點的數據結構,而是包含著用來創建虛擬DOM節點的輔助函數,如下

render(){returncreateVNode('div',{id:'foo'},[createVNode('p',null,'text')])}functioncreateVNode(tag,props,children){constkey=props&&props.keyprops&&deleteprops.key//省略部分代碼return{tag,props,children,key}}

createVNode的返回值是一個虛擬DOM節點

舉個例子:

<divid="foo"><pclass="bar">{{bar}}</p></div>

上面模版生成帶有補丁標志的渲染函數如下:

render(){returncreateVNode('div',{id:'foo'},[createVNode('p',{class:'bar'},text,PatchFlags.TEXT)])}

怎麼將根節點變成一個Block,如何將動態子代節點收集到該Block的dynamicChildren數組中?

可以發現,在渲染函數內,對createVNode函數的調用是層層嵌套結構,執行順序是內層先執行,外層再執行,當外層createVNode函數執行時,內層的createVNode函數已經執行完畢了。因此,為了讓外層Block節點能夠收集到內層動態節點,需要一個棧結構的數據來臨時存儲內層的動態節點。代碼實現如下:

//動態節點constdynamicChildrenStack=[]//當前動態節點集合letcurrentDynamicChildren=null//openBlock用來創建一個新的動態節點集合,並將該集合壓入棧中functionopenBlock(){dynamicChildrenStack.push((currentDynamicChildren=[]))}//closeBlock用來通過openBlock創建的動態節點集合從棧中彈出functioncloseBlock(){currentDynamicChildren=dynamicChildrenStack.pop()}

然後調整createVNode函數

<div><div>foo</div><p>{{bar}}</p></div>0

接著調整

<div><div>foo</div><p>{{bar}}</p></div>11.4.渲染器的運行時支持

傳統的節點更新方式如下:

<div><div>foo</div><p>{{bar}}</p></div>2

優化後的更新方式,直接對比動態節點

<div><div>foo</div><p>{{bar}}</p></div>3

存在對應的補丁標志,可以針對性地完成靶向更新

<div><div>foo</div><p>{{bar}}</p></div>42.Block樹

除了模版的根節點是Block外,帶有結構化指令的節點,如:v-if、v-for,也都應該是Block

2.1帶有v-if指令的節點<div><div>foo</div><p>{{bar}}</p></div>5

假設只有最外層的div標簽會作為Block,那麼變數foo的值為true還是false,block收集到的動態節點都是一樣的,如下:

<div><div>foo</div><p>{{bar}}</p></div>6

這意味著,在Diff階段不會更新。顯然,foo不同值下,一個是section,一個是div,是不同標簽,是需要更新的。

再舉個例子:

<div><div>foo</div><p>{{bar}}</p></div>7

一樣會導致更新失敗

問題在於:dynamicChildren收集的動態節點是忽略虛擬DOM樹層級的,結構化指令會導致更新前後模版的結構發生變化,即模版結構不穩定

解決方法:讓帶有v-if/v-else-if/v-else等結構化指令的節點也作為Block即可,如下所示

<div><div>foo</div><p>{{bar}}</p></div>8<div><div>foo</div><p>{{bar}}</p></div>9

在Diff過程中,渲染器根據key值區分,使用新的Block替換舊的Block

2.2帶有v-for指令的節點

帶有v-for指令的節點也會讓虛擬DOM樹變得不穩定

例子:

//傳統虛擬DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}0

list的值由[1,2]變成[1]

更新前後對應的Block樹如下:

//傳統虛擬DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}1

更新前後,動態節點數量不一致,無法進行diff操作(diff操作的前提是:操作的節點必須是同層級節點,dynamicChildren不一定是同層級的)

解決方法:讓v-for指令的標簽也作為Block角色,保證虛擬DOM樹具有穩定的結構,無論v-for在運行時怎樣變化。如下:

//傳統虛擬DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}2

由於v-for指令渲染的是一個片段,所以類型用Fragment

2.3Fragment的穩定性//傳統虛擬DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}3

發現Fragment本身收集的動態節點存在結構是不穩定的情況

結構不穩定:指更新前後一個block的dynamicChildren數組中收集的動態節點的數量或順序不一致

這種情況無法直接進行靶向更新

解決方法:回退到傳統虛擬DOM的Diff手段,即直接使用Fragment的children而非dynamicChildren來進行Diff操作

Fragment的子節點仍然可以是由Block組成的數組

//傳統虛擬DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}4

當Fragment的子節點更新時,就可以恢復優化模式

有穩定的Fragment嗎?如下:

//傳統虛擬DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}5

穩定的Fragment,可以使用優化模式

vue3模版中的多個根節點,也是穩定的Fragment

//傳統虛擬DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}63.靜態提升

減少更新時創建虛擬DOM帶來的性能開銷和內存佔用

如:

//傳統虛擬DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}7

沒有靜態提升時,渲染函數是:

//傳統虛擬DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}8

響應式數據title變化後,整個渲染函數會重新執行

把純靜態的節點提升到渲染函數之外

//傳統虛擬DOM描述constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar},]}9

響應式數據title變化後,不會重新創建靜態的虛擬節點

註:靜態提升是以樹為單位的

包含動態綁定的節點本身不會被提升,但是該節點上的靜態屬性是可以被提升的

//編譯優化後constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//這是動態節點]}0

可以減少創建虛擬DOM產生的開銷以及內存佔用

4.預字元串化

基於靜態提升,進一步採用預字元串化優化。

//編譯優化後constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//這是動態節點]}1

採用靜態提升優化策略後

//編譯優化後constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//這是動態節點]}2

採用預字元串化將這些靜態節點序列化為字元串,並生成一個Static類型的VNode

//編譯優化後constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//這是動態節點]}3

優勢:

大塊的靜態內容可以通過innerHTML設置,在性能上有一定優勢

減少創建虛擬節點產生的性能開銷

減少內存佔用

5.緩存內聯事件處理函數//編譯優化後constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//這是動態節點]}4//編譯優化後constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//這是動態節點]}5

每次重新渲染時,都會為Com組件創建一個全新的props對象。同時,props對象中onChange屬性的值也會是全新的函數。造成額外的性能開銷

//編譯優化後constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//這是動態節點]}66.v-once

v-once可以對虛擬DOM進行緩存

//編譯優化後constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//這是動態節點]}7

由於節點被緩存,意味著更新前後的虛擬節點不會發生變化,因此也就不需要這些被緩存的虛擬節點參與Diff操作了。編譯後的結果如下:

//編譯優化後constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//這是動態節點]}8

v-once包裹的動態節點不會被父級Block收集,因此不會參與Diff操作

v-once指令通常用於不會發生改變的動態綁定中,例如綁定一個常量

//編譯優化後constvnode={tag:'div',children:[{tag:'div',children:'foo'},{tag:'p',children:ctx.bar,patchFlag:1},//這是動態節點]}9

v-once帶來的性能提升

避免組件更新時重新創建虛擬DOM帶來的性能開銷。因為虛擬DOM被緩存了,所以更新時無需重新創建

避免無用的Diff開銷。因為被v-once標記的虛擬DOM樹不會被父級Block節點收集

7.總結

1.vue3提出了Block的概念,利用Block樹及補丁標志

2.靜態提升:可以減少更新時創建虛擬DOM產生的性能開銷和內存佔用

3.預字元串化:在靜態提升的基礎上,對靜態節點進行字元串化。這樣做能夠減少創建虛擬節點產生的性能開銷以及內存佔用

4.緩存內聯事件處理函數:避免造成不必要的組件更新

5.v-once指令:緩存全部或部分虛擬節點,能夠避免組件更新時重新創建虛擬DOM帶來的性能開銷,也可以避免無用的Diff操作

原文:https://juejin.cn/post/7101859824203202568

❷ 應用編譯優化三種模式

應用編譯優化三種模式分別是:編譯時間優化模式、執行時間優化模式和代碼大小優化模式。
1、編譯時間優化模式:關注編譯速度的提升,以縮短應用程序高脊的編譯時間為目標。在這種模式下,編譯器會減少編譯時間,會降低應用程序的執行效率。
2、執行時間優化模式:關注應用程序的執行效率,以提高應用程序的性能為目標。在這種模式下,編譯器會優化應用程序的代碼,以提高執行效率,會增加編譯時間。
3、代碼大小優化模式:關注應用程序的大小,以減小應兆培用程序的體積為目標。族念唯在這種模式下,編譯器會減小應用程序的代碼大小,以減小應用程序的體積,會降低應用程序的執行效率。

❸ 深度學習推理引擎的一些思考

深度學習推理引擎,特別是走編譯優化路徑的引擎,是解決現代深度學習應用的關鍵技術之一。作為曾經的傳統編譯器開發者,我見證了從傳統編譯器到深度學習領域的轉變。在阿里巴巴工作期間,我積極推動基於編譯優化的深度學習推理引擎的開發,這一領域在短短幾年內已經取得了顯著進展。

在18年初加入阿里巴巴時,基於編譯優化的深度學習推理引擎並不佔據主流地位,當時流行的解決方案是TFLite和NCNN等框架,它們依賴高效GEMM加速庫或針對特定CPU的手寫匯編代碼。然而,我堅信編譯器優化才是解決這個問題的最佳途徑和未來方向。我的堅定信念得到了老闆的支持,我們順利推動了這個項目,最終取得了很好的落地效果。現今,TVM、GLOW、MLIR等框架已成為業界認可的編譯優化深度學習推理引擎。

我選擇TVM作為基礎框架,原因在於它在編譯優化領域與我的想法最為契合。盡管TVM在18年初並不成熟,但相比其他框架,它更加接近我的技術理想。雖然沒有從零開始開發,但我認為基於已有的成熟框架進行擴展,可以更快地解決問題,同時也節省了大量時間和資源。

做深度學習推理引擎,並非易事。一方面,它涉及矩陣計算的優化,這需要對編譯器、體系結構、高性能計算等領域有深刻理解。另一方面,它並非想像中那麼簡單,深度學習推理引擎的真正實現需要下足功夫,並涵蓋量化壓縮、圖優化、子圖分離、異構執行等多個方面。例如,在支持Hexagon DSP時,深入了解其體系結構與編程模型是關鍵。

對於深度學習推理引擎,接收模型是第一步,包括TensorFlow、TFLite、MXNet等。目前,這一環節在不同框架中都存在不足,模型支持程度參差不齊。以TVM為例,雖然已實現了部分運算元支持,但仍有大量運算元未覆蓋。對於開發者而言,可選擇在框架基礎上進行擴展,共同推動技術進步。

在解析模型後的計算圖階段,各框架實施的優化策略不盡相同,但普遍會涉及運算元融合等通用優化技術。TVM引入了類似LLVM的Pass機制,支持異構執行,但在自動化的異構子圖分離方面仍有改進空間。業界對於此問題的研究,包括基於傳統機器學習的Cost Model與強化學習的方法,為解決異構執行問題提供了新的思路。

計算圖對接外部推理引擎是另一個值得關注的點。在實際應用中,業務部門通常追求模型快速且高效執行。以GPU為例,TensorRT提供高性能推理能力,但可能不支持某些運算元。結合TVM與TensorRT,通過子圖分離實現不同運算元在不同硬體上的高效執行,是解決這一問題的有效途徑。這一策略同樣適用於NPU的支持,通過異構執行達到性能優化。

在運算元層面,卷積操作是優化的重點。編譯器、體系結構和高性能計算領域的專家在這方面能發揮關鍵作用。TVM的Auto TVM和Halide思想的應用,使得優化技術的移植和性能提升變得更為高效。編譯生成部分,TVM採用LLVM為基礎,簡化了代碼指令生成的工作量,同時提供了Tensorize機制,允許開發者自定義優化。

量化壓縮是深度學習領域的重要技術之一,TVM支持不同的量化策略,包括TFLite轉換和TensorRT量化。量化策略的選擇和優化是關鍵,業界的一些框架提供快速重訓練等工具,以提高模型准確度和執行效率。這方面的學習和實踐對於深度學習編譯器的發展具有重要意義。

總之,基於編譯優化的深度學習推理引擎是未來趨勢,而TVM等框架在這一領域展現出巨大潛力。隨著技術的不斷發展,我們可以期待更多創新和突破,為深度學習應用提供更高效、更靈活的解決方案。

閱讀全文

與做編譯器優化有前途嗎相關的資料

熱點內容
嵌入式能編譯文件的許可權 瀏覽:12
轎車空調壓縮機突然怎麼不工作了 瀏覽:432
dd命令怎麼解壓 瀏覽:397
舊版安卓怎麼開鎖 瀏覽:247
開發程序員推薦 瀏覽:263
企信如何禁止訪問其他app 瀏覽:71
程序員辦公本推薦2019 瀏覽:197
手機qq下載app在哪裡 瀏覽:536
阿里程序員喊話 瀏覽:982
軟體伺服器地址不對怎麼辦 瀏覽:156
gcco的編譯格式 瀏覽:192
手持噴碼機加密怎麼買墨盒 瀏覽:744
cadcc命令 瀏覽:902
安卓手機攝像頭為什麼不用藍寶石 瀏覽:958
編譯器保留數字 瀏覽:8
linux解壓war命令 瀏覽:48
紅與黑中央編譯 瀏覽:570
我的世界簡單命令方塊教學 瀏覽:196
什麼游戲解壓最合適 瀏覽:508
安卓怎麼搞黑色的界面 瀏覽:961