# 2021q1 Homework2 (quiz2) contributed by < `robinsonweng` > ## 測驗1 ### COND1 & COND2 閱讀 get_middle 程式碼,並將巨集 list_for_each 解開,其程式碼如下: ```c static list_ele_t *get_middle(struct list_head *list) { struct list_head *fast = list->next, *slow; for (slow = (list)->next; slow != (list); slow = slow->next) { if (COND1 || COND2) break; fast = fast->next->next; } return list_entry(TTT, list_ele_t, list); } ``` 可以發現每當 slow 走 n 個節點,fast 就會走 n+2 個節點,考慮到是找到中間的節點,將 linked list 為奇數以及雙數的情況都畫出來 1. 雙數 linked list, slow 移動了1個節點到達節點3,fast 移動了2個節點到達節點4 ```graphviz digraph { node [shape=box] head -> 6 [dir=both, label=" "] 6->3 [dir=both] 3->4 [dir=both] 4->5 [dir=both] 5->head [dir=both] slow -> 3 fast -> 4 {rank=same; 3, 4, 5, 6, head} } ``` 2. 單數 linked list, slow 移動了2個節點到達節點4,fast 移動了4個節點到達節點7 ```graphviz digraph { node [shape=box] head -> 6 [dir=both, label=" "] 6->3 [dir=both] 4->5 [dir=both] 7->head [dir=both] 3->4 [dir=both] 5->7 [dir=both] slow-> 4 fast->7 {rank=same; head, 6, 3, 4, 5, 7} } ``` 所以如果要將以上兩種情況都概括,`COND1` 和 `COND2` 必須分別為 `fast->next == list`, `fast->next->next == list` ## TTT 根據上方作業敘述,傳入成員位址,型態以及名稱給 list_entry,它會回傳當下 struct 的位址。我們需要知道當下 slow 指向的節點位址,故 TTT 應為 `slow` ## MMM 先解析 list_cut_position 的作用: 註解指出,list_cut_position,會從 head_from 指向的 linked list,在 node 點切開,並讓 head_to 接收另一段 linked list,如下圖 ```graphviz digraph { node [shape=box] head_from -> 6 [dir=both, label=" "] 6->3 [dir=both] "node"->5 [dir=both] 7->head_from [dir=both] 5->7 [dir=both] 3->"node" [dir=both] head_from_first->6 head_to {rank=same; head_from, 6, 3, 5, 7, "node"} } ``` ``` head_from->next = node->next; head_from->next->prev = head_from; ``` ```graphviz digraph { node [shape=box] 6->head_from [label=" "] head_from->5 [dir=both] 6->3 [dir=both] "node"->5 7->head_from [dir=both] 5->7 [dir=both] 3->"node" [dir=both] head_from_first->6 head_to {rank=same; 6, 3, 5, 7, "node"} } ``` ``` head_to->prev = node; node->next = head_to; ``` ```graphviz digraph { node [shape=box] 6->head_from [label=" "] head_from->5 [dir=both] 6->3 [dir=both] 7->head_from [dir=both] 5->7 [dir=both] 3->"node" [dir=both] head_from_first->6 "node"->head_to [dir=both] {rank=same; 6, 3, 5, 7, "node"} } ``` ``` head_to->next = head_from_first; head_to->next->prev = head_to; ``` ```graphviz digraph { node [shape=box] head_from->5 [dir=both, label=" "] 6->3 [dir=both] 7->head_from [dir=both] 5->7 [dir=both] 3->"node" [dir=both] head_from_first->6 "node"->head_to [dir=both] head_to->6 [dir=both] {rank=same; 6, 3, 5, 7, "node"} } ``` 其參數MMM必須是要切開的節點,也就是透過 get_middle 得到的 struct 位址,而 get_middle 的參數要是 list_head 的指標型態,故要得到當下 struct 的地址,程式碼應為 `get_middle(&q->list)` :::warning TODO: 解釋上述程式碼運作原理,指出改進空間並著手實作 研讀 Linux 核心的 lib/list_sort.c 原始程式碼,學習 sysprog21/linux-list 的手法,將 lib/list_sort.c 的實作抽離為可單獨執行 (standalone) 的使用層級應用程式,並設計效能評比的程式碼,說明 Linux 核心的 lib/list_sort.c 最佳化手法 將你在 quiz1 提出的改進實作,和 Linux 核心的 lib/list_sort.c 進行效能比較,需要提出涵蓋足夠廣泛的 benchmark ::: --- ## 測驗2 :::warning TODO: 1.解釋上述程式碼運作原理 2. 在 The Linux Kernel API 頁面搜尋 “power of 2”,可見 is_power_of_2,查閱 Linux 核心原始程式碼,舉例說明其作用和考量,特別是 round up/down power of 2 。特別留意 `__roundup_pow_of_two` 和 `__rounddown_pow_of_two` 的實作機制 3. 研讀 slab allocator,探索 Linux 核心的 slab 實作,找出運用 power-of-2 的程式碼和解讀 :::