1. 程式人生 > 實用技巧 >軟中斷會吃掉你多少CPU?

軟中斷會吃掉你多少CPU?

前面的幾篇文章裡討論過了程序上下文切換和系統呼叫對系統性能的影響,我們今天再來看另外一個CPU吃貨,那就是軟中斷。

你在用vmstat或者其他一些工具檢視系統CPU消耗的時候,發現有兩列是單獨列出來的,分別是是hi和si。他們分別是硬中斷和軟中斷。既然vmstat把中斷的開銷單獨列出來了,就說明一個問題,中斷吃起CPU來那也是絲毫不含糊。

我們沒必要啃明白軟中斷的所有原理,但從一名追求效能的開發者的角度來看,我們有必要了解以下問題:

  • 一次軟中斷的開銷到底多大?
  • 你的伺服器上被軟中斷吃掉了多少CPU時間?

如果你和我一樣好奇上面的問題的答案,那請跟我來!

軟中斷的誕生

CPU正常情況下都是專心處理使用者的程序的,當外部的硬體或軟體有訊息想要通知CPU,就會通過中斷請求(interrupt request,IRQ)

的方式來進行。比如當你的滑鼠有了點選產生,再比如磁碟裝置完成了資料的讀取的時候,都會通過中斷通知CPU工作已完成。

但是當中斷機制應用到網路IO的時候,就產生了一點點問題。網路包收到後的處理工作,不像滑鼠、鍵盤、磁碟IO讀取完成那樣簡單,而是要進行大量的核心協議棧的處理,最終才能放到程序的接收快取區中。假如只用一種中斷(硬終端)的方式來處理網路IO,由於硬中斷的優先順序又比較高,這樣CPU就會忙於處理大量的網路IO而不能及時響應鍵盤滑鼠等事情,導致作業系統實時性變差,你會感覺機器以卡一卡的。

所以現代的Linux又發明了軟體中斷,配合硬中斷來處理網路IO。 硬中斷你可以理解只是個收包的,把包收取回來放到“家裡”就完事,很快就能完成,這樣不耽誤CPU響應其它外部高優先順序的中斷。而軟中斷優先順序較低,負責將包進行各種處理,完成從驅動層、到網路協議棧,最終把處理出來的資料放到socker的接收buffer中。

軟中斷消耗的CPU週期相對比硬中斷要多不少,所以我們本文來重點關注軟中斷的開銷。

軟中斷開銷估算

前面大致介紹了軟中斷的來龍去脈,好了直接進入本文的主題上,軟中斷開銷到底多大。好了,請跟我來一起計算:

1) 檢視軟中斷總耗時
首先用top命令可以看出每個核上軟中斷的開銷佔比,是在si列

top
top - 19:51:24 up 78 days,  7:53,  2 users,  load average: 1.30, 1.35, 1.35  
Tasks: 923 total,   2 running, 921 sleeping,   0 stopped,   0 zombie  
Cpu(s):  7.1%us,  1.4%sy,  0.0%ni, 90.1%id,  0.1%wa,  0.2%hi,  1.2%si,  0.0%st  
Mem:  65872372k total, 64711668k used,  1160704k free,   339384k buffers  
Swap:        0k total,        0k used,        0k free, 55542632k cached  

如上圖所示,CPU大約花費了1.2%的時鐘週期在軟中斷上,也就是說每個核要花費12ms。

2)檢視軟中斷次數
再用vmstat命令可以看到軟中斷的次數

$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 1231716 339244 55474204    0    0     6   496    0    0  7  3 90  0  0  
 2  0      0 1231352 339244 55474204    0    0     0   128 57402 24593  5  2 92  0  0  
 2  0      0 1230988 339244 55474528    0    0     0   140 55267 24213  5  2 93  0  0  
 2  0      0 1230988 339244 55474528    0    0     0   332 56328 23672  5  2 93  0  0  

每秒大約有56000次左右的軟中斷(該機器上是web服務,網路IO密集型的機器,其它中斷可以忽略不計)。

3)計算每次軟中斷的耗時
該機器是16核的物理實機,故可以得出每個軟中斷需要的CPU時間是=12ms/(56000/16)次=3.428us

從實驗資料來看,一次軟中斷CPU開銷大約3.4us左右

軟中斷的上下文切換

前文我們計算出了一個相對比較精確的開銷時間。這個時間裡其實包含兩部分,一是上下文切換開銷,二是軟中斷核心執行開銷。 其中上下文切換和系統呼叫、程序上下文切換有很多相似的地方。讓我們將他們進行一個簡單的對比:

1.和系統呼叫開銷對比

《深入理解Linux核心-第五章》開頭的一句話,很形象地把中斷和系統呼叫兩個不相關的概念聯絡了起來,巧妙地找到了這二者之間的相似處。“你可以把核心看做是不斷對請求進行響應的伺服器,這些請求可能來自在CPU上執行的程序,也可能來自發出中斷的外部裝置。老闆的請求相當於中斷,而顧客的請求相當於使用者態程序發出的系統呼叫”。

軟中斷和系統呼叫一樣,都是CPU停止掉當前使用者態上下文,儲存工作現場,然後陷入到核心態繼續工作。二者的唯一區別是系統呼叫是切換到同進程的核心態上下文,而軟中斷是則是切換到了另外一個核心程序ksoftirqd上。

而事實上,早期的系統呼叫也還真的是通過彙編指令int(中斷)來實現的,當用戶態程序發出int $0x80指令時,CPU切換到核心態並開始執行system_call函式。後來大家覺得系統呼叫實在是太慢了,因為int指令要執行一致性和安全性檢查。後來核心又該用了Intel提供的“快速系統呼叫”的sysenter指令,才算是和中斷脫離了一點點干係。而軟中斷必須得進行這些檢查,所以從這點上來看,中斷的開銷應該是比系統呼叫的開銷要多的。

根據前文的實驗結果,系統呼叫開銷是200ns起步。沒看過這個文章的同學可以關注我,然後從歷史文章裡找。

2.和程序上下文切換開銷對比

和程序上下文切換比較起來,程序上下文切換是從使用者程序A切換到了使用者程序B。而軟中斷切換是從使用者程序A切換到了核心執行緒ksoftirqd上。
而ksoftirqd作為一個核心控制路徑,其處理程式比一個使用者程序要輕量,所以上下文切換開銷相對比程序切換要稍一些。大家感興趣的,可以繼續閱讀《深入理解Linux核心》的-第五章。

根據前文的實驗結果,程序上下文切換開銷是3us-5us。沒看過這個文章的同學可以關注我,然後從歷史文章裡找。

相關Linux命令

  • top: si列展示軟中斷造成CPU開銷
  • vmstat 1:in列每秒展示軟中斷次數
  • cat /proc/softirqs:展示所有軟中斷髮生的總數,包括TIMER、NET_TX、NET_RX等


開發內功修煉之CPU篇專輯:


我的公眾號是「開發內功修煉」,在這裡我不是單純介紹技術理論,也不只介紹實踐經驗。而是把理論與實踐結合起來,用實踐加深對理論的理解、用理論提高你的技術實踐能力。歡迎你來關注我的公眾號,也請分享給你的好友~~~