- 論壇徽章:
- 0
|
小弟剛剛鳥槍換小炮。得到一臺(tái)Intel(R) Core(TM)2 CPU 6400 @ 2.13GHz + PCI-E 4X 2.5GB的機(jī)器,以前看大家討論多核,IRQ中斷親和的問題,心里頭就發(fā)癢,現(xiàn)在終于有機(jī)會(huì)測(cè)試了。!反復(fù)做了些測(cè)試,有一些值得思考的地方,將整個(gè)測(cè)試過程發(fā)上來(不包括性能改進(jìn)方面的內(nèi)容),與大家一起討論(有點(diǎn)長(zhǎng),適合有耐心的TX看):
一些個(gè)人結(jié)論性的東西可能有誤,希望大家指點(diǎn)。!
一、測(cè)試環(huán)境:
發(fā)包機(jī)(PC_A) -------- (eth1)Linux(eth2)---------收包機(jī)(PC_B)
內(nèi)核版本:2.6.12
網(wǎng)卡驅(qū)動(dòng):Intel e1000e[Intel現(xiàn)在把pci-e的千兆網(wǎng)卡單獨(dú)拿出來了。整了個(gè)e1000e],NAPI模式;
發(fā)包工具:bwtest
Linux配置:網(wǎng)橋 + Netfilter;
數(shù)據(jù)包是單向發(fā)送64bytes小包。即PC_B不發(fā)包。
二、不開啟IRQ中斷均衡;
內(nèi)核編譯中,不開啟此選項(xiàng)。
- Cpu(s): 0.0% user, 0.5% system, 0.0% nice, 50.3% idle
- Cpu0 : 1.0% user, 0.0% system, 0.0% nice, 1.0% idle
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 100.0% idle
- Cpu(s): 0.0% user, 0.0% system, 0.0% nice, 50.8% idle
- Cpu0 : 0.0% user, 0.0% system, 0.0% nice, 1.0% idle
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 100.0% idle
- Cpu(s): 0.5% user, 0.0% system, 0.0% nice, 50.8% idle
- Cpu0 : 0.0% user, 1.0% system, 0.0% nice, 2.0% idle
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 100.0% idle
復(fù)制代碼
此時(shí)數(shù)據(jù)轉(zhuǎn)發(fā)約166Mb(這是我發(fā)包機(jī)的上限了……)
從三次采樣結(jié)果來看,所有負(fù)載都被放在了CPU0上面,CPU1基本上是在睡大覺。
同時(shí),查看/proc/interrupt,也可以看到,CPU1上面沒有中斷。
結(jié)論:多核下不啟用IRQ中斷均衡功能是一種資源浪費(fèi)。
三、開啟IRQ中斷均衡:
在內(nèi)核編譯中,啟用該選項(xiàng)。
- [root@SkyNet ~]# cat /proc/interrupts
- CPU0 CPU1
- 74: 154789 1 PCI-MSI eth1
- 82: 16393 2102221 PCI-MSI eth2
復(fù)制代碼
并沒有去手動(dòng)修改smp_affinity文件。在開機(jī)的時(shí)候,短暫的把eth2的中斷也放到了CPU0后,立馬自己學(xué)習(xí),轉(zhuǎn)到cpu1上面去了。實(shí)現(xiàn)了兩張網(wǎng)卡,兩個(gè)CPU,一人一個(gè)。哥倆好!!
但是,這并不能讓我高興,因?yàn)閱栴}才剛剛開始:
- Cpu(s): 0.0% user, 0.0% system, 0.0% nice, 38.5% idle
- Cpu0 : 1.0% user, 1.0% system, 0.0% nice, 2.0% idle
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 73.7% idle
- Cpu(s): 0.0% user, 0.0% system, 0.0% nice, 37.2% idle
- Cpu0 : 0.0% user, 0.0% system, 0.0% nice, 2.1% idle
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 72.4% idle
- Cpu(s): 0.5% user, 0.5% system, 0.0% nice, 38.2% idle
- Cpu0 : 0.0% user, 0.0% system, 0.0% nice, 3.0% idle
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 73.7% idle
復(fù)制代碼
從三次采樣結(jié)果來看,
1、CPU總負(fù)載不降反升了,從50%左右,上升到63%左右了。[從ilde的百分比可以看出來]
2、CPU0的下來了(因?yàn)閑th2的中斷不需要它去處理了);
3、CPU1的負(fù)載從0%上升到了27%左右。
為什么會(huì)有這種情況發(fā)生呢?此時(shí)猜測(cè)唯一可以解釋的就是:
- “CPU1此時(shí)只分擔(dān)到了發(fā)送數(shù)據(jù)幀的中斷工作,網(wǎng)絡(luò)內(nèi)核棧的工作,從net_rx_action開始,包括網(wǎng)橋、Netfilter、隊(duì)列調(diào)度等等工作,全部集中到了CPU0上,網(wǎng)絡(luò)棧的工作,并沒有實(shí)現(xiàn)負(fù)載均衡,換句話說,net_rx_action這個(gè)軟中斷,只在一個(gè)CPU上運(yùn)行了,并沒有實(shí)現(xiàn)多個(gè)CPU的同時(shí)運(yùn)行和調(diào)度(通過后面的實(shí)驗(yàn)和ShadowStar同學(xué) 的指點(diǎn),最后這一句的結(jié)論是錯(cuò)的,我最后會(huì)說明)”
復(fù)制代碼
為了進(jìn)一步證明我的這個(gè)結(jié)論,我在Netfilter的raw表的PREROUTING中,丟棄所有數(shù)據(jù):
- Cpu(s): 0.0% user, 0.0% system, 0.0% nice, 78.6% idle, 0.0% x, 2.1% y
- Cpu0 : 0.0% user, 0.0% system, 0.0% nice, 57.0% idle, 0.0% x, 5.4% y
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 100.0% idle, 0.0% x, 0.0% y
- Cpu(s): 0.0% user, 0.0% system, 0.0% nice, 78.1% idle, 0.0% x, 2.7% y
- Cpu0 : 0.0% user, 0.0% system, 0.0% nice, 55.3% idle, 0.0% x, 5.3% y
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 100.0% idle, 0.0% x, 0.0% y
- Cpu(s): 0.0% user, 0.0% system, 0.0% nice, 80.1% idle, 0.0% x, 2.2% y
- Cpu0 : 0.0% user, 0.0% system, 0.0% nice, 60.6% idle, 0.0% x, 4.3% y
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 100.0% idle, 0.0% x, 0.0% y
復(fù)制代碼
當(dāng)數(shù)據(jù)被丟棄時(shí),從三次采樣的結(jié)果來看,
1、CPU1因?yàn)椴辉侔l(fā)送數(shù)據(jù),又沒有事情干了。它的空閑是100%,所以,像網(wǎng)橋處理,軟中斷,肯定也沒有它的份。再一次印證了剛才的想法(盡管它是錯(cuò)的);
2、CPU0負(fù)載也大幅的下降,這是因?yàn)。它不再處理連接跟蹤那些東東了——再一次證明,Netfilter是一個(gè)很吃CPU的東東。
那有沒有可能:讓一個(gè)CPU來處理內(nèi)核網(wǎng)格棧的功能,一個(gè)CPU來專門處理網(wǎng)卡中斷呢??我突發(fā)奇想了。!
即然現(xiàn)在net_rx_action軟中斷是運(yùn)行在CPU0上的,那我調(diào)整中斷親和,把CPU0上的中斷負(fù)載調(diào)整到CPU1上去,不就完美了么??呵呵:
- Cpu(s): 0.0% user, 0.0% system, 0.0% nice, 59.0% idle, 0.0% x, 0.5% y
- Cpu0 : 0.0% user, 1.1% system, 0.0% nice, 98.9% idle, 0.0% x, 0.0% y
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 18.1% idle, 0.0% x, 1.1% y
- Cpu(s): 0.0% user, 0.0% system, 0.0% nice, 59.6% idle, 0.0% x, 0.5% y
- Cpu0 : 0.0% user, 0.0% system, 0.0% nice, 100.0% idle, 0.0% x, 0.0% y
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 18.1% idle, 0.0% x, 1.1% y
- Cpu(s): 0.0% user, 0.0% system, 0.0% nice, 59.6% idle, 0.0% x, 0.5% y
- Cpu0 : 0.0% user, 0.0% system, 0.0% nice, 100.0% idle, 0.0% x, 0.0% y
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 20.2% idle, 0.0% x, 1.1% y
復(fù)制代碼
實(shí)驗(yàn)結(jié)果讓我失望:
1、總CPU負(fù)載的確是下降了;
2、此時(shí)Cpu0變?yōu)榭臻e又變?yōu)?00%——軟中斷函數(shù)并沒有像預(yù)期的那樣,跑到Cpu0上面去;而是所有的東東又跑到Cpu1了,此時(shí)CPU1負(fù)載明顯上升很多,net_rx_action好像是隨著中斷落到哪個(gè)CPU上,它就跑到哪個(gè)CPU上面去;
3、一個(gè)有趣的現(xiàn)像是:所有任務(wù)由Cpu0處理,總負(fù)載是50%,所有任務(wù)由Cpu1處理,總負(fù)載下降很明顯,這個(gè)原因沒有仔細(xì)去考究了,難道是第二個(gè)核性能比第一個(gè)好???
因?yàn)橥ㄟ^上述實(shí)驗(yàn),得到了“net_rx_action好像是隨著中斷落到哪個(gè)CPU上,它就跑到哪個(gè)CPU上面去”的結(jié)論,那么一開始的“net_rx_action這個(gè)軟中斷,只在一個(gè)CPU上運(yùn)行了,并沒有實(shí)現(xiàn)多個(gè)CPU的同時(shí)運(yùn)行和調(diào)度”的結(jié)論就被推翻了。∧菫槭裁磿(huì)造成這種情況呢??我陷入了沉思當(dāng)中。
四、為什么會(huì)是這樣呢?
通過查看代碼,找到了原因(代碼有刪減):
- static void net_rx_action(struct softirq_action *h)
- {
- struct softnet_data *queue = &__get_cpu_var(softnet_data);
-
- while (!list_empty(&queue->poll_list)) {
- struct net_device *dev;
- dev = list_entry(queue->poll_list.next,
- struct net_device, poll_list);
- netpoll_poll_lock(dev);
- if (dev->quota <= 0 || dev->poll(dev, &budget)) {
- list_del(&dev->poll_list);
- list_add_tail(&dev->poll_list, &queue->poll_list);
- if (dev->quota < 0)
- dev->quota += dev->weight;
- else
- dev->quota = dev->weight;
- } else {
- }
- }
- out:
- local_irq_enable();
- return;
- softnet_break:
- __get_cpu_var(netdev_rx_stat).time_squeeze++;
- __raise_softirq_irqoff(NET_RX_SOFTIRQ);
- goto out;
- }
復(fù)制代碼
所有問題有核心在于,softnet_data是一個(gè)pre_cpu變量,net_rx_action被某個(gè)CPU?qǐng)?zhí)行時(shí),它只會(huì)遍歷屬于自己的網(wǎng)絡(luò)設(shè)備隊(duì)列。如上面的實(shí)驗(yàn)中,當(dāng)eth1只會(huì)出現(xiàn)在cpu0的網(wǎng)絡(luò)設(shè)備隊(duì)列,eth2只會(huì)出現(xiàn)在CPU1的隊(duì)列中。
遺憾的是,我的測(cè)試中,數(shù)據(jù)發(fā)送是單向的,所以,eth2沒有接收數(shù)據(jù)。所以,所有的網(wǎng)絡(luò)棧的工作,就理所當(dāng)然地落到了CPU0上面來了。
那為什么,“當(dāng)eth1只會(huì)出現(xiàn)在cpu0的網(wǎng)絡(luò)設(shè)備隊(duì)列,eth2只會(huì)出現(xiàn)在CPU1的隊(duì)列中”,也就是隨著硬件中斷落到哪個(gè)CPU上,它就會(huì)在哪個(gè)CPU響應(yīng)呢???這需要看poll_list這個(gè)網(wǎng)絡(luò)設(shè)備隊(duì)列的添加的實(shí)現(xiàn)過程了。
這個(gè)過程,都是在網(wǎng)卡中斷函數(shù)中,它會(huì)調(diào)用:
netif_rx_schedule
- static inline void netif_rx_schedule(struct net_device *dev)
- {
- if (netif_rx_schedule_prep(dev))
- __netif_rx_schedule(dev);
- }
復(fù)制代碼
- static inline void __netif_rx_schedule(struct net_device *dev)
- {
- unsigned long flags;
- local_irq_save(flags);
- dev_hold(dev);
- list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
- if (dev->quota < 0)
- dev->quota += dev->weight;
- else
- dev->quota = dev->weight;
- __raise_softirq_irqoff(NET_RX_SOFTIRQ);
- local_irq_restore(flags);
- }
復(fù)制代碼
所以,每個(gè)網(wǎng)絡(luò)設(shè)備中斷,會(huì)把產(chǎn)生中斷的網(wǎng)絡(luò)設(shè)備(也就是自己)放到響應(yīng)中斷的那個(gè)CPU的softnet_data的隊(duì)列上去。這就是原因所在了。
對(duì)于上面的實(shí)驗(yàn),當(dāng)一個(gè)網(wǎng)卡一個(gè)CPU時(shí):eth1產(chǎn)生中斷,把自己放到cpu0 的隊(duì)列,eth2產(chǎn)生中斷,把自己放到cpu1的隊(duì)列,因?yàn)閿?shù)據(jù)發(fā)送是單向的,當(dāng)cpu1進(jìn)入net_rx_action時(shí),它的設(shè)備列表中顯然不會(huì)有eth1,所以它也就沒有了處理后續(xù)處理工作的機(jī)會(huì),而所有的革命重任都落到了cpu0上。這就是前面實(shí)驗(yàn)中,為什么雖然硬中斷已經(jīng)實(shí)現(xiàn)一人處理一個(gè),但是cpu0的負(fù)載很高,而cpu1的負(fù)載很低的原因了。
五、最后一個(gè)實(shí)驗(yàn)
為了證明以上的推斷,將測(cè)試數(shù)據(jù)包方向改為雙向發(fā)送。這樣,eth2也會(huì)產(chǎn)生接收中斷,會(huì)把eth2的接收幀放到CPU1的隊(duì)列上去。就能夠?qū)崿F(xiàn)兩個(gè)net_rx_action并行——cpu0的隊(duì)列中包含eth1,cpu1的隊(duì)列中包含eth2……
- Cpu(s): 0.5% user, 0.5% system, 0.0% nice, 16.6% idle, 0.0% x, 1.6% y
- Cpu0 : 1.1% user, 0.0% system, 0.0% nice, 11.6% idle, 0.0% x, 0.0% y
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 21.9% idle, 0.0% x, 2.1% y
- Cpu(s): 0.0% user, 0.0% system, 0.0% nice, 16.8% idle, 0.0% x, 2.1% y
- Cpu0 : 0.0% user, 1.1% system, 0.0% nice, 10.5% idle, 0.0% x, 2.1% y
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 22.1% idle, 0.0% x, 2.1% y
- Cpu(s): 0.5% user, 0.5% system, 0.0% nice, 15.1% idle, 0.0% x, 2.1% y
- Cpu0 : 1.0% user, 0.0% system, 0.0% nice, 11.5% idle, 0.0% x, 1.0% y
- Cpu1 : 0.0% user, 0.0% system, 0.0% nice, 19.8% idle, 0.0% x, 3.1% y
復(fù)制代碼
1、cpu0的負(fù)載下降了,從2%的空閑到10%左右。這跟我的測(cè)試環(huán)境有關(guān)——數(shù)據(jù)包改為雙向后,發(fā)包機(jī)的性能下降,它發(fā)送的數(shù)據(jù)幀從166Mb/s降到了100Mb/s。
2、可以看到CPU1負(fù)載明顯地上升了,從70%多的空閑到20%左右,很明顯,它此時(shí)也要運(yùn)行net_rx_action,處理從收包機(jī)過來的接收到的數(shù)據(jù)幀,并處理網(wǎng)橋,Netfilter……等網(wǎng)絡(luò)棧的工能。
六:初步結(jié)論
1、多核下,IRQ的負(fù)載均衡應(yīng)該開啟;
2、中斷親和內(nèi)核自己可以通過調(diào)度算法解決,自己定義也可以;
3、中斷實(shí)現(xiàn)多核并行后,內(nèi)核協(xié)議棧的并行工作,包括網(wǎng)橋、ipv4、防火墻……的多核并行,跟硬中斷落到哪個(gè)CPU上,也有直接關(guān)系。
在實(shí)踐中,可能會(huì)遇到CPU數(shù)量大于/小于/等于網(wǎng)卡的情況,也有可能出現(xiàn)上/下行流量極不對(duì)稱的情況,但是以上實(shí)驗(yàn)對(duì)于多核下調(diào)整內(nèi)核的性能,還是很有意義的!
[ 本帖最后由 獨(dú)孤九賤 于 2009-5-19 15:51 編輯 ] |
|