# 2016q3 Homework2 (phonebook-concurrent) contribute by <`petermouse`> ## 開發環境 * OS:Lubuntu 16.04 LTS * Memory: 8 GB * CPU: * Name: * Intel(R) Core(TM) i5-4200H CPU @ 2.80GHz * Cache: * L1d Cache: 32K * L1i Cache: 32K * L2 Cache: 256K * L3 Cache: 3072K --- ## 資料閱讀 ### [The Free Lunch is Over](http://www.gotw.ca/publications/concurrency-ddj.htm) 文章討論到現今的CPU硬體發展已經遇到了瓶頸,過去的程式可以透過CPU的時脈與執行指令的最佳化來使提昇程式效能,不需經過修改也有很好的表現,這就是Free Lunch。但現今CPU發展走向已經改變,所以需了解新的趨勢(尤其是Concurrency),改變程式設計,以因應時代的變遷。 ### Concurrency vs Parallelism Concurrency(並行):同一個任務分割成幾個執行片段給同個CPU處理,提昇CPU的使用效率(因為CPU有I/O等待...之類硬體層面問題) Parallelism(平行):將任務給分割多段分別給不同CPU處理 ### Refactoring 參考[什麼是Refactoring?](http://teddy-chen-tw.blogspot.tw/2014/04/refactoring.html)與[對於重構的兩則常見誤解](http://www.ithome.com.tw/node/79813) 定義: ``` 在不改變軟體的外在行為之下,改善既有軟體的內部設計 ``` 目的:改善程式碼的可讀性,以便維護、修正、使用、增添。 ==不等於==:提昇效能,debug,但重構對這些有助益。 [Bad Smells列表](https://sourcemaking.com/refactoring/smells) >> 說好的 code refactoring 呢? [name=jserv] >> 對不起,我還在努力中。[name=petermouse] >> 已填寫至`phonebook-concurrent 改進` 的次標題`Code Refactoring`之中[name=petermouse] ### 關於linux的mmap 用途:將硬碟上的檔案位置映射到(虛擬)記憶體位置中,針對硬碟檔案存取->改針對虛擬記憶體存取 好處:可以加快對檔案的存取速度,因為中間經過了較少的複製以及方便隨機存取。 [stackoverflow](http://stackoverflow.com/questions/9817233/why-mmap-is-faster-than-sequential-io)有對mmap較詳盡的解釋,雖然我看得沒有很懂。 prototype: ```clike void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); ``` addr:起始位址,NULL則由系統決定,回傳該值。 length:檔案大小 prot:決定權限 flags:決定行程的可見度 fd:檔案描述符 offset:檔案偏移量(需為分頁大小的倍數) --- ## phonebook-concurrent 改進 ### Code Refactoring 原本的程式碼有點凌亂而且不易閱讀,所以做了一些調整。 1. 增加註解 這次又多了很多看不懂的程式碼,因此將一些不易理解的程式碼新増註釋,比如說為標頭檔標示所用的函式 ```clike= #include "file.c" //file_align() #include "debug.h" //dprintf():print debug message #include <fcntl.h> //open() fsize() ``` 還有較為複雜的結構 ```clike= append_a **app = (append_a **) malloc(sizeof(append_a *) * THREAD_NUM); // define a pointer to dymatic allocated pointer array to append_a ``` ```clike= for (int i = 0; i < THREAD_NUM; i++) app[i] = new_append_a(map + MAX_LAST_NAME_SIZE * i, map + fs, i, THREAD_NUM, entry_pool + i); //set every pointer to append_a an address of dynamic allocated append_a ``` 用詞上可能還不夠精確。 程式碼分為`OPT`與`ORIG`版本,可以為相同功能的區塊加上註解 ```clike= /*Add some comments to descripting a block*/ #ifndef OPT /*code segment*/ #else /*code segment*/ #endif ``` 2. 統一程式碼 在main()可以看到以下程式碼 ```clike= #ifndef OPT ... #else #include "file.c" #include "debug.h" #include <fcntl.h> #define ALIGN_FILE "align.txt" #endif ``` 將標頭檔統一移至main之前,才不會看起來穿插,code看起來比較乾淨。 此外, ```clike= #if defined(OPT) output = fopen("opt.txt", "a"); #else output = fopen("orig.txt", "a"); #endif ``` 因為程式碼幾乎是`#ifndef OPT`開頭,在這也維持慣例: ```clike= #ifndef OPT output = fopen("orig.txt", "a"); #else output = fopen("opt.txt", "a"); #endif ``` 3. 刪除未使用的變數 `mid`在程式碼中出現了兩次 ```clike struct timespec mid; clock_gettime(CLOCK_REALTIME, &mid); ``` 但從來沒有真正使用到,可以把它刪除。 以及`append`中的`tid`未使用到,將其與相關函數參數刪除。 4. 更改變數名稱 (待續) ### 程式正確性驗證 參考[TempoJiJi的共筆](https://hackmd.io/s/rymKa4aT) 在`phonebook_opt.c`定義了`show_entry()`方便檢視,使用`wc -l [FILE]`查看行數,結果發現自己output出來的檔案比words.txt(349900行)少4行(349896行) 原因:app[i]->pHead已經是entry的第一個位置,結果再一個Next指到下一個entry的位置 (pHead已經是entry的第一個位置,是因為append()時第一次for迴圈底下pLast未改變位置) ```clike= entry *j = app->entryStart; //第一個位置=pHead=pLast for (char *i = app->ptr; i < app->eptr; i += MAX_LAST_NAME_SIZE * app->nthread, j += app->nthread,count++) { app->pLast->pNext = j; //pLast的Next為自己 app->pLast = app->pLast->pNext;//pLast未改變位置 app->pLast->lastName = i; //在pHead=pLast指標指向的物件位置dereference設定值 dprintf("thread %d append string = %s\n", app->tid, app->pLast->lastName); app->pLast->pNext = NULL; //pNext為NULL } ``` 圖表: ### 建立thread-pool --- ## 參考資料 [解釋multithread](http://programmers.stackexchange.com/questions/97615/what-can-multiple-threads-do-that-a-single-thread-cannot) [Code Smells](https://sourcemaking.com/refactoring/smells) [記憶體映射函數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) [維基百科:mmap](https://en.wikipedia.org/wiki/Mmap) [stackoverflow上關於mmap的解釋](http://stackoverflow.com/questions/9817233/why-mmap-is-faster-than-sequential-io) [linux-mmap](http://man7.org/linux/man-pages/man2/mmap.2.html) [TempoJiJi的共筆](https://hackmd.io/s/rymKa4aT)