91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

Linux內(nèi)核:soft lockup是由于什么原因?qū)е碌哪兀?/h1>

提到soft lockup,大家都不會陌生:

BUG:softlockup-CPU#3stuckfor23s![kworker/332]

這個幾乎和panic,oops并列,也是非常難以排查甚至比panic更麻煩。至少panic之后你可以去分析一個靜態(tài)的尸體,然而soft lockup,那是一個動態(tài)的過程,甚至轉(zhuǎn)瞬即逝,自帶自愈功能。

那么soft lockup是由于什么原因?qū)е碌哪兀?/p>

幾乎沒有這方面的文章,能找到的也只有個別的案例分析,所以我想趁著周末降至來寫一篇關于soft lockup的通用解釋。

首先澄清兩個關于soft lockup的誤區(qū):

soft lockup并不僅僅是由死循環(huán)引起的。

soft lockup并不是說在一段代碼里執(zhí)行了23秒,22秒。

這里簡單解釋一下上面的兩點。

事實上,死循環(huán)并不一定會導致soft lockup,比如Linux內(nèi)核生命周期內(nèi)的0號進程就是一個死循環(huán),此外很多的內(nèi)核線程都是死循環(huán)。

此外,更難指望一段代碼可以執(zhí)行20多秒,要對現(xiàn)代計算機的速度有所概念。

soft lockup發(fā)生的真實場景是:

soft lockup是針對單獨CPU而不是整個系統(tǒng)的。

soft lockup指的是發(fā)生的CPU上在20秒(默認)中沒有發(fā)生調(diào)度切換。

第一點無須解釋,下面重點看第二點。

很顯然,只要讓一個CPU在20秒左右的時間內(nèi)都不發(fā)生進程切換,就會觸發(fā)soft lockup,這個“20秒內(nèi)不切換”就是soft lockup發(fā)生的根因!

好了,現(xiàn)在我們來看20秒不切換的場景。

死循環(huán)的情況
這是最簡單的場景,但細節(jié)往往不像看起來那么簡單。比如你寫了一個死循環(huán)在內(nèi)核中執(zhí)行,它一定會導致soft lockup嗎?

我們來看一個內(nèi)核死循環(huán):

#include #include static int loop_func(void *arg){ int i = 0; while(!kthread_should_stop()) { i++; } return 0;} struct task_struct *kt;static int __init init_loop(void){ kt = kthread_run(loop_func, NULL, "loop_thread"); if (IS_ERR(kt)) { return -1; } return 0;} static void __exit exit_test(void){ kthread_stop(kt);} module_init(init_loop);module_exit(exit_loop);MODULE_LICENSE("GPL");

加載這個模塊,會soft lockup嗎?

我們知道,雖然loop thread是一個死循環(huán),但是它看起來正如一個普通用戶態(tài)進程一樣,在執(zhí)行i++循環(huán)的時候,其實是可以被其它task搶占掉的,這是最基本的進程調(diào)度的常識。

但是如果你真的去加載這個模塊,你會發(fā)現(xiàn)在有些機器上,它確實會soft lockup,但有的機器上不會,這又是為什么?

這里的關鍵在于內(nèi)核搶占。你看下自己系統(tǒng)內(nèi)核的配置文件,如果下面的配置打開,意味著上述模塊的死循環(huán)不會造成soft lockup:

CONFIG_PREEMPT=y

如果這個配置沒有開,那么便刑不上內(nèi)核了,因為它在內(nèi)核態(tài)執(zhí)行,所以沒有誰可以搶占它,進而發(fā)生soft lockup。

我們對上述的死循環(huán)代碼是否會觸發(fā)soft lockup已經(jīng)很明確了,下面我們看另一種情況。

如果死循環(huán)不在內(nèi)核線程上下文,而是在軟中斷上下文,會怎樣?

很顯然,軟中斷不能被進程搶占,所以一定會soft lockup。

當然,如果真的發(fā)生了死循環(huán)導致的soft lockup,那肯定是在一個循環(huán)代碼中執(zhí)行超過20秒了,不說20秒,如果無人干涉,200000秒都是有的…

現(xiàn)在我們來看另一種復雜的情況,即timer的情況。在討論timer時,我假設系統(tǒng)的內(nèi)核搶占是開啟的,這樣更容易分類討論,否則,如果關閉了內(nèi)核搶占,那么事情會變得更加嚴重。

timer的情況

我們先看下面的timer回調(diào)函數(shù):

static void timer_func(unsigned long data){ mdelay(1); mod_timer(&timer, jiffies + 200);}

僅僅執(zhí)行1ms的函數(shù),它會導致超過20秒不調(diào)度切換的soft lockup嗎?

