摘 要:為避免創建緩沖區過程中必須指定大小和多次釋放而導致可能的內存泄露和代碼崩潰的弊端,提出一種自適應的嵌入式協議棧的緩沖區管理機制AutoBuf。它是基于抽象緩沖區接口而設計的,具有自適應性,支持動態內存的自動分配與回收,同時實現了嵌入式TCP/IP協議棧各層之間的零拷貝通信。在基于研究平臺S3C44B0X的Web server網絡數據監控系統上的測試結果表明,該緩沖區的設計滿足嵌入式系統網絡通信的應用需求,是一種高效、可靠的緩沖區管理機制。
關鍵詞:嵌入式協議棧; 抽象緩沖區; 零拷貝; 內存分配
中圖分類號:TP316文獻標志碼:A
文章編號:1001-3695(2009)06-2254-03
doi:10.3969/j.issn.1001-3695.2009.06.077
Design and implementation of adaptive buffer for embedded protocol stack
WANG Pei-dong, WU Xian-wei
(College of Computer Science Technology, Harbin University of Science Technology, Harbin 150080, China)
Abstract:
To avoid traditional method of creating buffer, which must have the size of buffer and free memory for many times, which will result in memory leaks and codes crash. This paper proposed a flexible buffer management mechanism AutoBuf for embedded network protocol stack. It was adaptive and scalable and based on an abstract buffer interface, supported dynamic me-mory allocation and backup. By using the AutoBuf buffer management mechanism with data zero copy technology, it implemented to transfer data through the embedded network protocol stack. The management mechanism had been applied to the Web server system base on S3C44b0X platform successfully. The results in real network condition show that the system provides a good performance and meets the necessary of embedded network system.
Key words:embedded stack; abstract buffer; zero-copy; memory allocation
隨著網絡技術的快速發展,主機間的通信速率已經提高到了千兆數量級,同時多媒體應用還要求網絡協議支持實時業務。嵌入式設備網絡化已經深入到日常生活中,而將嵌入式設備接入到互聯網需要網絡協議棧的支持。通過分析Linux系統中TCP/IP協議棧的實現過程,可以看出在協議棧中要有大量數據不斷輸入輸出,而管理這些即時數據的關鍵是協議棧中的緩沖區管理機制,因此對嵌入式協議棧的緩沖區管理將直接影響到數據的傳輸速率和安全。通用以太網的緩沖區管理機制,例如4.4BSD mbuf[1]和現行Linux系統中的sk_buf[2]多是在大內存、高處理速率的基礎上設計的,非常龐大復雜。由于嵌入式設備的硬件資源有限,特別是可用物理內存的限制,通用的協議棧必然不適用于嵌入式設備,在應用時要對標準的TCP/IP協議進行裁剪[3]和重新設計緩沖區管理機制。
1 緩沖區管理機制的性能需求分析
緩沖區管理[4]是對內存提供一種統一的管理手段,通過該手段能夠對可用內存提供分配、回收、數據操作等行為。內存的分配操作是根據一定的內存分配策略從緩沖區中獲得相應大小的內存空間;緩沖區的數據操作主要是向緩沖區寫數據,從緩沖區讀數據,在緩沖區中刪除數據,對空閑的內存塊進行合并等行為;內存的回收就是將已空閑的內存重新變為可用內存,以供存儲其他新的數據。
為了滿足長度不一的即時數據的需求,緩沖區對內存的操作主要集中在不斷地分配、回收、合并空閑的內存塊等操作。因為網絡中的數據包小到幾個字節大到幾千個字節,不同長度的數據對內存的需求必然不同。現存嵌入式設備中的內存多是以物理內存,即實模式形式存在的,沒有虛擬內存的形式,對內存的操作實際是操作真實的物理內存,所以對內存操作要特別謹慎。在傳統使用動態分配的緩沖區(通過調用 malloc()/free())在函數之間傳遞數據。盡管該方法提供了靈活性,但它也帶來了一些性能影響。首先考慮對緩沖區的管理(分配和釋放內存塊)。如果分配和釋放不能在相同的代碼位置進行,那么必須確保在某個內存塊不再需要時,釋放一次(且僅釋放一次)該內存塊是很重要的,否則就會導致內存泄露。其次是必須確定緩沖區的大小才能分配該內存塊。然而,確定數據大小并非那么容易,傳統做法是采用最大的數據尺寸的保守估計。而采用保守估計預分配的內存大小總是遠超過實際需要的大小,而且沒有一定的范圍標準,這樣難免會導致資源的嚴重浪費。
隨著數據在協議棧中的不斷流動,內存塊的多次釋放和多次分配是難以避免的,而保守估計對于有限的資源來說又是一種浪費的策略。因此為了能有效地利用資源,設計一種可自控的、不用預判斷大小的數據緩沖區接口就勢在必行。
由于嵌入式設備資源的限制,嵌入式緩沖區管理機制的設計性能[5]要達到以下幾點要求:
a)高效性。嵌入式設備的實時性要求緩沖區的分配與回收必須快,盡量減少延遲,能滿足實時數據的存儲與釋放。
b)可靠性。一方面是系統的內存請求必須得到滿足;另一方面必須避免內存分配中的內存泄露問題,一旦內存泄露,則可能帶來系統崩潰的危險。
c)持久性。嵌入式設備一般要運行很長時間,系統盡可能減少資源的浪費,降低碎片的產生,提高內存的利用率,保證系統的穩定。
自適應緩沖區的設計要有以下能力:
a)在有限的內存空間可以存放不同長度的數據。
b)盡量減少因存儲和釋放不同長度數據產生的內存碎片。
c)盡量減少分配和回收時遍歷的次數。
d)盡量減少對預分配的內存進行長度估計。
e)盡量減少緩沖區之間的數據拷貝操作。
另外,為了更好地利用嵌入式設備的資源,需要優化通用協議棧,使得緩沖區的分配和回收簡單、高效,提高內存的利用率。
2 緩沖區管理機制AutoBuf的分析與設計
緩沖區的分配一般有以下兩種策略[5]:
a)靜態分配。是指內存在程序編譯時已經確定好了大小,內存范圍是固定不變的,實現簡單,只要在系統設計時設定一個足夠大的緩沖區可以接收最大的數據包就行了。這種實現方法數據結構簡單、操作方便,但是可能造成內存的浪費,產生資源競爭問題并且不便于動態操作。
b)動態分配。是指根據系統運行時的需要,根據某種內存分配策略動態地滿足用戶申請的需求。實現機制相對于靜態機制來說比較靈活,為系統的實現帶來極大的方便,可以隨著數據包的到來不斷地擴充內存塊鏈表,避免了固定緩沖區分配中即使小數據包也要占據大內存空間的浪費現象,提高了內存的利用率;而且不存在固定共享資源的競爭,從而在同一時間可以處理多個數據包,增強數據的處理能力。但由于數據包的長度不一,在分配內存時可能會產生碎片問題。
綜觀靜態分配和動態分配,動態分配相對于靜態分配在資源利用方面是比較有優勢的。本文采用動態分配策略來設計協議棧的緩沖區,同時提出一種抽象的緩沖區接口設計來最大程度地減少內存碎片發生的概率,使緩沖區的管理更加靈活,更好地利用內存資源。
2.1 抽象緩沖區接口的設計
根據應用對象Web server對網絡的需求,參考4.4 BSD Mbuf和Linux中的 sk_buf[6]的設計,本文提出一種抽象的動態緩沖區管理機制,該機制具有自適應性的管理內存,支持動態的內存分配、回收。
一般數據緩沖區的分配是由兩個操作完成的,即數據緩沖區實體的定義和實際內存的分配[7]。然而事實上,在實際數據變得可用之前,其實是不需要分配實際的內存。根據這樣的思想可以將兩個操作分離開來。為了表示抽象的數據緩沖區接口,需要新定義兩個數據結構:
typedef struct BufferBlockHeader_st
BufferBlockHeader
{BufferBlockHeader*pNextBlock;
long intcurrentLength;
short intused;
short intflag;
unsigned char*startPoint;
unsigned char*endPoint;
};//對要分配的內存塊實體的定義
typedef struct Buffer_st Buffer{
longinttotalLength;
BufferBlockHeader*pFirstBlock;
BufferBlockHeader*pLastBlock;
};//已創建的抽象緩沖區接口的信息
本文設計的AutoBuf抽象緩沖區接口模型如圖1所示。
AutoBuf 包含關于已創建的抽象緩沖區的信息,它還管理動態存儲的內存塊的一個鏈表。
如果分配了內存,BufferBlockHeader 結構中的 pNextBlock 總是指向該鏈表中的下一個內存塊。每個內存塊在分配時都包含一個 BufferBlockHeader 頭,后面跟著一個用于存儲實際數據的緩沖區塊。
CurrentLength 是表示當前數據包的長度,一般當前數據的長度是小于一個MTU的;flag是標志當前的內存塊是否被引用,flag=0則認為是未被引用;used是表示該內存塊是否空閑,used=0則表示其是空閑塊則可以被回收;startPoint和endPoint是兩個界限指針主要是界定數據包的范圍;totalLength 記錄當前存儲在緩沖區鏈表中所有未發或已經接收的數據包的總大小;pFirstBlock 指向該鏈表中的第一個內存塊,pLastBlock 指向該鏈表的最后一個內存塊,這兩個指針界定總分配的內存范圍,避免在釋放時的內存泄露。
2.2 AutoBuf的主要偽代碼實現例程
由于抽象緩沖區接口是將定義與實現分開考慮的,在緩沖區出現數據之前,必須創建抽象緩沖區接口,分配一個包含了一個AutoBuf的內存塊,并初始化它的結構體,指明它是一個空抽象緩沖區。下面是用偽代碼實現創建函數例程:
struct buffer *createAutoBuf(){
allocate new AutoBuf structure
initialize this structure is NULL
}//創建接口并初始化為空
創建了抽象接口后,當有數據需要存儲時,就可以追加數據到抽象緩沖區中。使用下面偽代碼實現追加數據過程:
int appendData(AutoBuf *pBuf, byte *pInpu, long offset, long dataLen)
{while (pInput != NULL)
{*pBuf++ = *pInput++;}
}//追加數據到抽象緩沖區中
如果要從緩沖區中獲得數據,使用下面的偽代碼實現從抽象緩沖區逐段讀取數據,該函數銷毀性地從 pBuf 所指向的抽象緩沖區讀取數據,并在內存塊變為空時從鏈表中刪除它們,然后返回成功讀取的字節數目。
long int readData(buffer *pBuf, byte *pOutput, long offset,long data-Len)
{while (pBuf)
{*pOutput++ = *(pbuf->pFirstBlock++)
if (pFirstBlock == NULL)
{free(pbuf);}
}
}//從抽象緩沖區中讀取數據
相應地,必須在使用抽象緩沖區之后通過調用下面的 freeBuffer() 函數來銷毀該緩沖區中的內存塊:
void freeBuffer(buffer * pBuf)
{while (pBuf != NULL)
{free the next memory block}
free the buffer structure}
使用內存塊的一個空鏈表來創建一個抽象緩沖區。抽象數據緩沖區僅在實際數據變得可用時才分配內存,釋放內存也變成了抽象數據緩沖的責任。集中內存管理數據操作就會帶來以下優點:
a)內核和驅動均能通過調用預定義的 API 函數來構造和/或銷毀數據緩沖區。
b)內存使用將保持接近最優狀態,因為緩沖區內存僅在必要時才分配,并且會盡快釋放,從而最小化內存泄露。
c)由于沒有哪一方需要管理內存,確定緩沖區的大小就變得不必要了(因而也不可能存在前面指出的多次執行問題)。 事實證明緩沖區溢出也不可能會發生,因為僅當存在額外數據空間時才會復制數據。
2.3 數據傳輸的分析與零拷貝策略
網絡協議棧對內核的緩沖區管理能力提出了很多的要求。這些要求包括能方便地操作可變長緩存、能在緩存頭部和尾部添加數據、能從緩存中移走數據,并能盡量減少為這些操作所做的數據復制。
通過分析TCP/IP的原理,在整個數據傳輸過程中,有以下幾個數據拷貝操作:從應用程序到系統內核的拷貝;從系統內核到網卡設備數據緩沖區的拷貝;網絡層由于網絡最大傳輸單元(MTU)的限制對傳輸層傳來的數據包進行分片及對分片的重新組合可能引起的拷貝。為了提高網絡協議的傳輸速率,就要盡量減少以上過程中的拷貝次數。
如果能減少拷貝次數將會大大提高協議棧性能,并且可以節約內存空間。為了減少對數據塊的大量拷貝,在緩沖區中應盡量使用指針結構作為參數向下層傳遞,這樣的好處是不再把拷貝后放在網絡內核緩存中的數據作為參數傳遞給下層協議。在協議棧中各層之間不再設立獨自的緩沖區,相互之間傳遞數據指針,只有當數據傳送時才真正地拷貝數據,達到協議棧內部數據傳遞零拷貝的目的。
在AutoBuf中可以通過pNextBlock、startPoint、lastPoint等字段的控制,保證當數據在協議棧中處理時,只是通過指針作為參數傳遞就可以將數據指針傳到不同的層來處理。當真正要發送數據時才把數據指針對應的數據拷貝到網絡接口的存儲區,最終發送出去,減少了數據在傳輸過程中的多次拷貝操作,達到提高傳輸速率的目的。
3 AutoBuf性能測試分析
測試平臺:采用以Samsumg公司的S3C44B0X為核心的ARM系統開發平臺,開發板存儲器主要配置包括8 MB SDRAM, 2 MB Flash。
測試方法:移植uCLinux到目標板S3C44B0X,并把網絡協議棧部分作為模塊加載并在應用層編寫測試程序進行測試。
1)基于AutoBuf的服務器的測試算法
1 初始化網絡服務
2 循環等待客戶端連接
2.1 對于一個客戶端連接建立一個進程
2.2 進程處理程序
2.3數據大小M=100 MB
2.4 接收傳輸長度L′
2.5 循環 直至M=0
2.5.1 L=L′
2.5.2 如果L>B1(服務器傳輸端塊大小),則
2.5.2.1 發送B1個字節
2.5.2.2 L=L-B1 轉至2.5.2
否則
2.5.3 發送L個字節
2.5.4 M=M-L′
2)基于AutoBuf的客戶端的測試算法
1 與服務器建立N個連接,對每個連接發送傳輸長度L′
2 M=100 MB
3 開始計時
4 循環 直至M=0
4.1 L=L′
4.2 如果L>B2(客戶端傳輸塊大小) 則
4.2.1對每個連接,接收B2個字節
4.2.2 L=L-B2,轉至5.2
否則
4.2.3 對每個連接接收L個字節
4.3 M=M-L′
5 結束計時,得到時間間隔T′,就算T=T′/N
6 對每個連接發送L=0,關閉連接
其中:L是每個連接發送的數據長度;N是客戶端與服務器端點連接的進程個數;B1是服務器每次發送快的大小;B2是客戶端每次接收塊的大小,固定為4 KB; M是最大的傳輸總量。
測試結果:分別移植Linux和uCLinux到目標板S3C44B0X中,然后分別對其協議棧緩沖區管理機制進行網絡性能測試。這里以系統利用率和網絡傳輸速率為功耗指標,對CPU利用率和網絡丟包率進行比較,其性能比較如圖2、3所示。CPU利用率的高低說明整體系統的穩定性比較好。由圖2數據可見,在一定網絡速率下,改進的AutoBuf機制總體CPU功耗比較低,基本在20%以下,適應ARM處理器的要求。網絡丟包率的高低說明網絡數據傳輸的性能高。由圖3數據可以看出,隨網絡速率的提高,原Linux的網絡丟包率持續高增長,而AutoBuf則保持低增長狀態,基本保持在20%以下,總體上能滿足應用對象Web server的實際需求。
經過實際的網絡測試后,結果證明在uCLinux中的AutoBuf管理機制的應用與零拷貝技術的結合能很好地減少CPU利用率和網絡丟包率,是一種高效的協議棧管理機制,完全適合特定的嵌入式Web server系統需求。
4 結束語
本文在參考4.4 BSD Mbuf和Linux中的 sk_buf的緩沖區管理機制基礎上,根據緩沖區的分配原理,將緩沖區的定義與內存的實體分配兩個過程分離來考慮,提出一種抽象緩沖區AutoBuf的設計。該緩沖區主要支持動態的內存分配,避免了傳統的動態內存分配時因不知道實際的數據大小,而進行的保守估計的預分配做法,減少了內存的浪費,提高了有限資源的利用率。
參考文獻:
[1]WRIGHT G R, STEVENS W R. TCP/IP illustrated vol2: the implementation[M].1995.
[2]HANGINO J I. Mbuf issues in 4.4BSD IPv6/IPSec support[C]//Proc of USENIX Annual Technical Conference.2000.
[3]付曉軍,夏應清,何軒.基于LWIP協議棧的內存管理[D].武漢:華中師范大學,2005:10-11.
[4]榮蘇娟,王沁,張曉彤.一種用于嵌入式系統的可變長緩沖區設計及其實現[J].微計算機信息,2005,21(23):10-12.
[5]宋麗華.一種高效嵌入式協議棧緩沖區管理機制[D].北京:北京科技大學,2008:35-37.
[6]JERRY CHU H K. Zero-copy TCP in solaris[C]//Proc of USENIX Annual Technical Conference.1996:253-264.
[7]LLIKKAL R, IYER R, NEWELL D. Microarchitectural anatomy of a commercal TCP/IP stack[J].Communication Technology Laboratory,2004,5(10):38-43.
[8]GUO Chuan-xiong, ZHENG Shao-ren, Analysis and and evalution of the TCP/IP protocol stack of Linux[C]//Proc of International Confe-rence on Communication Technology Proceedings.2000:444-453.