# 2019q1 Homework2 (fibdrv) contributed by < `JulianATA` > ### Reviewed by `jeffcarl67` * 在 `mutex` 的實驗中, 可以加入一份使用 mutex 相關操作的程式碼, 實際比較在有無 mutex 的情況下程式的行為有何不同 ## Environmet ```bash $ uname -a Linux 4.15.0-20-generic $ gcc -v gcc (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0 ``` ## 自我檢查清單 ### 檔案 fibdrv.c 裡頭的 MODULE_LICENSE, MODULE_AUTHOR, MODULE_DESCRIPTION, MODULE_VERSION 等巨集做了什麼事,可以讓核心知曉呢? insmod 這命令背後,對應 Linux 核心內部有什麼操作呢?請舉出相關 Linux 核心原始碼並解讀 #### `MODULE_LICENSE` In `fibdrv.c`: ```clike MODULE_LICENSE("Dual MIT/GPL"); MODULE_AUTHOR("National Cheng Kung University, Taiwan"); MODULE_DESCRIPTION("Fibonacci engine driver"); MODULE_VERSION("0.1"); ``` We used these macros to define our modules. Take a look at `linux/module.h`.(use License as example): ```clike #define MODULE_LICENSE(_license) MODULE_INFO(license, _license) . . . #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) ``` Found `__MODULE_INFO` in [`linux/moduleparam.h`](https://elixir.bootlin.com/linux/v4.18/source/include/linux/moduleparam.h): ``` clike #ifdef MODULE #define __MODULE_INFO(tag, name, info) \ static const char __UNIQUE_ID(name)[] \ __used __attribute__((section(".modinfo"), unused, aligned(1))) \ = __stringify(tag) "=" info #else /* !MODULE */ /* This struct is here for syntactic coherency, it is not used */ #define __MODULE_INFO(tag, name, info) \ struct __UNIQUE_ID(name) {} #endif ``` It'll like config the Module information if module has been defined. #### `insmod` It's a program with following steps 1. Call `init_module()` to tell kernel that a module is try to be load in the kernel and transfer the control to the kernel. 2. Run `sys_init_module()`, which verifies if the user who trying to load the module is allowed or not. If allowed do step3. 3. Call `load_module` function, which assigns temporary memory and duplicate the`elf` module from user space to kernel using `copy_from_user()`. Then check if the ELF file is proper or not. Copy users arguments to the kernel. Update the state of module to `MODULE_STATE_COMING`. Then returns a reference to the kernel module! 4. The reference returned will be added to a `doubly linked list` for modules loaded. 5. Module stat update to `MODULE_STATE_LIVE`. ### 當我們透過 insmod 去載入一個核心模組時,為何 module_init 所設定的函式得以執行呢?Linux 核心做了什麼事呢? Covered in last question. need to paste source code(todo). ### 試著執行 $ readelf -a fibdrv.ko, 觀察裡頭的資訊和原始程式碼及 modinfo 的關聯,搭配上述提問,解釋像 fibdrv.ko 這樣的 ELF 執行檔案是如何「植入」到 Linux 核心 ### 這個 fibdrv 名稱取自 Fibonacci driver 的簡稱,儘管在這裡顯然是為了展示和教學用途而存在,但針對若干關鍵的應用場景,特別去撰寫 Linux 核心模組,仍有其意義,請找出 Linux 核心的案例並解讀。提示: 可參閱 Random numbers from CPU execution time jitter ### 查閱 ktime 相關的 API,並找出使用案例 (需要有核心模組和簡化的程式碼來解說) In my fibdrv.c: ```clike static unsigned long long fib_sequence(long long k) { ktime_t t = ktime_get(); /* FIXME: use clz/ctz and fast algorithms to speed up */ unsigned long long f[k + 2]; f[0] = 0; f[1] = 1; for (int i = 2; i <= k; i++) { f[i] = f[i - 1] + f[i - 2]; } runtime = ktime_sub(ktime_get(), t); printk("iteration %llu runtime = %lldns\n", k, runtime); return f[k]; } ``` Use my own code as reference! The first variable `t` store the starting time of the calculation. Then after the calculation, use `ktime_sub` to get the differnce of the ending time and the starting time, whic can be represent as `runtime`! ### clock_gettime 和 High Resolution Timers (HRT) 的關聯為何?請參閱 POSIX 文件並搭配程式碼解說 In the manpage of `clock_gettime`, we find `clock_getres()`: ``` The function clock_getres() finds the resolution (precision) of the specified clock clk_id, and, if res is non-NULL, stores it in the struct timespec pointed to by res. The resolution of clocks depends on the implementation and cannot be configured by a particular process. If the time value pointed to by the argument tp of clock_settime() is not a multiple of res, then it is truncated to a multiple of res. ``` The word `Resolution` is to describe the `precision` of clock. I wrote a simple program to get resolution of `CLOCK_MONOTONIC` ```clike #include <time.h> #include <stdio.h> int main() { struct timespec t; clock_getres(CLOCK_MONOTONIC, &t); printf("resolution: %ld\n", t.tv_nsec); return 0; } ``` ``` bash resolution: 1000#The unit of the time is nano sec. ``` I found the rationale in [linux.org](https://elinux.org/High_Resolution_Timers) >Currently, timers in Linux are only supported at a resolution of 1 jiffy. The length of a jiffy is dependent on the value of HZ in the Linux kernel, and is 1 millisecond on i386 and some other platforms, and 10 milliseconds on most embedded platforms. >Higher resolution timers are needed to allow the system to wake up and process data at more accurate intervals. ### fibdrv 如何透過 Linux Virtual File System 介面,讓計算出來的 Fibonacci 數列得以讓 userspace (使用者層級) 程式 (本例就是 client.c 程式) 得以存取呢?解釋原理,並撰寫或找出相似的 Linux 核心模組範例 ### 注意到 fibdrv.c 存在著 DEFINE_MUTEX, mutex_trylock, mutex_init, mutex_unlock, mutex_destroy 等字樣,什麼場景中會需要呢?撰寫多執行緒的 userspace 程式來測試,觀察 Linux 核心模組若沒用到 mutex,到底會發生什麼問題 Mutex lock here is for protection of critical section! ```clike #include <stdio.h> #include <stdlib.h> #include <pthread.h> void thread1(void) { for(int i=0;i<5;i++) printf("This is a pthread1.\n"); } void thread2(void) { for(int i=0;i<5;i++) printf("This is a pthread2.\n"); } int main(void) { pthread_t t1, t2; pthread_create(&t1,NULL, (void *) thread1,NULL); pthread_create(&t2,NULL, (void *) thread2,NULL); for(int i=0;i<5;i++) printf("This is the main process.\n"); pthread_join(t1,NULL); pthread_join(t2,NULL); return (0); } ``` Expected outcome: ``` This is a pthread1. This is a pthread1. This is a pthread1. This is a pthread1. This is a pthread1. This is a pthread2. This is a pthread2. This is a pthread2. This is a pthread2. This is a pthread2. This is the main process. This is the main process. This is the main process. This is the main process. This is the main process. ``` What I got: ``` This is the main process. This is the main process. This is a pthread1. This is a pthread1. This is a pthread1. This is a pthread1. This is the main process. This is the main process. This is a pthread1. This is a pthread2. This is a pthread2. This is a pthread2. This is a pthread2. This is a pthread2. This is the main process. ``` ### 許多現代處理器提供了 clz / ctz 一類的指令,你知道如何透過演算法的調整,去加速 費氏數列 運算嗎?請列出關鍵程式碼並解說 ## Original Fibdrv time testing(100 Repeat) ktime_t vs get_time ![](https://i.imgur.com/Byyrcaw.png) ktime_t ![](https://i.imgur.com/G9oGBAu.png) ## dynamic programing(100 repeat) ![](https://i.imgur.com/i3lODpv.png) ## with clz cts(todo) ###### tags: `Cprogramming` `LinuxKernel`