之前 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 的簡寫。
這是有關本人在Cell上設計程式的心得Blog, 將來可能還會朝向CUDA前進, 當然也有其餘無關程式設計的ささやき出現於此, 如果有志同道合的網友瀏覽於此請多多指教、多給意見。
2011年2月10日 星期四
2010年12月29日 星期三
找到原因了...,原因有點囧就是了。
那就是 Shady 的測試主程式中的此段程式:
for(i = 32, j = 0; i > 0; i--, j += 128) {
__dcbf(d + j); /* 就是當中的 d+j,Shady 寫成 s+j 了。*/
}
因為 Shady 的測試程式一開始就是為 memcpy 類型的函式撰寫的,
所以會配置二個記憶體空間,
一個為來源 s、一個為目的 d,
故一直以來 Shady 都如上面程式解說般,
目的記憶體 d 都未從 cache 中消除,
而 memset 類型的函式就一直使用 d 而未更正,
因此 d 一直堵塞住 cache 而 Shady 卻不自知。
現在更正之後,
16KB 記憶體空間的測試就正常了,
但 setmem 的成績還不怎麼理想,
因為它還有至少 30 tick 的空間可以改善,
所以 Shady 下次放出的組語函式有可能是 setmem 修正版或 memcpy 的組語版,
也有可能二者同時釋放,
但不久之後 Shady 會比較忙,
所以釋放的頻率會比現在更低上很多,
因此請大家多體諒。
for(i = 32, j = 0; i > 0; i--, j += 128) {
__dcbf(d + j); /* 就是當中的 d+j,Shady 寫成 s+j 了。*/
}
因為 Shady 的測試程式一開始就是為 memcpy 類型的函式撰寫的,
所以會配置二個記憶體空間,
一個為來源 s、一個為目的 d,
故一直以來 Shady 都如上面程式解說般,
目的記憶體 d 都未從 cache 中消除,
而 memset 類型的函式就一直使用 d 而未更正,
因此 d 一直堵塞住 cache 而 Shady 卻不自知。
現在更正之後,
16KB 記憶體空間的測試就正常了,
但 setmem 的成績還不怎麼理想,
因為它還有至少 30 tick 的空間可以改善,
所以 Shady 下次放出的組語函式有可能是 setmem 修正版或 memcpy 的組語版,
也有可能二者同時釋放,
但不久之後 Shady 會比較忙,
所以釋放的頻率會比現在更低上很多,
因此請大家多體諒。
標籤:
Cell、PS3、Linux
2010年12月28日 星期二
超過 16KB 的記憶體配置後,造成程式緩慢之因素的猜測。
Shady 之前曾說過,
當配置的記憶體容量超過 16KB 時,
不管是出自 Linux 本身之函式、別人之函式或 Shady 的,
都將有很高的 tick 值出現。
而此情形有可能大於 4KB 記憶體配置就會出現,
只是 Shady 還未有稍大於 4KB 的測試就是了...XD
現在 Shady 最大的懷疑是" cache 堵塞"為主要原因,
因為不管是出自別人之函式或 Shady 的,
都有不當使用過多和未適時使用 lvxl、stvxl、dcbf等指令,
而這些指令都是將 cache line 標記為"最近最少使用"或"無效化",
所以目前 Shady 正在實驗這些指令的特性和它們在程式中的順序,
以更改配置的記憶體容量超過 16KB 時所造成的大失速。
當然主要的原因可能不在此處,
但目前也只能朝這方向猜測,
因為都已經用組語撰寫了,
甚至還避免使用微碼指令。
所以除了這個方向,
Shady 實在是想不出還會有啥其它的原因...囧rz
當配置的記憶體容量超過 16KB 時,
不管是出自 Linux 本身之函式、別人之函式或 Shady 的,
都將有很高的 tick 值出現。
而此情形有可能大於 4KB 記憶體配置就會出現,
只是 Shady 還未有稍大於 4KB 的測試就是了...XD
現在 Shady 最大的懷疑是" cache 堵塞"為主要原因,
因為不管是出自別人之函式或 Shady 的,
都有不當使用過多和未適時使用 lvxl、stvxl、dcbf等指令,
而這些指令都是將 cache line 標記為"最近最少使用"或"無效化",
所以目前 Shady 正在實驗這些指令的特性和它們在程式中的順序,
以更改配置的記憶體容量超過 16KB 時所造成的大失速。
當然主要的原因可能不在此處,
但目前也只能朝這方向猜測,
因為都已經用組語撰寫了,
甚至還避免使用微碼指令。
所以除了這個方向,
Shady 實在是想不出還會有啥其它的原因...囧rz
標籤:
Cell、PS3、Linux
2010年12月25日 星期六
memset 函式的組語版:setmem。
新的函式出爐囉:
setmem 原始碼。
這次也附上 setzero 的 bug 修正版:
setzero 修正版原始碼。
這次不論是 setzero 修正版或 setmem 都有加上 Altivec ABI,
這通常是編譯器做的事,
但在組語中,程式設計師只有自己手動撰寫,
有 Altivec ABI 的地方,Shady 會用 /* altivec abi */ 做註解。
至於成績,這次 Shady 只放出其 tick 值,如下:
setzero 修正版:16 ~ 17 ticks。
setmem:93 ~ 94 ticks。
這次的測試是用 4KB 的容量為測試對象,
在測試時,主程式是用 C 語言撰寫,其內容大致上如下:
#include < stdlib.h >
#include < stdio.h >
#include < ppu_intrinsics.h > /* PPU 在 C 語言下的專用底層函式表頭。*/
extern void setzero(void *, int);
int main() {
unsigned char *d;
unsigned long long i, j,start, finish;
if(posix_memalign((void *)&d, 128, 4096)) { /* 配置一對齊 128 Bytes */
printf("failed\n"); /* 邊界的 4KB 記憶體空間。*/
goto end;
}
for(i = 32, j = 0; i > 0; i--, j += 128) {
__dcbf(d + j); /* 將所配置的記憶體空間,從 cache 裡消除。*/
}
__dcbt(setzero); /* 將 setzero 函式預先提取到 cache 中 */
__dcbt(setzero + 128); /* 這也就是為什麼 setzero 的 tick 值較 */
__dcbt(setzero + 256); /* 上次小的原因,而要做 __dcbt(); 多少次,*/
__dcbt(setzero + 384); /* 需要視 setzero 之大小,而 __dcbt(); 一次載入 */
__dcbt(setzero + 512); /* 之大小為一 cache line,共 128 Bytes。*/
__dcbt(setzero + 640); /* Shady 建議最少六次,以掩蓋 cache、memory 的延遲。*/
__sync(); /* 同步、排空整個 PPU 管線。*/
start = __mftb();
setzero((void *) d, 4096);
finish = __mftb();
printf("%lld\n", finish - start); /* tick 值的計算兼印出。*/
end:
return 0;
}
老實說,這次的 setmem 成績不太理想,
而且還有當配置的記憶體超過 4KB 時,
一次所要設置的記憶體量不要超過 2KB,
否則將看到 2000 ticks 以上的成績出現,
這種狀況,不論是 Shady 的函式或別人的函式,
甚至是 Linux 的 libc 都會大失速。
當然 Shady 會找出原因所在,
而 setmem 的效率,Shady 也會盡量改進,
之後 Shady 還是會不定時釋放出新函式或修正函式,
只不過,可能頻率不會太常,
請大家見諒。
setmem 原始碼。
這次也附上 setzero 的 bug 修正版:
setzero 修正版原始碼。
這次不論是 setzero 修正版或 setmem 都有加上 Altivec ABI,
這通常是編譯器做的事,
但在組語中,程式設計師只有自己手動撰寫,
有 Altivec ABI 的地方,Shady 會用 /* altivec abi */ 做註解。
至於成績,這次 Shady 只放出其 tick 值,如下:
setzero 修正版:16 ~ 17 ticks。
setmem:93 ~ 94 ticks。
這次的測試是用 4KB 的容量為測試對象,
在測試時,主程式是用 C 語言撰寫,其內容大致上如下:
#include < stdlib.h >
#include < stdio.h >
#include < ppu_intrinsics.h > /* PPU 在 C 語言下的專用底層函式表頭。*/
extern void setzero(void *, int);
int main() {
unsigned char *d;
unsigned long long i, j,start, finish;
if(posix_memalign((void *)&d, 128, 4096)) { /* 配置一對齊 128 Bytes */
printf("failed\n"); /* 邊界的 4KB 記憶體空間。*/
goto end;
}
for(i = 32, j = 0; i > 0; i--, j += 128) {
__dcbf(d + j); /* 將所配置的記憶體空間,從 cache 裡消除。*/
}
__dcbt(setzero); /* 將 setzero 函式預先提取到 cache 中 */
__dcbt(setzero + 128); /* 這也就是為什麼 setzero 的 tick 值較 */
__dcbt(setzero + 256); /* 上次小的原因,而要做 __dcbt(); 多少次,*/
__dcbt(setzero + 384); /* 需要視 setzero 之大小,而 __dcbt(); 一次載入 */
__dcbt(setzero + 512); /* 之大小為一 cache line,共 128 Bytes。*/
__dcbt(setzero + 640); /* Shady 建議最少六次,以掩蓋 cache、memory 的延遲。*/
__sync(); /* 同步、排空整個 PPU 管線。*/
start = __mftb();
setzero((void *) d, 4096);
finish = __mftb();
printf("%lld\n", finish - start); /* tick 值的計算兼印出。*/
end:
return 0;
}
老實說,這次的 setmem 成績不太理想,
而且還有當配置的記憶體超過 4KB 時,
一次所要設置的記憶體量不要超過 2KB,
否則將看到 2000 ticks 以上的成績出現,
這種狀況,不論是 Shady 的函式或別人的函式,
甚至是 Linux 的 libc 都會大失速。
當然 Shady 會找出原因所在,
而 setmem 的效率,Shady 也會盡量改進,
之後 Shady 還是會不定時釋放出新函式或修正函式,
只不過,可能頻率不會太常,
請大家見諒。
標籤:
Cell、PS3、Linux
2010年12月24日 星期五
好想買個 GTX580 ~~XD
雖然現在 Shady 所使用的 GPU (GT200系列的入門款) 能支援CUDA,
但效能不佳,又沒錢換更好的,
看樣子得多爭點錢了...囧rz
目前 Shady 正在收集 CUDA 的相關資訊中,
也正在選擇是要在 Linux 下,
還是 Windows 下把玩 CUDA 或被 CUDA 把玩中,
而 Cell 的 PPU 的字串相關的組語版,
Shady 還是會不定期釋出新的函式,
只不過會不太常更新就是了...,
因為 Shady 有事情要忙了,
希望大家會諒解。
但效能不佳,又沒錢換更好的,
看樣子得多爭點錢了...囧rz
目前 Shady 正在收集 CUDA 的相關資訊中,
也正在選擇是要在 Linux 下,
還是 Windows 下把玩 CUDA 或被 CUDA 把玩中,
而 Cell 的 PPU 的字串相關的組語版,
Shady 還是會不定期釋出新的函式,
只不過會不太常更新就是了...,
因為 Shady 有事情要忙了,
希望大家會諒解。
2010年12月15日 星期三
心情好差!
將一句平凡無任何傷害之心的噓寒問暖的關心話,
說出來關心他人還被那個人當垃圾,
而且為此和 Shady 大吵一架,
而對方的理由是 Shady 多管閒事?
真不知大家會有何感想,
尤其是那個人居然是自己的家人...。
最後想了一想,
不只是對方錯了,
Shady 還很雞婆呢?
如果說家人都這樣了,
很難想像親戚、朋友給的反應會是如何?
反正心得很簡單:
少說少錯,
而事情做多也不一定對。
因此任何事都應該以不傷害他人為考量前提,
然後讓自己自私一些是沒錯的,
就算對方是自己的家人也是一樣,
因為良心、良言這種東西永遠是被踐踏之物,
所以除非對方主動找上門,
要不然你的良心、良言千萬不要主動付出。
經過此事後 Shady 也體會到社會會如此冷漠不是無原因的。
說出來關心他人還被那個人當垃圾,
而且為此和 Shady 大吵一架,
而對方的理由是 Shady 多管閒事?
真不知大家會有何感想,
尤其是那個人居然是自己的家人...。
最後想了一想,
不只是對方錯了,
Shady 還很雞婆呢?
如果說家人都這樣了,
很難想像親戚、朋友給的反應會是如何?
反正心得很簡單:
少說少錯,
而事情做多也不一定對。
因此任何事都應該以不傷害他人為考量前提,
然後讓自己自私一些是沒錯的,
就算對方是自己的家人也是一樣,
因為良心、良言這種東西永遠是被踐踏之物,
所以除非對方主動找上門,
要不然你的良心、良言千萬不要主動付出。
經過此事後 Shady 也體會到社會會如此冷漠不是無原因的。
2010年12月5日 星期日
忘了說的事項。
嘿嘿~~!
真是不好意思,
Shady 忘記向大家說明如何在 C 語言程式中呼叫組語函式了,
以 Shady 之前釋放出的 setzero.s 為例:
#include < stdlib.h >
extern void setzero(void *, int);
int main() {
unsigned char *d;
int a = 4096;
if(posix_memalign((void *)&d, 128, a)) {
printf("failed\n");
goto end;
}
setzero(d, a);
end:
return 0;
}
以上就是使用 C 語言程式呼叫 setzero.s 的例子,
當中的 posix_memalign 函式為配置一對齊 128 Bytes 邊界的記憶體區塊,
其大小為 4K Bytes。
最後 Shady 說明一下如何組譯、編譯程式,
首先是對 setzero.s 做組譯之指令:
ppu-as -o setzero.o setzero.s -mcell -maltivec --gdwarf-2
當中的 -mcell 選項為對 Cell CPU 做組譯,
而 -maltivec 為 VMX 的支援組譯選項。
假如上例的 C 程式的檔名為 test.c,
其編譯指令為:
ppu-gcc -o test test.c setzero.o -g
如此將二程式放在同個目錄下按順序在文字模式下輸入以上二個指令,
執行檔 test 就會出現在同個目錄下了。
真是不好意思,
Shady 忘記向大家說明如何在 C 語言程式中呼叫組語函式了,
以 Shady 之前釋放出的 setzero.s 為例:
#include < stdlib.h >
extern void setzero(void *, int);
int main() {
unsigned char *d;
int a = 4096;
if(posix_memalign((void *)&d, 128, a)) {
printf("failed\n");
goto end;
}
setzero(d, a);
end:
return 0;
}
以上就是使用 C 語言程式呼叫 setzero.s 的例子,
當中的 posix_memalign 函式為配置一對齊 128 Bytes 邊界的記憶體區塊,
其大小為 4K Bytes。
最後 Shady 說明一下如何組譯、編譯程式,
首先是對 setzero.s 做組譯之指令:
ppu-as -o setzero.o setzero.s -mcell -maltivec --gdwarf-2
當中的 -mcell 選項為對 Cell CPU 做組譯,
而 -maltivec 為 VMX 的支援組譯選項。
假如上例的 C 程式的檔名為 test.c,
其編譯指令為:
ppu-gcc -o test test.c setzero.o -g
如此將二程式放在同個目錄下按順序在文字模式下輸入以上二個指令,
執行檔 test 就會出現在同個目錄下了。
標籤:
Cell、PS3、Linux
訂閱:
文章 (Atom)