2016q3 Homework2 (phonebook-concurrent) === contributed by <`vic85821`> ## 開發環境 * Ubuntu 16.04.1 LTS * Linux version 4.4.0-38-generic * CPU : Intel® Core™ i5-3230M CPU @ 2.60GHz * Main memory : 8GB * L1d cache : 32K * L1i cache : 32K * L2 cache : 256K * L3 cache : 3072K ## 目標 - [x] 驗證結果 - [x] 實作hash table - [ ] 實作thread pool ## Pthread ## mmap Linux提供了記憶體映射函數 mmap,它把文件內容映射到一段虛擬記憶體上,**讓存取或是寫入檔案更快速直接**,不用經過buffer >原本以為將align的長度減少(min = 13)可以降低cache-miss,但實驗結果顯示align長度=16時cache-miss最低 >> Hint: cache line size [name=jserv] ```C== void *mmap(void *start,size_t length, int prot, int flags, int fd, off_t offsize); ``` **參數說明:** * `start` : 指定從虛擬記憶體的哪個位置開始存放,若傳入`NULL`則會隨機配置可用的記憶體位置 * `length` : 要映射的記憶體大小 * `prot` 映射區域的保護方式 ```== PROT_EXEC 映射區域可被執行 PROT_READ 映射區域可被讀取 PROT_WRITE 映射區域可被寫入 PROT_NONE 映射區域不能存取 ``` * `flags` : 影響映射區域的各種特性,以下為常見的 ```== MAP_SHARED 允許其他映射該文件的行程共享,對映射區域的寫入數據會複製回文件。 MAP_PRIVATE 不允許其他映射該文件的行程共享,對映射區域的寫入操作會產生一個映射的複製(copy-on-write),對此區域所做的修改不會寫回原文件。 ``` * `fd` : 由open返回的文件描述符,代表要映射到核心中的文件 >這部份不太清楚參數代表的意義[color=#6447c1] * `off_size` : 從文件映射開始處的偏移量,通常為0,代表從文件最前方開始映射。(需為page size的整數倍) 參考資料 : [mmap](http://welkinchen.pixnet.net/blog/post/41312211-%E8%A8%98%E6%86%B6%E9%AB%94%E6%98%A0%E5%B0%84%E5%87%BD%E6%95%B8-mmap-%E7%9A%84%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95) ## 案例分析 ### 測試正確性及效能 ``` size of entry : 24 bytes execution time of append() : 0.006272 sec execution time of findName() : 0.005810 sec ``` 正確性的部份參考[tempoJiJi](/s/rymKa4aT)的共筆,將程式的輸出與原本的字典檔做比較 ```c== #ifdef OPT show_entry(e); #endif ``` `./phonebook.opt > test.txt` 因為輸出的格式與字典檔內容有些不同,因此額外parse資料並sort 並利用`diff words.txt test.txt`檢測檔案差異 輸出只有349896筆,但word.txt有349900筆,少了幾筆資料 對程式碼做了修正 ``` for (int i = 0; i < THREAD_NUM; i++) { if (i == 0) { pHead = app[i]->pHead; dprintf("Connect %d head string %s %p\n", i, app[i]->pHead->pNext->lastName, app[i]->ptr); } else { etmp->pNext = app[i]->pHead; dprintf("Connect %d head string %s %p\n", i, app[i]->pHead->pNext->lastName, app[i]->ptr); } ``` `pHead = app[i]->pHead->pNext;` 改成 `pHead = app[i]->pHead` `etmp->pNext = app[i]->pHead->pNext;`改成`etmp->pNext = app[i]->pHead;` 原本的寫法,各個thread_ll head 單字都會消失,修正完之後,結果就是對的了 在作業1的phonebook,我是透過build binary search tree以提高findName()的速度,因此藉由檢查output檔的機會,這次便利用hash table來檢驗正確性 (原本想說利用array存取資料,再直接sort比較就好,但資料量太大了...) * check_right.c ```c= int hash_value(char* ptr) { unsigned int value = 0; unsigned int seed = 31; int i = 0; while(i < strlen(ptr)) { value = value * seed + *ptr; i++; } return value % TABLE_SIZE; } hTable *create() { hTable *table; table = malloc(sizeof(hTable)); table -> list = malloc(sizeof(entry_c*) * TABLE_SIZE); int i = 0; for(i = 0; i < TABLE_SIZE; ++i) table -> list[i] = NULL; return table; } ``` 寫完才得知,原來linux本身就有sort指令可以幫忙排序Orz!! `$ sort output.txt` ### 原始版本的效能改善與問題 ![](https://i.imgur.com/HljglnA.png) #### 效能改善 * thread pool * hash table #### 問題 * Pthread 假設有某個thread的執行時間過長,會拉低整個程式的效能 * 增加thread卻沒有增加效能的原因 * 透過 thread pool 來進行改善 * 程式是將整個words都串聯起來,因此findname()仍必須線性搜尋 * 透過hash table來提高findname() * 但必定會犧牲append()的效能 ### 優化1_Hash Table 使用hash table加快了findName()的速度,各個thread先分別建立hash table,最後再join ![](https://i.imgur.com/XlODSbW.png) * append(): 建表的時候需要較多的時間 * findName(): 利用hash table降低了許多 ``` Performance counter stats for './phonebook_opt' (100 runs): 452,045 cache-misses # 37.454 % of all cache refs ( +- 1.26% ) 1,206,946 cache-references ( +- 1.31% ) 323,977,868 instructions # 1.16 insns per cycle ( +- 0.06% ) 279,321,497 cycles ( +- 0.58% ) 0.080669329 seconds time elapsed ( +- 11.95% ) ``` ### 優化2_Thread Pool 為了降低append()的時間,因此想實作看看thread pool (研究中...) ## Refactoring **定義 : 在不改變軟體的外在行為之下,改善既有軟體的內部設計** 目標 : 判斷軟體中所存在的壞味道(smell),然後套用重構來移除這些壞味道 簡而言之,現行程式碼可以將內容分為**form**和**context**,我們可以透過挑除form當中的**壞味道**,讓程式更有效率.更好被理解 ### 程式的壞味道 ```C== typedef struct _append_a { char *ptr; char *eptr; int tid; int nthread; entry *entryStart; entry *pHead; entry *pLast; } append_a; ``` 從`append()`,`new_append_a()`中可以發現,沒有使用到tid這個變數,因此將tid移除,並針對`append()`,`new_append_a()`,`main()`中有assign tid的地方修改,整個程式仍然是正確的 >> 良性的批評是一併提出改進方案,show me the code! [name=jserv] 參考資料:[什麼是refactoring](http://teddy-chen-tw.blogspot.tw/2014/04/refactoring.html) ###### tags: `phonebook` `concurrent` `refactoring` `Pthread`