contributed by < jwang0306
>
0
求 和 1
求 和 ,再求 __builtin_clz()
得到 leading zero 的數量,再用 32 減掉,即為第一個非 0 的起始位置lsmod
的輸出結果有一欄名為 Used by
,這是 “each module’s use count and a list of referring modules”,但如何實作出來呢?模組間的相依性和實際使用次數 (reference counting) 在 Linux 核心如何追蹤呢?fibdrv.c
存在著 DEFINE_MUTEX
, mutex_trylock
, mutex_init
, mutex_unlock
, mutex_destroy
等字樣,什麼場景中會需要呢?撰寫多執行緒的 userspace 程式來測試,觀察 Linux 核心模組若沒用到 mutex,到底會發生什麼問題沒有 lock
fibdrv.c
的 mutex_trylock
拿掉,可以看到 thread 3 和 4 的順序是亂的有 mutex_trylock()
mutex_trylock
顧名思義會嘗試去取得 lock ,但是他不會等待,因此沒有取得 lock 的話該執行緒不會睡在那邊等,會直接回傳成功與否,然後接著下去執行了fibdrv
失敗,輸出也就會留白:有 mutex_lock()
mutex_lock
,如此一來若是沒有取得 lock ,該執行緒就會睡到可以取得為止等待 lock 所花時間
mutex_lock
直接得知 lock 到底是否正被佔著,因此我迂迴地進行了測試,如果 mutex_trylock
沒有搶到 lock ,那麼我就利用 mutex_lock
再去搶一次,目的是為了讓該 thread 「卡」在那邊,直到其他 thread 將 lock 釋出mutex_unlock
,否則程式會整個當掉,因為後面的執行緒永遠等不到 lockfd
會小於 0 ,再把所花時間印出來,即為該 thread 的等待時間經過多次實驗,有五個執行緒的情況下,萬一某執行緒沒有搶到 lock ,其等待的時間約為好幾萬、甚至是幾十萬 nsec 。因此在我們這個 case 底下,若是有多個執行緒,且只是單純對檔案進行讀取、沒有對共享資源進行操作的話,不使用 lock 的整體速度表現上會比較好(假設對輸出順序不在意,畢竟數字的計算仍然正確)。
我參考了 ambersun 的作法。我透過暫時修改 write
函式來計時:
回傳到 user space 時再透過與 monotonic time 之間的差異來得到 kernel to user 與 user to kernel 的時間:
如果作法是將 user space 測得的 fibonacci 執行時間與 kernel space 測得的 fibonacci 執行時間相減,那麼嚴格說起來是 kernel to user 與 user to kernel 時間的總和(藍色的線),並不能代表任何一方:
實驗結果顯示, user to kernel 的傳遞時間要多上一些。
首先進行干擾因素的排除,並透過 ktimer 於 kernel space 中測量執行不同 fibonacci 演算法所花的時間,回傳到 user space 再輸出並畫圖。全程透過指定 taskset 0x1
固定在同一個 CPU 上執行。
我們希望從 client 端去選擇想要執行的 fibonacci 方法,老師建議可以利用修改 sysfs 來完成。我原先透過 fib_write
來控制一個全域 integer 變數,然後根據這個 flag 來決定 fib_read
要執行的方法:
後來看到了 AndybnACT 的方法,我覺得比我的優雅多了,直接把 function 當成變數,就減少了我原先需要一直執行的 if-else block :
不是「直接把 function 當成變數」,而該說「傳遞 function pointer」,請複習 你所不知道的C語言:指標篇 和 你所不知道的 C 語言:物件導向程式設計篇,以得知 function pointer 使用案例。
jwang0306謝謝老師,已修正我錯誤的觀念以及說法
利用 __builtin_clz
找出 leading zero 從運算過程中排除,但與原本的 dynamic programming 版本放在一起比較時,看不出 fast double 演算法在 clz 的有無之下所造成的差異:
調整時間刻度再來觀察,關鍵是執行時間的分佈 (複習統計學)
jwang0306已補上實做,感謝老師提示
因此將有無 clz 與否的時間測量單獨拉出來比較,於每個 offset 採樣五次,畫出分佈圖,加入 clz 後於執行時間的分佈明顯低於沒有使用 clz 的版本,這時就能明顯看出加速了:
原本用 64 位元去存取,超過 之後就會遇到 overflow,也就是超出 64 位元無號整數所能表達的有效數值:
因此想法就是做一個大數運算,嘗試並評估後決定使用十進位來實做,因為二進位的轉換太難處理。
12345
arr[5,4,3,2,1,0,0,0,....]
,這樣迴圈可以從 0 開始算十進位運算麻煩之處:借位帶來的時間開銷和運算量。
jwang0306正在參考sysprog21/bignum的二進位實做手法
翻閱辭典,查閱「雙」的意義,不要將「二」和「雙」的適用情境搞混了!
jwang0306收到,附上辭典
12345
arr[5,4,3,2,1,0,0,0,....]
,因此從最後面數過來, 0 的話就減一,遇到非 0 時的 counter index 就是我要的 digit 數char *
型態的 buffer ,因此要將 integer 型態的一個一個數字放,要注意也要反過來放sprintf
在 Cppcheck 會跳出警告不給 commit ,因此改用 snprintf
copy_tp_user
回傳給 user space ,因為同樣叫做 buf
但是在 user space 和 kernel space 所指向的地址可能值會不同,因此不能直接透過 sprintf
寫進 buf
參數,否則整個 module 會直接被 Killedlong copy_to_user( void __user *to, const void * from, unsigned long n );
參考 sysprog21/bignum,全部用二進位就可透過 bitwise operation 加速