Linux 內核需要對連接到計算機上的所有硬件設備進行管理,毫無疑問這是它的份內事。如果要管理這些設備,首先得和它們互相通信才行,一般有兩種方案可實現這種功能:
- 輪詢(polling) 讓內核定期對設備的狀態進行查詢,然後做出相應的處理;
- 中斷(interrupt) 讓硬件在需要的時候向內核發出信號(變內核主動爲硬件主動)。
第一種方案會讓內核做不少的無用功,因爲輪詢總會週期性的重複執行,大量地耗用 CPU 時間,因此效率及其低下,所以一般都是採用第二種方案 。
對於中斷,Linux也有自己的負載均衡策略,既可以調用Linux自己的優化模塊irqbalance來實現自動的優化調節,也可以人爲的將中斷進行綁定的固定的物理CPU上。
1、irqbalance
(1)irqbalance簡介與使用
irqbalance用於優化中斷分配,它會自動收集系統數據以分析使用模式,並依據系統負載狀況將工作狀態置於 Performance mode 或 Power-save mode。處於Performance mode 時,irqbalance 會將中斷儘可能均勻地分發給各個 CPU core,以充分利用 CPU 多核,提升性能。處於Power-save mode 時,irqbalance 會將中斷集中分配給第一個 CPU,以保證其它空閒 CPU 的睡眠時間,降低能耗。
irqbalance這個進程默認是開機啓用的,可以通過如下命令它的狀態
# service irqbalance status
irqbalance (pid PID) is running…
對於人爲將中斷綁定到CPU上的情況時,爲了消除irqbalance的自適應調節,需要將該進程關閉,可以用下面的命令關閉它:
# service irqbalance stop
Stopping irqbalance: [ OK ]
或者乾脆取消開機啓動:
# chkconfig irqbalance off
(2)irqbalance原理分析
irqbalance的意義在於SMP系統的中斷優化,而SMP架構是一種CPU的分層拓撲,如下圖所示
一個NUMA node包括一個或者多個Socket,以及與之相連的local memory。一個多核的Socket有多個Core。如果CPU支持超線程並開啓,操作系統還會把這個Core看成 2個Logical Processor。因此irqbalance會需要考慮到各個CPU上的中斷負載以及CPU所處的拓撲位置來進行中斷優化調節。
irqbalance的源碼下載可以到github網站https://github.com/Irqbalance;
個人對其源碼的分析在https://github.com/lkn910907/Code-analyze/tree/master/irqbalance%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90,可便於新手瞭解。
//irqbalance.c
|
int
main( int
argc, char ** argv)
|
{
|
/* ... */ |
while
(keep_going) { |
sleep_approx(SLEEP_INTERVAL);
//#define SLEEP_INTERVAL 10 |
/* ... */ |
clear_work_stats();
|
parse_proc_interrupts();
|
parse_proc_stat();
|
/* ... */ |
calculate_placement();
|
activate_mappings();
|
/* ... */ |
}
|
/* ... */ |
} |
從程序的主循環可以很清楚的看到它的邏輯,在退出之前每隔10秒它做了以下的幾個事情:
1. 清除統計
2. 分析中斷的情況
3. 分析中斷的負載情況
4. 根據負載情況計算如何平衡中斷
5. 實施中斷親和性變更
如果不瞭解中斷親和性可以下面找到詳細說明 ~
在診斷模型下運行irqbalance可以給我們很多詳細的信息:
#irqbalance –debug
可以詳細看到irqbalcne對每個CPU的拓撲分層,以及每個拓撲域上的負載。
(2)自己設置中斷親和性
在 SMP 體系結構中,我們可以通過調用系統調用和一組相關的宏來設置 CPU 親和力(CPU affinity),將一個或多個進程綁定到一個或多個處理器上運行。中斷在這方面也毫不示弱,也具有相同的特性。中斷親和力是指將一個或多箇中斷源綁定到特定的 CPU 上運行。中斷親和力最初由 Ingo Molnar 設計並實現。
在 /proc/irq
目錄中,對於已經註冊中斷處理程序的硬件設備,都會在該目錄下存在一個以該中斷號命名的目錄
IRQ#
,IRQ#
目錄下有一個 smp_affinity
文件(SMP 體系結構纔有該文件),它是一個 CPU 的位掩碼,可以用來設置該中斷的親和力, 默認值爲
0xffffffff
,表明把中斷髮送到所有的 CPU 上去處理。如果中斷控制器不支持 IRQ affinity
,不能改變此默認值,同時也不能關閉所有的 CPU 位掩碼,即不能設置成
0x0
。
需要注意的是人爲設置中斷親和性需要關閉irqbalance,消除其自適應中斷調節
我們以網卡(eth1,中斷號 44 )爲例,在具有 8 個 CPU 的服務器上來設置網卡中斷的親和力(以下數據出自內核源碼Documentation\IRQ-affinity.txt
):
[root@moon 44]# cat smp_affinity ffffffff [root@moon 44]# echo 0f > smp_affinity [root@moon 44]# cat smp_affinity 0000000f
當我們通過 echo 命令將 CPU 掩碼寫進 smp_affinity
文件時,此時的調用路線圖爲:write()
->sys_write()
->vfs_write()
->proc_file_write()
->irq_affinity_write_proc()
->set_affinity()
->set_ioapic_affinity()
->set_ioapic_affinity_irq()
->io_apic_write()
;其中在調用
set_ioapic_affinity_irq()
函數時,以中斷號和 CPU 掩碼作爲參數,接着繼續調用 io_apic_write()
,修改相應的中斷重定向中的值,來完成中斷親和力的設置。
對於效果的檢驗,可以通過cat /proc/interrupts命令查看中斷在各個CPU上的分佈,如果是對特定中斷處理,再加上grep過濾更方便查看。通過可以發現,一旦設置了親和性,中斷就只在特定的CPU上觸發了。