contributed by < csm1735
>
fibdrv.c
存在著 DEFINE_MUTEX
, mutex_trylock
, mutex_init
, mutex_unlock
, mutex_destroy
等字樣,什麼場景中會需要呢?撰寫多執行緒的 userspace 程式來測試,觀察 Linux 核心模組若沒用到 mutex,到底會發生什麼問題。嘗試撰寫使用 POSIX Thread 的程式碼來確認。 搭配閱讀〈並行和多執行緒程式設計〉一開始須先將 Secure Boot 的功能關閉,這樣做 make check
時才能得到如下的預期結果:
其它指令輸出如下
觀察 fibdrv.c
中的 fib_sequence()
可發現,原先的費氏數列是透過迭代的手法來實做。
為了加速運算,我們可透過教材中提到的 Fast Doubling 手法來改寫,也就是以下公式:
由於 k = 1
跟 k = 2
時的結果皆為 1 ,這邊透過 !!k
的手法使此處的回傳值只會有 0 或 1。
__builtin_clzll
功能為去計算總共有幾個 leading zero ,以方便我們做位移,因為只要檢查目標數對應的位元,即可知曉下次應以 還是 為基礎進行計算
將使用的資料由 long long
更改為 uint64_t
,使得正整數的最大有效值從 來到 ,此更改讓 可以被正確計算出來,但從 開始仍會得到 overflow 後的數值。
因此這邊選擇使用數字字串的手法來實作大數運算,以計算到更後面的數值
定義了一個長度為 128 的字串來儲存大數,每個 index 分別用來儲存一個位數。
此處為字串的加法,由於 a = fib[i - 1].num, b = fib[i - 2].num
,我們可確保 size_a >= size_b
,因此我們只需要在 index < size_b
的時候去做 a[index]
跟 b[index]
的相加,當 index >= size_b
之後就只需要處理剩餘的 a
,而由於加法可能會導致進位,因此用了 carry
來儲存進位與否。
這邊將字串做反轉的動作,使輸出能如我們預期,實作上使用到了你所不知道的 C 語言:數值系統篇中所提到的 XOR swap ,這麼做的好處是完全不需要用到額外的記憶體。
計算出所求的 Fibonacci 數,再透過 copy_to_user
,將想傳給使用者模式的字串複製到 fib_read
的 buf
參數後,讓 client 端方可接收到此字串。
由於我們已經可以算到更後面的值了,所以要記得將 MAX_LENGTH
從 92 調整到 500
如此一來就能正確算到 的值。
引入 ktime 相關的 API 來測量在 kernel space 的執行時間
並對 fib_read
跟 fib_write
做改寫
接著修改 client.c
的程式碼,因為要先透過 read
去計算 kt
的值才能夠透過 write
得到執行時間,因此每次都在 read
完後去呼叫 write
如此一來便可得到預期結果
使用 clock_gettime 來測量在 user space 的執行時間
在 client.c
中定義了 user_time()
可透過 clock_gettime()
取得當前時間,第一個參數選擇 CLOCK_REALTIME
表示使用系統實際時間,需要 #include <time.h>
,而其中的 struct timespec
定義如下
有兩個成員,分別代表 seconds 跟 nanoseconds
如此一來,除了原先的 kernel space time ,還可計算 user space time ,並進一步算出 kernel to user 的傳遞時間
教材中提及了兩種讓特定的 CPU 核在開機時就被保留下來的方法
這邊選擇了以 2. 來實作
在 /etc/default/grub
中新增
並透過以下指令更新
接著重新開機,即可檢查是否成功
可看到第 0 個 cpu 被保留了下來,接著就可以透過 taskset 命令將這個 CPU 核指定給要執行的程式使用。
抑制 address space layout randomization (ASLR)
設定 scaling_governor 為 performance。
準備以下 shell script,檔名為 performance.sh
:
之後再用 $ sudo sh performance.sh
執行
針對 Intel 處理器,關閉 turbo mode
關閉 SMT (Intel 稱它為 Hyper-Threading)