天天看點

Linux核心工作隊列探秘

工作隊列的節能特性最早由3.11核心引入,此後,50多個子系統和裝置驅動開始使用它。而節能工作隊列則被廣泛用于手持裝置(如平闆電腦,智能手機)。ARM平台上,在Android系統中使用節能工作隊列,可以顯著降低能源消耗。

在Linux kernel中,工作隊列是常見的延後執行機制,經常出現在異步執行上下文中。上下文由核心工作線程提供,當有任務被放入隊列(入隊操作)時,工作線程将會被喚醒。核心實作時,工作隊列由strut workqueue_struct表示,而任務由strut work_struct表示。work_struct中包含一個回調函數,該函數将會被工作線程調用,以表示任務被執行。一旦工作隊列上的所有任務執行完畢,工作線程又繼續睡眠。

下面是工作隊列相關的常見API:

bool queue_work(...); bool queue_work_on(...); bool queue_delayed_work(...); bool queue_delayed_work_on(...);

queue_work_on()和queue_delayed_work_on()指定了任務由哪個cpu上的工作線程執行,另兩個函數允許任務運作在任意cpu上。對于前兩個函數,任務将會被立即執行;而對于後兩個函數,任務需要等待一段時間才會被執行。

綁定工作隊列的缺陷

在核心中,一種常見的使用工作隊列的場景是處理周期性的工作:不斷重複執行隊列任務,并由回調函數重新将任務放入隊列。下面是一段示範程式: 

static void foohandler(struct work_struct *work)
{
    struct delayed_work *dwork = to_delayed_work(work);
    /* Do some work here */
    queue_delayed_work(system_wq,dwork,10);
}
voidfoo_init(void)
{
    struct delayed_work *dwork = kmalloc(sizeof(*dwork), GFP_KERNEL);
    INIT_DEFERRABLE_WORK(dwork,foo_handler);
    queue_delayed_work(system_wq,dwork,10);
}      

讀者可能會認為,任務将會被任意cpu執行(由排程器選出一個最合适的cpu)。遺憾的是,這不完全正确。工作隊列機制傾向于将任務放入local cpu(即,執行queue_delayed_work()的那個cpu),除非local cpu被wq_unbound_cpumask屏蔽了。舉個例子,在8核平台上,上面示範程式中的回調函數總是在一個cpu上執行,盡管該cpu處于idle狀态且存在其它cpu處于運作狀态。

wq_unbound_cpumask表示可以執行“工作隊列任務”的cpu集合,注意,隻有當該任務沒有通過API(xxx_work_on())指定到某個特定的cpu時,該掩碼才生效。該掩碼可以通過 /sys/devices/virtual/workqueue/cpumask設定。

從節能的角度看,一個正在執行正常程式的cpu被中斷,然後執行工作隊列任務,這是可接受的。反之,如果喚醒一個處于idle狀态的cpu,然後僅僅更新時鐘和将任務放入隊列,這将消耗更多能源。cpu綁定有時并不能帶來好的性能,因為被綁定的cpu并不一定是排程器認為的負載最輕的cpu,此時排程器不能進行負載均衡。

工作隊列的節能特性

預設情況下,工作隊列的節能特性是關閉的。使能該特性有兩種方式:

  1. 核心啟動參數 workqueue.power_efficient=true
  2. 編譯核心時打開開關 CONFIGWQPOWER_EFFICIENT = y

一旦使能節能模式,我們就可以在調用 alloc_workqueue() 時傳入WQ_POWER_EFFICIENT标志,建立節能工作隊列。核心中還維護了兩個全局的節能工作隊列:system_power_efficient_wq 和 system_freezable_power_efficient_wq,當使用者不想建立自己私有的隊列時,可以使用它們。

不同于之前的local cpu政策,節能模式下,任務入隊時,總是由排程器提供一個target cpu,然後将任務放入target cpu上的工作隊列。是以,現在任務可以在不同的cpu執行了。

不幸的是,這并不意味着排程器總是選擇一個最優的cpu去執行工作隊列任務。排程器的排程算法非常複雜,但總體上,它在考慮cache親和性的基礎上,傾向于選擇一個負載最輕的cpu。如果,工作隊列任務沒有被快速執行完,任務還有可能會被排程器遷移到别的cpu上。

節能特性的實作依賴于cpu排程器,但cpu排程器更主要的設計點是性能,其次才在排程政策中加入了能效方面的考慮。是以,目前實作的節能工作隊列顯然沒有采用最優的節能政策,但它在能效方面确實表現得更好了。

很自然的,我們會想到,是否所有的工作隊列都應該工作在節能模式下呢?節能工作隊列有一個明顯的缺點:每次執行任務都在不同的cpu上,cache親和性被破壞,可能會導緻大量cache miss(取決于任務的訪存特性),這會顯著降低性能。但有的時候,隊列任務對cache miss不敏感,排程器的負載均衡操作反而能顯著降低隊列任務的響應延遲。考慮到上述兩方面,在使用節能隊列時需要仔認真地評估。

測試資料

在32-bit ARM big.LITTLE平台上運作benchmark,該平台具有4個Cortex A7核和4個Cortex A15核。除了用aplay在背景播放音樂外,整個系統沒有其它負載。測試核心采用Linaro公司的ubuntu-devel版本,此外還打了一些排程器更新檔。測試結果顯示,節能工作隊列的能源效率平均提高15.7%。具體資料如下:

Vanilla kernel +        Vanilla   Kernel+
                                                 scheduler patches +
                 scheduler patches       power-efficient wq
A15 cluster      0.322866            0.2289042
A7 cluster       2.619137            2.2514632
Total               2.942003            2.4803674      

如果使用upstream kernel,節能工作隊列将會工作得更好。因為在後續排程其中,越來卻多的考慮了能源效率。

—— 完 ——

加入龍蜥社群

加入微信群:添加社群助理-龍蜥社群小龍(微信:openanolis_assis),備注【龍蜥】拉你入群;加入釘釘群:掃描下方釘釘群二維碼。歡迎開發者/使用者加入龍蜥OpenAnolis社群交流,共同推進龍蜥社群的發展,一起打造一個活躍的、健康的開源作業系統生态!

Linux核心工作隊列探秘
Linux核心工作隊列探秘

龍蜥社群釘釘交流群                            龍蜥社群-小龍

關于龍蜥社群

龍蜥社群是由企事業機關、高等院校、科研機關、非營利性組織、個人等按照自願、平等、開源、協作的基礎上組成的非盈利性開源社群。龍蜥社群成立于2020年9月,旨在建構一個開源、中立、開放的Linux上遊發行版社群及創新平台。

短期目标是開發Anolis OS作為CentOS替代版,重新建構一個相容國際Linux主流廠商發行版。中長期目标是探索打造一個面向未來的作業系統,建立統一的開源作業系統生态,孵化創新開源項目,繁榮開源生态。

龍蜥OS 8.4已釋出,支援x86_64和ARM64架構,完善适配Intel、飛騰、海光、兆芯、鲲鵬晶片。

歡迎下載下傳:

https://openanolis.cn/download

加入我們,一起打造面向未來的開源作業系統!

Https://openanolis.cn

繼續閱讀