# 2024q1 Homework6 (integration)
contributed by < `aa860630` >
## 實驗環境
```shell
$ gcc --version
gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Address sizes: 39 bits physical, 48 bits virtual
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Vendor ID: GenuineIntel
Model name: 11th Gen Intel(R) Core(TM) i5-11300H @ 3.10GHz
CPU family: 6
Model: 140
Thread(s) per core: 2
Core(s) per socket: 4
Socket(s): 1
Stepping: 1
CPU max MHz: 4400.0000
CPU min MHz: 400.0000
BogoMIPS: 6220.80
Virtualization features:
Virtualization: VT-x
Caches (sum of all):
L1d: 192 KiB (4 instances)
L1i: 128 KiB (4 instances)
L2: 5 MiB (4 instances)
L3: 8 MiB (1 instance)
NUMA:
NUMA node(s): 1
NUMA node0 CPU(s): 0-7
$ uname -r
6.5.0-26-generic
```
## 自我檢查清單
- [ ] 研讀前述 Linux 效能分析描述,在自己的實體電腦運作 GNU/Linux,做好必要的設定和準備工作 $\to$ 從中也該理解為何不希望在虛擬機器中進行實驗;
- [x] 閱讀〈[Linux 核心模組運作原理](https://hackmd.io/@sysprog/linux-kernel-module)〉並對照 Linux 核心原始程式碼 (v6.1+),解釋 `insmod` 後,Linux 核心模組的符號 (symbol) 如何被 Linux 核心找到 (使用 List API)、`MODULE_LICENSE` 巨集指定的授權條款又對核心有什麼影響 (GPL 與否對於可用的符號列表有關),以及藉由 [strace](https://man7.org/linux/man-pages/man1/strace.1.html) 追蹤 Linux 核心的掛載,涉及哪些系統呼叫和子系統?
[insmod](https://man7.org/linux/man-pages/man8/insmod.8.html) 的主要功能是將特定的模組檔案載入到核心中。這個程序直接處理模組插入,因此並不會自動處理模組間的依賴關係。如果模組有未解決的依賴,insmod 可能會失敗。
#### 藉由 [strace](https://man7.org/linux/man-pages/man1/strace.1.html) 追蹤 Linux 核心的掛載,涉及哪些系統呼叫和子系統?
```
$ sudo strace insmod fibdrv.ko
execve("/usr/sbin/insmod", ["insmod", "fibdrv.ko"], 0x7ffd6b299d08 /* 26 vars */) = 0
brk(NULL) = 0x5cafc9612000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffec5eccf40) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x78d3c2a8a000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=71415, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 71415, PROT_READ, MAP_PRIVATE, 3, 0) = 0x78d3c2a78000
close(3) = 0
```
利用 strace 追蹤執行`insmod fibdrv.ko`的過程可以發現如 `close()`、`mmap()`、`read()`、`openat()`等函式 :
* [openat()](https://linux.die.net/man/2/openat) :`openat()`系統調用的操作方式與`open()`完全相同,如果```pathname```中給出的路徑名是相對的,則它將相對於由檔案描述符`dirfd`指示的目錄進行編譯
```int openat(int dirfd, const char *pathname, int flags, mode_t mode);```
* [close()](https://linux.die.net/man/2/close) : `close()`關閉檔案描述符,使其不再指向任何文件並且可能被重新使用。
* [read()](https://linux.die.net/man/3/read):`read()`函數將嘗試從與打開的檔案描述符 fildes 相關的文件中讀取`nbyte`字節,並將其放入由`buf`指向的緩衝區。
```ssize_t read(int fildes, void *buf, size_t nbyte);```
* [mmap](https://linux.die.net/man/2/mmap) : `mmap()`會在呼叫進程的虛擬地址空間中創建一個新的映射。這個映射的起始地址由`addr`指定,而`length`參數指定了映射的長度。
```void *mmap(void *addr, size_t lengthint " prot ", int " flags , int fd, off_t offset);int munmap(void *addr, size_t length);```
- [x] 閱讀《[The Linux Kernel Module Programming Guide](https://sysprog21.github.io/lkmpg/)》(LKMPG) 並解釋 [simrupt](https://github.com/sysprog21/simrupt) 程式碼裡頭的 mutex lock 的使用方式,並探討能否改寫為 [lock-free](https://hackmd.io/@sysprog/concurrency-lockfree);
* Producer (生產者):產生新資料,並將其插入到 fast_buf 中,以便快速存儲,或插入到 kfifo 中,以便後續傳輸或消費
* Consumer (消費者):從 fast_buf 中讀取資料,然後進一步處理這些資料,可能是將其傳輸到 kfifo,或者進行其他操作
不管是生產者在產生新資料抑或是消費者在讀取資料,我們都不希望這個期間被干擾。舉例來說,當消費者在讀取資料時,我們希望操作是原子性的,不受其他操作的影響。這樣做的目的是避免數據競爭或緩衝區內資料的不一致。
在這個程式碼片段中,```consumer_lock```用於保護從```fast_buf```中讀取資料的操作。在```mutex_lock(&consumer_lock)```和```mutex_unlock(&consumer_lock)```之間,確保只有一個執行緒可以訪問```fast_buf```,避免同時讀取或修改帶來的競爭條件,```mutex_lock(&producer_lock)```與```mutex_unlock(&producer_lock)```亦是如此
```c
while (1) {
/* Consume data from the circular buffer */
mutex_lock(&consumer_lock);
val = fast_buf_get();
mutex_unlock(&consumer_lock);
if (val < 0)
break;
/* Store data to the kfifo buffer */
mutex_lock(&producer_lock);
produce_data(val);
mutex_unlock(&producer_lock);
}
```
- [ ] 探討 Timsort, Pattern Defeating Quicksort (pdqsort) 及 Linux 核心 [lib/sort.c](https://github.com/torvalds/linux/blob/master/lib/sort.c) 在排序過程中的平均比較次數,並提供對應的數學證明;
> 對照 [fluxsort](https://github.com/scandum/fluxsort) 和 [crumsort](https://github.com/scandum/crumsort) 的分析和效能評比方式
- [ ] 研讀 [CMWQ](https://www.kernel.org/doc/html/latest/core-api/workqueue.html) (Concurrency Managed Workqueue) 文件,對照 [simrupt](https://github.com/sysprog21/simrupt) 專案的執行表現,留意到 worker-pools 類型可指定 "Bound" 來分配及限制特定 worker 執行於指定的 CPU,Linux 核心如何做到?CMWQ 關聯的 worker thread 又如何與 CPU 排程器互動?
> 搭配閱讀《Demystifying the Linux CPU Scheduler》
- [ ] 解釋 `xoroshiro128+` 的原理 (對照〈[Scrambled Linear Pseudorandom Number Generators](https://arxiv.org/pdf/1805.01407.pdf)〉論文),並利用 [ksort](https://github.com/sysprog21/ksort) 提供的 `xoro` 核心模組,比較 Linux 核心內建的 `/dev/random` 及 `/dev/urandom` 的速度,說明 `xoroshiro128+` 是否有速度的優勢?其弱點又是什麼?
> $\to$ 搭配閱讀: [不亂的「亂數」](https://blog.cruciferslab.net/?p=599)
- [ ] 解釋 [ksort](https://github.com/sysprog21/ksort) 如何運用 CMWQ 達到並行的排序;