歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux管理 >> Linux網絡 >> NAPI技術在Linux網絡驅動上的應用(三)

NAPI技術在Linux網絡驅動上的應用(三)

日期:2017/2/27 14:23:15   编辑:Linux網絡
  能讓接收速度更快一些嗎?   我們現在來思考一下如何提高 NAPI 效率的問題,在說到效率這個問題之前我們先看一下在Linux 的文檔中 NAPI_HOWTO.txt 中提供一個模型用來構造自己 NIC 的 POLL 方法,不過和 8139 有一些不一樣,其中 NIC 設備描述中有一個 dirty_rx 字段是在 8139CP 中沒有使用到的。     dirty_rx 就是已經開辟了 sk_buff 緩沖區指針和已經提交到 NIC 的 rx_ring 參與接收的緩沖,但是還沒有完成傳輸的緩沖區和已經完成傳輸的緩沖區的數量總和,與之相類似的是 cur_rx 這個表示的是下一個參與傳輸的緩沖區指針,我們在 NAPI_HOWTO.txt 的舉例中可以看到這個字段的一些具體使用方式:     /*cur_rx為下一個需要參與傳輸的緩沖區指針,如果cur_rx指針大於dirty_rx那麼表示已經有在rx-ring中開辟的rx-ring中的每個傳輸緩沖已經被耗盡了,這個時候需要調用refill_rx_ring 把一些已經向網絡層提交了數據的rx-ring接收單元開辟新的緩沖區,增加dirty_rx的數值,為下一次數據接收做准備,*/  if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2   tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)   refill_rx_ring(dev);    /*如果已經當前的cur_rx和dirty_rx之間相差不超過總的rx_ring接收單元的一半,而且剩下的一半中間有空的傳輸單元,那麼我們不必擔心了,因為還有足夠的緩沖區可以使用(憑經驗推斷的),就可以退出當前的程序,等待下一次軟中斷調用POLL來處理在這之間收到的數據,(NAPI_HOWTO.txt中是重新啟動時鐘計數,這樣做是在沒有使能NIC中斷處理的情況下)*/    if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)        restart_timer();  /*如果執行到這裡了,那表示有幾種情況可能發生,第一當前的cur_rx和dirty_rx之間相差不超過總的rx_ring接收單元的一半,調用refill_rx_ring後dirty_rx並未增加,(也許在rx-ring中大量的單元收到數據沒有得到網絡層函數的處理),結果dirty_rx沒有增加,而且也沒有空閒的單元來接收新到的數據,這樣就要重新調用netif_rx_schedule 來喚醒軟中斷,調用設備的POLL方法,采集在rx-ring的數據。*/   else netif_rx_schedule(dev); /* we are back on the poll list */     在 RTL-8169 的驅動程序中就使用了 dirty_rx 這個字段,但是在 8139CP 中並未使用,其實這個並非 8139CP 驅動不成熟的表現,大家閱讀 NAPI_HOWTO.txt 中可以知道,現在 8139CP 中並未嚴格按照 NAPI 所提出的要求去做,如果大家有興趣的話,可以比較一下 8139CP 和 RTL-8169 這兩個驅動之間的不同,大家會發現雖然兩者都沒有在 NIC 中斷處理中去完成數據從驅動層向網絡層上的轉發,而都放在了軟中斷之中完成,但是在 8139 中利用了自己的一些獨特的硬件特性,使 NIC 在利用關斷中斷接收數據的同時利用數據包到達位(RxOK)通知到達事件,然後采用 POLL 方法把數據從 NIC 直接轉發到上層;而 RTL8169 還需要借助 softnet_data 結構中的 input_pkt_queue(套接字緩沖(sk_buff)輸入隊列)來完成從 NIC 中斷到軟中斷之間的 sk_buff 數據調度;這樣對於 8139CP 來說最大的好處就是不要了 dirty_rx 字段和 cur_rx 字段來讓 POLL 方法以及 NIC 中斷知道當前的傳輸單元的狀況,還包括不需要不時定期的調用 refill_rx_ring 來刷新 rx-ring 獲得空閒的傳輸單元;說到壞處我想就是重寫了一個 POLL 方法,完全不能借用 /net/core/dev.c 中的 process_backlog 來作為自己的POLL方法,不過這個代價值得。     說了這麼多,似乎都和提高效率沒有關系,其實正好相反,通過這些了解我們對 softnet_data中的一些字段的意思應該更加清晰了,下面所敘述的,提高效率的方法就是在 8139CP 的基礎上借用了 NAPI_ HOWTO.txt 中的一些方法,從實際上的使用效果來看,在某些應用場合之下比 Linux的 8139CP 的確是有了一定的提高,我們首先看看在 Linux2.6.6 的內核使用 8139CP 在x86(PIII-900Mhz)平台上的數據包接收處理情況:比較表如下:     Psize  Ipps    Tput   Rxint      Done  ----------------------------------------------------  60   490000   254560   21       10  128   358750   259946   27       11  256   334454   450034   34       18  512   234550   556670   201239     193455  1024  119061   995645   884526     882300  1440   74568   995645   995645     987154     上表中表示:  "Pszie"表示包的大小  "Ipps" 每秒鐘系統可以接收的包數量  "Tput" 每次POLL超過 1M 個數據包的總量  "Rxint" 接收中斷數量  "Done" 載入 rx-ring 內數據所需要的 POLL 次數,這個數值也表示了我們需要清除 rx-ring 的次數。     從上表可以看出,8139CP 中當接收速率達到 490K packets/s 的時候僅僅只有 21 個中斷產生,只需要 10 次 POLL 就可以完成數據從 rx_ring 的接收,然而對於大數據包低速率的情況,接收中斷就會急劇增加,直到最後每個數據包都需要一次 POLL 的方法來進行處理,最後的結果就是每個中斷都需要一次 POLL 的方法,最後造成效率的急劇下降,以至於系統的效率就會大大降低,所以 NAPI 適用於大量的數據包而且盡可能是小的數據包,但是對於大的數據包,而且低速率的,反而會造成系統速度的下降。     如果要改善這種情況,我們可以考慮采用以下的方法,我們在 MIPS,Xsacle 和 SA1100 平台上進行一系列的測試取得了良好的效果:     1. 完全取消 NIC 中斷,使用 RXOK 位置控制接收中斷。  2. 采用定時器中斷 timer_list 的控制句柄,根據硬件平台設定一個合適的間隔周期(間隔周期依據平台不同而異),對 rx-ring 直接進行 POLL 輪詢,我們在 MIPS 和 Xscale 上直接使用了中斷向量 0--irq0 作為對 rx-ring 進行輪詢的 top-half(注意我們在上述兩個平台上選擇的 HZ 數值是 1000,而通常這個數值是 100,並且重新編寫了 Wall-time 的記數程序,讓 Wall-Time 的記數還是以 10MS 為間隔),當然也可以根據自己的平台和應用程序的狀況選擇合適的定時時間。  3. 借助 softnet_data 中的 input_pkt_queue 隊列,在時鐘中斷 bottom-half 中完成 POLL 方法之後,並不直接把數據傳輸到網絡層進行處理,而是把 sk_buff 掛在 input_pkt_queue隊列上,喚醒軟中斷在過後處理,當然可以想象,這樣需要付出一定的內存代價,而且實時性能也要差一些。  4. 使用 dirty_rx 字段和 refill_rx_ring 函數,在調用完 POLL 方法以後,而且網絡層程序比較空閒的時候為一些 rx-ring 中的單元建立新緩沖掛在環形緩沖隊列上,這樣可以在新的數據包達到的時候節省時間,操作系統不必要手忙腳亂地開辟新的空間去應付新來的數據。  5. 最後請注意:我們上層的應用程序是以網絡數據轉發為主的,並沒有在應用層面上有很多後台進程的復雜的應用,上述的 1 到 4 點中所做的顯而易見是以犧牲系統效率整體效率而單獨改善了網絡數據的處理。     我們再來看改善的 8139CP 驅動程序使用 8139CP 在 x86(PIII-900Mhz) 平台上的接收情況:     Psize  Ipps    Tput   Rxint    Done  ----------------------------------------------------  60   553500  354560  17     7  128   453000  350400  19     10  256   390050  324500  28     13  512   305600  456670  203    455  1024   123440  340020  772951   123005  1440   64568   344567  822394   130000     從上圖來看,數據傳輸的效率和波動性有很明顯的改善,在高速率和低速率的時候所需要的POLL 次數的差距以前的 8139CP 驅動程序那麼顯著了,這樣的而且最大的包接收能力也提高到了 553K/s,我們在 MIPS 系列以及 Xscale 系列平台上最大的包接收能力可以提高大約 15%-25%。     最後使用 NAPI 並不是改善網絡效率的唯一途徑,只能算是權益之策,根本的解決途徑還是在於上層應用程序能夠獨占網絡設備,或者是提供大量的緩沖資源,如果這樣,根據我們的實驗數據表明可以提高 100%-150% 以上的接收效率。




Copyright © Linux教程網 All Rights Reserved