# 2016q3 Homework1 (phonebook) contributed by <`jeff6907`> >>請依照格式填寫標題和"contributed by"[name=課程助教] [作業說明](https://hackmd.io/s/S1RVdgza) ## 預期目標 * 準備 GNU/Linux 開發工具 * 學習使用 Git 與 GitHub * 學習效能分析工具 * 研究軟體最佳化 # 首先安裝開發環境 Lubuntu 16.04 * 先下載官方64bit安裝的ISO檔案 * 上網查如何建立一個開機USB [製作開機USB教學](http://pgl823.com/rufus/) * 進入BIOS選擇 UEFI USB開機 依序進行安裝動作 * 開發環境建置完成 ``` lscpu 查看CPU、快取內容 CPU:Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 8192K ``` * 下載開發編寫所需套件 之前使用Vim 所以額外安裝 ``` $ sudo apt-get update $ sudo apt-get install build-essential $ sudo apt-get install linux-tools-common linux-tools-generic $ sudo apt-get install astyle colordiff gnuplot $ sudo apt-get install vim ``` * [閱讀git基本教學](http://wiki.csie.ncku.edu.tw/github) * 完成ssh綁定並fork專案 [github](https://github.com/jeff60907/phonebook-1) * 閱讀perf、gnuplot工具教學,觀看課程解說 ## Phonebook 分析 ### 未優化前探討 ``` $ make run ``` ``` size of entry : 136 bytes execution time of append() : 0.049215 sec execution time of findName() : 0.004698 sec ``` ``` $ make cache-test ``` ``` Performance counter stats for './phonebook_orig' (100 runs): 191,9147 cache-misses # 94.189 % of all cache refs ( +- 0.64% ) 203,7547 cache-references ( +- 0.63% ) 2,6132,5661 instructions # 1.44 insns per cycle ( +- 0.02% ) 1,8125,5269 cycles ( +- 0.31% ) 0.083815399 seconds time elapsed ( +- 1.72% ) ``` catche-miss 高達94% 代表大部分時間都是浪費掉的 運作中如何發生miss?硬體操作應該是怎樣進行 以前計算機結構學過的一些知識幾乎都忘光了,要找時間好好惡補一下 [淺談memory cache](http://enginechang.logdown.com/posts/249025-discussion-on-memory-cache) ![](https://i.imgur.com/HVNHpaL.png) ### 優化版本測試1 結構體的有效資料是一個問題,在搜尋過程中大部分的資料幾乎沒用到,只針對last name搜尋,嘗試改寫結構測試。 註解沒打開 圖形一直跑出原本的樣子 卻又看不出來那邊有問題 差點崩潰 QQ ``` #define OPT 1 ``` 把用不到的資料成員自己存放在detail_entry,縮小搜尋的結構。 ```c= typedef struct __PHONE_BOOK_ENTRY { char lastName[MAX_LAST_NAME_SIZE]; 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]; struct __PHONE_BOOK_ENTRY *pNext; } detail_entry; ``` ```c= typedef struct _LASTNAME_ENTRY { char lastName[MAX_LAST_NAME_SIZE]; detail_entry *detail; struct _LASTNAME_ENTRY *pNext; } entry; ``` #### 原本錯誤的資料 <s> Performance counter stats for './phonebook_opt' (100 runs): 2,4047 cache-misses # 37.837 % of all cache refs ( +- 0.79% ) 6,3555 cache-references ( +- 0.58% ) 9177,8996 instructions # 1.68 insns per cycle ( +- 0.00% ) 5456,2927 cycles ( +- 0.24% ) 0.015713119 seconds time elapsed </s> <s>結構改完 原先94.189% 現在優化後37.837% cache-miss 大幅度降低 append()效能 從0.067 -> 0.014 將近 4倍 findName()效能 從 0.0058 ->0.000006 約960倍!!! </s> > phonebook_opt.c 只有把phonebook_orig.c 填過去 > 但是看了幾位同學優化結構體出來的效果, > findName下降幅度沒有這麼誇張,覺得有點納悶[name=陳致佑] > 再重新檢查後 發現code寫錯誤 *append() 內 一開始就回傳 NULL 所以 後續根本沒有進行動作。 > * 撰寫過程細節要注意 !!! ![](https://i.imgur.com/eEDCYMC.png) #### 修訂後正常版本的資料 ``` size of entry : 32 bytes execution time of append() : 0.058506 sec execution time of findName() : 0.003626 sec ``` 資料size從 136bytes 降為32bytes ``` Performance counter stats for './phonebook_opt' (100 runs): 33,0411 cache-misses # 76.053 % of all cache refs ( +- 0.25% ) 43,4447 cache-references ( +- 0.34% ) 2,0402,4276 instructions # 1.75 insns per cycle ( +- 0.02% ) 1,1676,7439 cycles ( +- 0.30% ) 0.036660150 seconds time elapsed ( +- 2.52% ) ``` 結構改完cache從94%降為76% append()效能 0.0675 -> 0.0329 findName() 0.059 -> 0.0022 效能進步程度約一半 ![](https://i.imgur.com/UMKonHp.png) ### 優化版本測試2 根據老師提示嘗試HASH的作法,先查資料複習hash概念跟作法 發現自己對於hash觀念非常薄弱,概念好像有聽過但卻很模糊 可能是過去沒有真正修過演算法,近日趕緊找線上課程補回來 * 透過關鍵字建立一個雜湊表,而不用完整一一比對目標資料,可以加速查詢的時間速度 * 依照不同得需求有許多演算法可以參考(應該要好好熟讀並嘗試實作看看T.T) 看了dada跟louielu的資料,都推薦使用`BKDR hash function`的演算法;查了一些資料發現還是有點不太懂,其他演算法也是蠻相近的,使用不同的乘數跟加法或者xor方法,這些 > BKDR演算法效能比較高是因為使用 131 這個質數? 先試著模仿網路的程式碼實作看看效能 ```c= unsigned int BKDRHash(char *str) { unsigned int hash = 0; while (*str) { hash = hash * 131 + (*str++); } return (hash & 0x7FFFFFFF); } ``` [參考dada的共筆資料](https://embedded2016.hackpad.com/ep/pad/static/YkqjhwgnQcA) [參考louielu的共筆資料](https://hackmd.io/CYJgZgHA7AnADAFgLQGMCmaCGSEGYCsyMARjPkgIwhS4gT4VwogJA===) [中文hash table wiki](https://zh.wikipedia.org/zh-tw/%E5%93%88%E5%B8%8C%E8%A1%A8) [hashc函式衝突率分析](http://blog.csdn.net/qq7366020/article/details/8730425) [建中培訓講義](http://pisces.ck.tp.edu.tw/~peng/index.php?action=showfile&file=f3443505c4cd3d8598eee689618327ef8af0f8af7) ``` size of entry : 32 bytes execution time of append() : 0.055206 sec execution time of findName() : 0.000040 sec ``` ``` Performance counter stats for './phonebook_hash' (100 runs): 32,1662 cache-misses # 50.916 % of all cache refs ( +- 0.10% ) 63,1753 cache-references ( +- 0.32% ) 2,2877,0781 instructions # 1.66 insns per cycle ( +- 0.02% ) 1,3750,3651 cycles ( +- 0.74% ) 0.058662636 seconds time elapsed ( +- 2.78% ) ``` cache-miss 降為 50.916% append() 上升幅度差異不大 0.0563 findName() 時間降到 0.000041 ![](https://i.imgur.com/GzPUvgd.png) 同樣的code 上面hashtable size 設定為1024 底下為4096 findName() 效能卻進步快一半,愈高愈好?還是有最佳化的範圍值? 待查詢驗證.... ``` size of entry : 32 bytes execution time of append() : 0.036046 sec execution time of findName() : 0.000017 sec ``` ``` Performance counter stats for './phonebook_hash' (100 runs): 32,5422 cache-misses # 43.617 % of all cache refs ( +- 0.44% ) 74,6086 cache-references ( +- 0.15% ) 2,2930,0036 instructions # 1.67 insns per cycle ( +- 0.02% ) 1,3771,3216 cycles ( +- 0.17% ) 0.058282629 seconds time elapsed ( +- 2.47% ) ``` ![](https://i.imgur.com/Txdne1Y.png) Hashtable size = 16384 ``` size of entry : 32 bytes execution time of append() : 0.036036 sec execution time of findName() : 0.000010 sec ``` ``` Performance counter stats for './phonebook_hash' (100 runs): 35,6412 cache-misses # 36.596 % of all cache refs ( +- 0.54% ) 97,3921 cache-references ( +- 0.11% ) 2,3148,5077 instructions # 1.60 insns per cycle ( +- 0.02% ) 1,4431,1873 cycles ( +- 0.16% ) 0.064716269 seconds time elapsed ( +- 2.40% ) ``` ![](https://i.imgur.com/Hrfl8bn.png) Hashtable size = 32768 ``` size of entry : 32 bytes execution time of append() : 0.053946 sec execution time of findName() : 0.000010 sec ``` ``` Performance counter stats for './phonebook_hash' (100 runs): 44,1435 cache-misses # 38.960 % of all cache refs ( +- 0.26% ) 113,3038 cache-references ( +- 0.13% ) 2,3406,4289 instructions # 1.51 insns per cycle ( +- 0.02% ) 1,5466,7970 cycles ( +- 0.22% ) 0.065952826 seconds time elapsed ( +- 2.30% ) ``` ![](https://i.imgur.com/NB4SbZQ.png) 發現 提高 table的SIZE可以提高執行速率,並降低 cache-miss 但是高於某一個值 cache-miss反而開始上升,並不是愈高愈好 真正原因 ---- 查 #### 設定 gnuplot ``` Makefile 先設定完成 了解make plot 執行什麼動作 plot: output.txt gnuplot scripts/runtime.gp $ cd scripts 編輯 runtime.gp ``` ``` reset set ylabel 'time(sec)' set style fill solid set title 'perfomance comparison' set term png enhanced font 'verdana,10' set output 'runtime.png' plot [:][:0.100]'output.txt'\ using 2:xtic(1) with histogram title 'original', \ '' using 3:xtic(1) with histogram title 'optimized', \ '' using 4:xtic(1) with histogram title 'BKDRHash', \ '' using ($0-0.2):($2+0.008):2 with labels title ' ', \ '' using ($0+0.1):($3+0.006):3 with labels title ' ', \ '' using ($0+0.4):($4+0.004):4 with labels title ' ', ``` 參數要自己調整範圍,讓數字不要重疊再一起 ## 挑戰題