- 論壇徽章:
- 0
|
NAPI的由來(lái):
NAPI是2.4.20后的內(nèi)核版本在網(wǎng)卡驅(qū)動(dòng)做的一項(xiàng)優(yōu)化措施,當(dāng)年某個(gè)商業(yè)測(cè)試2.2的Linux和Winnt的網(wǎng)絡(luò)效率,Linux在小包處理吞吐量輸了,這個(gè)報(bào)告引起了很大的爭(zhēng)議,后來(lái)Linux在驅(qū)動(dòng)采取了一系列的優(yōu)化措施,NAPI是很重要的一個(gè)。
NAPI的原理: 一般情況下,每接收到一個(gè)幀,都會(huì)出發(fā)一次網(wǎng)絡(luò)中斷,然后軟中斷處理這個(gè)報(bào)文,直到報(bào)文到目的地(轉(zhuǎn)發(fā)或用戶socket buffer).
現(xiàn)在的做法,大流量情況下,收中斷是不啟用的。這樣收幀不會(huì)頻繁觸發(fā)網(wǎng)絡(luò)中斷,而是報(bào)文到了一定數(shù)量后觸發(fā)一次中斷,如8139網(wǎng)卡。在cp_interrupt()中,會(huì)調(diào)用NAPI的接口,將網(wǎng)卡加入到softirq任務(wù)鏈表中,然后喚醒softirq, 在softirq中,回調(diào)dev中的接口批量處理報(bào)文。
if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
if (netif_rx_schedule_prep(dev)) {
cpw16_f(IntrMask, cp_norx_intr_mask);
__netif_rx_schedule(dev);
}
__netif_rx_schedule() -->
{
unsigned long flags;
raw_local_irq_save(flags);
dev_hold(dev);
/* 將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);
raw_local_irq_restore(flags);
}
軟中斷處理中,會(huì)利用dev->poll() 函數(shù),實(shí)現(xiàn)一次軟中斷,處理大量報(bào)文,如8139
cp_rx_poll() -->
批量處理網(wǎng)卡buffer中的報(bào)文。
softirq處理過(guò)程也有同樣的優(yōu)化,正常情況下,所有的報(bào)文都是在軟中斷中完成,但是當(dāng)軟中斷一直有處理不完的報(bào)文,為了提高系統(tǒng)實(shí)時(shí)行,軟中斷處理完一定數(shù)量的報(bào)文后,必須退出,剩余的報(bào)文通過(guò)喚醒softirqd 內(nèi)核線程來(lái)完成。
void ___do_softirq(void) -->
/* 如果處理一輪后,仍然后報(bào)文要處理,喚醒softirqd任務(wù)代為處理 */
if (pending)
trigger_softirqs();
trigger_softirqs()-->
static void trigger_softirqs(void)
{
u32 pending = local_softirq_pending();
int curr = 0;
while (pending) {
if (pending & 1)
/* 喚醒softirqd */
wakeup_softirqd(curr);
pending >>= 1;
curr++;
}
}
內(nèi)核: 2.6.15-rt2 |
|