# 2016q3 Homework 1(phonebook) contributed by <`Weinux`> ### Reviewed by `believe7028` - git commit 時可以忽略執行檔(phonebook_hash) - 可以比較更多的雜湊函式。 - Hash 對資料表增加與刪除的操作會使得程式整體效能下降,也可以增加刪除的方法與效能評估。 - 如果未來資料一直增長,Hash 沒有機制應對而退化成Linked list。 - 如果資料一直增加,記憶體會放置不下。 - 可以加入刪除的功能以符合實際的需求。 ## 開發環境 * OS:Lubuntu 15.10 * Linux系統版本: 4.2.0-42-generic * CPU: Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz * MEM: 6GB * Cache: * L1d cache: 32K * L1i cache: 32K * L2 cache: 256K * L3 cache: 3072K 使用指令:`$ lstopo`可列出機器的 cache 架構。lstopo 由 `hwloc`套件提供 * [感謝Louie Lu同學的問題與Scott Tsai, Champ Yen學長](https://www.facebook.com/groups/system.software2016/permalink/1124571464289024/) ![](https://i.imgur.com/3mcDtmW.png) ## 開發目標 * 準備 GNU/Linux 開發工具 * 學習使用 Git 與 GitHub * 學習效能分析工具 * 研究軟體最佳化 ## 案例分析:Phonebook ### Makefile + Makefile 裡面幫我們整理要編譯哪些檔案,並且輸出成執行檔. 包含使用編譯器的最佳化等級警告訊息與遵循哪種c語言的規格.....等 + 其中的 -DIMPL="" 是 #define IMPL是什麼.以下的程式碼代表在編譯 phonebook_orig 這個執行檔過程中,IMPL 為"phonebook_orig.h" 這樣在main.c中就可以根據不同的-DIMPL 來#include 不同的.h file 而只需要一個main.c檔案即可。 + 要注意的是為了顯示出雙引號 " 前面必須加入跳脫符號\ ```c= phonebook_orig: $(SRCS_common) phonebook_orig.c phonebook_orig.h $(CC) $(CFLAGS_common) $(CFLAGS_orig) \ -DIMPL="\"$@.h\"" -o $@ \ $(SRCS_common) $@.c ``` ### main.c ```c= #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <assert.h> #include IMPL ``` ### **Cache Miss** ### 原始版本 + #### PHONE_BOOK_ENTRY struct ```c= #define MAX_LAST_NAME_SIZE 16 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; } entry; ``` ```text= size of entry : 136 bytes execution time of append() : 0.062888 sec execution time of findName() : 0.006345 sec ``` + 比較未優化前的append() 與 findName()所執行的時間, ![](https://i.imgur.com/nZhfC7j.png) ``` text= Performance counter stats for ./phonebook_orig (100 runs): 2,067,590 cache-misses # 91.407 % of all cache refs 2,263,739 cache-references 263,109,049 instructions # 1.26 insns per cycle 205,633,764 cycles 0.077700382 seconds time elapsed ( +- 1.27% ) ``` + 使用pref 觀察 `./phonebook_orig & sudo perf top -p $!` * 可以分析出消耗 CPU 週期最多的部份,結果顯示函式 **findName()** 佔了近 20.31%, ```text = 30.50% libc-2.21.so [.] __strcasecmp_l_avx 20.31% phonebook_orig [.] findName 12.21% phonebook_orig [.] main 3.49% libc-2.21.so [.] __strcpy_sse2_unaligned 3.08% libc-2.21.so [.] _IO_getline_info ``` + 由於搜尋時僅會尋找 lastName ```c=69 assert(findName(input, e) && "Did you implement findName() in " IMPL "?"); assert(0 == strcmp(findName(input, e)->lastName, "zyxel")); ``` ### 縮小Struct size + level 1 cache 有 32 kbit,struct 的大小有 136 bytes,32 * 1024 / (136*8) =30.12,若把整個struct entry都丟進 findName() 尋找,level 1 cache 最多也只能放 30 個entry,一共有 35 萬個單字,必定會發生頻繁的 cache miss。 + 將**entry**內其他資料封裝到另一個結構 **detail**, 並且用指標加入原來的entry 結構中 ```c= 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; typedef struct __PHONE_BOOK_ENTRY { char lastName[MAX_LAST_NAME_SIZE]; detail *pDetail; struct __PHONE_BOOK_ENTRY *pNext; } entry; ``` + 結構從136 byte 降為 32 byte, 而且**append()** 與 **findName()** 執行時間也有下降 ```text= size of entry : 32 bytes execution time of append() : 0.041963 sec execution time of findName() : 0.002994 sec ``` ![](https://i.imgur.com/NjtXbTM.png) ```text= Performance counter stats for './phonebook_opt' (100 runs): 369,581 cache-misses # 57.650 % of all cache refs 628,276 cache-references 245,601,976 instructions # 1.66 insns per cycle 154,732,401 cycles 0.057283161 seconds time elapsed ( +- 1.63% ) ``` ### Hash table ```c= unsigned int BKDRHash(char *str) { unsigned int seed = 131; unsigned int hash = 0; while (*str) { hash = hash * seed + (*str++); } return (hash & 0x7FFFFFFF); } ``` ```c= unsigned int hash(hash_table *hashtable , char *str) { unsigned int hash_value = 0; while(*str) hash_value = (hash_value << 5) - hash_value + (*str++); return (hash_value % SIZE); } ``` ![](https://i.imgur.com/2ZUHODp.png) ###### tags: `phonebook` `cache miss` `Weinux`