這是以前研究所學生的時候寫的一篇文章
今天看了一篇文章關于cpu亂序執行的講解,主題思想是cpu能并行的處理指令,這裡的并行不是多核并行的處理,而是在某種情況下,上下2條指令可以被一個核一起送行,還有可能在下面的指令先運作,稱為亂序執行,out of order,這也帶來了超标量,1個時鐘周期可以運作大于1條指令。這在以前是不可想象的,在理想情況下,一個時鐘最多執行1條,但是創新是無界限的。
一個簡單的實驗
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcukTNkBzM4czYkRTM1cjYmJWNmBzMxkTYilzMjVTOxQDNvwVbvNmLj5Wat4Wd5lGbh5iY1BXLn1WauU3bop3ZuFGat42YucWbp1iMhRXYvw1LcpDc0RHaiojIsJye.png)
過程為對eax執行3次加法,循環差不多4g次,差一點點,無關緊要,産生執行檔案反彙編如下
循環内部一共五條指令,4g次循環,就是20g個指令需要執行,使用time 計算運作時間10次測試值為
7.12 7.23 7.24 7.07 7.14 7.17 7.21 7.30 7.16 6.99這裡是user時間,使用者态時間,忽略其他函數包括main之前的函數執行時間
就是在這20g次得指令執行上花了大約7s時間,本機的配置為酷睿的2.1ghz,7s的時間最多也隻能有14g的周期,按照一般理論,執行不了20g次指令,這還是在每個指令都是單周期的理想情況下
這就是亂序執行帶來的超标量性能。
對于此現象的稍微詳細一點的解釋可以是這樣,
5條指令,每一條都是對cpu狀态機的一個改變,對于上下沒有依賴的指令可以一起執行
比如
這2條可以并行運作,但是
這2條就不可以并行運作,對于這5條指令可以了解為這樣的一個過程
每一行代表一個機器周期,對eax的三次相加,必須等到前一次運算完成以後才能進行下一次的相加,但是對于edx的減法就可以和第一次eax的加法一起運作,其實edx就是c代碼的那個i,這裡就是亂序的展現,因為edx的減法在後面,但是先于2個eax的加法運作,沒有按照固定順序。但是不管怎麼亂序,指令執行完以後的結果需要和順序的一樣。jne 80483a8這個指令要等到對edx減法完成是才能運作,因為要根據減法運算的結果的判斷。
是以這5條指令 4g次循環其實是3個周期 4g次循環為12g個周期,7s的時間2ghz 處理器可以有14g個周期。是以加上main之前的庫代碼為2g個周期,就差不多7s 的運作時間。
以下是對代碼的另一種實驗。對eax的3次加法改成分别對eax ebx ecx的3次加法,這個看上去是差不多,都是對寄存器加法運算,但是對于現代的處理器有很大的差别。
c代碼改為
對于的a.out執行檔案反彙編為
循環還是5條指令和原來的一樣,隻是原來是eax3次加法變成現在的eax ebx ecx的三次加法,測試的運作時間為
4.31 4.48 4.28 4.33 4.28 4.25 4.19 4.34 4.34 4.33
這是絕對的減少,這就很奇怪,隻是對寄存器不一樣,按照上面的方法可以畫一下cpu運算資料流向圖
因為對eax ebx ecx 3條指令沒有上下依賴關系,目前intel處理器每個核有三個獨立的加法器(可以測試具體有幾個加法器),是以其實這3條指令是一起運作的,估計cpu資料流,一次循環其實隻需要2個周期就可以了,4g次循環隻需要8g個周期,對于一個2ghz的處理器來說時間也剛好是4s差不多,和測試結果完全比對。這就是cpu的亂序執行的能力。對于性能優化,在c的展現中,在循環中,在連續的幾次運算中資料沒有依賴性是重點。把運算過程的中間結果都放在同一個變量中會比較慢。
就算再增加一個加法運算把原來的3次改為4次,
運算時間還是和上一次是一樣的。
因為cpu資料流圖
在一個循環的運作周期上還是一樣的,4.22 4.44 4.31 4.30 4.23 4.21 4.22 4.24 4.22 4.23
如果增加到5個的話,資料流回變成
在2個時鐘周期中三個加法器會滿負載運作,這樣就會影響到jne 80483a8的運算,
其實這條指令也是需要加法器支援的,從上面可以看到這條指令的機器碼是 75 f2效果是向前跳12個偏移,這是一個相對偏移跳轉指令,運算過程為下一條指令位址0xbc+2=0xbe 加上0xf2
加上f2就是減14 等于0xb0,是以需要加法器計算最終的位址。但是加法器在前面已經滿負荷運作,是以勢必會增加每個循環的周期數。測試結果為
5.17 5.52 5.05 5.31 5.09 5.15 5.30 5.31 5.39 5.04
明顯的比前面的運算時間要增加。