1. 程式人生 > >核心如何檢測soft lockup與hard lockup?

核心如何檢測soft lockup與hard lockup?

原帖地址:

所謂lockup,是指某段核心程式碼佔著CPU不放。Lockup嚴重的情況下會導致整個系統失去響應。Lockup有幾個特點:

  • 首先只有核心程式碼才能引起lockup,因為使用者程式碼是可以被搶佔的,不可能形成lockup(只有一種情況例外,就是SCHED_FIFO優先順序為99的實時程序即使在使用者態也可能使[watchdog/x]核心執行緒搶不到CPU而形成soft lock,參見《Real-Time程序會導致系統Lockup嗎?》)
  • 其次核心程式碼必須處於禁止核心搶佔的狀態(preemption disabled),因為Linux是可搶佔式的核心,只在某些特定的程式碼區才禁止搶佔,在這些程式碼區才有可能形成lockup。

Lockup分為兩種:soft lockup 和 hard lockup,它們的區別是 hard lockup 發生在CPU遮蔽中斷的情況下。

  • Soft lockup是指CPU被核心程式碼佔據,以至於無法執行其它程序。檢測soft lockup的原理是給每個CPU分配一個定時執行的核心執行緒[watchdog/x],如果該執行緒在設定的期限內沒有得到執行的話就意味著發生了soft lockup,[watchdog/x]是SCHED_FIFO實時程序,優先順序為最高的99,擁有優先執行的特權。
  • Hard lockup比soft lockup更加嚴重,CPU不僅無法執行其它程序,而且不再響應中斷。檢測hard lockup的原理利用了PMU的NMI perf event,因為NMI中斷是不可遮蔽的,在CPU不再響應中斷的情況下仍然可以得到執行,它再去檢查時鐘中斷的計數器hrtimer_interrupts是否在保持遞增,如果停滯就意味著時鐘中斷未得到響應,也就是發生了hard lockup。

Linux kernel設計了一個檢測lockup的機制,稱為NMI Watchdog,是利用NMI中斷實現的,用NMI是因為lockup有可能發生在中斷被遮蔽的狀態下,這時唯一能把CPU搶下來的方法就是通過NMI,因為NMI中斷是不可遮蔽的。NMI Watchdog 中包含 soft lockup detector 和 hard lockup detector,2.6之後的核心的實現方法如下。

NMI Watchdog 的觸發機制包括兩部分:

  1. 一個高精度計時器(hrtimer),對應的中斷處理例程是kernel/watchdog.c: watchdog_timer_fn(),在該例程中:
    • 要遞增計數器hrtimer_interrupts,這個計數器供hard lockup detector用於判斷CPU是否響應中斷;
    • 還要喚醒[watchdog/x]核心執行緒,該執行緒的任務是更新一個時間戳;
    • soft lock detector檢查時間戳,如果超過soft lockup threshold一直未更新,說明[watchdog/x]未得到執行機會,意味著CPU被霸佔,也就是發生了soft lockup。
  2. 基於PMU的NMI perf event,當PMU的計數器溢位時會觸發NMI中斷,對應的中斷處理例程是 kernel/watchdog.c: watchdog_overflow_callback(),hard lockup detector就在其中,它會檢查上述hrtimer的中斷次數(hrtimer_interrupts)是否在保持遞增,如果停滯則表明hrtimer中斷未得到響應,也就是發生了hard lockup。

hrtimer的週期是:softlockup_thresh/5。
注:

  • 在2.6核心中:
    softlockup_thresh的值等於核心引數kernel.watchdog_thresh,預設60秒;
  • 而到3.10核心中:
    核心引數kernel.watchdog_thresh名稱未變,但含義變成了hard lockup threshold,預設10秒;
    soft lockup threshold則等於(2*kernel.watchdog_thresh),即預設20秒。

NMI perf event是基於PMU的,觸發週期(hard lockup threshold)在2.6核心裡是固定的60秒,不可手工調整;在3.10核心裡可以手工調整,因為直接對應著核心引數kernel.watchdog_thresh,預設值10秒。

檢測到 lockup 之後怎麼辦?可以自動panic,也可輸出條資訊就算完了,這是可以通過核心引數來定義的:

  • kernel.softlockup_panic: 決定了檢測到soft lockup時是否自動panic,預設值是0;
  • kernel.nmi_watchdog: 定義是否開啟nmi watchdog、以及hard lockup是否導致panic,該核心引數的格式是”=[panic,][nopanic,][num]”.
    (注:最新的kernel引入了新的核心引數kernel.hardlockup_panic,可以通過檢查是否存在 /proc/sys/kernel/hardlockup_panic來判斷你的核心是否支援。)

參考資料:

Softlockup detector and hardlockup detector (aka nmi_watchdog)

kernel/watchdog.c:
設定PMU NMI perf event的程式碼 wachdog_nmi_enable()
響應NMI perf overflow中斷的程式碼 watchdog_overflow_callback()
[watchdog/x]核心執行緒 watchdog()
響應hrtimer中斷的程式碼 watchdog_timer_fn()