# 2017q1 Homework1(phonebook) contributed by<`yanang`> ###### tags:`yananag` ## **Reviewed by `csielee`** * 最後 append() 時間上沒有下降,可以考慮實作 memory pool ,讓 malloc 呼叫次數減少,讓 append() 時間下降 ## 開發環境 * OS: Ubuntu 16.04 LTS * L1d cache: 32K * L1i cache: 32K * L2 cache: 256K * L3 cache: 3072K * Architecture: x86_64 * CPU 作業系統: 32-bit, 64-bit * Byte Order: Little Endian * CPU(s): 4 * Model name: Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz * Linux yanang 4.8.0-36-generic #36~16.04.1-Ubuntu SMP ## 未優化版本 * 執行: `$ ./phonebook_orig` ``` size of entry : 136 bytes execution time of append() : 0.105205 sec execution time of findName() : 0.004954 sec ``` * cache test `$sudo make cache-test` ```Performance counter stats for './phonebook_orig' (100 runs): 4,868,866 cache-misses # 93.482 % of all cache refs ( +- 0.20% ) 5,208,353 cache-references ( +- 0.38% ) 262,398,775 instructions # 1.35 insn per cycle ( +- 0.02% ) 194,347,267 cycles ( +- 0.77% ) 0.064319469 seconds time elapsed ``` ## version 1 - 減少資料結構 * 在 main.c append() findName() 當中可以發現目前只使用了 lastName 這項數據,也就是說其他項數據都是可以忽略的,但是考慮到不能喪失原本 phonebook 的功能,所以我們將其餘的數據到另一個 struct 。 ```c= typedef struct __PHONE_BOOK_ENTRY_REMAIN { 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_remain; typedef struct __PHONE_BOOK_ENTRY { char lastName[MAX_LAST_NAME_SIZE]; struct __PHONE_BOOK_ENTRY_REMAIN *remain; struct __PHONE_BOOK_ENTRY *pNext; } entry; ``` * 資料將以 linklist 方式 * 執行時間: ``` size of entry : 32 bytes execution time of append() : 0.137438 sec execution time of findName() : 0.002579 sec ``` * cache test * **cache miss 明顯降低** ```Performance counter stats for './phonebook_opt' (100 runs): 1,679,608 cache-misses # 68.692 % of all cache refs ( +- 0.48% ) 2,445,143 cache-references ( +- 0.81% ) 244,480,047 instructions # 1.84 insn per cycle ( +- 0.02% ) 132,706,657 cycles ( +- 1.11% ) 0.044007362 seconds time elapsed ``` * 圖表分析: ![](https://i.imgur.com/vFmi4uq.png) 雖然由此來看 append() 的時間是減少的,但是如果要使用到其餘的資料,則 append() 的時間應該會略高於原本的時間。 ## version 2 - hash function * 在閱讀許多資料後,我將 hash table 建於 main.c ,並利用 `#ifdef OPT_HASH` 達到目的。 * 因為在 [各種字符串Hash函数比較](https://www.byvoid.com/zhs/blog/string-hash-compare) 當中 BKDRHash 函數的綜合評分最高,所以就選用此種方式。 >可以參考閱讀 [BKDR hash 詳盡解說](http://blog.csdn.net/wanglx_/article/details/40400693) 並嘗試引入其他 hash function 實驗比較[name=課程助教][color=red] ```c= unsigned int BKDRHash(char *str) { unsigned int seed = 131; unsigned int hash = 0; while (*str) { hash = hash * seed + (*str++); } return (hash & 0x7FFFFFFF) % SIZE_OF_TABLE; } ``` * 原先想以後置的方式將資料 link 起來,但是若要找到 list 的尾端將需要多 loop ,為了增進效能就放棄改為前置。 ```c= entry *pHead = (entry *) malloc (sizeof(entry)); pHead->pNext = e[hash]; e[hash] = pHead; strcpy(pHead->lastName,lastName); /* entry *pLast = (entry *) malloc (sizeof(entry)); pLast -> pNext = NULL ; strcpy(pLast->lastName,lastName); e[hash] -> pNext = pLast; * not finished * should add loop to find the last data */ ``` * 執行時間: ``` size of entry : 24 bytes execution time of append() : 0.039091 sec execution time of findName() : 0.000009 sec ``` * cache test: ```Performance counter stats for './phonebook_opt_hash' (100 runs): 437,137 cache-misses # 58.419 % of all cache refs ( +- 1.13% ) 748,282 cache-references ( +- 2.45% ) 232,794,043 instructions # 1.82 insn per cycle ( +- 0.02% ) 127,598,545 cycles ( +- 0.89% ) 0.042041802 seconds time elapsed ``` * 圖表分析: * hash 主要是將 findname() 的時間大幅減少。 ![](https://i.imgur.com/etrknXy.png) ## 修改錯誤訊息 * git push 之後突然發現 git commit 的 message 打錯字了,參閱 [XYZ的筆記本](http://xyz.cinc.biz/2016/07/git-edit-commit-message-after-push.html) ``` $ git commit --amend $ git push --force-with-lease origin master ```