contributed by < 2020leon >
lsmod
的輸出結果有一欄名為 Used by
,這是 "each module's use count and a list of referring modules",但如何實作出來呢?模組間的相依性和實際使用次數 (reference counting) 在 Linux 核心如何追蹤呢?
搭配閱讀 The Linux driver implementer’s API guide » Driver Basics
fibdrv.c
存在著 DEFINE_MUTEX
, mutex_trylock
, mutex_init
, mutex_unlock
, mutex_destroy
等字樣,什麼場景中會需要呢?撰寫多執行緒的 userspace 程式來測試,觀察 Linux 核心模組若沒用到 mutex,到底會發生什麼問題。嘗試撰寫使用 POSIX Thread 的程式碼來確認。fibdrv
計算 Fibinacci 數列的執行效率,過程中需要量化執行時間,可在 Linux 核心模組和使用層級去測量
/dev/fibonacci
裝置檔案來變更不同的 Fibonacci 求值的實作程式碼。fibdrv
分支) 的實作,理解其中的技巧並與你的實作進行效能比較,探討個中值得取鏡之處。
原程式碼如下。
其中宣告處可見 long long f[k + 2]
,其雖合乎 C99 標準,但其實有更好的實做可以避免 VLA 。修正後如下。
直接以費波那契數的定義實做,時間複雜度為 ,若改以 fast doubling 的方式則可使時間複雜度降為 。
根據作業要求所給出的虛擬碼實做 fast doubling ,首次嘗試如下。
在以上嘗試中,將 k
最高位的 1 對齊 MSB ,並逐次將 k
左移偵測最高位以實做 fast doubling 。
後來發現更為簡化的實做方式。
以上實做中,不再將 k
進行位移。反之,以 mask
變數作為遮罩,逐次將 mask
右移以對 k
進行檢查。
最後則是為未來大數運算做準備。由於目前的程式碼在 fib_read
函式中直接回傳所算得之費波那契數,然而此機制無法應付數值超過 ssize_t
所能表示之最大值的情況。因此回歸 read
函式之用法,將所得之數放進 fib_read
函式的 buf
參數中。
原 fib_read
實做如下。
先修改 fib_read
。當 buf
的大小不足以放入 long long
整數時,回傳 -1
。
再修改 client.c
關於 read
的部份。
在此實做固定長度有號大數。新增 bignum.h
,定義 struct bignum
。
struct bignum
以 little endian 的方式儲存數值:最低位位於 num[0]
,最高位位於 num_and_sign
。在此選擇以 32 位元整數作為成員型態的原因是考慮在進行運算時可以 64 位元的變數儲存會溢位的數值。將最高位獨立為 int32_t
型態可避免在實做時過度轉型。此結構的數值範圍為 。
接下來實做基本大數運算於 bignum.c
。函式原型如下。
實做後,需修改 Makefile
以將 bignum
導入模組及 client 中。
在編譯前,需了解到在 user mode 和 kernel mode 所引入的標頭檔不盡相同。可以藉由檢查 __KERNEL__
巨集是否有被定義來決定所引入的標頭檔。如下。
接著以 fast doubling 和大數實做費波那契數,最後稍稍修改 fib_read
及 client.c
。
最後執行 make check
發現無法通過測試,原因為 scripts/expected.txt
中大於 92 的費波那契數為錯誤的。修改後方可通過測試。
根據作業要求,將可能會影響效能的因素排除。
接著再次改寫程式碼,將多個需比較的內容寫入 driver 中,並以 enum
來決定所要執行的程式碼區段。
改寫 fib_write
,使之成為使用者改變 driver mode 的函式。
接著在 driver 中安插計時相關程式碼,所得之時間單位為奈秒。
並在 user mode 中也安插計時相關程式碼。
最後利用 gnuplot 將資料轉換為折線圖。
第一張圖為利用 bignum fast doubling 所得之數據。
第二張及第三張圖為根據不同的演算法所得之時間數據。