# 2016q3 Homework4 (software-pipelining)
contributed by <`fzzzz`>
## 什麼是 prefectching?
節錄自wikipedia
In computer architecture, instruction prefetch is a technique used in central processor units to speed up the execution of a program by reducing wait states.
## 論文閱讀
[論文 When Prefetching Works, When It Doesn’t, and Why](http://www.cc.gatech.edu/~hyesoon/lee_taco12.pdf)
>論文的部份只有稍微掃過一次,大部份還是看學長姐的筆記
### Key points
* source code-level analysis
* study of the synergistic(協同) and antagonistic(拮抗) effects between sw/hw
* evaluation of HW prefetching training policies
### Software / Hardware Prefetching 的背景知識
* Software : 通常會在程式碼間安插一些 extension 的 intrinsics ,來告訴 compiler 哪邊要做 prefetch 及 prefetch distance
* prefetch 要有實際效果,傳送要求時間點要夠早,要能和 memory latency 抵銷。
* Hardware : 利用 CPU 中的 GHB(Global History Buffer),通常需要做 training,要經過幾次的 cache misses 來偵測。
* Prefetch distance :
* ![](https://i.imgur.com/wVw6qIr.png)
* l : prefetch latency (memory)
* s : 迴圈當中的最短路徑
### 文章閱讀概要
現在內建有 software prefetching algorithms 的 compiler 有 icc(intel) / gcc,但是對於如何安插 prefetch instrinsics 的 guideline 相關文件不多,再來就是對於軟體及硬體 prefetching 的分界是不清楚的。(沒有夠嚴謹的標準存在),所以這篇論文表示他想要提供一個 prefetch distance 標準。
![](https://i.imgur.com/xq57kqO.png)
* 左Y軸為正規化後執行時間(除以未做 prefetch 的執行時間)
* 右Y軸為加速倍率
* 從這張圖的結果來看,最好的結果是 SW+STR (stream prefetcher) or SW+GHB (stride prefetcher)
結論為
* software prefetching 在 short array streams , irregular memory address patterns 和 L1 cache reduction 上有較為顯著的正面影響。
#### Synergistic effects using software + hardware prefetching
* 可以同時處理多個 data streams 。
* software prefetching能夠解決不規則的 stream ,而 hardware 則去做規律的部份。
* Positive training
* 如果一個 software prefetch 太慢的話,可以藉由 hardware prefetch來增加 prefetch 的即時性。
#### Antagonistic Effects when Using Software and Hardware Prefetching
* Negative training
* 沒有完整地對所有 stream 做 sw prefetch的話,會使 hardware prefecting 的訓練結果不正確或過度訓練造成工作量過大。
* Harmful software prefecting
* 通常 hardware prefecthing 的精度會低於 software ,而當 prefecting request 出現的時間點不對或是過早的話,會造成再記憶體及快取頻寬上的負擔,甚至是降低 hardware prefetching 的效率。
## 作業實驗結果 ( native / sse / sse-prefetch )
### 更改 Makefile 並重新執行
```
native_transpose:
$(GIT_HOOKS) main.c
$(CC) $(CFLAGS_common) -DIMPL="\"$@.h\"" -o $@ main.c
echo $@
sse_transpose:
$(GIT_HOOKS) main.c
$(CC) $(CFLAGS_common) $(CFLAGS_sse) -DIMPL="\"$@.h\"" -o $@ main.c
sse_prefetch_transpose:
$(GIT_HOOKS) main.c
$(CC) $(CFLAGS_common) $(CFLAGS_sse) -DIMPL="\"$@.h\"" -o $@ main.c
```
native transpose
```
fzzzz@fzzzz-Aspire-V3-571G:~/Workspace/prefetcher$ ./native_transpose
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
0 4 8 12
1 5 9 13
2 6 10 14
3 7 11 15
native_transpose.h: 237301 us
```
sse transpose
```
fzzzz@fzzzz-Aspire-V3-571G:~/Workspace/prefetcher$ ./sse_transpose
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
0 4 8 12
1 5 9 13
2 6 10 14
3 7 11 15
sse_transpose.h: 123182 us
```
sse transpose using software prefetching
```
fzzzz@fzzzz-Aspire-V3-571G:~/Workspace/prefetcher$ ./sse_prefetch_transpose
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
0 4 8 12
1 5 9 13
2 6 10 14
3 7 11 15
sse_prefetch_transpose.h: 60141 us
```
### 修改成 AVX 版本
這邊筆記一下會用到的 function
* `__m256i _mm256_unpacklo_epi32 (__m256i a, __m256i b)`
* 將 src1 與 src2 的低/高位元以交錯的方式做排列,尾端的 32 就是每次交錯排列的位元數
* `__m256i _mm256_permute2f128_si256 (__m256i a, __m256i b, int imm8)`
* 將 src1 與 src2 各取一半進行排列,
* 方法如下
```
SELECT4(src1, src2, control){
CASE(control[1:0])
0: tmp[127:0] := src1[127:0]
1: tmp[127:0] := src1[255:128]
2: tmp[127:0] := src2[127:0]
3: tmp[127:0] := src2[255:128]
ESAC
IF control[3]
tmp[127:0] := 0
FI
RETURN tmp[127:0]
}
dst[127:0] := SELECT4(a[255:0], b[255:0], imm8[3:0])
dst[255:128] := SELECT4(a[255:0], b[255:0], imm8[7:4])
dst[MAX:256] := 0
```
修改過後的程式碼 [( code )](https://github.com/FZzzz/prefetcher/blob/master/avx_transpose.h)
#### 在桌機上跑(筆電沒有支援到 AVX2)
```
./native_transpose
native_transpose.h: 308829 us
./sse_transpose
sse_transpose.h: 157873 us
./sse_prefetch_transpose
sse_prefetch_transpose.h: 80256 us
./avx_transpose
avx_transpose.h: 85646 us
./avx_prefetch_transpose
avx_prefetch_transpose.h: 84487 us
```
其實在看完論文和學長姐的筆記後,我還是不太知道怎麼取 prefetch distance。即便是按照內文提到的演算法來算的話,也仍然會因為各處理器 IPC 不同,而有不同的 prefetch distance。所以總結了一下想法,我還是全都跑一次看哪個 prefetch distance 會帶來最好的效果。
下圖為 avx_prefetch 在各個 prefetch distance 下的執行時間。
![](https://i.imgur.com/96kjz1B.png)
可以看到在 prefetch distance = 8 的時候最快
#### 各版本的 cache misses
native_transpose
```
Performance counter stats for './native_transpose' (5 runs):
16,543,459 cache-misses # 91.690 % of all cache refs ( +- 0.05% )
18,042,742 cache-references ( +- 0.03% )
1,448,816,603 instructions # 0.86 insns per cycle ( +- 0.00% )
1,690,823,261 cycles ( +- 0.48% )
0.453539595 seconds time elapsed ( +- 1.14% )
```
sse_transpose
```
Performance counter stats for './sse_transpose' (5 runs):
4,271,798 cache-misses # 78.221 % of all cache refs ( +- 0.18% )
5,461,196 cache-references ( +- 0.09% )
1,236,784,781 instructions # 1.17 insns per cycle ( +- 0.00% )
1,061,389,121 cycles ( +- 1.19% )
0.303614305 seconds time elapsed ( +- 7.57% )
```
sse_prefetch_transpose
```
Performance counter stats for './sse_prefetch_transpose' (5 runs):
4,272,500 cache-misses # 78.128 % of all cache refs ( +- 0.21% )
5,468,597 cache-references ( +- 0.02% )
1,282,833,253 instructions # 1.60 insns per cycle ( +- 0.00% )
803,852,552 cycles ( +- 0.37% )
0.213622428 seconds time elapsed ( +- 0.50% )
```
avx_transpose
```
Performance counter stats for './avx_transpose' (5 runs):
3,243,450 cache-misses # 73.077 % of all cache refs ( +- 0.03% )
4,438,375 cache-references ( +- 0.09% )
1,149,164,499 instructions # 1.42 insns per cycle ( +- 0.00% )
810,729,581 cycles ( +- 0.30% )
0.219928612 seconds time elapsed ( +- 2.58% )
```
avx_prefetch_tanspose ( PFDIST = 8 )
```
Performance counter stats for './avx_prefetch_transpose' (5 runs):
3,269,625 cache-misses # 50.112 % of all cache refs ( +- 0.02% )
6,524,581 cache-references ( +- 0.04% )
1,172,166,712 instructions # 1.42 insns per cycle ( +- 0.00% )
825,967,980 cycles ( +- 0.31% )
0.218844538 seconds time elapsed ( +- 0.29% )
```
從 cache misses 的比例上來看 可以看見 avx 在做了 prefetch 之後,有很大幅度的改善。但在執行時間上仍然是和 avx_transpose 與 sse_prefetch_transpose 沒有相差太多。(甚至是更慢的),另外 avx 的兩個版本的 IPC 均比 sse_prefetch 來的低。 我個人猜測這很可能是為什麼 avx 效能上不及 sse_prefetch 的原因 ( 整整少了10% 的 IPC )。
## Reference
* [Instruction Prefetching](https://en.wikipedia.org/wiki/Instruction_prefetch)
* [作業網站](https://hackmd.io/s/ry7eqDEC)
* [Carol Chen的筆記](https://hackmd.io/s/rk8ivCT0)
* [許元杰的筆記](https://embedded2015.hackpad.com/-Homework-7-8-XZe3c94XjUh)
* [周曠的宇的共筆](https://embedded2015.hackpad.com/Week8--VGN4PI1cUxh)
###### tags: `fzzzz` `sysprog`