[RCU stall] RCU stall 分析,RCU stall 內核文檔翻譯


使用RCU的CPU失速檢測器

 

本文檔首先討論RCU的CPU停頓檢測器可以定位哪些問題,然后討論可用於微調檢測器操作的內核參數和Kconfig選項。最后,本文解釋了失速檢測器的“splat”格式。

 

是什么導致RCU CPU停頓警告?

 

是因為您的內核會打印RCU CPU停止警告。下一個問題是“是什么原因引起的?” 以下問題可能導致RCU CPU停頓:

 

警告:

 

o             RCU read-side 關鍵部分中出現CPU循環。

o             禁用中斷時出現CPU循環。

o             禁用搶占時出現CPU循環。這種情況可能會導致RCU調度的停頓,並且,如果使用kso??ftirqd,則會導致RCU-bh停頓。

o             下半部禁用時出現CPU循環。這種情況可能導致RCU調度和RCU-bh停頓。

o             對於!CONFIG_PREEMPT內核,CPU可以在內核中的任何位置循環,而無需調用schedule()。如果確實確實希望在內核中循環,這是您期望的行為,則可能需要向cond_resched()添加一些調用。

 

o             使用太慢的控制台連接來引導Linux,以致無法跟上引導時控制台消息的速率。例如,115Kbaud串行控制台的速度可能太慢而無法跟上啟動時消息的速率,經常會導致RCU CPU停頓警告消息。特別是如果您添加了printk()調試代碼。

 

o             阻止RCU寬限期kthread運行的任何措施。這可能會導致“All QSes seen”控制台日志消息。此消息將包含有關kthread上次運行的時間以及應該運行的頻率的信息。它還可能導致控制台日志消息“ rcu _.*kthread starved for”,其中將包含其他調試信息。

 

O             CONFIG_PREEMPT內核中的CPU綁定的實時任務,這可能恰好搶占了RCU讀取側關鍵部分中間的低優先級任務。如果不允許該低優先級任務在任何其他CPU上運行,則這尤其有害,在這種情況下,下一個RCU寬限期將永遠無法完成,最終將導致系統內存不足並掛起。當系統正在運行其自身的內存不足時,您可能會看到停頓警告消息。

 

o             CONFIG_PREEMPT_RT內核中的CPU綁定實時任務,其運行優先級高於RCU softirq線程。這將防止調用RCU回調,並且在CONFIG_PREEMPT_RCU內核中,將進一步防止RCU寬限期完成。無論哪種方式,系統最終都將耗盡內存並掛起。在CONFIG_PREEMPT_RCU情況下,您可能會看到stall-warning消息。

 

o             周期性中斷,其處理程序花費的時間比連續兩次中斷之間的時間間隔長。這可以阻止RCU的kthread和softirq處理程序運行。請注意,某些高開銷的調試選項(例如function_graph跟蹤程序)可能導致中斷處理程序花費的時間比正常時間長得多,進而可能導致RCU CPU停頓警告。

 

o             在快速的系統上測試工作負載,將停頓警告超時降低到幾乎不能避免RCU CPU停頓警告,然后在慢速系統上以相同的停頓警告超時運行相同的工作負載。請注意,溫度控制器和按需調速器可能導致單個系統有時快而有時慢!

 

o             硬件或軟件問題關閉了不在dyntick-idle模式下的CPU上的調度程序時鍾中斷。此問題確實發生過,並且似乎最有可能導致CONFIG_NO_HZ_COMMON = n內核出現RCU CPU停頓警告。

 

o             RCU實現中的錯誤。

 

o             硬件故障。雖然不太可能的,但在現實生活中發生過。一個正在運行的系統中的CPU發生故障,變得無響應,但沒有立即導致崩潰。這導致了一系列RCU CPU停頓警告,最終導致人們認識到CPU發生了故障。

 

RCU/RCU-sched/RCU-bh和RCU-tasks實現具有CPU停止警告。注意SRCU確實沒有CPU停止警告。請注意,只有在寬限期內,RCU才會檢測到CPU停頓。沒有寬限期,沒有CPU停頓警告。

 

要診斷失速的原因,請檢查堆棧蹤跡。需要關注的函數通常位於堆棧頂部附近。如果您從單個擴展的停頓中獲得了一系列停頓警告,則比較堆棧跟蹤通常可以幫助確定發生停頓的位置,通常該函數位於最靠近棧頂部分(與跟蹤保持不變)頂部的函數中追蹤。如果您可以可靠地觸發停頓,則ftrace可能會很有幫助。

 

通常可以借助CONFIG_RCU_TRACE和RCU的事件跟蹤來調試RCU錯誤。有關RCU事件跟蹤的信息,請參見 include/trace/events/rcu.h。

 

