LINUX內核CPU負載均衡機制【轉】


轉自:http://oenhan.com/cpu-load-balance

還是神奇的進程調度問題引發的,參看Linux進程組調度機制分析,組調度機制是看清楚了,發現在重啟過程中,很多內核調用棧阻塞在了double_rq_lock函數上,而double_rq_lock則是load_balance觸發的,懷疑當時的核間調度出現了問題,在某個負責場景下產生了多核互鎖,后面看了一下CPU負載平衡下的代碼實現,寫一下總結。

內核代碼版本:kernel-3.0.13-0.27。

內核代碼函數起自load_balance函數,從load_balance函數看引用它的函數可以一直找到schedule函數這里,便從這里開始往下看,在__schedule中有下面一句話。

從上面可以看出什么時候內核會嘗試進行CPU負載平衡:即當前CPU運行隊列為NULL的時候。
CPU負載平衡有兩種方式:pull和push,即空閑CPU從其他忙的CPU隊列中拉一個進程到當前CPU隊列;或者忙的CPU隊列將一個進程推送到空閑的CPU隊列中。idle_balance干的則是pull的事情,具體push下面會提到。
在idle_balance里面,有一個proc閥門控制當前CPU是否pull:

sysctl_sched_migration_cost對應proc控制文件是/proc/sys/kernel/sched_migration_cost,開關代表如果CPU隊列空閑了500us(sysctl_sched_migration_cost默認值)以上,則進行pull,否則則返回。
for_each_domain(this_cpu, sd) 則是遍歷當前CPU所在的調度域,可以直觀的理解成一個CPU組,類似task_group,核間平衡指組內的平衡。負載平衡有一個矛盾就是:負載平衡的頻度和CPU cache的命中率是矛盾的,CPU調度域就是將各個CPU分成層次不同的組,低層次搞定的平衡就絕不上升到高層次處理,避免影響cache的命中率。

圖例如下;
oenhan_sched_domain

最終通過load_balance進入正題。

首先通過find_busiest_group獲取當前調度域中的最忙的調度組,首先update_sd_lb_stats更新sd的狀態,也就是遍歷對應的sd,將sds里面的結構體數據填滿,如下:

 

決定選擇調度域中最忙的組的參照標准是該組內所有 CPU上負載(load) 的和, 找到組中找到忙的運行隊列的參照標准是該CPU運行隊列的長度, 即負載,並且 load 值越大就表示越忙。在平衡的過程中,通過比較當前隊列與以前記錄的busiest 的負載情況,及時更新這些變量,讓 busiest 始終指向域內最忙的一組,以便於查找。
調度域的平均負載計算

在比較負載大小的過程中, 當發現當前運行的CPU所在的組中busiest為空時,或者當前正在運行的 CPU隊列就是最忙的時, 或者當前 CPU隊列的負載不小於本組內的平均負載時,或者不平衡的額度不大時,都會返回 NULL 值,即組組之間不需要進行平衡;當最忙的組的負載小於該調度域的平均負載時,只需要進行小范圍的負載平衡;當要轉移的任務量小於每個進程的平均負載時,如此便拿到了最忙的調度組。
然后find_busiest_queue中找到最忙的調度隊列,遍歷該組中的所有 CPU 隊列,經過依次比較各個隊列的負載,找到最忙的那個隊列。

通過上面的計算,便拿到了最忙隊列。
當busiest->nr_running運行數大於1的時候,進行pull操作,pull前對move_tasks,先進行double_rq_lock加鎖處理。

move_tasks進程pull task是允許失敗的,即move_tasks->balance_tasks,在此處,有sysctl_sched_nr_migrate開關控制進程遷移個數,對應proc的是/proc/sys/kernel/sched_nr_migrate。
下面有can_migrate_task函數檢查選定的進程是否可以進行遷移,遷移失敗的原因有3個,1.遷移的進程處於運行狀態;2.進程被綁核了,不能遷移到目標CPU上;3.進程的cache仍然是hot,此處也是為了保證cache命中率。

判斷進程cache是否有效,判斷條件,進程的運行的時間大於proc控制開關sysctl_sched_migration_cost,對應目錄/proc/sys/kernel/sched_migration_cost_ns

在load_balance中,move_tasks返回失敗也就是ld_moved==0,其中sd->nr_balance_failed++對應can_migrate_task中的"too many balance attempts have failed",然后busiest->active_balance = 1設置,active_balance = 1。

push整個觸發操作代碼機制比較繞,stop_one_cpu_nowait把active_load_balance_cpu_stop添加到cpu_stopper每CPU變量的任務隊列里面,如下:

而cpu_stopper則是cpu_stop_init函數通過cpu_stop_cpu_callback創建的migration內核線程,觸發任務隊列調度。因為migration內核線程是綁定每個核心上的,進程遷移失敗的1和3問題就可以通過push解決。active_load_balance_cpu_stop則調用move_one_task函數遷移指定的進程。

上面描述的則是整個pull和push的過程,需要補充的pull觸發除了schedule后觸發,還有scheduler_tick通過觸發中斷,調用run_rebalance_domains再調用rebalance_domains觸發,不再細數。

 


Linux內核CPU負載均衡機制來自於OenHan

鏈接為:http://oenhan.com/cpu-load-balance


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM