# 2016q3 Homework1 (phonebook) contributed by <`aweimeow`> ###### tags: `sysprog21` `aweimeow` ### Reviewed by `HuangWenChen` * 這裡只有使用一個 hash function 作效能分析,可以嘗試使用不同 hash function 去做各個 hash function 效能比較 * 可以利用字串壓縮法將名子長度縮小 * github 尚未更新 ### 作業環境 * OS: Ubuntu 14.04.4 LTS * CPU: Intel(R) Core(TM) i5-4210M CPU @ 2.60GHz * Memory: 8G * Cache: * L1d cache: 32KB * L1i cache: 32KB * L2 cache: 256KB * L3 cache: 3072KB ### 安裝前置作業 這邊看到 [@louielu](https://hackmd.io/CYJgZgHA7AnADAFgLQGMCmaCGSEGYCsyMARjPkgIwhS4gT4VwogJA===#) 用了 `lstopo` 這個工具覺得很酷所以也想安裝一下,這邊紀錄一下安裝的流程: #### Install lstopo ```bash wget https://www.open-mpi.org/software/hwloc/v1.11/downloads/hwloc-1.11.4.tar.gz tar zxvf hwloc-1.11.4.tar.gz cd hwloc-1.11.4 cat README # 不過他的 README 沒有說明要怎麼安裝 Orz ./configure make sudo make install ``` BUT ... ! :::danger libhwloc.so.5: cannot open shared object file: No such file or directory ::: 後來找了一下發現 `libhwloc.so.5` 在 `/usr/local/lib` 裡面,所以我手動修改了 `/usr/local/lib`,再執行 `ldconfig` 輸出: ``` Machine (7879MB) Package L#0 + L3 L#0 (3072KB) L2 L#0 (256KB) + L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0 PU L#0 (P#0) PU L#1 (P#1) L2 L#1 (256KB) + L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1 PU L#2 (P#2) PU L#3 (P#3) HostBridge L#0 PCIBridge PCI 10de:1341 PCI 8086:0416 GPU L#0 "card0" GPU L#1 "renderD128" GPU L#2 "controlD64" PCIBridge PCI 10ec:8168 Net L#3 "eth0" PCIBridge PCI 168c:0036 Net L#4 "wlan0" PCI 8086:8c03 Block(Removable Media Device) L#5 "sr0" Block(Disk) L#6 "sda" ``` #### Install perf 根據 [wiki](http://wiki.csie.ncku.edu.tw/embedded/perf-tutorial) 上面的說明,我的操作如下,過程沒有碰到任何問題: ``` $ sudo apt-get install linux-tools-common $ sudo apt-get install linux-tools-4.2.0-27-generic linux-cloud-tools-4.2.0-27-generic ``` perf stat 存取局域性結果差異: ``` $ perf stat --repeat 5 -e cache-misses,cache-references,instructions,cycles ./test Performance counter stats for './test' (5 runs): 2,614,830 cache-misses # 2.525 % of all cache refs 100,415,393 cache-references 2,006,482,671 instructions # 0.81 insns per cycle 2,409,393,663 cycles 0.803709786 seconds time elapsed ( +- 14.38% ) ``` ``` $ perf stat --repeat 5 -e cache-misses,cache-references,instructions,cycles ./test Performance counter stats for './test' (5 runs): 217,059 cache-misses # 63.407 % of all cache refs 347,854 cache-references 2,005,971,913 instructions # 1.93 insns per cycle 1,032,907,799 cycles 0.334975609 seconds time elapsed ( +- 0.97% ) ``` #### Install gnu plot ``` $ apt-get install gnuplot ``` #### Install astyle ``` $ apt-get install astyle ``` ### 進入主題: phonebook 在我的電腦上,未修改的程式碼的 cache-miss 為 81.418% ``` Performance counter stats for './phonebook_orig' (100 runs): 1,154,821 cache-misses # 81.418 % of all cache refs 1,389,198 cache-references 263,656,721 instructions # 1.06 insns per cycle 240,380,961 cycles 0.081547701 seconds time elapsed ( +- 0.82% ) ``` 以下先試試使用改變資料結構來改善效能 #### 改變資料結構です 我們先從 `phonebook_opt.h` 來開始下手,讓我們先思考一個問題:在要查找電話簿時, key 應該是什麼?想當然是名字,在翻找電話簿時,找到名字後,跟隨在其後的地址、信箱、電話號碼 ... 才會需要被看到。 因此,來修改一下程式碼,將 `firstName`, `email`, `phone`, ... 這些資料先藏起來放到另一個資料結構中,我把它取名為 `detail`,搜尋到時可以存取這一筆 entry 裡面的細節(信箱、電話、...) ```c typedef struct __PHONE_BOOK_ENTRY_DETAIL { char firstName[16]; char email[16]; char phone[10]; char cell[10]; char addr1[16]; char addr2[16]; char city[16]; char state[2]; char zip[5]; } detail; typedef struct __PHONE_BOOK_ENTRY { char lastName[MAX_LAST_NAME_SIZE]; struct detail *detail; struct __PHONE_BOOK_ENTRY *pNext; } entry; ``` 這樣子改善之後,我們的 `cache-miss` 會下降多少呢? ``` Performance counter stats for './phonebook_opt' (100 runs): 158,618 cache-misses # 38.030 % of all cache refs 437,759 cache-references 245,272,988 instructions # 1.52 insns per cycle 163,283,836 cycles 0.053033708 seconds time elapsed ( +- 1.06% ) ``` 從輸出當中我們可以觀察到 `cache-miss` 從 ==81.418%== 下降到 ==38.030%== 下圖是這個階段執行完的 function 時間比較: ![compare for modify data structure](http://imgur.com/BwQlPmx.png) 可以從圖中發現,時間也有明顯的下降。 #### 使用 Hash Function Hash Function 選用 [djb2](http://stackoverflow.com/questions/7666509/hash-function-for-string) > 不過真的很久沒有碰過 C 語言了,改改 header file 還可以,要重拾三年前的 C 語言讓我碰到滿滿的挫折(或者說以前根本沒好好學 C) ##### 撰寫時碰到的問題們(以下會以我的理解盡力解釋問題,如果有誤請務必指正我感謝 QQ): * Pointer 的觀念 ~~略懂略懂~~ 完全不懂 QQ >> 無法用 C 語言開發出 C compiler & UNIX 等級的軟體,就是不懂 C 語言,沒有「略懂」這回事。 [name=jserv] ``` entry *people; strcpy(people->lastName, lastName); ``` 然後就 `Segment Fault` 了,後來查到[問題](http://stackoverflow.com/questions/6447744/segmentation-fault-around-strcpy)才發現原來我這樣子作是不對的。 在這邊都是指標,指標儲存的是一個記憶體位址,所以我直接把 `lastName` copy 到 `people->lastName` 就相當於:以 `lastName` 為 'AAAA' 來說,就是把 0x41414141 寫到 `people->lastName`,所以這個 pointer 就會指到這個奇怪的地址去,所以就錯了。 *