微調RCU CPU失速檢測器

 

rcu update.rcu_cpu_stall_suppress模塊參數禁用RCU的CPU停頓檢測器,該檢測器檢測不適當地延遲RCU寬限期的條件。 默認情況下,此模塊參數啟用CPU停頓檢測,但可以通過啟動時參數或在運行時通過sysfs進行覆蓋。停頓檢測器對“過度延遲”的含義由一組內核配置變量和cpp宏控制:

 

CONFIG_RCU_CPU_STALL_TIMEOUT

 

此內核配置參數定義RCU從寬限期開始到發出RCU CPU停止警告的等待時間,該時間段通常為21秒。

 

可以在運行時通過 /sys/module/rcupdate/parameters/ rcu_cpu_stall_timeout更改此配置參數,但是僅在循環開始時才檢查此參數。因此,如果您進入40秒停頓的時間為10秒,則將此sysfs參數設置為(例如)5將縮短-next-停頓的超時時間,或者縮短當前停頓的以下警告時間(假設停頓持續足夠長的時間)。它不會影響當前停頓的下一個警告的時間。

 

可以通過 /sys/module/rcupdate/parameters/rcu_cpu_stall_suppress 完全啟用和禁用失速警告消息。

 

RCU_STALL_DELAY_DELTA

 

盡管lockdep工具非常有用,但確實會增加一些開銷。因此,在CONFIG_PROVE_RCU下,RCU_STALL_DELAY_DELTA宏在給出RCU CPU停頓警告消息之前允許額外的五秒鍾。(這是一個cpp宏,而不是內核配置參數。)

 

RCU_STALL_RAT_DELAY

 

CPU停頓檢測器試圖使有問題的CPU打印自己的警告,因為這通常會提供質量更好的堆棧跟蹤。但是,如果有問題的CPU在RCU_STALL_RAT_DELAY指定的抖動數量中未檢測到自己的停頓,則其他CPU會檢查。此延遲通常設置為2個jiffies。(這是一個cpp宏,而不是內核配置參數。)

 

rcupdate.rcu_task_stall_timeout

 

此boot/sysfs參數控制RCU任務停止警告間隔。零或更少的值將抑制RCU任務停止警告。正值將設置stall-warning警告間隔(單位為jiffies)。RCU-tasks停頓警告從以下行開始:

 

INFO: rcu_tasks detected stalls on tasks:

 

並繼續執行每個任務的sched_show_task()輸出,以停止當前的RCU-tasks寬限期。

 

解釋RCU的CPU停頓檢測器 "Splats"

 

對於RCU的非RCU-tasks類型,當CPU檢測到它正在停止時,它將打印類似於以下內容的消息:

INFO: rcu_sched detected stalls on CPUs/tasks:

2-...: (3 GPs behind) idle=06c/0/0 softirq=1453/1455 fqs=0

16-...: (0 ticks this GP) idle=81c/0/0 softirq=764/764 fqs=0

(detected by 32, t=2603 jiffies, g=7075, q=625)

 

此消息表明CPU 32檢測到CPU 2和16都引起了停頓,並且該停頓正在影響RCU調度的時間。在此消息后通常會出現每個CPU的堆棧轉儲。請注意,PREEMPT_RCU builds可以由任務以及CPU停止,並且任務將由PID指示,例如“ P3421”。甚至有可能由兩個CPU和任務引起rcu_preempt_state停頓,在這種情況下,將在列表中調出所有有問題的CPU和任務。

 

CPU 2's "(3 GPs behind)" 表示該CPU在過去的三個寬限期內未與RCU內核進行交互。相反,CPU 16's "(0 ticks this GP)" 表示該CPU在當前停滯的寬限期內沒有采取任何調度時鍾中斷。

 

log中的"idle="部分顯示dyntick-idle狀態。第一個"/"之前的十六進制數是dynticks計數器的低12位,如果CPU處於dyntick-idle模式,則其將具有偶數值,否則,將具有奇數值。兩個"/"之間的十六進制數是嵌套的值,如果在空閑循環中,則將是一個小的非負數(如上所示),否則將是一個非常大的正數。

 

