日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

程序分析与优化 - 6 循环优化

發布時間:2024/1/8 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 程序分析与优化 - 6 循环优化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

🚀 優質資源分享 🚀

學習路線指引(點擊解鎖)知識定位人群定位
🧡 Python實戰微信訂餐小程序 🧡進階級本課程是python flask+微信小程序的完美結合,從項目搭建到騰訊云部署上線,打造一個全棧訂餐系統。
💛Python量化交易實戰💛入門級手把手帶你打造一個易擴展、更安全、效率更高的量化交易系統

本章是系列文章的第六章,介紹了循環的分析方法。循環優化的邏輯相對簡單,但對性能提升的效果卻非常明顯。循環優化的分析還產生了一個圖靈獎。

本文中的所有內容來自學習DCC888的學習筆記或者自己理解的整理,如需轉載請注明出處。周榮華@燧原科技

6.1?循環的重要性

  • 90/10定律,90%的算力消耗在10%的代碼上,這些代碼絕大多數都是各種循環
  • 循環的優化對獲得更高的性能非常重要
  • 基于循環的迭代空間轉換的優化(本章不涉及)
  • 維持循環的迭代空間不變進行的優化(本章重點):
    • 代碼提升(code hoisting)
    • 強度削減(strength reduction)
    • 循環展開(loop unrolling)
    • 等等

6.2?分解控制流圖

對于下面的C代碼,分析一下有幾重循環?怎么從控制流圖中定義循環?

1 #include 2 int main(int argc, char **argv) {3 int sum = 0;4 int i = 1;5 while (i < argc) {6 char *c = argv[i++];7 while (*c != '\0') {8 c++;9 sum++; 10 } 11 } 12 printf("sum = %d\n", sum); 13 }

控制流圖的生成方法就不多說了,忘記的同學可以回過頭去看看第二章(2.1.3 LLVM),生成的svg圖如下:

控制流圖中的自然循環是具有下列屬性的節點的集合S:

  • 存在一個頭結點h
  • S中的任意一個元素都存在路徑到頭結點h
  • S外不存在任何節點有邊指向S中除h意外的其他節點

編譯器中說的循環(loop)和拓撲意義上的環(cycle)是不同的。編譯器領域中的環只能有一個入口,多個入口的環在編譯器領域不叫做循環,因為絕大多數對循環的優化在多入口的環中都不適用。

多個入口的環在編碼過程中也非常罕見,所以也不是編譯器需要關心的場景。

6.2.1?控制流圖的簡化過程

如果對于邊(n1, n2),n1是n2的唯一前驅,或者n1和n2是強連通圖的一部分,可以用下面的方法簡化:

  • 刪除邊(n1, n2)
  • 新建節點n12
  • 將所有n1的前驅改成n12的前驅
  • 將所有n2的后繼改成n12的后繼
  • 刪除節點n1和n2

重復上述操作,直到控制流圖保持不變。

例如下面的控制流圖:

簡化流程是這樣的:

為什么要簡化控制流圖:

  • 入口單一,可以在優化過程中在頭結點處增加 冗余代碼
  • 簡化后的圖數據流分析速度更快
  • 常規的循環語法,例如for,while,repeat,continue和break都會產生可簡化的控制流圖
  • goto會產生不可簡化的流圖

6.3?自然循環

6.3.1?支配節點(Dominators)

節點d是節點n的支配節點,當且僅當所有從控制流圖入口到n的所有路徑都經過d。

D[s0] = {s0} D[n] = {n}?∪?(∩?p∈?pred[n]D[p]), for n ≠ s0支配節點的計算:

6.3.2?直接支配節點(Immediate Dominators)

每個階段n都 只有唯一一個直接支配節點idom(n),定義如下:

  • idom(n) 不是n
  • idom(n)是n的支配節點
  • idom(n)不是n的其他支配節點的支配節點

6.3.3?支配節點樹(Dominator Tree)

把每個節點的直接支配節點畫一條邊到該節點,就形成了圖的支配節點樹:

嵌套循環中優先優化內存循環。

循環的頭節點h:在循環的節點集中,存在一個節點n,h是它的支配節點,并且存在邊(n, h)。

如果兩個循環的頭結點存在支配關系,則被支配的頭節點所在的循環稱為內循環,支配的頭節點所在的循環稱為外循環。

6.4?安全的不變代碼提升(SAFE INVARIANT CODE HOISTING)

6.4.1?循環不變性

如果某個計算在循環的每次迭代中都產生同樣的值,則該計算時循環不變的。

循環不變表達式的通常優化方法是將該表達式提升到循環外。

滿足下面任意一條要求的表達式是循環不變表達式:

  • 表達式的參數是常量
  • 表達式的參數定義在循環外
  • 表達式的參數是循環不變表達式,并且在該表達式之前沒有其他定義

將循環不變表達式提升到循環外的做法稱為代碼提升。

6.4.2?安全的不變代碼提升

在程序點d,如果滿足下面3個條件,可以對表達式t = a + b 安全的進行代碼提升:

  • d是所有t生效區域內節點的支配節點
  • t在循環內只有一個定義
  • t在循環的頭結點外沒有使用

6.4.3?循環倒置(Loop Inversion)

將常規的while循環轉換成repeat-util循環的做法稱為循環倒置。倒置后的循環可以安全的進行不變代碼提升。

repeat-utill循環在循環過程中每次迭代只需要進行一次跳轉,所以性能也比常規的while循環要好。

6.5?因變量(INDUCTION?VARIABLES)

6.5.1?基本概念

基本因變量(Basic induction variable):如果一個變量i在循環內部僅定義一次,并且每次定義都是在原有值基礎上增加或者減少循環不變量的值。

派生因變量(Derived induction variables):如果一個變量k在循環內部僅定義一次,并且k是一個因變量與循環不變量的乘積或者和。

i系列的派生因變量(a derived induction variable in the family of i):如果一個變量k定義中使用的因變量j僅定義一次,并且定義在循環內部,在j和k之間沒有i的定義。

6.5.2?強度削減

將乘法運算換算成加法運算。例如下面的優化:

強度削減的算法基本上就是將派生因變量轉換成基本因變量。算法過程一般如下:

  • 對所有j = i * c, 假定變量i每個迭代增加b,i 初始化為a,那j每個迭代就要增加 b*c。
  • 在循環外新增一個變量j’為第一次迭代時的j的值, j’ = a*c
  • 在循環外新增一個變量k,用來保存每個迭代j需要增加的值b*c
  • 這樣循環內部就可以優化成
  • j = j’
  • j’ += k

6.5.3?無用代碼刪除(Dead Code Elimination)

首先刪除的是j’,因為k’已經完成了類似的功能:

由于i除了定義就只有和循環不變量的比較,所以實際上i也是可以刪除的:

刪除冗余拷貝:

循環倒置:

初始版本和最終優化版本的對比:

6.5.4?循環展開

循環展開是通過減少循環次數并增加循環內部的計算來優化的一種方式。例如對下面的代碼:

以2為因子進行循環展開之后的結果是這樣的:

6.5.5?指針分析簡史

  • Lowry, E. S. and Medlock, C. W. “Object Code Optimization”. CACM 12(1), 13-22 (1969) 引入因變量優化和支配節點的概念
  • Allen, F. E. “Control Flow Analysis”. SIGPLAN Notices 23(7) 308-317 (1970)引入控制流圖的化簡,并因此獲得圖靈獎

總結

以上是生活随笔為你收集整理的程序分析与优化 - 6 循环优化的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。