2016q3 Homework (software-pipelining)
===
contributed by <`kaizsv`>
:::info
第四周作業要比較不同大小的矩陣的影響,我另外還比較了不同 prefetch distance 的影響。 [跳到書籤](/s/r1IWtb9R#不同distance對prefetch的影響)
:::
### sse_transpose
用`8X8`矩陣終於懂了,它把大矩陣分成許多的`4X4`矩陣,如果是在對角線上,反轉後放回原位,若是其它的,反轉後放在其對角的位置。
相比於`navie_transpose`是一個一個放在對角的位置。
### sse_prefetch_transpose
這裡使用固定長度8的`prefetch distance`,每次執行時候會告訢CPU載入下一次運算用的資料,如果超出範圍CPU就不會載入([SSE 介紹 [Page 7]](https://www.csie.ntu.edu.tw/~r89004/hive/sse/page_7.html)),而`_MM_HINT_T1`告訴CPU要把載入的資料放在 L2 Cache。
因為每一次`for`迴圈的載入是 row base,而儲存到新的 dst 是 column base,因此用`prefetch`可以降底`cache miss`。
### perf raw counter
在一些系統架構下,有一些 counter 沒有在`perf list`裡面,參考這篇文章[perf Examples](http://www.brendangregg.com/perf.html),如果是 Intel CPU 的話可以看[Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 3B](http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3b-part-2-manual.html)的19章,要對應到自己的 CPU 型號查 mask number 及 event number。
基本用法如下
```
# perf stat -e cycles,instructions,r80a2,r2b1 gzip file1
Performance counter stats for 'gzip file1':
5,586,963,328 cycles # 0.000 GHz
8,608,237,932 instructions # 1.54 insns per cycle
9,448,159 raw 0x80a2
11,855,777,803 raw 0x2b1
1.588618969 seconds time elapsed
```
`r80a2`80是 mask number,a2 是 event number,可以查出`raw 0x80a2`是`RESOURCE_STALLS.OTHER`用來查看因為其它 resource issues 而被 stall 的 cycle數。`r2b1`同理是`UOPS_DISPATCHED.CORE`。
### avx_prefetch_transpose
在寫`avx_prefetch`版本時遇到一個問題,PFDIST 到底要多少,從[官網的資料](https://software.intel.com/node/524263)`_mm_prefetch()`會載入一個 cache line 的長度,我的 CPU cache line = 64B,
:::info
這裡的 cache-misses 及 seconds 有包含了兩個 clock_gettime() 及一個 printf(),我想說若只是比較的話沒有必要把多餘的程式碼刪掉。
:::
| | cache-misses | seconds |
|:-| ------------: | -------: |
|naive | 23,787,617 | 0.414481027 |
|sse| 11,093,003 | 0.294677882 |
|sse_prefetch (DIST 8)| 8,311,259 | 0.236825513 |
|avx| 8,671,298 | 0.244085014 |
|avx_prefetch (DIST 8)| 9,273,692 | 0.227254568 |
|avx_prefetch (DIST 16)| 8,783,887 | 0.232082226 |
sse+prefetch 確實讓 cache-misses 下降,但`avx`加上 prefetch 後 cache-misses 不降反升,雖然執行時間有稍微下降,我在想會不會跟兩件事有關。
* 前面提到的 prefetch cache line 的問題。
* static distance and optimal distance
在[When Prefetching Works, When It Doesn’t, and Why](http://www.cc.gatech.edu/~hyesoon/lee_taco12.pdf) 5.1.4提到,若程式移植到不同的機器上,最佳的 distance 是會變動的
:::info
應該要像 Fig. 7 那樣畫出不同 distance 的影響,但我時間拿捏不好
:::
矩陣更大或更小有無影響,cache-misses
## 不同Distance對prefetch的影響
下圖是 distance 從 0~16 跑 10 次的平均時間 (us),從圖的趨勢可以觀察到 distance 為`0, 8, 16`是比較有代表性的,因此抓出這三個 distance 的 perf stat 在下表。block size 固定為 4096。
![](https://i.imgur.com/UhhRDUo.png)
| |sse_prefetch |avx_prefetch |
|-:|------------: |------------: |
|cache-misses (DST = 0)|11,109,048|8,928,395|
|L1-dcache-load-misses (DST = 0)|8,519,002|8,182,973|
|L1-icache-load-misses (DST = 0)|50,920|48,207|
|||
|cache-misses (DST = 8)|8,294,171|9,254,506|
|L1-dcache-load-misses (DST = 8)|8,518,941|8,176,969|
|L1-icache-load-misses (DST = 8)|46,718|50,224|
|||
|cache-misses (DST = 16)|8,837,080|8,634,863|
|L1-dcache-load-misses (DST = 16)|8,518,229|8,169,116|
|L1-icache-load-misses (DST = 16)|46,210|48,421|
> 用perf stat計算cache-misses還包含了`fopen`, `fprintf`等呼叫
因為我的hint是`_MM_HINT_T1`很明顯 L1 cache misses 變動不大。參考[吳彥寬](https://hackmd.io/EYMwbAhgDArAnAFgLQmGATEhB2AppiCAZhCQBMBGXGBGXCkCMEIA#最初實驗數據)同學筆記,`register L1 L2`的成本不一樣,因此又用`_MM_HINT_T0`做了同樣的實驗。
![](https://i.imgur.com/gKvNXpf.png)
| |sse_prefetch |avx_prefetch |
|-:|------------: |------------: |
|cache-misses (DST = 0)|11,111,058|8,930,902|
|L1-dcache-load-misses (DST = 0)|8,519,557|8,188,156|
|L1-icache-load-misses (DST = 0)|47,861|44,154|
|||
|cache-misses (DST = 8)|8,010,660|8,967,156|
|L1-dcache-load-misses (DST = 8)|8,816,422|9,012,397|
|L1-icache-load-misses (DST = 8)|40,924|43,270|
|||
|cache-misses (DST = 16)|8,779,192|8,477,066|
|L1-dcache-load-misses (DST = 16)|12,701,238|10,329,813|
|L1-icache-load-misses (DST = 16)|43,528|45,176|
就 runtime 的圖來看,趨勢是差不多的,但在`DST = 8`的時候時間又減少了一點,再看 L1-cache,`L1-icache-misses`有減少,`L1-dcache-misses`增加,而 cache-misses 在`DIST = 8`時略微下降
## 不同block size的影響
![](https://i.imgur.com/1CX5ZRV.png)
`y`軸是對數座標,prefetch distance 固定為 8,跑 10 次的平均值,就時間上來看,`1024 2048 4096 8192`的 runtime 正好差 4 倍,cache-misses 大約比 4 倍多一點。
|cache-misses|naive|sse|sse_prefetch|avx|avx_prefetch|
|-|-:|-:|-:|-:|-:|
|1024|1,091,966|602,467|500,244|514,517|528,372|
|2048|5,899,170|2,705,538|2,087,994|2,119,224|2,282,681|
|4096|23,868,323|11,098,391|8,260,486|8,633,959|9,254,081|
|8192|95,162,778|45,083,319|36,873,007|35,296,137|39,163,892|
|16384|523,578,908|148,994,080|156,092,042|145,099,308|150,593,769|
## 我的想法
* software prefetch distance對於 cache-misses 有明顯的影響,`sse`一次處理 4x4 個 int,DST = 8 表示會載入下一次迴圈的資料,同理`avx`一次處理 8x8 的矩陣,DST = 16 時的 cache-misses 較低,但 cache-misses (L1 cache-misses)及 runtime 就沒有明顯的關係。
* 就不同 block-size 的實驗而言,runtime 正好都差4倍,而 block-size 愈大 cache-misses 也差不多是差 4 倍,其中`naive`異外得多,`sse`大楖差 3點多倍,
## OpenMp
[stackoverflow 討論 OpenMp task](http://stackoverflow.com/questions/13788638/difference-between-section-and-task-openmp)
###### tags: `assigment_8` `software-pipelining`