2011年5月7日 星期六

電腦壞了!

因 Shady 的電腦掛點,
而 Cell 的相關程式及資料都未備份出來,
又因工作關係,
人現在住在台北,
所以 Blog 的更新非常的不頻繁,
等 Shady 購入下台能安裝 Linux 的 PS3 時,
才有可能會頻繁些。

2011年2月28日 星期一

Shady 錯了!TOC 沒比立刻開起一個堆疊快。

之前 Shady 的有關 TOC 之文章中有說 TOC 較堆疊快,
但實際是直接使用堆疊會較快。

Shady 之所以會說 TOC 會較快的原因為:
IBM 的 PowerPC 組合語言相關文章中有提到 TOC 通常是在 Cache 中。

但經 Shady 以更改 setzero 組語函式實際測試後又再想想,
64KB 的 TOC 根本不可能一開始就在 Cache 中,
就算它有在 Cache 中,
那也是 L2 Cache 而不是 DCache。

害 Shady 以為就算直接馬上開個堆疊,
也不會比直接載入在 DCache 中的 TOC 還快,
但經 Shady 證明後並非如此。

所以馬上開個堆疊,
這堆疊會在 Dcache 中,
而 TOC 還是從記憶體載入到 L2 Cache、DCache 中,
故 TOC 只有在第一次載入後,
於第二次載入時才會對整體效能有所幫助。

雖說 TOC 沒比馬上開啟堆疊快,
但會比資料在記憶體或者是更新出 Cache 中的堆疊快就是了。

在 IBM 的一些有關組語的文章中,
其組語的例子中都會有類似以下的 " TOC 宣告 " (紅字):
_start:
       .quad ._start, .TOC.@tocbase, 0

如果你不使用 TOC 請省略這 " TOC 宣告 ",
因為就算沒使用 " TOC 內容 " 或 " 設置 TOC 內容 ",
只要有 " TOC 宣告 " 就會造成函式被呼叫時,
函式和其 TOC 會同時被載入到 Cache 中。

目前最快的 setzero.s

其 tick 值於 4KB 下的測試結果為:13 ~ 16 ticks。(注1)

當中無使用 TOC 也沒有 " TOC 宣告 ",
亦無 Altivec ABI 的指令,
但若做了 " TOC 宣告 " 則會使 tick 值增加到 25 ticks 以上 (注2),
所以不要隨便做 " TOC 宣告 "。

注1:呼叫函式前有使用 dcbt 預先載入函式,
    若無使用 dcbt 則成績為 17 ~ 25 ticks。
注2:呼叫函式前有使用 dcbt 預先載入函式。

2011年2月10日 星期四

再提"雙發射"。

Shady 曾在「撰寫 Cell 的 PPU 之組語所需的知識及技巧。」此文章中提過 "雙發射",
當中有提到「這也是 "雙執行緒" 用來加強 IPC 的機制。」
這裡的 "雙執行緒" 打錯了,應該為 "單執行緒"。

現在來談談如何最佳化 "雙發射" 所該有的注意事項,
由於 PPU 的指令長度都是 32bits ( 4Bytes ),
且指令的預先提取為四個指令、解碼為二個指令同時解碼,
所以預先提取與指令解碼的指令之位址將會是連續的,
以下列程式為例:
    位址       標籤       指令
0x1000_04F0          vand 3,1,2
0x1000_04F4          beq .Lend
0x1000_04F8          add 5,6,7
0x1000_04FC          add 3,8,9
0x1000_0500  .Lend:  sub 4,5,6
0x1000_0504          ldu 10,16(7)
0x1000_0508          stvx 0,5,4
0x1000_050C          std 4,16(7)

從此例中可發現指令位址的尾數都是以 0、4、8、C 為循環,
而 IB (註1) 會提取前四行指令,
而第一、二行指令會先同時解碼,
在解碼的同時亦會檢查 "相依性" 與是否可以 "雙發射",
所以此例的 "雙發射" 結果為:
第一、二行指令可 "雙發射",原因為指令執行單元是 VSU1 與 BRU。
第三、四行指令不可 "雙發射",原因為指令執行單元是 FXU 與 FXU。
第五、六行指令不可 "雙發射",原因為指令執行單元是 FXU 與 LSU、FXU。
第七、八行指令可 "雙發射",原因為指令執行單元是 VSU2 與 LSU。

從結果可看出執行單元的不同就能 "雙發射",
要注意第七、八行的 VSU2 單元一定要在 LSU 之前,
如此順序才能讓 VSU2 與 LSU 達成 "雙發射"。

還有如 ldu、stdu 等指令會同時使用 LSU、FXU 等二個以上的執行單元,
有些指令甚至會使用到三個以上的執行單元。

