# 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)