contributed by < kylekylehaha
>
linux2020
計算 load average 時,採用指數平滑法以及定點數。這邊我們主要討論定點數的運用。
這邊簡單介紹定點數:
e.g.
浮點數 0.5 換成 3 位精準度的定點數:
在探討code之前,需要先了解 linux load average 如何計算。
其中, 對應於 1min, 5min, 15min 分别是0.920044415, 0.983471454, 0.994459848。
由於該公式不能直接在 linux kernel 用浮點數計算,因此採用定點數來運算。這裡我們用 1min 來解釋,將小數位數定為 2 進制的的 11 位。
最後可以將原本公式改寫成
終於,來進入我們的程式碼。
在include/linux/sched.h 中,先來看一些marco
接著,在kernel/sched/proc.c,我們來看calc_global_load
,當中呼叫calc_load
即為上述公式的運算。
當 load average 計算出來後,我們必須正確的將結果顯示出來。
在fs/proc/loadavg.c 可以找到一下程式碼。
LOAD_INT
: 即為將小數去掉,顯示整數部份。
LOAD_FRAC
: 因 FIXED_1 = ,FIXED_1 - 1 = 。透過 AND 的方式即可取出小數部份。
接著將其乘以 100 後,再取 LOAD_INT
,即為小數前面的兩位數。
從 test-simple.c
中,可以看到在 main
中主要呼叫兩個函式: expr_create
& expr_eval
。
expr_create
: 將字串轉成 expr
type。expr_eval
: 則是計算結果,並回傳 float 型態。expr_create
:
expr_next_token
,去找出token。expr_calc
:
case OP_UNARY_MINUS
case OP_DIVIDE
在 experssion.h
中,可以找到 struct expr_func
。
name
: 函式名稱f
: function pointer在 test-simple.h
中,我們定義 add
,並將自己定義的函式加入 user_funcs[]
。之後,user_func
也會一同被丟入 expr_create
,去判斷字串中是否含有自定義的函式。
在 expression.c
中可以找到 expr_func
,用來判斷字串中是否含有自定義的函式。
除法負數處理
在做除法之前,我們先判斷被除數或除數是否為負數,用 sign
來紀錄該運算結果為正或負。因此我們將 n1
及 n2
都變為正數後再去做除法運算後,其結果與正確結果差一個原本的 sign
。故在最後 n3
乘上 sign
做修正。
加法的 overflow 處理
當計算完 n1 + n2
時,須檢查是否產生 overflow。如果產生 overflow,則一律回傳 -1,並用 printk
印出發生overflow。
乘法的 overflow 處理
乘法的部份,分成 frac
與 num
兩個部份:
frac
判斷方式和加法一樣: 當兩個正數相加變成負數時,即為發生overflow ; 當兩個負數相加變成正數時,即為發生 overflow。
num
判斷方式我們採乘完的結果除乘數,應為被乘數,來判斷是否發生 overflow。
如果發生 overflow,則印出警告訊息,並回傳 -1。
減法 underflow 的處理
判斷減法 underflow,分成兩種 case:
n1
大於結果 n3
,n2
小於零。n1
小於結果 n3
,n2
大於零。根據上面所談到的,若要加入自訂的函數,只須在 user_funcs[]
加入即可。這邊我們加入 user_func_fib
和 user_func_fib_cleanup
。
我們在 user_func_fib
中先呼叫 expr_eval(&vec_nth(&args, 0))
,來取得變數 n
,也就是欲計算的第 n
項 fibonacci number。之後,在傳入計算 fibonacci 的函式 fib_clz
。(此函式目前錯誤的,之後要利用 livepatch 進行修補。)
接著來到 livepatch-calc.c
中,在 funcs
內加入欲修改的函式。
.old_name
為欲修改的函式名稱。.new_func
為用來修補的函式名稱。因此,我們在這邊利用 livepatch_fib
來修補原本的 fib_clz
。
這邊我們利用 fibdrv 中的 clz
指令,以及 fast doubling 來做 fibonacci 的計算。
n
為 expr_eval
的回傳值,其中 MathEx 的格式由左至右分別為:
故真實所代表的 number,其公式為:
也就是 script/eval.sh
中 fromfixed
的內容。
來測試一下,在 scripts/test.sh
中加入 fib(11)。