log中的"softirq="部分跟蹤停滯的CPU已執行的RCU softirq處理程序的數量。"/"之前的數字是自該CPU啟動以來到上次記錄寬限期開始時執行的數字,寬限期可能是當前的(停頓的)寬限期,也可能是更早的寬限期(例如,如果CPU可能長時間處於dyntick-idle模式,而"/"后的數字是自啟動以來直到當前時間為止執行的數字。警告消息,則可能是RCU的softirq處理程序不再能夠在此CPU上執行。如果停滯的CPU在中斷時自旋,或者在-rt內核中,可能會發生這種情況。

 

"fps="表示自該CPU上次注意到寬限期開始以來,寬限期kthread在該CPU上進行的強制靜態狀態空閑/脫機檢測通過的次數。

 

"detected by"行指示哪個CPU檢測到停頓(在這種情況下為CPU 32),自寬限期開始(在這種情況下為2603)以來已經經過了多少次jiffies,寬限期序號(7075),並估算所有CPU中排隊的RCU回調總數(在這種情況下為625)。

 

在具有CONFIG_RCU_FAST_NO_HZ的內核中,將為每個CPU打印更多信息:

 

0: (64628 ticks this GP) idle=dd5/3fffffffffffffff/0 softirq=82/543 last_accelerate: a345/d342 nonlazy_posted: 25 .D

 

當該CPU上次從rcu_needs_cpu()調用rcu_try_advance_all_cbs()或從rcu_prepare_for_idle()上一次調用rcu_accelerate_cbs()時,"last_accelerate:"打印jiffies計數器的低16位(十六進制)。"nonlazy_posted:"顯示自上次調用rcu_needs_cpu()以來發布的非延遲回調的數量。

最后,"L"表示當前沒有非延遲回調(如上所示,否則打印"."),而"D"表示啟用dyntick-idle處理(否則打印".",例如,如果通過"nohz="內核引導參數禁用了)。

 

如果在停止警告開始打印時寬限期結束,則會出現虛假的停止警告消息,其中包括以下內容:

 

INFO: Stall ended before state dump start

 

這種情況很少見,但在現實生活中確實時有發生。在這種情況下,也可以標記zero-jiffy的失速,具體取決於失速警告和寬限期初始化如何發生相互作用。請注意,如果不訴諸stop_machine()之類的事情,就不可能完全消除這種誤報,這對於此類問題來說是過大的。

 

如果所有CPU和任務都經過了quiescent狀態,但是寬限期仍未結束,則停頓警告腳本將包括以下內容:

 

All QSes seen, last rcu_preempt kthread activity 23807 (4297905177-4297881370), jiffies_till_next_fqs=3, root ->qsmask 0x0

 

"23807"表示自寬限期kthread運行以來,已超過2.3萬次jiffies。"jiffies_till_next_fqs"表示該kthread應該運行的頻率,給出兩次強制靜態掃描之間的間隔,在這種情況下為3,比23807小得多。最后,打印出 root rcu_node structure的-> qsmask字段,通常為零。

 

如果相關的寬限期kthread在停頓警告之前無法運行(如上面"All QSes seen"行中的情況),則會打印以下附加行:

 

kthread starved for 23807 jiffies! g7075 f0x0 RCU_GP_WAIT_FQS(3) ->state=0x1 ->cpu=5

 

即使所有CPU和任務均已通過所需的靜態狀態,使CPU時間的寬限期kthreads Starving, 當然也會導致RCU CPU停頓警告。"g"數字顯示當前的寬限期序列號,"f"在寬限期kthread的-> gp_flags命令之前,"RCU_GP_WAIT_FQS"指示kthread正在等待短暫的超時,"state"在task_struct-> state字段的值之前,"cpu"表示寬限期kthread最后在CPU 5上運行。

 

一個stall時的多個警告

 

如果停頓持續足夠長的時間,則會為它打印多個停頓警告消息。第二條消息和后續消息的打印時間間隔較長,因此(例如)第一條消息和第二條消息之間的時間大約是停頓開始時間和第一條消息之間的間隔的三倍。

 

Expedited寬限期的失速警告

 

如果expedited的寬限期檢測到停頓,它將在dmesg中放置如下消息:

 

INFO: rcu_sched detected expedited stalls on CPUs/tasks: { 7-... } 21119 jiffies s: 73 root: 0x2/.

 

這表明CPU 7無法響應重新調度IPI。CPU編號后面的三個句點("...")表示CPU處於在線狀態(否則,第一個周期為"O"),CPU在加寬寬限期開始時處於在線狀態(否則,第二個周期而是從啟動開始,CPU至少已聯機一次(否則,第三個時間段將改為"N")。"jiffies"之前的數字表示加速的寬限期已經進行了21119個jiffies。"s:"后面的數字表示expedited寬限期序列計數器為73。該最后一個值為奇數的事實表示加倍寬限期正在運行。"root:"之后的數字 是一個位掩碼,指示根rcu_node結構的哪些子代對應於阻止當前加急寬限期的CPU and/or tasks。如果樹具有多個級別,則將為樹中其他rcu_node結構的狀態打印其他十六進制數字。

 

與正常寬限期一樣,PREEMPT_RCU構建可以由任務以及CPU暫停,並且任務將由PID指示,例如"P3421"。

 

完全有可能在同一輪運行中同時從正常和加速寬限期看到失速警告。


免責聲明!

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



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