# 2018q3 Homework3 (dict)
Contributed by <`aben20807`>
###### tags: `sysprog2018`
<style>
.red {
color: red;
}
</style>
## 環境
```
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
Thread(s) per core: 2
Core(s) per socket: 2
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 142
Model name: Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz
Stepping: 9
CPU MHz: 702.352
CPU max MHz: 3500.0000
CPU min MHz: 400.0000
BogoMIPS: 5808.00
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 4096K
NUMA node0 CPU(s): 0-3
```
## 計時
+ `tvgetf()`:獲取當前時間的秒數
+ 定義在 bench.c 中 [[link]](https://github.com/sysprog21/dict/blob/c6700cd5260e8c81eb8e4bcd30dc8cb1482402ed/bench.c#L10)
+ 利用 [`clock_gettime()`](https://linux.die.net/man/3/clock_gettime)
+ 從標準時間點 (epoch) 1970-01-01 00\:00\:00
+ return 0 for success, or -1 for failure (in which case errno is set appropriately).
## perf
+ 權限全開 `$ sudo sh -c " echo -1 > /proc/sys/kernel/perf_event_paranoid"`
+ 測試
```c
static char array[10000][10000];
int main (void){
int i, j;
for (i = 0; i < 10000; i++)
for (j = 0; j < 10000; j++)
array[j][i]++;
return 0;
}
```
```bash
$ gcc cache_miss.c -o v1
$ perf stat --repeat 5 -e cache-misses,cache-references,instructions,cycles ./v1
Performance counter stats for './v1' (5 runs):
2088,5552 cache-misses # 5.292 % of all cache refs ( +- 8.71% )
3,9464,1930 cache-references ( +- 0.50% )
23,9823,4687 instructions # 1.27 insn per cycle ( +- 0.01% )
18,8919,7407 cycles ( +- 1.19% )
0.542310617 seconds time elapsed ( +- 1.15% )
```
```c
static char array[10000][10000];
int main (void){
int i, j;
for (i = 0; i < 10000; i++)
for (j = 0; j < 10000; j++)
array[i][j]++;
return 0;
}
```
```bash
$ gcc cache_miss.c -o v2
$ perf stat --repeat 5 -e cache-misses,cache-references,instructions,cycles ./v2
Performance counter stats for './v2' (5 runs):
224,2803 cache-misses # 89.966 % of all cache refs ( +- 0.21% )
249,2955 cache-references ( +- 1.13% )
23,9755,2326 instructions # 2.51 insn per cycle ( +- 0.01% )
9,5651,4574 cycles ( +- 0.31% )
0.274339463 seconds time elapsed ( +- 0.33% )
```
## Makefile
+ 清除 cache
+ linux 2.6.16 後提供 [[Ref]](https://linux-mm.org/Drop_Caches)
```bash
$ echo 3 | sudo tee /proc/sys/vm/drop_caches;
```
+ tee 指令 [[man]](http://man7.org/linux/man-pages/man1/tee.1.html)
+ 顯示並另存一份文檔
+ 例如上方指令就是在螢幕印出 `3`,且將 `3` 寫入 /proc/sys/vm/drop_caches 中
+ 指定搜尋字串
```bash
$ make test TEST_DATA='s Tain'
```
+ `$ make plot`
```
bench_cpy.txt: test_cpy
./test_cpy --bench
bench_ref.txt: test_ref
./test_ref --bench
plot: bench_cpy.txt bench_ref.txt
gnuplot scripts/runtimept.gp
eog runtime2.png &
```
## gnuplot
### cpy.txt
```bash
$ make
$ ./test_cpy
```
+ 會把製作 ternary_tree 載入時間計算出來存在 cpy.txt
```bash
$ make test # 執行 100 次 ./test_cpy --bench $(TEST_DATA)
```
+ 因為寫入 cpy.txt 時是用 append 所以會記錄 100 次時間
### bench_cpy.txt
+ 安裝 `$ sudo apt-get install gnuplot`
+ 發現專案中 scripts 中有 gnuplot 的 .gp 檔
+ 其中 scripts/runtime3.gp 有提到 bench_cpy.txt
+ 發現 test_cpy.c 中有寫到若有 `--bench` 的 argv[1] 就會輸出 bench_cpy.txt
```bash
$ make
$ ./test_cpy --bench
$ gnuplot scripts/runtime3.gp
$ eog runtime3.png &
```
![](https://i.imgur.com/Caio1qD.png =300x)
+ 發現全部壓在 0 附近
+ 利用 `$ vim -u NONE bench_cpy.txt` 觀察,y 軸最大設 1000 過大
+ 把 y 軸的最大值 1000去掉 `[:1000]` -> `[:]`
+ ![](https://i.imgur.com/rmdnNcZ.png =300x)
### ref.txt
+ 比較 test_ref.c、test_cpy.c 發現 test_ref.c 缺少一部份程式碼
```c
FILE *output;
output = fopen("ref.txt", "a");
if (output != NULL) {
fprintf(output, "%.6f\n", t2 - t1);
fclose(output);
} else
printf("open file error\n");
```
```bash
$ make test # 產生 100 次建置時間
```
### bench_ref.txt
+ 一樣在 test_ref.c 補上缺少區塊
```c
if (argc == 2 && strcmp(argv[1], "--bench") == 0) {
int stat = bench_test(root, BENCH_TEST_FILE, LMAX);
tst_free_all(root);
return stat;
}
```
```bash
$ make
$ ./test_ref --bench # 產生 bench_ref.txt
```
### scripts/runtimept.gp
+ 有了 bench_cpy.txt、bench_ref.txt 就可以畫 scripts/runtimept.gp 了
+ 一樣修改 y 軸最大值
```bash
$ gnuplot scripts/runtimept.gp
$ eog runtime2.png &
```
+ ![](https://i.imgur.com/rNMHpHe.png =300x)
+ 發現數值相當奇怪
+ 參考[`siahuat0727`](https://hackmd.io/s/HJElcrA9Q#benchc-%E4%B8%AD-bug-%E4%BF%AE%E5%BE%A9)解決 bench.c 中 `char prefix[4] = "";`
+ 解決後利用一樣指令即可畫出
+ ![](https://i.imgur.com/JPghOwS.png =300x)
+ 修改單位問題 (是 **µs** 不是 s)
+ ![](https://i.imgur.com/ieh5Pq6.png =400x)
+ 發現執行 test_ref `$ ./test_ref --bench` 會有 Address boundary error
```bash
$ gdb -q test_ref
Reading symbols from test_ref...done.
(gdb) r --bench
Starting program: /home/ben/pro/col7/dict/test_ref --bench
ternary_tree, loaded 259112 words in 0.126777 sec
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff76ddc01 in __GI___libc_free (mem=0x7fffd8986eea) at malloc.c:3123
3123 malloc.c: No such file or directory.
(gdb) f 1
#1 0x00005555555569df in tst_free_all (p=0x555555ba7470) at tst.c:413
413 free(p->eqkid);
```