Linux scheduler 排程原始碼初步閱讀

2021-10-05 12:30:17 字數 2980 閱讀 6572

schedule 流程

可排程實體的vruntime、load計算

為什麼要先看fork的源**呢?

因為在schedule函式裡面一開始我就有點看不懂:

cpu = smp_processor_id();
按理來說很好理解呀,不就是獲取當前的cpu的id嗎?但是什麼叫做當前?在多處理器的機器上面,當前的定義是什麼?是在哪一塊cpu上面?我有點搞不懂,所以開始先看看fork都做了些什麼。

具體的流程可以看上面的圖,fork系統呼叫走到最後呼叫的是kernel/fork.c裡面的do_fork函式。

上圖中,我只是把我認為關鍵的函式提了出來。

從上面的圖可以看到do_fork有兩個主要的函式:

copy_process 和 wake_up_new_task

copy_process 主要是對父程序task struct 的複製,做一些新程序的初始化,然後呼叫sched_fork函式。

sched_fork
主要就是這兩個函式,先獲取當前的cpu的id,好了,又是當前cpu,但是現在這個當前比較好理解:因為肯定是有乙個執行緒來呼叫fork這個函式的,不管是直接還是間接。這個執行緒能執行那肯定是在某一塊cpu上面,那麼get_cpu()函式就是獲取當前執行這個執行緒的cpu。然後暫時把新的執行緒的可執行cpu設定跟呼叫fork的執行緒一樣。

注意這裡只是暫時地設定,而且新的執行緒並沒有真正地執行在任何一塊cpu上面。

wake_up_new_task
主要的函式就是上面的這些,還是先獲取當前的cpu id,然後到了最重要的函式:select_task_rq,這個函式會根據新建立的這個執行緒所屬的排程類去執行不同的select_task_rq。

對於real time 任務

看當前在這個cpu上面執行的任務【當前任務】是不是realtime的,當前任務是否之能在這個cpu上面執行,新建的執行緒能否在其他的cpu上面執行。如果都滿足的話,就會呼叫find_lowest_rq來獲取可執行的cpu,否則直接返回當前的cpu。

對於normal任務(cfs)

先會根據cgroup,cpu_domain,task cpu親和性來選取適合的cpu,如果沒有這些要求的話,那麼會找到負載最低的cpu。

呼叫完這個函式之後,再呼叫set_task_cpu就設定相關的task struct 裡面的變數。最後再呼叫activate_task這個函式,activate_task又會呼叫enqueue_task這個函式,這個函式也是根據不同的排程類去呼叫不同的函式、

對於real time 任務

直接放入rt_rq對應優先順序的鍊錶尾。

對於normal任務(cfs)

放入cfs_rq的紅黑樹裡面。

好了,到這裡整個fork流程就結束了,只是粗略地走了一遍,很多細節等到需要閱讀相關模組的時候再深入。

看這個fork的流程的目的是知道smp_process_id()這個函式到底是獲得哪一塊cpu,現在已經清楚了,就是獲取當前程序執行的cpu,schedule函式也跟fork一樣,是被一些程序通過系統呼叫來呼叫的,所以能獲取當前程序的cpu。

schedule比較清晰,主要的函式只有三個

schedule
這個函式會根據不同的排程類來排程不同的函式,我暫時只看到了實時任務的排程類實現了這個函式。

會把其他cpu裡面的比當前cpu實時佇列的最高優先順序低的任務拉到當前的cpu實時佇列裡面。

這個就是主要的選取下乙個可以執行的任務的函式。

if (likely(rq->nr_running == rq->cfs.nr_running))
先是乙個小優化,然後再遍歷每個排程類來排程不同的函式

對於real time 任務

選取最高優先順序佇列鍊錶裡面的第乙個任務。

對於normal任務(cfs)

選取vrun_time最小的那個任務,紅黑樹最左邊的那個節點。

這個就是跟體系相關的上下文切換函式了,儲存暫存器裡面的值等等。

vruntime:

具體**在:kernel/sched_fair.c:__update_curr()

__update_curr()

update_delta_fair()

calc_delta_mine()

最主要的函式是最後乙個,裡面的計算邏輯除開對溢位的處理外,最後歸成下面的式子:

delta = delta * weight / lw

對於cfs的計算,weight是nice值為0的程序weight:1024

lw是可排程實體的curr->load.weight

load weight:

static const int prio_to_weight[40] = ;

max_rt_prio

set_load_weight()

通過上面可以看到,只有cfs的程序load weight有意義。同時這個load weight 在程序進入cpu的cfs rq的時候也會把這個值加到就緒佇列的load上面來反應這個cpu的負載程度。

《深入理解linux核心》

《深入linux核心架構》

spark調優 shuffle調優

基於spark1.6 引數可以通過 new sparkcontext set 來設定,也可以通過命令的引數設定 conf spark.shuffle.file.buffer 預設值 32k 引數說明 該引數用於設定shuffle write task的bufferedoutputstream的buf...

Spark Spark調優 資源調優

spark在乙個executor的記憶體分為三塊,1.一塊是execution記憶體 2.一塊是storge 記憶體 3.一塊是其他記憶體 執行記憶體是執行記憶體,加入,聚合都是在這部分記憶體中執行.shuffle的資料也會先快取在這個記憶體中,滿了再寫入磁碟,能減少io,其實地圖過程也是在這個記憶...

尾調遞迴 ,尾調優化

尾調優化 title head body p pre 尾調優化,值得是函式最後一步呼叫了另乙個函式,函式呼叫會在內部形成乙個 呼叫記錄 儲存呼叫位置,內部變數等,a函式呼叫b函式,形成乙個 a到b的呼叫幀,直到結果返回,幀消失,b呼叫c函式,這樣,就形成了 呼叫棧,pre p h4 pre 尾調,不...