初看,應該不會,但是如果我們詳細看了Linux內(nèi)核timer的執(zhí)行原理,就會明白:

pending在一個CPU上的所有過期timer是順序遍歷執(zhí)行的。

一輪timer的順序遍歷執(zhí)行是持有自旋鎖的。

這意味著在執(zhí)行一輪過期timer的過程中,watchdog實時線程將無法被調(diào)度從而喂狗,這意味著:

同一CPU上的過期timer積累到一定量,其回調(diào)函數(shù)的延時之和大于20秒,將會soft lockup。

我們需要進一步了解一下Linux timer的工作機制。

可以把timer的執(zhí)行過程抽象成下面的邏輯:

run_timers(){ while (now > base.early_jiffies) { for_each_timer(timer, base.list) { detach_timer(timer) forward_early_jiffies(base) call_timer_fn(timer) } }}

很簡單的流程,內(nèi)核把當前過期的timer執(zhí)行到結束。run_timers可以在軟中斷上下文中執(zhí)行,也可以在softirqd內(nèi)核線程上下文中執(zhí)行,為了營造soft lockup,我們假設它是在時鐘中斷退出時的軟中斷上下文中執(zhí)行的(記住之前還有個假設,即系統(tǒng)是開啟內(nèi)核搶占的?。藭r,run_timers不能被watchdog搶占。

如果一個timer中耗時1ms,那么一個循環(huán)需要20000個timer遍歷執(zhí)行,才能湊齊20秒的不能被搶占的時間,進而引發(fā)soft lockup。我的天,20000個timer,不可思議!

其實根本就不需要20000個timer,200個足矣!

問題就出現(xiàn)在call_timer_fn,它實際上是調(diào)用該timer回調(diào)函數(shù)的封裝!我們知道,timer回調(diào)函數(shù)中執(zhí)行了mod_timer的操作,它的邏輯如下:

mod_timer(timer, expires){ list_add_timer(timer, expires, base.list)}

它事實上是把timer又插回了list,如果我們把這個list看作是一條時間線的話,它事實上只是往后移了expires這么遠的距離:

假設所有timer的expire都是固定的常量,如果:

我們的timer的足夠多,多到按照其expires重新requeue時恰好能填補中間的那段空隙。

我們的timer回調(diào)函數(shù)耗時恰好和timer的expires流逝速率相一致。

那么,兩個甚至多個batch就合并成了一個batch,這意味著一輪timer的執(zhí)行將不會結束!

我們來試一下:

#include #include #include static int stop = 1; // timer的數(shù)量static int size = 1;module_param(size, int, 0644);MODULE_PARM_DESC(size, "size"); // timer的expiresstatic int interval = 200;module_param(interval, int, 0644);MODULE_PARM_DESC(interval, ""); // 回調(diào)函數(shù)耗時static int dt = 100;module_param(dt, int, 0644);MODULE_PARM_DESC(dt, ""); struct wrapper { struct timer_list timer; spinlock_t lock;}; struct wrapper *wr; static void timer_func(unsigned long data){ int i = data; struct wrapper *w = &wr[i]; spin_lock_bh(&(w->lock)); if (stop == 0) { udelay(dt); // 以忙等模擬耗時 } spin_unlock_bh(&(w->lock)); w->timer.data = i; if (stop == 0) { mod_timer(&(w->timer), jiffies + interval); }} static int __init maint_init(void){ int i; wr = (struct wrapper *)kzalloc(size*sizeof(struct wrapper), GFP_KERNEL); for (i = 0; i < size; i++) { struct wrapper *w = &wr[i]; spin_lock_init(&(w->lock)); init_timer(&(w->timer)); w->timer.expires = jiffies + 20; w->timer.function = timer_func; w->timer.data = i; add_timer(&(w->timer)); } stop = 0; return 0;} static void __exit maint_exit(void){ int i; stop = 1; udelay(100); for (i = 0; i < size; i++) { struct wrapper *w = &wr[i]; del_timer_sync(&(w->timer)); } kfree(wr); } module_init(maint_init);module_exit(maint_exit);MODULE_LICENSE("GPL");

我的測試虛擬機HZ為1000,這意味1ms將會產(chǎn)生一次時鐘中斷,我們以每個timer函數(shù)持鎖執(zhí)行1ms,一共400個timer來加載模塊,看下結果:


單核跑滿,這意味著timer已經(jīng)拼接成龍,20秒后,我們將看到soft lockup:


事實上,每個timer回調(diào)函數(shù)delay 800us,一共200個timer即可觸發(fā)soft lockup!使用這個代碼,你基本可以確定你要測試的機器的timer執(zhí)行時間的安全閾值。

這就是timer導致的soft lockup的動力學。

關于HZ1000
1ms間隔的時鐘中斷對于服務器而言是悲哀的,1ms的時間無法容納太多的timer,也不允許每個timer中有哪怕稍微的合理耗時,1ms一次中斷很容易觸發(fā)run_timers在軟中斷上下文中被執(zhí)行,但很遺憾,這就是事實。

拋開timer不談,HZ1000更多的意義在于快速響應事件而不是增加系統(tǒng)吞吐,這對服務器的單機性能是有傷害的!

說了這么多,現(xiàn)在讓我們考慮一下現(xiàn)實。

除了不要在內(nèi)核中寫死循環(huán)之外,我們也不應該讓timer回調(diào)函數(shù)執(zhí)行過久,特別是系統(tǒng)中timer特別多,且expires特別短的情況下。

回到現(xiàn)實中,我們來看一個實例。

假設你使用的內(nèi)核版本還不支持TCP的lockless listener,那么我們特別要注意一個函數(shù),即inet_csk_reqsk_queue_prune:

這是一個在TCP的per listener的timer中執(zhí)行的函數(shù)。

這個函數(shù)的實現(xiàn)采用兩層循環(huán),循環(huán)耗時取決于:

外層循環(huán):該listener的backlog大小,受程序配置控制。

內(nèi)層循環(huán):該listener的半連接隊列的大小,受系統(tǒng)快照控制。

如果系統(tǒng)中的listener特別多,在收到SYN掃描攻擊時,特別容易陷入soft lockup的深淵!幸運的是,這個問題已經(jīng)在TCP lockless listener的版本中修了,它的效果如下:

將per listener的半連接隊列timer換成了per request timer,減少了回調(diào)函數(shù)處理耗時。

per request timer增加了timer的數(shù)量,會不會抵消縮短回調(diào)耗時帶來的收益,需要攻擊來驗證。

我們看一個相關issue和patch:
https://patchwork.ozlabs.org/patch/452426/

好了,再次回到核心主題。

觸發(fā)soft lockup的當然不止死循環(huán)和timer,我只是用這兩個來說明soft lockup的動力學,即超過2倍的kernel.watchdog_thresh時間不能進行進程調(diào)度,就會觸發(fā)soft lockup告警。至于說stuck for 23s!那只是表象,并不是如其字面表達的那樣,23秒的時間在執(zhí)行一段代碼。

此外,頻繁的spinlock,rwlock也會導致soft lockup,我這有一個關于IPv6路由查詢機制的實例,詳情參見:
https://blog.csdn.net/dog250/article/details/91046131

總之,所有的情況將不勝枚舉,也不可能通過一篇文章來展示,所以說,遇到此類問題,還是要有一個明確的排查思路或者說范式,才能快速定位問題的根因并且解決之。

當然了,經(jīng)理并不關注這些爛八七糟的東西。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • cpu
    cpu
    +關注

    關注

    68

    文章

    11287

    瀏覽量

    225182
  • Linux
    +關注

    關注

    88

    文章

    11771

    瀏覽量

    219111

原文標題:Linux內(nèi)核為什么會發(fā)生soft lockup?

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    什么是內(nèi)核LOCKUP故障復位?

    當 CPU 遇到嚴重異常(如讀取到的指令無效、訪問 FLASH 時位寬和目標地址不匹配),會將 PC 指針停在當前地址處鎖定,并產(chǎn)生內(nèi)核 LOCKUP 故障復位信號。 芯片上電后,LOCKUP 復位
    發(fā)表于 12-15 08:33

    內(nèi)核LOCKUP故障復位方法

    當 CPU 遇到嚴重異常(如讀取到的指令無效、訪問 FLASH 時位寬和目標地址不匹配),會將 PC 指針停在當前地址處鎖定,并產(chǎn)生內(nèi)核 LOCKUP 故障復位信號。芯片上電后,LOCKUP 復位
    發(fā)表于 12-11 07:15

    PWM停止輸出,什么原因導致這種現(xiàn)象發(fā)生?

    IR2010SPBF驅(qū)動器控制半橋電路輸出PWM設備安裝在地鐵上,在運行過程中會出現(xiàn)TMS檢測到輸出頻率占空比都是零,取回故障設備通電測量PWM正常輸出,什么原因導致這種現(xiàn)象發(fā)生?
    發(fā)表于 11-26 09:38

    NucleiStudio仿真GD32VF103CB報錯是什么原因導致的?

    有沒有人知道這是什么原因導致
    發(fā)表于 11-11 06:07

    gd32 env配置報錯是什么原因?

    rtt官網(wǎng)下載源碼和env后使用env配置gd32報如下錯誤請問是什么原因?
    發(fā)表于 09-25 06:19

    kconfig里寫的英文,setting里面顯示的是中文,這是什么原因導致的?

    最近在學習artpi2,發(fā)現(xiàn)圖片顯示的這里 這里用的是英文,但是setting這里是中文 gpio的setting上也有類似的現(xiàn)象,請問這是什么原因導致
    發(fā)表于 09-22 06:10

    線程超時函數(shù)中 assert 失敗是什么原因導致的?

    定位后,發(fā)現(xiàn)在調(diào)用棧中經(jīng)常會同時出現(xiàn)兩個中斷,一個串口中斷和systick 中斷,就挺奇怪的,這是定時器中斷被別的中斷打斷了嗎? rt_sched_lock 的作用似乎就是關閉全局中斷吧。。。 請問可能是什么原因? 謝謝! rt-thread 版本: 5.2.1
    發(fā)表于 09-09 06:56

    你知道什么原因導致安規(guī)電容損壞嗎?

    安規(guī)電容通常用于抑制噪聲、濾波或電氣隔離等。安規(guī)電容在設計時必須具備一定的安全標準,以保證在故障情況下不會對使用者造成電擊或火災等危險。然而,安規(guī)電容也有可能因各種原因發(fā)生損壞,常見的原因包括: 一
    的頭像 發(fā)表于 07-13 11:03 ?1364次閱讀

    網(wǎng)絡光纖出問題一般是什么原因導致

    (如道路開挖)、重物碾壓、動物啃咬(如老鼠咬斷)。 案例:某小區(qū)寬帶中斷,經(jīng)排查發(fā)現(xiàn)施工隊挖斷主干光纖,導致整棟樓斷網(wǎng)。 檢測方法:使用OTDR(光時域反射儀)定位斷點位置。 光纖彎曲過度 原因:布線時彎曲半徑過小( 案例:辦公室網(wǎng)絡時斷
    的頭像 發(fā)表于 06-17 10:05 ?4002次閱讀
    網(wǎng)絡光纖出問題一般是<b class='flag-5'>什么原因</b><b class='flag-5'>導致</b>的<b class='flag-5'>呢</b>

    使用STM32H755ZIQ-NUCLEO時,由于數(shù)據(jù)線的原因導致固件升級失敗怎么解決?

    使用STM32H755ZIQ-NUCLEO時,由于數(shù)據(jù)線的原因導致固件升級失敗,目前沒有辦法下載程序,大佬們解決的辦法?
    發(fā)表于 06-17 06:47

    使用STM32H755ZIQ-NUCLEO時,由于數(shù)據(jù)線的原因導致固件升級失敗,怎么解決?

    使用STM32H755ZIQ-NUCLEO時,由于數(shù)據(jù)線的原因導致固件升級失敗,目前沒有辦法下載程序,大佬們解決的辦法?
    發(fā)表于 06-16 06:20

    什么原因導致的無法下載FX3的SDK?

    /com.ifx.tb.tool.ezusbfx3sdk 但是,現(xiàn)在不可用,我無法訪問文件“ Windows (x32-x64) (exe)”。 有什么原因導致我無法下載 SDK? 另外,我可以直接下載驅(qū)動嗎?
    發(fā)表于 05-21 06:40

    使用STM32捕獲PWM時同時捕獲2個通道時會出現(xiàn)捕獲的頻率值不準確,是什么原因導致的?

    在使用STM32F103芯片的2個定時器捕獲2路PWM波時,當2路信號同時輸入時,會出現(xiàn)捕獲的頻率不準確,但是分開一路一路的輸入捕獲時,捕獲的PWM頻率是正確的,這是什么原因導致?
    發(fā)表于 05-14 06:24

    使用STM32捕獲PWM時同時捕獲2個通道時會出現(xiàn)捕獲的頻率值不準確是什么原因導致的?

    在使用STM32F103芯片的2個定時器捕獲2路PWM波時,當2路信號同時輸入時,會出現(xiàn)捕獲的頻率不準確,但是分開一路一路的輸入捕獲時,捕獲的PWM頻率是正確的,這是什么原因導致?
    發(fā)表于 04-27 08:39

    使用STM32捕獲PWM時同時捕獲2個通道時會出現(xiàn)捕獲的頻率值不準確的問題,是什么原因導致的?

    在使用STM32F103芯片的2個定時器捕獲2路PWM波時,當2路信號同時輸入時,會出現(xiàn)捕獲的頻率不準確,但是分開一路一路的輸入捕獲時,捕獲的PWM頻率是正確的,這是什么原因導致?
    發(fā)表于 04-25 08:29