如果在無相依的狀況下,
但執行單元卻是相同的話,
就會如第五、六行指令一樣不能 "雙發射",
而且第六行指令會在第五行指令的下個 CPU 週期發射。
若第五行指令的執行單元為 LSU 和 FXU 以外的執行單元,
這樣就能讓第五、六行達成 "雙發射" 之條件。
第三、四之行情形如同第五、六行之情形。

所以無相依性、不同單元可一個 CPU 週期發射二個指令,
而無相依性、相同單元只能二個 CPU 週期發射二個指令,
但有相依性、不論相不相同單元都會是二個以上 CPU 週期發射二個指令。

另外,分支指令最好放置在位址尾數為 0x4 和 0x8,
這樣能對分支預測及程式執行有益處。
然後分支目標最好座落於位址尾數為 0x0 和 0x8,
因為解碼都是 0x0 配 0x4,
而 0x8 配 0xC。

最後就是盡量不要使用會 stall 的指令、非管線化的指令和微碼指令,
因為它們會讓 "雙發射" 失效。
其餘該注意的事項之嚴重性都較以上小,
若有興趣者請多參考 IBM 所放出來的文件。

註1:Instruction Buffer 的簡寫。

之前提過的" Altivec ABI "與現在要提的" TOC "。

之前有略提 Altivec ABI,
而這次 Shady 也不會深入講解,
因為 Linux 的預設下,
vrsave 暫存器為 0xFFFF_FFFF 的數值,
也就是所有的向量暫存器 vr0 ~ vr31 都可以使用,
所以之前的程式中若有 Altivec ABI 的相關指令可以刪掉了。

至於 TOC,
Shady 就直接提供網址給大家參考,
因為 Shady 懶得打了 XD。

Linux on POWER 中的 GNU C/C++ 工具鏈。
用於 Power 體系結構的彙編語言,第 2 部分。

以上網頁會有 TOC 的說明和 TOC 的使用簡介。

老實說 TOC 比堆疊還快...。

之前提過的" Cache 堵塞"。

之前 Shady 曾經說過在 16KB 的測試下於沒有執行 dcbf(); 時,
函式測試之結果都會變慢,
其原因被 Shady 稱作" Cache 堵塞",
而正確的稱呼為" Cache 飽和"。

因為 L2 Cache 為 write-back 設計,
又因配置記憶體的相關函式,
它可能於記憶體配置完成時也將 L1 Data Cache (DCache) 塞滿了,
所以當 DCache、L2 Cache 要將資料丟回記憶體時,
就會造成大量資料堵塞住 Cache 和記憶體之間的 Bus,
而且當資料量愈大時,
就會有部分資料在 DCache、L2 Cache中,
而另一部分資料還在記憶體中,
如此又會造成從記憶體區的資料要搬進 Cache 時,
會遇到舊的資料還在 write-back 中,
因此又造成等待時間加長。

在這邊 Shady 要列出一些 DCache 相關組語指令:
dcbt:將資料從記憶體搬入 DCache,
      預備給 load 相關動作使用,
      但若資料不在 L2 Cache 中,
      此指令只會將資料搬到 L2 Cache。
dcbtst:將資料從記憶體搬進 DCache 和 L2 Cache,
        預備給 store 相關動作使用。
dcbst:將資料從 DCache 和 L2 Cache 中更新回記憶體,
       但保留此 Cache line 在 DCache 和 L2 Cache 中。
dcbf:將資料從 DCache 和 L2 Cache 中更新回記憶體,
      但不保留此 Cache line 在 DCache 和 L2 Cache 中。
dcbz:將被指定的 Cache line 設置為零。

當中的 Cache line 又稱為 Cache block,
其長度有 128Bytes,
所以資料要盡量對齊 128Byte 位址,
以方便資料搬進 Cache 中。

還有盡量只使用 dcbt 和 dcbz 指令,
因為其它 DCache 相關指令不會比較快,
而 dcbt 需連續拿取六個不同位址且對齊 128Byte 之資料,
也就是六個 Cache line,
這樣才能掩蓋記憶體延遲,
而 dcbz 需連續拿取四個。
另外將資料 load 進或 store 出暫存器會有四個 CPU 週期,
所以當第一行指令為 load、store 相關指令時,
需再通過三行無相依指令才能於第五行以後的指令使用此暫存器。

以下列出 PS3 的階層式記憶體架構之延遲值:
Memory 到 L2 Cache:~ 400 cycles。
L2 Cache 到 DCache、ICache (註1):~ 40 cycles。
DCache 到 Register:4 cycles。
ICache 到 IB (註2):4 cycles。

註1:L1 Instruction Cache 的簡寫。
註2:Instruction Buffer 的簡寫。