天天看點

Linux:怎麼了解Linux軟中斷?

為了解決中斷處理程式執行過長和中斷丢失的問題,Linux 将中斷處理過程分成了兩個階段,也就是上半部和下半部:

  • 上半部用來快速進行中斷,它在中斷禁止模式下運作,主要處理跟硬體緊密相關的或時間敏感的工作。
  • 下半部用來延遲處理上半部未完成的工作,通常以核心線程的方式運作。

舉個最常見的網卡接收資料包的例子,讓你更好地了解。

網卡接收到資料包後,會通過硬體中斷的方式,通知核心有新的資料到了。這時,核心就應該調用中斷處理程式來響應它。你可以自己先想一下,這種情況下的上半部和下半部分别負責什麼工作呢?

對上半部來說,既然是快速處理,其實就是要把網卡的資料讀到記憶體中,然後更新一下硬體寄存器的狀态(表示資料已經讀好了),最後再發送一個軟中斷信号,通知下半部做進一步的處理。

而下半部被軟中斷信号喚醒後,需要從記憶體中找到網絡資料,再按照網絡協定棧,對資料進行逐層解析和處理,直到把它送給應用程式。

是以,這兩個階段你也可以這樣了解:

  • 上半部直接處理硬體請求,也就是我們常說的硬中斷,特點是快速執行;
  • 而下半部則是由核心觸發,也就是我們常說的軟中斷,特點是延遲執行。

實際上,上半部會打斷 CPU 正在執行的任務,然後立即執行中斷處理程式。而下半部以核心線程的方式執行,并且每個 CPU 都對應一個軟中斷核心線程,名字為 “ksoftirqd/CPU 編号”,比如說, 0 号 CPU 對應的軟中斷核心線程的名字就是 ksoftirqd/0。

不過要注意的是,軟中斷不隻包括了剛剛所講的硬體裝置中斷處理程式的下半部,一些核心自定義的事件也屬于軟中斷,比如核心排程和 RCU 鎖(Read-Copy Update 的縮寫,RCU 是 Linux 核心中最常用的鎖之一)等。

那要怎麼知道你的系統裡有哪些軟中斷呢?

檢視軟中斷和核心線程

proc 檔案系統,它是一種核心空間和使用者空間進行通信的機制,可以用來檢視核心的資料結構,或者用來動态修改核心的配置。其中:

  • /proc/softirqs 提供了軟中斷的運作情況;
  • /proc/interrupts 提供了硬中斷的運作情況。

運作下面的指令,檢視 /proc/softirqs 檔案的内容,你就可以看到各種類型軟中斷在不同 CPU 上的累積運作次數:

$ cat /proc/softirqs
                    CPU0       CPU1
          HI:          0          0
       TIMER:     811613    1972736
      NET_TX:         49          7
      NET_RX:    1136736    1506885
       BLOCK:          0          0
    IRQ_POLL:          0          0
     TASKLET:     304787       3691
       SCHED:     689718    1897539
     HRTIMER:          0          0
         RCU:    1330771    1354737      

在檢視 /proc/softirqs 檔案内容時,你要特别注意以下這兩點。

第一,要注意軟中斷的類型,也就是這個界面中第一列的内容。從第一列你可以看到,軟中斷包括了 10 個類别,分别對應不同的工作類型。比如 NET_RX 表示網絡接收中斷,而 NET_TX 表示網絡發送中斷。

第二,要注意同一種軟中斷在不同 CPU 上的分布情況,也就是同一行的内容。正常情況下,同一種中斷在不同 CPU 上的累積次數應該差不多。比如這個界面中,NET_RX 在 CPU0 和 CPU1 上的中斷次數基本是同一個數量級,相差不大。

不過你可能發現,TASKLET 在不同 CPU 上的分布并不均勻。TASKLET 是最常用的軟中斷實作機制,每個 TASKLET 隻運作一次就會結束 ,并且隻在調用它的函數所在的 CPU 上運作。

是以,使用 TASKLET 特别簡便,當然也會存在一些問題,比如說由于隻在一個 CPU 上運作導緻的排程不均衡,再比如因為不能在多個 CPU 上并行運作帶來了性能限制。

另外,剛剛提到過,軟中斷實際上是以核心線程的方式運作的,每個 CPU 都對應一個軟中斷核心線程,這個軟中斷核心線程就叫做 ksoftirqd/CPU 編号。那要怎麼檢視這些線程的運作狀況呢?

$ ps aux | grep softirq
root         7  0.0  0.0      0     0 ?        S    Oct10   0:01 [ksoftirqd/0]
root        16  0.0  0.0      0     0 ?        S    Oct10   0:01 [ksoftirqd/1]      

繼續閱讀