contributed by < plusline
, jason53415
, butastur-rtos
>
github: countbit cache_mountain
For example:
加上 force inline,降低函式呼叫的成本
:notes: jserv能否用 macro ?
butastur-rtosSat, Nov 3, 2018 2:11 PM
似乎有改善一點點
由 494,228 cycles 進步到 484,403,大約 2%,才加一個關鍵字就能有如此效益,感覺還不錯
居然 macro 輸了,明明名字聽起來比較厲害。
不該只做單次比較,要考慮誤差範圍
"jserv"
Difference Between Inline and Macro in C++ 提到10點 macro 與 inline 的差別。
inline
;一個是 #define
。這一點不太清楚 each time 是什麼意思? 是指 inline 是在組合語言的時候就一次把所有 inline function展開; macro 是在程式執行時才展開嗎?
plusline
為什麼不去讀 C 語言規格書呢?inline 是一種編譯器最佳化的提示,可搭配 SSA optimization 運用
jserv
這裡的 binding becomes difficult when macro contains more that one statements 是什麼意思?是因為如同C 語言之多行巨集中提到的,macro在換行的操作很容易出錯,所以困難?
plusline
macro 無法做有效的參數型態檢查,更沒辦法讓編譯器推導同等效果的型態,後者是編譯器最佳化很關鍵的部分
"jserv"
至於效能,參考 An Inline Function is As Fast As a Macro,似乎不分上下,不過許多關於 macro 和 inline 的效能比較都會強調 macro 的缺點,都會得出 macro 不好維護,建議用 inline 的結論。
避免用「歪樓」這樣不具體的描述,工程講究證據和精準用語
"jserv"
已修正不當用語,並加強詞彙的準確性。
第一版–-符合原本題目規定
483,536 cycles
第二版–-(~y+1)==-y
482,650 cycles
第三版–-branch
484,148 cycles
第四版–-使用 Elvis operator
482,785 cycles
cycles 這幾種的差異比誤差還小,感覺不到是否有真的優化。
plusline
你檢驗幾組數值輸入呢?不是單次「變快」就叫改善,這裡我們期待的是 branch-less 和常數時間運算
"jserv"
在後面的研究方法已經透過增加取樣引入統計方法改善問題。
plusline
Tips for Optimizing C/C++ Code 提供幾個改善效能的方法
1. 由 Amdahl’s Law 可以知道,要改善最常發生的情形,並且使最糟情形的運作時間合理。
2. 改善演算法能夠大大的改善瓶頸
3. 改善效能是一件耗時的事
4. 使用分支的代價是昂貴的,盡量在短函式上使用 inline;遞迴的代價高於迴圈;把迴圈寫在函式裡(出乎意料的建議);switch 比多個 if…else if 好。
5. 由於陣列在記憶體中的存放方式,導致多維陣列在連續存取時,index 的順序會影響效能。(這點之前的課程有提到過)
Faster Population Counts Using AVX2 Instructions
其實我們兩個方法很接近,但是實做出來的結果就有不小差距。我們一樣都是先計算相鄰的兩位元的數量,再來計算相鄰四位元的數量,然後相鄰八位元,一直到三十二位元。差別在 Linjingchun97 先將不用的位元先去掉,而我為了不讓沒有用的位元影響到其他正確的位元,我採用加法器的作法,先用加法器的作法做到相鄰四位元後才轉入與 Linjingchun97 的作法,直到看到 Linjingchun97 的作法之後我才意識到加法器的部份有點多餘。而效能在下圖,可以看到雖然都是常數時間的演算法,僅僅就減少運算子,就能看到效能的提昇。
這個作法是真的是一個一個數,重複的程式碼跑32次,因此加上 macro 提昇效能,但看結果也是不太好 。
這個作法是直接枚舉8個位元的所有可能,先在 itsSetTable256 算出每個8位元所能表示的值的1的個數, B2 是最低兩位,B4 是加上次低兩位, B6 再加上兩位,最後呼叫 define 4次,建構出8位元的表。
再把32位元切成4個8位元,分別計數後加總起來,就得到答案了。
把table變大並沒有比較好,在最佳情形時的時間都一樣,但是最糟情形卻甚至會比使用分之還糟糕。
方法: 依據中央極限定理,先求點估計,再查t表,算信賴區間,帶入有限母體信賴區間公式, 。
Column 1 | 平均時間 x (ns) | 標準差 s | 95% 信賴區間 |
---|---|---|---|
non-pipeline | 120.325 | 10.7768 | 120.325±0.667953 |
inline | 117.108 | 6.53489 | 117.108±0.424398 |
solution2 | 93.721 | 6.84727 | 93.721±1.77908 |
macro + one by one | 264.497 | 51.7969 | 264.497±3.21041 |
:+1: look up table 8 | 73.104 | 6.06788 | 73.104±0.376091 |
look up table 16 | 131.782 | 116.333 | 131.782±7.21042 |
利用 fabiensanglard 的專案進行讀取吞吐量的實驗,在用 gnuplot 畫出統計圖。
注意:這一個部份的取樣極少,部份極值的發生是抽樣的偏差造成的。
實驗目的:
觀察步長1~11加上資料大小32K~128M 吞吐量的的分布。
討論:隨著資料越大步長越長,吞吐量會越低,不過看起來跟課本的圖沒有很像,有可能是設備不一樣。課本使用
實驗目的:觀察只使用核心的數量會不會影響到吞吐量。
測量方式:
討論:跟課本的圖比較像一點,但還是看不出 L1快取 L2快取 L3快取 主記憶體,四個明顯的區段。在試試看增加 stride 和 size 看看。
大功告成,加上等高線後,可以看到寄存器山的走勢。
修改fabiensanglard 的專案,用 perf 抓取 L1 cache misses ,加上 sh 處理 perf 的輸出,再用 gnuplot 繪出。
討論:
沒想到居然不是步長越短 cache misses 越低,反倒是在步長10上下會是在低點。
討論:
可以看出步長小資料小 L1 cache misses rate 會稍微小一點,在步長大資料量大時 misses rate 回大幅增加,不過在步長以及資料量中等時 misses rate 是差別不大的。
討論:
last level cache (LLC) 在這裡指的是 L3 cache ,在這個測試環境中 L3 cache 是5360K ,可以對應到圖中的最低點。
實驗目的:
讀取 countbit 的 look-up table 是循序的,觀察隨著步長 L1 cache misses rate 的變化
討論:
在步長小於 L1 cache 的時候,隨著步長增加,misses rate 也會隨著增加,至於超過 L1 cache 容量之後,大部分的情形會讓 cache misses rate 維持在接近50的位置,但讓我好奇的事,到底是什麼原因造成 misses rate 的抖動,而不是維持在一個定值?
實驗目的:
造成實驗一 cahe misses rate 抖動的原因是取樣不夠嗎?我抓取步長100到120的區間,增加取樣頻率,比較取樣頻率10(原本)和取樣頻率1000差異。
討論:
這段資料有明顯的抖動,而從這張圖看得出來,兩種不同的取樣頻率所繪出的曲線是高度重合的,因此推論這樣的抖動不是取樣頻率造成。
實驗目的:
比較 countbit 中兩種不同的大小 lootup table 在循序情況下的效能 。
討論:
在尋序讀 table 的情況下,8 bits 的 table cache misses 是非常低的。反觀 16 bits ,則是會隨著步長提昇 misses rate 。
實驗目的:
比較 countbit 中兩種不同的大小 lootup table 在亂序情況下的效能 。
討論:
在 countbit的實驗中,對於時間平均計算時間的統計如下,8 bits 的 lookup table 執行時間是較短的。
Column 1 | 平均時間 x (ns) | 標準差 s | 95% 信賴區間 |
---|---|---|---|
:+1: look up table 8(index 256) | 73.104 | 6.06788 | 73.104±0.376091 |
look up table 16(index 65526) | 131.782 | 116.333 | 131.782±7.21042 |
致命問題:
sysprog2018