contributed by<SwimGlass
>, <carolc0708
>
Data reference patterns can be classified as follows:
1.請在中英關鍵字間加上空白區隔
2.記得更新github連結喔!
課程助教
CPU: Intel’s Core 2 and Nehalem
使用 icc compiler (也有對gcc compiler做實驗)
GHB(stride prefetcher)/STR(stream prefetcher): compiler + HW prefetcher
SW: compiler + 程式中插入內聯函數
SPEC CPU 2006 benchmark(x軸)
執行時間標準化(y軸): 使用baseline binaries(只有compiler插入的SW prefetcher)的執行時間
Speed up(Positive/Neutural/Negative): SW+HW prefetcher中最好的
比 HW prefetcher最好的
快多少
這裡的標準化不知道是用哪種公式??
cache-line access: stream & stride
不同資料結構適合的SW prefetch 和 HW prefetch策略:
[小補充] 各種資料結構都適用: dead-block-based prefetching
在實驗中…
content-based prefetcher?
該好好研究一下不同的prefetching機制!!實驗結果評估那邊會講 Carol Chen
使用 SSE 的__mm_prefetch(char *ptr, int hint)
內聯函數翻譯成組合語言:
redundant_dc就是我們想驗證的部分!!
for example 的縮寫是 e.g.,不是 ex,後者是前男友、前主管的前綴詞
book-keeping machanism?
book-keeping 英文的意思就是記帳,在電腦科學的衍生意義為往復追蹤紀錄 jserv
Short Streams
Irregular Memory Access
Cache Locality Hint
Loop Bounds
想要知道上述SW prefetch(使用loop unrolling、SW pipelining、使用branch instrcution)如何實作
Increased Instruction Count
Static Insertion
Adaptivity is important because it is well-known that the pattern of memory addresses can exhibit phase behavior [Zhang et al. 2006].
what is that?
loop splitting是什麼?
就是字面上的意思,為了讓 prefetching 發揮作用,要適度切割迴圈內的指令 jserv
想辦法重現這個實驗 jserv
prefetch 候選對象: L1 cache misses / 1000 個指令 (MPKI) > 0.05
prefetch distance:
其中 k 為常數
L 為平均的 memory latency
IPCbench 是每個 benchmark 的 profiled average IPC
Wloop 是迴圈平均每一輪的指令數
instruction overhead: 指令大量增加
SW prefetching overhead: 分別去除一些 SW prefetch 造成的負面影響,來觀察效能提升的情況
實驗中,分別除去 cache pollution overhead (SW+P)、bandwidth consumption (SW+B,在 CPU 核心和記憶體之間)、memory access latency (SW+L)、redundant prefetch overhead (SW+R)、instruction overhead (SW+I) 來觀察效能提升的狀況
造成 cache pollution 可能的原因為 early prefetch 或 incorrect prefetch,但兩者在實驗中很少發生,因此除去 cache pollution (圖中的 SW+P) 對 cycle 次數是否減少影響不大
去除 bandwidth consumption (圖中的 SW+B) 的影響也不大,代表在實驗中的單執行緒應用之下, bandwidth 都還算夠用
去除 memory access latency (圖中的 SW+L)對效能影響極大,代表在此實驗之下,prefetch 並沒有達到完全隱藏 memory latency
即便在實驗中存在著大量的 redundant prefetch,去除 redundant prefetch overhead (圖中的 SW+R) 影響幾乎小到可以忽略
雖說 GemsFDTD、bwaves、leslie3d 存在大量的 instruction overhead,去除之後 (圖中的 SW+I)的影響也不大
prefetch distance 的影響: 觀察各個 benchmark 對於 prefetch distance 的敏感度
不太清楚這邊的五組是怎麼切的?
好像就是 narrow / wide Optimal Zone & low / high Perf. Delta 下去排列組合在將 benchmark 的表現大致歸類Carol Chen
perf Delta 代表最佳效能和非最佳的差?
固定 prefetch distance vs. 機器組態: 測試最佳 prefetch distance 對於機器設定的敏感度
Cache-Level Insertion 策略
HW Prefetcher 訓練效果
實驗中對下列兩種訓練方式來評估:
下圖為各個 benchmark 的 HW prefetcher 經過 SW prefetch 要求 訓練的結果:
訓練後效能正成長可以達 3-5%,這些都來自於提前對 HW prefetcher 做訓練,減少 late prefetching
訓練後效能退化的退化幅度相當大: libquantum 為 -55.9%,milc 為 -22.5% 。
結論: 雖然訓練後有些 benchmark 效能能有正向成長,但是會造成效能退化的幅度遠大於正向成長的。因此在一般的情況來說,用 SW prefetching 來訓練 HW prefetcher 並不是一個很好的選擇
Prefetch Coverage (ratio)
Coverage: Percentage of misses avoided due to prefetching
100 x (Prefetch Hits / (Prefetch Hits + Cache Misses))
(a) GHB 和 STR 的有效 prefetch coverage (和所有的 L2 miss 相比)
(b) SW 、SW + GHB 、SW + STR 的 prefetch coverage。 HW prefetch 產生額外有效的 prefetch 以白色表示。
一般來說,SW prefetching 的 coverage 會比 HW prefetching 還高,但在效能表現中間或負向退步的組別中情況相反
==> 因此可以歸納出 coverage 太低是造成效能無法提升的主要原因
Prefetching Classification
對 prefetch 的分類:
根據上表對實驗結果做分類:
回顧之前實驗結果 SW+L 、 SW+R:
這邊的 prefetch cache 是指…? 它如何實作?
dependent load instrcution 發生的情況?
排除 icc compiler 的結果,因為 compiler 中沒有插入 prefetch 內聯函數
開啟 gcc 4.4 的 fprofile-generate
和 fprofile-use
flag,結果如下圖所示:
表現介在 base 和 SW 之間,但效能的正向提升並非都來自於 prefetch
==> 由圖 ( c ) ( d )可以看到 PGO 的全部指令以及 prefetch 的指令是有減少的
prologue/epilogue transformations 如何用來處理overhead?
(1) 即使在處理 regular access patterns,如 streams,HW prefetcher 時常有割雞焉用牛刀的情形。特別是在處理 short stream 的時候,此時使用 SW prefetch 會比較有效率
(2) SW prefetch distance 對於 HW 的組態不太敏感。但即使如此還是必須好好設定 prefetch distance。在一般的應用中,prefetch distance 只要大於定義公式算出的最小距離,效能上都不會差太多
(3) 雖然大部分的 L1 cache misses 會被 out-of-order 執行的處理器容忍,但在 L1 cache misses 太大時 (> 20 %),還是採取 prefetch 降低 L1 cache misses 對效能的提升比較有效率
(4) 大部分有 prefetch instruction 的應用也同時會遇到 memory operation 的限制,因次在 SW prefetching 中,instruction overhead 對效能的影響並不是很大。
(5) SW prefetching 可以用來訓練 HW prefetcher 因此能夠獲得效能上的提升。但是在有些情況中,也可能因此造成效能嚴重下降,必須小心使用。
參照原文第六部分
知道是microarchitecture是哪種,搜尋時才可以確定 HW prefetcher有哪些種類
what is page boundary?
L2 Streaming Prefetch(Adjacent Cache Line Prefetch):
DCU(L1-data cache) Prefetcher: also known as the streaming prefetcher, is triggered by an ascending access to very recently loaded data. The processor assumes that this access is part of a streaming algorithm and automatically fetches the next line.
DCU(L1-data cache) IP Prefetcher: Uses sequential load history (based on Instruction Pointer of previous loads) to determine whether to prefetch additional lines
through BIOS
changing the bits in the IA32_MISC_ENABLE register – MSR 0x1A4 of each core (older microarchitecture uses 0x1A0)
[ 小實驗 ] 使用msr-tools查看MSR 0x1A4的資訊
先載入msr模組
$ sudo modprobe msr
接著讀入msr 0x1A4資訊
$ sudo rdmsr -a 0x1A4
語法: rdmsr -option [register no.],這裡-a代表分別列出4個processor的資訊。結果如下:
0
0
0
0
==>4個processor的 4個HW prefetcher都是enable的狀態
prefetching 和 paging的關係?
NEON是一種基於SIMD的ARM技術,比較ARMv6或之前的架構,NEON结合了64-bit和128-bit的兩種SIMD指令集,提供128-bit的向量運算(vector operations)。NEON從ARMv7開始被使用,目前可以在ARM Cortex-A和Cortex-R系列處理器中使用。
NEON在Cortex-A7、Cortex-A12、Cortex-A15處理器中被設置為預設選項,但在其餘的ARMv7 Cortex-A系列中是可以選的。NEON與VFP共享了同樣的暫存器,但它具有自己獨立的執行管線。
NEON data type說明:
Unsigned integer:U8 U16 U32 U64
Signed integer:S8 S16 S32 S64
Integer of unspecified type:I8 I16 I32 I64
Floating-point number:F16 F32
Polynomial over {0,1}:P8
ps:F16不適合用來做數據處理,只適用於數據轉換
NEON暫存器有幾種類型:
16128-bit暫存器(Q0-Q15);
或3264-bit暫存器(D0-D31)
或上述暫存器的组合。
ps:每一个Q0-Q15暫存器對應到一對D暫存器。(如上圖)
暫存器之間的對應關係:
D<2n>
對應到 Q 的最低有效半部;
D<2n+1>
對應到 Q 的最高有效半部;
结合NEON支援的data type,NEON暫存器有像是下圖的幾種型態:
詳細情形可以參考這邊
參考:Using your C compiler to exploitNEON™ Advanced SIMD 實作 arm SIMD transpose
void neon_transpose(int *src, int *dst, int w, int h)
{
for (int x = 0; x < w; x += 4) {
for(int y = 0; y < h; y += 4) {
int32x4_t I0 = vld1q_s32((int32_t *)(src + (y + 0) * w + x));
int32x4_t I1 = vld1q_s32((int32_t *)(src + (y + 1) * w + x));
int32x4_t I2 = vld1q_s32((int32_t *)(src + (y + 2) * w + x));
int32x4_t I3 = vld1q_s32((int32_t *)(src + (y + 3) * w + x));
vzipq_s32(I0 , I1);//I0: T0, I1:T2
vzipq_s32(I2 , I3);//I2: T1, I3:T3
int32x4_t T0 = vcombine_s32(vget_low_s32(I0), vget_low_s32(I1));//vcombine_s32(low,high)
int32x4_t T1 = vcombine_s32(vget_high_s32(I0), vget_high_s32(I1));
int32x4_t T2 = vcombine_s32(vget_low_s32(I2), vget_low_s32(I3));
int32x4_t T3 = vcombine_s32(vget_high_s32(I2), vget_high_s32(I3));
vst1q_s32((int32_t *)(dst + ((x + 0) * h) + y) , T0);
vst1q_s32((int32_t *)(dst + ((x + 1) * h) + y) , T1);
vst1q_s32((int32_t *)(dst + ((x + 2) * h) + y) , T2);
vst1q_s32((int32_t *)(dst + ((x + 3) * h) + y) , T3);
}
}
}
要在Makefile中新增關於arm相關的參數
main_arm: $(GIT_HOOKS) main.c
arm-linux-gnueabihf-gcc -c -g -Wall -Wextra -Ofast -mfpu=neon -o main_arm.o main.c
arm-linux-gnueabihf-gcc -Wall -g -Wextra -Ofast -o main_arm main_arm.o
執行結果如下,我們的code是放在raspberry pi 3 model B+上面執行
上面有四顆ARM Cortex-A53指令集是ARMv8 (64/32-bit)
swimglass@swimglass-desktop:~/prefetcher$ ./main_arm
neon: 769104 us
參考資料 NEON prefetch 用法
void neon_prefetch_transpose(int *src, int *dst, int w, int h)
{
for (int x = 0; x < w; x += 4) {
for(int y = 0; y < h; y += 4) {
#define PFDIST 8
__builtin_prefetch(src+(y + PFDIST + 0) *w + x);
__builtin_prefetch(src+(y + PFDIST + 1) *w + x);
__builtin_prefetch(src+(y + PFDIST + 2) *w + x);
__builtin_prefetch(src+(y + PFDIST + 3) *w + x);
int32x4_t I0 = vld1q_s32((int32_t *)(src + (y + 0) * w + x));
int32x4_t I1 = vld1q_s32((int32_t *)(src + (y + 1) * w + x));
int32x4_t I2 = vld1q_s32((int32_t *)(src + (y + 2) * w + x));
int32x4_t I3 = vld1q_s32((int32_t *)(src + (y + 3) * w + x));
vzipq_s32(I0 , I1);//I0: T0, I1:T2
vzipq_s32(I2 , I3);//I2: T1, I3:T3
int32x4_t T0 = vcombine_s32(vget_low_s32(I0), vget_low_s32(I1));//vcombine_s32(low,high)
int32x4_t T1 = vcombine_s32(vget_high_s32(I0), vget_high_s32(I1));
int32x4_t T2 = vcombine_s32(vget_low_s32(I2), vget_low_s32(I3));
int32x4_t T3 = vcombine_s32(vget_high_s32(I2), vget_high_s32(I3));
vst1q_s32((int32_t *)(dst + ((x + 0) * h) + y) , T0);
vst1q_s32((int32_t *)(dst + ((x + 1) * h) + y) , T1);
vst1q_s32((int32_t *)(dst + ((x + 2) * h) + y) , T2);
vst1q_s32((int32_t *)(dst + ((x + 3) * h) + y) , T3);
}
}
}
執行結果:
swimglass@swimglass-desktop:~/prefetcher$ ./main_arm_pre
neon_pre: 458715 us
變快了 30000 us