2017q3 Homework1(phonebook) === contributed by <`TsengWen`> > #### Review by `maskashura` >- Hash table採用26個字母為key value,是否有考量key value crush所造成的效能瓶頸? >- 試著用未排序過的資料做輸入,觀察是否有不同的效能差異 >- 試著解釋加入 hash table 對 append() 所造成的影響 ## 預期目標 - [x]準備 GNU/Linux 開發工具 - [x]學習使用 Git 與 GitHub - [x]學習效能分析工具 - [ ]研究軟體最佳化 - [ ]技術報告寫作練習 ## 開發環境 ### 安裝雙系統 - 作業系統:Ubuntu 16.04 LTS (64bit) - CPU:4-core 2.50 GHz - Memory:8G - Cache - L1d cache: 32K - L1i cache: 32K - L2 cache: 256K 使用 `lscpu` 可查詢硬體資訊 > 也可以使用Portable Hardware Locality (hwloc) 取得硬體資訊 [網址](https://www.open-mpi.org/projects/hwloc/) ``` $sudo apt-get install hwloc $lstopo ``` ![](http://imgur.com/mDrl11C.png) ### 修改terminal prompt ==vim .bachrc 中加入== ``` ## Set git prompt function git_branch { ref=$(git symbolic-ref HEAD 2> /dev/null) || return; echo "("${ref#refs/heads/}")"; } function git_since_last_commit { now=`date +%s`; last_commit=$(git log --pretty=format:%at -1 2> /dev/null) || return; seconds_since_last_commit=$((now-last_commit)); minutes_since_last_commit=$((seconds_since_last_commit/60)); hours_since_last_commit=$((minutes_since_last_commit/60)); minutes_since_last_commit=$((minutes_since_last_commit%60)); echo "${hours_since_last_commit}h${minutes_since_last_commit}m"; } PS1="${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u\[\033[00m\]@\[\033[01;36m\]\h\[\033[00m\]:[\[\033[1;32m\]\w\[\033[0m\]]\[\033[0m\]\[\033[1;36m\]\$(git_branch)\[\033[0;33m\]\$(git_since_last_commit)\[\033[0m\]$ " ``` ### vimrc 設定 >中英文字間需以空白隔開 >[name=課程助教][color=red] 參考 - [個人化自己的 vim 文字編輯器(.vimrc 設定教學) | MagicLen](https://magiclen.org/vimrc/) - [凍仁的筆記: Vim 環境設定 - vimrc](http://note.drx.tw/2008/01/vimrc-config.html) ``` " 自動縮排:啟用自動縮排以後,在貼上剪貼簿的資料時排版可能會亂掉,這時可以手動切換至貼上模式 :set paste 再進行貼上。 set ai " 文字編碼加入 utf8。 set enc=utf8 " 標記關鍵字。 set hls " 只在 Normal 以及 Visual 模式使用滑鼠,也就是取消 Insert 模式的滑鼠, set mouse=nv " 顯示行號。 " set number " 搜尋不分大小寫。 set ic " 自訂縮排 (Tab) 位元數。 set tabstop=2 set shiftwidth=2 " 字數過長時換行。 set wrap " 自動切換當前目錄。 set autochdir " 捲動時保留底下 3 行。 set scrolloff=3 " 摺疊 Folding。 set foldenable set foldmethod=indent set foldcolumn=1 set foldlevel=5 " 在 fish 裡相容 Vim 裡的 Neobundle。 set shell=/bin/bash " 複製模式 set paste ``` ### Git 操作 - 參考網站 [Learn Git Branching](http://learngitbranching.js.org/) [GitHub 設定指引](http://wiki.csie.ncku.edu.tw/github) [連猴子都能懂的Git入門指南 | 貝格樂(Backlog)](https://backlogtool.com/git-guide/tw/) - 建立好 Git 帳號後 ,ssh 設定 ``` $ssh-keygen $cat ~/.ssh/id_rsa.pub ``` - 將~/.ssh/id_rsa.pub 加入到 Github 網站 測試是否成功 ``` $ssh -T git@github.com 結果 Hi TsengWen! You've successfully authenticated, but GitHub does not provide shell access. ``` - [個人設定筆記](https://hackmd.io/s/rkXknFtb) ``` $ git config --global user.email "benson326789@gmail.com" $ git config --global user.name "TsengWen" git config --global alias.st status git config --global alias.cm "commit -m" git config --global alias.last 'log -1 HEAD' ``` ### Perf(效能分析工具) - 參考網址 [Wiki - Linux 效能分析工具: Perf](http://wiki.csie.ncku.edu.tw/embedded/perf-tutorial) 需要先將 perf 權限打開 ``` $ sudo sh -c " echo 0 > /proc/sys/kernel/perf_event_paranoid" ``` 照著步驟實作了一下,但途中使用到一些指令: - $ uname 顯示作業系統 - $ uname -r 顯示release time number 應該就是kernel版本 - $ perf top -p <pid> 偵測這個process 每個指令所耗費的CPU cycle - $ perf list 列出可以偵測的event - $ perf state --repeat <num> -e <event> <bin>.對這個執行檔,偵測所指定的event - $ ./phonebook_opt & sudo perf top -p $! 這可以省略寫sleep()再開令一個終端機輸入pid ==$./phonebook_orig & sudo perf top -p $!== ``` Samples: 27 of event 'cycles', Event count (approx.): 1019759 Overhead Shared Object Symbol 40.36% libc-2.23.so [.] __strcasecmp_l_avx 14.18% phonebook_orig [.] findName 9.12% [kernel] [k] release_pages 9.07% [kernel] [k] unmap_page_range 4.56% [kernel] [k] unlink_file_vma 4.55% [kernel] [k] free_pcppages_bulk 4.55% [kernel] [k] free_hot_cold_page_list 4.55% [kernel] [k] free_hot_cold_page 4.54% [kernel] [k] free_pages_and_swap_cache 4.53% [kernel] [k] _raw_spin_lock_irqsave ``` ### Valgrind(分析工具) - 參考網站 - [0140454學長共筆](https://hackmd.io/EwMwhgDBDGBsYFoDsBGWAOBAWdSCsCAnCIQEYLAoRgAmApvHiAMylA==?both) - [分析工具valgrind的使用](http://ottoshare.blogspot.tw/2012/03/valgrind.html) - [valgrind 的其他用途](http://rueiyuanlu.blogspot.tw/2011/09/valgrind.html) - Memory Leak的問題 ``` $valgrind --leak-check=full [./要測的檔案] ``` - 原本main.c ``` ==13294== LEAK SUMMARY: ==13294== definitely lost: 136 bytes in 1 blocks ==13294== indirectly lost: 16,034,808 bytes in 117,903 blocks ==13294== possibly lost: 31,551,320 bytes in 231,995 blocks ==13294== still reachable: 0 bytes in 0 blocks ==13294== suppressed: 0 bytes in 0 blocks ``` - 參考共筆修改 main.c內 ```clike if (pHead->pNext) free(pHead->pNext); free(pHead); ``` - 修改成 ```clike= while(pHead->pNext){ entry *next = pHead->pNext; pHead->pNext = next->pNext; free(next); } free(pHead); ``` >程式碼縮排為四個空白鍵,請修正 >[name=課程助教][color=red] >>OK[name=TsengWen][color=#29ccf4] - 再次測試 ``` ==13448== All heap blocks were freed -- no leaks are possible ``` ### Gnuplot(繪圖工具) - 參考網站 - [語法解說和示範](https://hackmd.io/s/Skwp-alOg) ## 效能分析 - 優化前 程式碼: [phonebook](https://github.com/sysprog21/phonebook) - make run ``` size of entry : 136 bytes execution time of append() : 0.068333 sec execution time of findName() : 0.004988 sec ``` - make cache-test ``` Performance counter stats for './phonebook_orig' (100 runs): 4,733,809 cache-misses # 93.978 % of all cache refs ( +- 0.08% ) 5,037,124 cache-references ( +- 0.14% ) 262,003,100 instructions # 1.45 insn per cycle ( +- 0.02% ) 180,647,686 cycles ( +- 0.17% ) 0.060747507 seconds time elapsed ( +- 2.18% ) ``` ## 效能分析 - 優化後 ### 方法一 - 由於筆電為L1-cache -32Kbit,原本entry結構136Byte, - 計算能放入cache數量 $$\frac{32\times1024}{136\times8}= {30.1}$$ - 將結構化簡,將搜尋用不到的另外弄成指標,希望能再cache放入多一點entry來減少cache miss。 - 計算能放入cache數量 $$\frac{32\times1024}{32\times8}= {128}$$ --- ```clike typedef struct __PHONE_BOOK_ENTRY { char lastName[MAX_LAST_NAME_SIZE]; struct __PHONE_BOOK_ENTRY *pNext; struct __PHONE_BOOK_DETAIL *detail; } entry; typedef struct __PHONE_BOOK_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; ``` - 修改結果 - cache-miss 下降至70% - 所花時間也略微下降 ``` size of entry : 32 bytes execution time of append() : 0.034991 sec execution time of findName() : 0.004266 sec ``` ``` Performance counter stats for './phonebook_opt' (100 runs): 1,595,412 cache-misses # 70.061 % of all cache refs ( +- 0.12% ) 2,277,159 cache-references ( +- 0.12% ) 244,541,000 instructions # 2.07 insn per cycle ( +- 0.02% ) 118,021,002 cycles ( +- 0.08% ) 0.038790988 seconds time elapsed ( +- 0.52% ) ``` ![](https://i.imgur.com/HMfWHLM.png) ### 方法二 - 加上hash 想法:依照26個字母,做26個Linked list,做搜尋時根據開頭做搜尋。 - 加上後,修改結果 ``` size of entry : 32 bytes execution time of append() : 0.032146 sec execution time of findName() : 0.000010 sec ``` ``` Performance counter stats for './phonebook_hash' (100 runs): 510,975 cache-misses # 74.046 % of all cache refs ( +- 0.21% ) 690,076 cache-references ( +- 1.02% ) 188,311,835 instructions # 1.83 insn per cycle ( +- 0.03% ) 102,881,580 cycles ( +- 0.35% ) 0.037837179 seconds time elapsed ( +- 7.15% ) ``` ![](https://i.imgur.com/KUUOd6S.png) ## astyle ``` $ astyle --style=kr --indent=spaces=4 --indent-switches --suffix=none *.[ch] ``` - style決定程式中,大括弧{ }的擺放方式。 - indent=space決定程式中,每個縮排為設定數值的倍數。 - indent-switches讓程式中 switch-case 的 case statements 對齊 - suffix=none不保留格式化前的文件