這次的文章,
Shady 將分享一些組語程式的知識及技巧。
首先寫組語或其他語言之程式時,
若只要求能運作、能有正確結果,
那程式就不會快了,當然,
以上要求也是寫程式時的第一要求,
但當為了程式最佳化的話,
就必須針對您所控制之晶片的架構有所熟悉才行。
所以我們有必要知道 Cell 的 PPU 之架構,
而它的架構敘述如後。
在 Linux 使用者空間下,
能使用的暫存器有 32 個整數暫存器 (GPR)、
32 個浮點暫存器 (FPR)、32 個向量暫存器 (VR) 和連結暫存器 (LR)、
計數暫存器 (CTR)、整數例外暫存器 (XER)、條件暫存器 (CR)、
浮點狀態控制暫存器 (FPSCR)、向量狀態控制暫存器 (VSCR)、
向量保存暫存器 (VRSAVE) 各 1 個,
至於每個暫存器寬度 (所能容納的 bit 數量),
按以上介紹順序為 64、64、128、64、64、64、32、32、32、32。
由於 PPU 只支援大端記憶體排序,
所以以 GPR 來說,其最大的 bit 在最左端,編號為 0,
最小則在右端,編號為 63,
故十六進位數值 0x800000010 在暫存器中,
bit0 之數值為 1,之後的 bit1 ~ bit61 皆為 0,
而後的 bit62、bit63 各為 1、0。
其餘暫存器的詳細介紹就請各位參考 IBM 的 Cell 網頁之文件了。
不要以為知道暫存器後就高枕無憂囉。
接著要介紹的是 PPU 對指令的處理過程。
PPU 是個循序單核心、雙執行緒且管線深度很深的 CPU,
所以在程式撰寫上,盡量以執行緒撰寫,
雖然執行緒不如雙核心之效能,
但也能盡量將其管線填滿。
故 Shady 推薦在 C 以上的高階語言,
盡量以此方式撰寫,如 Linux 上的 POSIX 所提供的 pthread。
可是 "雙執行緒" 對組合語言適用嗎?
Shady 的回答是對小函式是不適用,
而大函式亦不適用。
為什麼大、小函式都不適用?
因為小函式太過於殺雞用牛刀了,
而大函式則是開發困難,
所以通常以 C 等高階語言主程式的 thread 來呼叫組語函式為佳。
所以我們需將焦點轉移到單一執行緒上的指令處理,
首先要注意的是 "指令相依性",
"指令相依性" 指的是第一個指令的結果為第二個指令的運算元,
遇到此狀況會導致第二個指令延遲,
若第一個指令為微碼或複雜指令,
將會導致 6 ~ 11 個以上的 CPU 週期且避免 "雙發射",
所以最好以二個獨立指令交互排列且盡量不使用微碼和複雜指令,
其例子如:
add ra,rb,rc
add rd,ra,re /* 此行與前一行相依 */
add rf,rg,rh
add ri,rj,rf /* 此行與前一行相依 */
改成:
add ra,rb,rc
add rf,rg,rh
add rd,ra,re
add ri,rj,rf
會比較好。
再來介紹 "雙發射",
它的意思是單一 CPU 週期能發送二個不同執行單元之指令,
而這也是 "單執行緒" 用來加強 IPC (Instruction Per cycle) 的機制,
雖然在單一執行緒程式很難全都 "雙發射",但不無小補。
至於 PPU 有多少執行單元且哪些指令是對應什麼執行單元,
就請各位多參考 IBM 的文件了。
以下為 "雙發射" 的典型例子:
add ra,rb,rc /* 整數單元 */
ldx rd,re,rf /* 加載 / 存儲單元 */
此二個指令中間並沒有其它指令,
這樣子的指令排序方式就能令 "雙發射" 成立。
最後 Shady 要介紹最後的一項技巧:"分支演算法"。
"分支演算法" 被提出的原因為分支的代價對 PPU 效能的影響很重大,
因為分支的成功與否都會因分支後的指令不在指令快取中,
而且分支的預測也會對循序架構的 PPU 有效能衝擊,
因而導致慢長的 CPU 週期延遲,
所以為了提升整體程式之效率,
減少分支指令是勢在必行的。
雖然 "分支演算法" 不會比分支指令的最好例子快,
但平均下來,"分支演算法" 會較好。
以下為 C 的 if 例子:
if ( a >= b ) {
c = b;
} else {
c = a;
}
其組語 "分支演算法":
sub rd,ra,rb /* a - b */
srdi rd,rd,63 /* 取出正負號 bit */
neg rd,rd /* 取正負號 bit 的 "二捕數" */
and re,ra,rd /* a 和正負號 bit 的 "二補數" 做 and 運算 */
andc rf,rb,rd /* b 和正負號 bit 的 "二補數" 的 "一補數" 做 and 運算 */
or rc,re,rf /* c = a 或 c = b,使用 c = a | b 運算式運算 */
雖說 "指令相依性" 不少,
但只要有更多的 "分支演算法" 或獨立指令交互穿插,
就能掩蓋 "指令相依性" 造成的延遲。
下篇文章中,
Shady 將會提供功能相當於 bzero 函式的組語函式,
而且會說明組語撰寫的一些注意事項。
沒有留言:
張貼留言