# 2019q1 Homework7 (skiplist)
contributed by < `bauuuu1021` >
* [作業要求](https://hackmd.io/s/rkl7BqCi4)
## 測驗及延伸
### 題目
給定一個 circular linked list 實作如下: (檔案 `list.h`)
```cpp
#ifndef INTERNAL_LIST_H
#define INTERNAL_LIST_H
/* circular doubly-linked list */
typedef struct __list_t {
struct __list_t *prev, *next;
} list_t;
/*
* Initialize a list to empty. Because these are circular lists, an "empty"
* list is an entry where both links point to itself. This makes insertion
* and removal simpler because they do not need any branches.
*/
static inline void list_init(list_t *list) {
list->prev = list;
list->next = list;
}
/*
* Append the provided entry to the end of the list. This assumes the entry
* is not in a list already because it overwrites the linked list pointers.
*/
static inline void list_push(list_t *list, list_t *entry) {
list_t *prev = list->prev;
entry->prev = prev;
entry->next = list;
prev->next = entry;
list->prev = entry;
}
/*
* Remove the provided entry from whichever list it is currently in. This
* assumes that the entry is in a list. You do not need to provide the list
* because the lists are circular, so the list's pointers will automatically
* be updated if the first or last entries are removed.
*/
static inline void list_remove(list_t *entry) {
list_t *prev = entry->prev;
list_t *next = entry->next;
prev->next = next;
next->prev = prev;
}
/*
* Remove and return the first entry in the list or NULL if the list is empty.
*/
static inline list_t *list_pop(list_t *list) {
list_t *foo = list->prev;
if (foo == list)
return NULL;
LL1
}
#endif
```
請參照上方程式註解,補完對應程式碼。
### 作答區
根據 `list_pop()` 的註解
```cpp
/*
* Remove and return the first entry in the list or NULL if the list is empty.
*/
```
預期的行為是使用 `list_remove()` 移除並回傳該節點,或 list 為空時回傳 `NULL`,前半段程式碼就是在處理 list 為空的情況
```cpp
list_t *foo = list->prev;
if (foo == list)
return NULL;
```
而針對必須回傳節點的情況,可以發現選項中
* `(a)` return foo;
* `(b)` return foo->next;
* `(c)` return foo->prev;
* `(d)` list_remove(foo->prev); return foo;
* `(e)` list_remove(foo); return foo;
* `(f)` list_remove(foo->next); return foo->next;
* `(g)` list_remove(foo); return foo->next;
只有 (e) (f) 兩個選項有做到==移除並回傳==,但 `(f) list_remove(foo->next); return foo->next;` 中 `foo->next` 指向的是 `list`,其實是 list 的 head 而不是一個 entry
故答案應為 ==`(e)` list_remove(foo); return foo;==
### 延伸題目
:::success
延伸問題:
1. 研讀 2019q3 Week11 的 [cache-oblivious data structures](https://rcoh.me/posts/cache-oblivious-datastructures/) 參考資料,記錄所見所聞;
2. 依據之前給定的 Linux 核心 linked list 實作,開發 cache-oblivious 的版本,並證實其效益;
3. 實作 Skip list,並且比照之前的 unit test 提供對應的測試、效能分析,還有改善機制
:::
### 延伸問題 - 1
* 作者在 [Retrieve element from BST](https://github.com/rcoh/treelayout) 實驗中發現 cache-oblivious (綠線) 的效能隨著實驗大小變大而開始與另外兩個對照組有明顯差別
![ ](https://rcoh.me/images/cache-oblivious-graph.png)
* 根據記憶體實際運作的情形來設計演算法
* 記憶體不是一次載入一個 Byte,而是一個 Block
* 因此在對較慢的記憶體做存取時,該考慮的其實不是讀一個 Byte 需要多少時間,而是為了此 Byte 所在的 Block 載入需要多少時間
* 故如果可以將演算法調整為針對某 Block 運算結束後再載入其他 Block ,可以大幅降低 I/O 成本
* 以下示意圖用同樣色線框在一起的代表在同一個 block
* leveled
![ ](https://rcoh.me/images/breadthfirst.svg)
* preorder
![ ](https://rcoh.me/images/depthfirst.svg)
因此以上兩種資料結構,在從根節點開始尋找 BST 中特定節點都不是理想的,可能花大量時間載入一個 block 卻只用到其中的 1~少數個
* 但若修改儲存 BST 的記憶體方式,使每個 block 會被使用到的 element 數量提高,配置如下
![ ](https://rcoh.me/images/van-layout.svg)
(假設 B elements/block)<br>則不管搜尋目標在 BST 的何處,都固定會讀取路徑上每個 block 中 ${\log B}$ 個 element,因此會有差不多且不錯的效能表現
## skip list 在 Linux 之應用
>在 Linux 核心原始程式碼使用 skip list 的案例,介紹其原理,設計 Linux 核心模組的實驗
>* 需要涵蓋 kernel API 同步機制的運用
>* 執行時期的分析 (提示: 可善用 eBPF)
>
### 同步機制 API
根據 LWN 這篇 [文章](https://lwn.net/Articles/553047/)
>Insertion into the skiplist requires the programmer to get a "preload token" — skiplist_preload() ensures that the necessary memory is available and disables preemption. With the token in hand, it's possible to actually insert the item, then re-enable preemption.
可實作為類似下面 function 形式
```cpp
int skiplist_preload(struct sl_list *list, gfp_t gfp_mask);
```
稍後完成 insertion 後必須根據上面 function 回傳的 `integer token` re-enable preemption
## 參考資料
* [Homework7 作業區](https://hackmd.io/s/S1xQB5RsV)
* [A kernel skiplist implementation - part 1](https://lwn.net/Articles/551896/)
* [A kernel skiplist implementation - part 2](https://lwn.net/Articles/553047/)
###### tags: `bauuuu1021` `linux2019` `2019spring`