依據 fibdrv 作業規範,重新進行 (刪去原有的 GitHub repository,做更好的自己!)。
閱讀 fibdrv 作業規範,包含「作業說明錄影」和「Code Review 錄影」,本著「誠實面對自己」的心態,在本頁紀錄所有的疑惑,並與授課教師預約討論。
過程中,彙整 Homework3 學員的成果,挑選至少三份開發紀錄,提出值得借鏡之處,並重現相關實驗。
回答「自我檢查清單」的所有問題,需要附上對應的參考資料和必要的程式碼,以第一手材料 (包含自己設計的實驗) 為佳
理解其中的技巧並導入到 fibdrv 中,並留意以下:
確保應用程式不需要過多的計算量才可重現 Fibonacci 數列,並需要充分驗證 fibdrv 行為。
分析程式的運行時間,可以作為性能好壞的判斷標準之一。使用 ktime_t
中的 ktime_get()
來紀錄在 kernel 中運行的時間,並經由 ktime_sub()
來計算經歷的時間長,方法如下
計算 Fibonacci 是在 fib_read()
中進行,因此在此函式中計算運行時間
參考 yanjiew1 的時間測量程式,將結果寫入 TimeTaken.txt
中,再匯入 Python 繪製數據圖
由圖形可以發現,隨著數列要計算的值越大,運算時間也會花費越多。另外,因為目前還沒有實作大數運算,因此在 Fibonacci sequence 第 92 個數字之後的計算耗時呈現定值
上面的數據圖是 fib_sequence()
尚未修正 Variable-length array (VLA) 在 Linux kernel 中不被允許的問題所繪製的圖,因為我將原本的陣列改為動態陣列後,雖然解決了 VLA 的問題,但是繪製出的圖形較不易看出趨勢,並且因為持續佔用記憶體的關係,導致運算時間較沒有一致性
可以使用 time.h
的 clock_gettime
在 user space 中進行時間測量。取得的時間即為 struct timespec
,其定義如下
若要將此結構的時間轉成 ktime_t
,只需要將時間單位都換成奈秒 (ns) 再相加即可,因為 ktime_t
是奈秒級別的結構
從繪製出的數據圖發現有幾個極端的數據點,導致數據圖較缺乏參考價值。因此參考 < 用統計手法去除極端值 > ,利用實作 4ce43c4 來將極端值去除,並且將 user space , kernel 以及 kernel to user 的時間花費圖放在一起做比較
理論上, kernel 的運算時間會較少, user space 的運算時間因為有經過資料傳輸,會比 kernel 還要多。從數值圖判斷,測量到的時間趨勢理論上是正確的。
在參考的程式碼中有一行 code 寫到
Ys
是圖中三個數據所組成的 array ,而上面這行 code 在做的事情是將刪除 的數據加入 Ys
中。一開始我不解為何要刪掉第一項數據,因此我就將沒有刪除的數據再畫一次圖
發現第一項數據會是極端值,因此先做數據刪除的動作。但還是不確定為何不會自動被 outlier_filter()
給濾掉
研讀〈費氏數列〉,知道費氏數列有多種不同的計算方法,這邊簡述其中三種方式
Fast doubling 的概念是只進行必要的運算,不會將目標項以前的每一個數值都計算出來。從上式 與 可以知道,想要求出 與 只需要用到 跟 項,計算量比遞迴加法少了一半以上
參考 fewletter 的實作,將 Fast doubling 的概念以下方程式碼呈現
再次進行時間測量,得到下方數據圖
相較於先前的遞迴加法,從數據圖中不難發現計算時間受費氏數列項次的影響盛微,並且 kernel to user 的傳輸時間降低了不少,使得 user space 的耗費時間壓在 1050 奈秒左右,至少比遞迴加法所耗費的時間少了 450 奈秒
礙於資料型態的空間限制, long long
只能儲存 64 位元的資料大小,若費氏數列的值超過 long long
所能夠儲存的範圍,則會發生溢位。為了支援大數運算,可以加入以下結構體
在結構體中,將大數以 為一個單位做進位, size
則儲存單位的數目
而為了要表示資料大小比 long long
還要大的數值,必須具備以下條件
bn
bn
運算bn_add
bn_swap
bn
的位置,常用於迭代bn_to_string
0
的差以 char 陣列儲存,並且從高位逐一檢查是否有進位,若有進位則處理成沒有進位的數字bn
加入費氏數列的運算參考程式碼將 bn
加入費氏數列的計算
接著將加入大數運算的程式進行時間測量,把 設為 1000 觀察數據圖的趨勢
從結果來看,此圖形是合理的。隨著計算量變大,運算時間也跟著拉長,同時因為資料傳輸量變大的緣故, user space 所耗費的時間相比於在 kernel 進行運算要長很多