contributed by <baimao8437
>
這兩句話很簡單的可以理解並行與平行的差別
A = B + 1; // (1)
B = 1; // (2)
```
Compiler 最佳化編譯後組語為:
```
movl B(%rip), %eax
movl $1, B(%rip) //(2) finish
addl $1, %eax
movl %eax, A(%rip) //(1) finish
```
雖然後者先結束 但看起來效果像先 1 再 2 即符合 Happens-Before
「在不改變軟體的外在行為之下,改善既有軟體的內部設計」
重構的主要目的就是為了提升可讀性,以及為了日後有了需求的變化時,可以更容易因應修改或是擴充。
一些常見的 「Bad smell」[2]
baimao@baimao-Aspire-V5-573G:~$ lscpu
Architecture: x86_64
CPU 作業模式: 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
每核心執行緒數:2
每通訊端核心數:2
Socket(s): 1
NUMA 節點: 1
供應商識別號: GenuineIntel
CPU 家族: 6
型號: 69
Model name: Intel(R) Core(TM) i5-4200U CPU @ 1.60GHz
製程: 1
CPU MHz: 1711.242
CPU max MHz: 2600.0000
CPU min MHz: 800.0000
BogoMIPS: 4589.38
虛擬: VT-x
L1d 快取: 32K
L1i 快取: 32K
L2 快取: 256K
L3 快取: 3072K
NUMA node0 CPU(s): 0-3
記得 echo 3 | sudo tee /proc/sys/vm/drop_caches
清空 cache
$ ./phonebook_orig
size of entry : 136 bytes
execution time of append() : 0.111719 sec
execution time of findName() : 0.005537 sec
Performance counter stats for './phonebook_orig' (100 runs):
1,202,610 cache-misses # 78.679 % of all cache refs ( +- 0.49% )
1,528,504 cache-references ( +- 0.19% )
320,439,956 instructions # 1.48 insn per cycle ( +- 0.02% )
216,931,003 cycles ( +- 0.15% )
0.087285532 seconds time elapsed ( +- 0.27% )
./phonebook_opt
這裡預設的 thread_num = 4orginal file size = 3206080
size of entry : 24 bytes
execution time of append() : 0.012572 sec
execution time of findName() : 0.003665 sec
Performance counter stats for './phonebook_opt' (100 runs):
387,281 cache-misses # 23.459 % of all cache refs ( +- 0.47% )
1,650,873 cache-references ( +- 0.71% )
247,715,431 instructions # 1.43 insn per cycle ( +- 0.09% )
173,636,294 cycles ( +- 0.64% )
0.091929529 seconds time elapsed ( +- 1.40% )
opt 版本主要實作了以下去優化 append 效能:
至於 findName() 時間也變快的原因 下面 show_entry 後就可以看出來
針對特定測資就會出現一些誤差 預設搜尋的zyxel
在 orig 版本 所在位置在 349891 行
而用 opt 版本 由於順序是會被打亂的 此次出現在 262423 行 所以搜尋的時間花費較少 但速度其實是一樣的
append:
利用 phonebook_opt.c
定義的show_entry
來檢視用 pthread 建立的 linked list 是否與來源(words.txt)一致
可以發現
pHead = thread_args[0]->lEntry_head->pNext;
...
for (int i = 1; i < THREAD_NUM; i++) {
e->pNext = thread_args[i]->lEntry_head->pNext;
...
pHead = thread_args[0]->lEntry_head;
...
for (int i = 1; i < THREAD_NUM; i++) {
e->pNext = thread_args[i]->lEntry_head;
...
findName:
opt 版的 findName 有點小疑惑 建好 list 後 show_entry 為 349900 行沒錯
但不知道為何 findName 完後再執行 show_entry 就變成 349899 少了一行
回頭看完學長影片才知道這是故意設計成這樣的
但我下面要實作 delete 所以設計回 findName 完後可以 show_entry 出完整 list 的版本
while (pHead) {
if (strncasecmp(lastname, pHead->lastName, len) == 0
&& (pHead->lastName[len] == '\n' ||
pHead->lastName[len] == '\0')) {
// pHead->lastName[len] = '\0';
for (int i = 0; i < THREAD_NUM; i++)
thread_args[i] = createThread_arg(map + MAX_LAST_NAME_SIZE * i, map + file_size, i,THREAD_NUM, entry_pool + i);
for (int i = 0; i < THREAD_NUM; i++)
pthread_create(&threads[i], NULL, (void *)&append, (void *)thread_args[i]);
for (int i = 0; i < THREAD_NUM; i++)
THREAD_SET(i);
append()0.004217 findName() 0.005007
execution time of append() : 0.052377 sec
execution time of delete() : 0.005598 sec
execution time of findName() : 0.005562 sec
execution time of append() : 0.004075 sec
execution time of delete() : 0.003510 sec
execution time of findName() : 0.003502 sec
在建完 list 後 可以透過指令DELETE(name)
來刪除特定的資料
delete 的速度應該跟 findName 是差不多的
phonebook_orig.h
& phonebook_opt.h
合併成 phonebook.h
實現多型(polymorphism)重構之後 程式碼好閱讀多了 依照階段來完成任務 並會自動對應到不同版本的實作 成就感UPUP~
然後剩不到一天 還剩兩個作業…