# 2019q3 Homework5 (dict)
contributed by < `YenHengLin` >
## 預備知識
### bloom filter 的 hash function (djb2)
djb2 function 其形式跟 [LCG(線性同餘方法)](https://zh.wikipedia.org/wiki/%E7%B7%9A%E6%80%A7%E5%90%8C%E9%A4%98%E6%96%B9%E6%B3%95)相同都為 $N_{j+1} \equiv ( N_j*A + B ) mod\ M$ , 將 `hash = ((hash << 5) + hash) + c` 轉換一下就能得到 $hash = hash * 33 + c$ ,帶入上一個函式 A 為 33, B 為 character ,至於 M 由於是在 2 進位系統, unsigned int 只能儲存到 32位的數字, 所以 M 就為 $2^{32}$ 。
LCG 的最大週期為 M 但是大部分情況都會小於 M,為了要達到最大週期,A B M 就必須要特殊選取過
* B,M 互質
* M 的所有質因數都能整除 A-1
* 若 M 是 4 的倍數, A-1 也是
* A,B 是正整數
回到 djb2 現在我們可以知道 5381 和 33 這兩個數字是怎麼選出來的
* 5381 為質數符合 B,M互質,所以將 5381 換成其他質數也能有一樣的效果
* $33-1=32$ ,而 $2^{32}$ 的質因數為 2,符合 M 的所有質因數都能整除 A-1,另外 M 是 4 的倍數,A-1也是。
djb2 透過合理的選擇數字使得 $0\sim2^{32}-1$,都有 1 對 1 對應的數字使得碰撞率不會過高,另外 *33 改成用 left shift 操作,來增加運算的速度
### LCG 特性證明
* B,M 互質
LCG 的週期 T 等於 M 的時候,B 跟 M 互質,所以利用若 P 則 Q ,非 Q 則非 P 來證明。
一開始假設 B 跟 M 不互質,則 B 跟 M 會有共同的因數 d,我們可以將 B 跟 M 寫成 $B= b*d$ ,$M=m*d$ ,則 $N_{j+1} \equiv ( N_j*A + b*d ) mod\ m*d$ 可以改寫成 $N_{j+1} \equiv ( N_j*A + B ) mod\ M$
將 Nj 初始值帶 0 進去就會發現上式可改寫成 $N_{j+1} \equiv ( N_j*A + b*d ) mod\ m*d$
### bloom filter 的 hash function (jenkins)
* [雪崩性](https://zh.wikipedia.org/wiki/%E9%9B%AA%E5%B4%A9%E6%95%88%E5%BA%94):當輸入的資料發生最微小的變化,一個 bit 發生改變時,輸出的 bit 要有 50% 都發生變化
* jenkins 就符合雪崩性,當一個 bit 改變則輸出會有 16 個bit 都發生改變,符合 50% 都變化的原則(輸出為 unsigned int 有 32 bit)
## 對[隱藏在字典裡的數學](https://hackmd.io/@sysprog/BkE3uSvdN)依樣畫葫蘆
### 在 makefile 新增 perf-search
* code
```cmake
perf-search: $(TESTS)
@for test in $(TESTS);do \
echo 3 | sudo tee /proc/sys/vm/drop_caches; \
perf stat \
-e cache-misses,cache-references,instructions,cycles \
./$$test --bench; \
done
```
執行 `$make perf-search` 顯示 `You may not have permission to collect stats.`,去查 perf_event_paranoid 發現值為 3,屬於不允任何量測也不允許任何 cpu events data 的權限,透過指令 ` $sudo sh -c " echo -1 > /proc/sys/kernel/perf_event_paranoid"` 將權限修該成 -1,也就是權限全開的狀態
* 從新執行 `$make perf-search`,得到了
```
3
ternary_tree, loaded 259112 words in 0.211776 sec
Performance counter stats for './test_cpy --bench':
383,077,458 cache-misses # 55.469 % of all cache refs
690,617,085 cache-references
49,869,063,023 instructions # 0.56 insn per cycle
89,164,787,279 cycles
26.868986327 seconds time elapsed
26.628128000 seconds user
0.111832000 seconds sys
3
ternary_tree, loaded 259112 words in 0.188451 sec
Performance counter stats for './test_ref --bench':
447,661,956 cache-misses # 56.466 % of all cache refs
792,799,520 cache-references
49,846,958,921 instructions # 0.47 insn per cycle
105,727,595,852 cycles
31.934900738 seconds time elapsed
31.548879000 seconds user
0.111847000 seconds sys
```
發現 ref 的 cache-misses 比 cpy 還要高,所以在一次用 perf 指令 `$perf record -e cache-misses ./test_ref --bench && perf report`,檢查哪個 instruction 導致 miss 率最高
```
98.32% test_ref test_ref [.] tst_suggest ◆
0.22% test_ref test_ref [.] tst_search_prefix ▒
0.12% test_ref test_ref [.] tst_ins_del ▒
0.11% test_ref test_ref [.] tst_free
```
發現 **tst_suggest** 是我們要找的 bottle neck 修改 tst.c 的 suggest 函式
```c
void tst_suggest(...)
{
...
...
else //if (*(((char *) p->eqkid) + nchr - 1) == c && *n < max)
a[(*n)++] = (char *) p->eqkid;
tst_suggest(p->hikid, c, nchr, a, n, max);
}
```
將 dereference 的部分註解掉,再次執行 `$make perf-search`
```
3
ternary_tree, loaded 259112 words in 0.225895 sec
Performance counter stats for './test_cpy --bench':
336,505,388 cache-misses # 52.624 % of all cache refs
639,455,417 cache-references
45,931,523,827 instructions # 0.59 insn per cycle
78,327,966,745 cycles
23.668885649 seconds time elapsed
23.472659000 seconds user
0.083859000 seconds sys
3
ternary_tree, loaded 259112 words in 0.289854 sec
Performance counter stats for './test_ref --bench':
327,947,273 cache-misses # 51.669 % of all cache refs
634,713,384 cache-references
45,905,355,900 instructions # 0.59 insn per cycle
77,171,338,083 cycles
23.404041016 seconds time elapsed
23.171297000 seconds user
0.071873000 seconds sys
```
發現 cache-misses 數有明顯的下降,利用 gnuplot 可以清楚的看出執行效能 ref 比 cpy 還要好
## 參考資料
* [LCG(線性同餘方法)](https://zh.wikipedia.org/wiki/%E7%B7%9A%E6%80%A7%E5%90%8C%E9%A4%98%E6%96%B9%E6%B3%95)
* [雪崩性](https://zh.wikipedia.org/wiki/%E9%9B%AA%E5%B4%A9%E6%95%88%E5%BA%94)
* [隨機算法線性同餘法的理解](https://zhuanlan.zhihu.com/p/36301602)