擴充 fibdrv,強化其並行處理能力,預計達成:
學習 ktcp,引入 kthread 和 CMWQ 到 fibdrv,確保 Fibonacci 數的運算可發揮硬體能力
確保並行處理的效益,不僅要確認結果正確,還要讓並行的 fibdrv 得以更有效的運算
思考如何運用 Linux 核心的 RCU (或其他 lock-free 機制) 有效釋放並行處理過程中的記憶體資源
閱讀大數運算 協助計算出 Fibonacci 第一百萬個
以下為欲支援運算的函式,部分參考教材
該函式用於將 bn 轉換為十進制字串表示
用 (8 * sizeof(int) * src.size) / 3 + 2 + src.sign
算出需要的字元存放空間,再由 kmalloc()
分配這段空間
使用 memset()
對字元陣列 s 所有元素初始化為 0
,最後一個元素設置為 \0
表示字串的結束
在 fibdrv.c
新增以下內容
建立名為 million.c
的檔案,負責接收回傳回來的資料
執行以下命令
得到以下結果
隨後用 perf 進行 f(0)~f(10000)
分析,初步分析出 bn_to_string
這個函式有問題,佔總執行時間 98.87%
, 而 bn_fib_fdoubling
僅占 1.07%
,裏頭有 在執行 bn_to_string
上圖 f(100000)、f(1000000) 的結果和 WolframAlpha 的結果一致
f(100000)如下
f(1000000)如下
可將 bn_to_string
搬到使用者層級來處理,讓核心模組聚焦在 Fibonacci 求值和相關大數運算/數值表示。
好的老師,我試試看
將 bn_to_string
搬到使用者層級來處理,讓核心模組聚焦在 Fibonacci 求值和相關大數運算/數值表示
以下為調整過後的版本
以下為調整過後的版本
在million.c
我發現有重複計算的情況,所以我直接將變數 i
調至我們要的目標值,便可減少重複計算的缺點。
執行以下命令:
得到以下結果,可以發現確實改善重複計算的問題
將 bn_to_string
移至 user level 後,其中 及 的運算結果和 WolframAlpha 的結果一致,達成其中一個目標計算出第一百萬個的 fibonacci
執行以下命令:
得到以下結果,但是 bn_to_string
的問題仍需要改進
bn_fib_fdoubling
進行改良原先 bn_cpy
採取從 src
記憶體區域複製至 dest
記憶體區域。
memcpy
The memcpy() function copies n bytes from memory area src to
memory area dest. The memory areas must not overlap. Use
memmove(3) if the memory areas do overlap.
後來採用 bn_swap
達成交換 bn
位置,如下
改良前
改良後
改良前
改良後
swap
這個策略比 memcpy()
來的好Q-Matrix
進行改良學習 Q-Matrix 如何使用
參考公式如下
得到以下測試結果
參考 Linux 核心的 hash table 實作 來設計 Hash table
儘量使用 Linux 核心提供的標頭檔和 API。
目前已使用老師說的標頭檔和API了
宣告出 pprev
(指標的指標) 並不指向上個節點,而是指向上個節點的 next 指標,當要刪除的節點是首個節點,可通過 *pprev = next
直接修改指標的指向。詳細內容請看Linux 核心的 hash table 實作
為保存我們需要的數值,定義出以下 struct
示意圖如下:
目前想先從 n = 100
做起,所以先定義出 128 個 buckets
目前考慮到 fast doubling 和 Fibonacci 數的特性,不用保存連續數值,而是關注第 N 個和第 2N 個 Fibonacci 數的關聯,想先保存 第 N 和第 2N 個數值
參考 Matrix Difference Equation for Fibonacci Sequence,把 Fibonacci Q-Matrix 公式重新推導一次,已理解以下 Fast Doubling 的由來
參考 Calculating Fibonacci Numbers by Fast Doubling
學習下方方法,可以幫助我們找到目標值,如下
舉 f(100) 為例子,說明 bn_fib_doubling
如何運算出 count, n = 100,經i = 1U << (31 - __builtin_clz(n))
,會先將 100 轉為 1100100(binary),再執行 __builtin_clz(1100100)
,可以得到 24,結果 i 可得 1000000。
Other Builtins
Built-in Function: int __builtin_clz (unsigned int x)
Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.
經過 (n & i) ? (count << 1) + 1 : count << 1
可得到每一次 for loop 的 count 值,依序為
0000001 = (1100100 & 1000000) ? (0000000 << 1) + 1 : 0000000 << 1
0000011 = (1100100 & 0100000) ? (0000001 << 1) + 1 : 0000001 << 1
0000110 = (1100100 & 0010000) ? (0000011 << 1) + 1 : 0000011 << 1
0001100 = (1100100 & 0001000) ? (0000110 << 1) + 1 : 0000110 << 1
0011001 = (1100100 & 0000100) ? (0001100 << 1) + 1 : 0001100 << 1
0110010 = (1100100 & 0000010) ? (0011001 << 1) + 1 : 0011001 << 1
1100100 = (1100100 & 0000001) ? (0110010 << 1) + 1 : 0110010 << 1
算出 count 之後,將用於 hashtable 中,儲存我們每一階段計算好的 fibonacci ,有f(0), f(1), f(3), f(6), f(12), f(25), f(50), f(100)
當我們要嘗試驗證我們儲存的資料是否正確,我們需要先確認好儲存位置,分別為f(0), f(1), f(3), f(6), f(12), f(25), f(50), f(100),再針對key 設為 0,1,3,6,12,25,50,100
可得到以下結果,確定 f(0), f(1), f(3), f(6), f(12), f(25), f(50), f(100) 在 hashtable 中儲存是正確的
文字訊息「不要」用圖片展現,尊重視覺障礙者閱讀的權益。
上圖結果和 WolframAlpha 一致
也可以透過 dmeg
檢查我們的是否成功儲存我們的數值,命令如下
我們考慮 fast doubling 和 Fibonacci 數的特性,所以不保存連續數值,而是關注第 N 個和第 2N 個 Fibonacci 數的關聯,儲存第 N 個和第 2N 個 Fibonacci 數,降低記憶體開銷。
針對我們的 hashtable 逐一釋放記憶體
參考 The __init
and __exit
Macros其中提到以下內容
The
__exit
macro causes the omission of the function when the module is built into the kernel, and like__exit
, has no effect for loadable modules. Again,if you consider when the cleanup function runs, this makes complete sense;
於是便把 hashtable_release
放在 __exit
內部
研究中…
〈Concurrency Managed Workqueue(cmwq)〉提到,cmwq 是 wq 的改進,專注以下目標