Linux中的零拷貝技術(shù),第2部分_第1頁(yè)
Linux中的零拷貝技術(shù),第2部分_第2頁(yè)
Linux中的零拷貝技術(shù),第2部分_第3頁(yè)
Linux中的零拷貝技術(shù),第2部分_第4頁(yè)
Linux中的零拷貝技術(shù),第2部分_第5頁(yè)
已閱讀5頁(yè),還剩9頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、Linux中的直接I/O如果應(yīng)用程序可以直接訪問(wèn)網(wǎng)絡(luò)接口存儲(chǔ),那么在應(yīng)用程序訪問(wèn)數(shù)據(jù)之前存儲(chǔ)總線就不需要被遍歷,數(shù)據(jù)傳輸所引起的開銷將會(huì)是最小的。應(yīng)用程序或者運(yùn)行在用戶模式下的庫(kù)函數(shù)可以直接訪問(wèn)硬件設(shè)備的存儲(chǔ),操作系統(tǒng)內(nèi)核除了進(jìn)行必要 的虛擬存儲(chǔ)配置工作之外,不參與數(shù)據(jù)傳輸過(guò)程中的其它任何事情。 直接I/O使 得數(shù)據(jù)可以直接在應(yīng)用程序和外圍設(shè)備之間進(jìn)行傳輸,完全不需要操作系統(tǒng)內(nèi)核 頁(yè)緩存的支持。關(guān)于直接I/O技術(shù)的具體實(shí)現(xiàn)細(xì)節(jié)可以參看 developerWorks上 的另一篇文章” Linux中直接I/O機(jī)制的介紹”,本文不做過(guò)多描述。圖1.使用直接I/O的數(shù)據(jù)傳輸針對(duì)數(shù)據(jù)傳輸不需要經(jīng)過(guò)應(yīng)用程

2、序地址空間的零拷貝技術(shù)利用 mmap()在Linux中,減少拷貝次數(shù)的一種方法是調(diào)用mmap()來(lái)代替調(diào)用read,比如:tmp_buf = mmap(file, le n); write(socket, tmp_buf, len);首先,應(yīng)用程序調(diào)用了 mmap()之后,數(shù)據(jù)會(huì)先通過(guò) DMA拷貝到操作系統(tǒng)內(nèi) 核的緩沖區(qū)中去。接著,應(yīng)用程序跟操作系統(tǒng)共享這個(gè)緩沖區(qū),這樣,操作系統(tǒng) 內(nèi)核和應(yīng)用程序存儲(chǔ)空間就不需要再進(jìn)行任何的數(shù)據(jù)拷貝操作。應(yīng)用程序調(diào)用了write()之后,操作系統(tǒng)內(nèi)核將數(shù)據(jù)從原來(lái)的內(nèi)核緩沖區(qū)中拷貝到與socket相關(guān)的內(nèi)核緩沖區(qū)中。接下來(lái),數(shù)據(jù)從內(nèi)核socket緩沖區(qū)拷貝到協(xié)議引

3、擎中去,這是第三次數(shù)據(jù)拷貝操作。圖2.利用 mmap()代替read()應(yīng)用程序fl應(yīng)用隕序緩沖區(qū) Il V內(nèi)核頁(yè)緩存socket緩沖區(qū)通過(guò)使用mmap()來(lái)代替read(),已經(jīng)可以減半操作系統(tǒng)需要進(jìn)行數(shù)據(jù)拷貝的 次數(shù)。當(dāng)大量數(shù)據(jù)需要傳輸?shù)臅r(shí)候,這樣做就會(huì)有一個(gè)比較好的效率。但是,這 種改進(jìn)也是需要代價(jià)的,使用 mma()p其實(shí)是存在潛在的問(wèn)題的。當(dāng)對(duì)文件進(jìn) 行了內(nèi)存映射,然后調(diào)用 write()系統(tǒng)調(diào)用,如果此時(shí)其他的進(jìn)程截?cái)嗔诉@個(gè)文 件,那么write()系統(tǒng)調(diào)用將會(huì)被總線錯(cuò)誤信號(hào) SIGBUS中斷,因?yàn)榇藭r(shí)正在 執(zhí)行的是一個(gè)錯(cuò)誤的存儲(chǔ)訪問(wèn)。這個(gè)信號(hào)將會(huì)導(dǎo)致進(jìn)程被殺死,解決這個(gè)問(wèn)題可 以

4、通過(guò)以下這兩種方法:1. 為SIGBUS安裝一個(gè)新的信號(hào)處理器,這樣,write()系統(tǒng)調(diào)用在它被中 斷之前就返回已經(jīng)寫入的字節(jié)數(shù)目,errno會(huì)被設(shè)置成success但是這 種方法也有其缺點(diǎn),它不能反映出產(chǎn)生這個(gè)問(wèn)題的根源所在,因?yàn)?BIGBUS信號(hào)只是顯示某進(jìn)程發(fā)生了一些很嚴(yán)重的錯(cuò)誤。2. 第二種方法是通過(guò)文件租借鎖來(lái)解決這個(gè)問(wèn)題的,這種方法相對(duì)來(lái)說(shuō)更好一些。我們可以通過(guò)內(nèi)核對(duì)文件加讀或者寫的租借鎖,當(dāng)另外一個(gè)進(jìn)程嘗試對(duì)用戶正在進(jìn)行傳輸?shù)奈募M(jìn)行截?cái)嗟臅r(shí)候,內(nèi)核會(huì)發(fā)送給用戶一個(gè)實(shí)時(shí)信號(hào):RT_SIGNAL_LEASE信號(hào),這個(gè)信號(hào)會(huì)告訴用戶內(nèi)核破壞了用 戶加在那個(gè)文件上的寫或者讀租借鎖,那

5、么write()系統(tǒng)調(diào)用則會(huì)被中斷,并且進(jìn)程會(huì)被SIGBUS信號(hào)殺死,返回值則是中斷前寫的字節(jié)數(shù),errno也會(huì)被設(shè)置為success文件租借鎖需要在對(duì)文件進(jìn)行內(nèi)存映射之前設(shè)置。使用mmap是POSIX兼容的,但是使用mmap并不一定能獲得理想的數(shù)據(jù)傳 輸性能。數(shù)據(jù)傳輸?shù)倪^(guò)程中仍然需要一次CPU拷貝操作,而且映射操作也是一個(gè)開銷很大的虛擬存儲(chǔ)操作,這種操作需要通過(guò)更改頁(yè)表以及沖刷TLB (使得TLB的內(nèi)容無(wú)效)來(lái)維持存儲(chǔ)的一致性。但是,因?yàn)橛成渫ǔ_m用于較大范圍, 所以對(duì)于相同長(zhǎng)度的數(shù)據(jù)來(lái)說(shuō),映射所帶來(lái)的開銷遠(yuǎn)遠(yuǎn)低于CPU拷貝所帶來(lái)的開銷。sen dfile()為了簡(jiǎn)化用戶接口,同時(shí)還要繼續(xù)保

6、留mmap()/write()技術(shù)的優(yōu)點(diǎn):減少 CPU的拷貝次數(shù),Linux在版本2.1中引入了 sendfile()這個(gè)系統(tǒng)調(diào)用。sendfile()不僅減少了數(shù)據(jù)拷貝操作,它也減少了上下文切換。首先:sendfile()系 統(tǒng)調(diào)用利用DMA引擎將文件中的數(shù)據(jù)拷貝到操作系統(tǒng)內(nèi)核緩沖區(qū)中,然后數(shù) 據(jù)被拷貝到與socket相關(guān)的內(nèi)核緩沖區(qū)中去。接下來(lái),DMA引擎將數(shù)據(jù)從內(nèi) 核socket緩沖區(qū)中拷貝到協(xié)議引擎中去。如果在用戶調(diào)用sendfile ()系統(tǒng)調(diào)用進(jìn)行數(shù)據(jù)傳輸?shù)倪^(guò)程中有其他進(jìn)程截?cái)嗔嗽撐募?,那么sendfile ()系統(tǒng)調(diào)用會(huì)簡(jiǎn) 單地返回給用戶應(yīng)用程序中斷前所傳輸?shù)淖止?jié)數(shù),errno會(huì)

7、被設(shè)置為success如果在調(diào)用sen dfile()之前操作系統(tǒng)對(duì)文件加上了租借鎖,那么se ndfile()的操作和返回狀態(tài)將會(huì)和 mmap()/write () 一樣圖3.利用sendfile ()進(jìn)行數(shù)據(jù)傳輸應(yīng)用程序應(yīng)用程序緩沖區(qū)內(nèi)核MM頁(yè)緩存socket緩沖區(qū)sen dfile()系統(tǒng)調(diào)用不需要將數(shù)據(jù)拷貝或者映射到應(yīng)用程序地址空間中去,所以 sen dfile()只是適用于應(yīng)用程序地址空間不需要對(duì)所訪問(wèn)數(shù)據(jù)進(jìn)行處理的情況。 相對(duì)于mmap()方法來(lái)說(shuō),因?yàn)閟endfile傳輸?shù)臄?shù)據(jù)沒有越過(guò)用戶應(yīng)用程序/ 操作系統(tǒng)內(nèi)核的邊界線,所以sendfile ()也極大地減少了存儲(chǔ)管理的開銷。但

8、是, sen dfile ()也有很多局限性,如下所列: sendfile()局限于基于文件服務(wù)的網(wǎng)絡(luò)應(yīng)用程序,比如web服務(wù)器。據(jù)說(shuō), 在Linux內(nèi)核中實(shí)現(xiàn)sendfile()只是為了在其他平臺(tái)上使用 sendfile() 的Apache程序。由于網(wǎng)絡(luò)傳輸具有異步性,很難在sendfile ()系統(tǒng)調(diào)用的接收端進(jìn)行配對(duì) 的實(shí)現(xiàn)方式,所以數(shù)據(jù)傳輸?shù)慕邮斩艘话銢]有用到這種技術(shù)。*基于性能的考慮來(lái)說(shuō),se ndfile ()仍然需要有一次從文件到 socket緩沖 區(qū)的CPU拷貝操作,這就導(dǎo)致頁(yè)緩存有可能會(huì)被傳輸?shù)臄?shù)據(jù)所污染。帶有DMA收集拷貝功能的 sendfile()上小節(jié)介紹的sen df

9、ile()技術(shù)在進(jìn)行數(shù)據(jù)傳輸仍然還需要一次多余的數(shù)據(jù)拷貝 操作,通過(guò)引入一點(diǎn)硬件上的幫助,這僅有的一次數(shù)據(jù)拷貝操作也可以避免。為了避免操作系統(tǒng)內(nèi)核造成的數(shù)據(jù)副本,需要用到一個(gè)支持收集操作的網(wǎng)絡(luò)接口, 這也就是說(shuō),待傳輸?shù)臄?shù)據(jù)可以分散在存儲(chǔ)的不同位置上,而不需要在連續(xù)存儲(chǔ)中存放。這樣一來(lái),從文件中讀出的數(shù)據(jù)就根本不需要被拷貝到socket緩沖區(qū)中去,而只是需要將緩沖區(qū)描述符傳到網(wǎng)絡(luò)協(xié)議棧中去,之后其在緩沖區(qū)中建立起數(shù)據(jù)包的相關(guān)結(jié)構(gòu),然后通過(guò)DMA收集拷貝功能將所有的數(shù)據(jù)結(jié)合成一個(gè)網(wǎng)絡(luò)數(shù)據(jù)包。網(wǎng)卡的 DMA引擎會(huì)在一次操作中從多個(gè)位置讀取包頭和數(shù)據(jù)。 Linux 2.4版本中的socket緩沖區(qū)就

10、可以滿足這種條件,這也就是用于Linux中的眾所周知的零拷貝技術(shù),這種方法不但減少了因?yàn)槎啻紊舷挛那袚Q所帶來(lái)開 銷,同時(shí)也減少了處理器造成的數(shù)據(jù)副本的個(gè)數(shù)。對(duì)于用戶應(yīng)用程序來(lái)說(shuō),代碼沒有任何改變。首先,sendfile()系統(tǒng)調(diào)用利用DMA引擎將文件內(nèi)容拷貝到內(nèi) 核緩沖區(qū)去;然后,將帶有文件位置和長(zhǎng)度信息的緩沖區(qū)描述符添加到socket緩沖區(qū)中去,此過(guò)程不需要將數(shù)據(jù)從操作系統(tǒng)內(nèi)核緩沖區(qū)拷貝到socket緩沖區(qū)中,DMA引擎會(huì)將數(shù)據(jù)直接從內(nèi)核緩沖區(qū)拷貝到協(xié)議引擎中去,這樣就避免了最后一次數(shù)據(jù)拷貝。圖4.帶有 DMA 收集拷貝功能的 sendfile應(yīng)用趕序應(yīng)用程序緩沖區(qū)內(nèi)核tndr11«

11、;:頁(yè)緩存無(wú)加範(fàn)福-店睜socket韁沖區(qū)通過(guò)這種方法,CPU在數(shù)據(jù)傳輸?shù)倪^(guò)程中不但避免了數(shù)據(jù)拷貝操作,理論上, CPU也永遠(yuǎn)不會(huì)跟傳輸?shù)臄?shù)據(jù)有任何關(guān)聯(lián),這對(duì)于 CPU的性能來(lái)說(shuō)起到了積 極的作用:首先,高速緩沖存儲(chǔ)器沒有受到污染;其次,高速緩沖存儲(chǔ)器的一致 性不需要維護(hù),高速緩沖存儲(chǔ)器在DMA進(jìn)行數(shù)據(jù)傳輸前或者傳輸后不需要被刷新。然而實(shí)際上,后者實(shí)現(xiàn)起來(lái)非常困難。源緩沖區(qū)有可能是頁(yè)緩存的一部分, 這也就是說(shuō)一般的讀操作可以訪問(wèn)它,而且該訪問(wèn)也可以是通過(guò)傳統(tǒng)方式進(jìn)行的。 只要存儲(chǔ)區(qū)域可以被 CPU訪問(wèn)到,那么高速緩沖存儲(chǔ)器的一致性就需要通過(guò) DMA傳輸之前沖刷新高速緩沖存儲(chǔ)器來(lái)維護(hù)。而且,這種

12、數(shù)據(jù)收集拷貝功能的 實(shí)現(xiàn)是需要硬件以及設(shè)備驅(qū)動(dòng)程序支持的。splice()splice()是 Linux 中與 mmap()和sendfile()類似的一種方法。它也可以用于用戶應(yīng)用程序地址空間和操作系統(tǒng)地址空間之間的數(shù)據(jù)傳輸。splice()適用于可以確定數(shù)據(jù)傳輸路徑的用戶應(yīng)用程序,它不需要利用用戶地址空間的緩沖區(qū)進(jìn)行顯式的數(shù)據(jù)傳輸操作。那么,當(dāng)數(shù)據(jù)只是從一個(gè)地方傳送到另一個(gè)地方,過(guò)程中所傳輸?shù)臄?shù)據(jù)不需要經(jīng)過(guò)用戶應(yīng)用程序的處理的時(shí)候,spice()就成為了一種比較好的選擇。splice()可以在操作系統(tǒng)地址空間中整塊地移動(dòng)數(shù)據(jù),從而減 少大多數(shù)數(shù)據(jù)拷貝操作。而且,splice()進(jìn)行數(shù)據(jù)傳輸

13、可以通過(guò)異步的方式來(lái)進(jìn) 行,用戶應(yīng)用程序可以先從系統(tǒng)調(diào)用返回, 而操作系統(tǒng)內(nèi)核進(jìn)程會(huì)控制數(shù)據(jù)傳輸 過(guò)程繼續(xù)進(jìn)行下去。splice()可以被看成是類似于基于流的管道的實(shí)現(xiàn),管道可 以使得兩個(gè)文件描述符相互連接,splice的調(diào)用者則可以控制兩個(gè)設(shè)備(或者協(xié) 議棧)在操作系統(tǒng)內(nèi)核中的相互連接。splice()系統(tǒng)調(diào)用和sendfile()非常類似,用戶應(yīng)用程序必須擁有兩個(gè)已經(jīng)打開 的文件描述符,一個(gè)用于表示輸入設(shè)備,一個(gè)用于表示輸出設(shè)備。與sendfile()不 同的是,splice()允許任意兩個(gè)文件之間互相連接, 而并不只是文件到socket進(jìn) 行數(shù)據(jù)傳輸。對(duì)于從一個(gè)文件描述符發(fā)送數(shù)據(jù)到soc

14、ket這種特例來(lái)說(shuō),一直都是使用sendfile()這個(gè)系統(tǒng)調(diào)用,而splice 一直以來(lái)就只是一種機(jī)制,它并不 僅限于sendfile()的功能。也就是說(shuō),sendfile()只是splice()的一個(gè)子集,在 Linux 2.6.23中,sendfile()這種機(jī)制的實(shí)現(xiàn)已經(jīng)沒有了,但是這個(gè)API以及相應(yīng)的功能還存在,只不過(guò) API以及相應(yīng)的功能是利用了splice()這種機(jī)制來(lái)實(shí)現(xiàn)的。在數(shù)據(jù)傳輸?shù)倪^(guò)程中,splice()機(jī)制交替地發(fā)送相關(guān)的文件描述符的讀寫操作, 并且可以將讀緩沖區(qū)重新用于寫操作。它也利用了一種簡(jiǎn)單的流控制,通過(guò)預(yù)先定義的水印(watermark )來(lái)阻塞寫請(qǐng)求。有實(shí)驗(yàn)表

15、明,利用這種方法將數(shù)據(jù) 從一個(gè)磁盤傳輸?shù)搅硪粋€(gè)磁盤會(huì)增加30%到70%的吞吐量,數(shù)據(jù)傳輸?shù)倪^(guò)程中,CPU的負(fù)載也會(huì)減少一半。Linux 2.6.17內(nèi)核引入了 splice()系統(tǒng)調(diào)用,但是,這個(gè)概念在此之前其實(shí)已 經(jīng)存在了很長(zhǎng)一段時(shí)間了。1988年,Larry McVoy提出了這個(gè)概念,它被看成是一種改進(jìn)服務(wù)器端系統(tǒng)的I/O性能的一種技術(shù),盡管在之后的若干年中經(jīng)常 被提及,但是splice系統(tǒng)調(diào)用從來(lái)沒有在主流的Linux操作系統(tǒng)內(nèi)核中實(shí)現(xiàn)過(guò),一直到Linux 2.6.17版本的出現(xiàn)。splice系統(tǒng)調(diào)用需要用到四個(gè)參數(shù),其中兩個(gè) 是文件描述符,一個(gè)表示文件長(zhǎng)度,還有一個(gè)用于控制如何進(jìn)行數(shù)據(jù)

16、拷貝。splice 系統(tǒng)調(diào)用可以同步實(shí)現(xiàn),也可以使用異步方式來(lái)實(shí)現(xiàn)。在使用異步方式的時(shí)候, 用戶應(yīng)用程序會(huì)通過(guò)信號(hào) SIGIO來(lái)獲知數(shù)據(jù)傳輸已經(jīng)終止。splice()系統(tǒng)調(diào)用 的接口如下所示:longsplice(i ntfdin, int fdout, size_t len, un sig nedint flags);調(diào)用splice()系統(tǒng)調(diào)用會(huì)導(dǎo)致操作系統(tǒng)內(nèi)核從數(shù)據(jù)源fdin移動(dòng)最多l(xiāng)en個(gè)字節(jié)的數(shù)據(jù)到fdout中去,這個(gè)數(shù)據(jù)的移動(dòng)過(guò)程只是經(jīng)過(guò)操作系統(tǒng)內(nèi)核空間,需 要最少的拷貝次數(shù)。使用splice()系統(tǒng)調(diào)用需要這兩個(gè)文件描述符中的一個(gè)必須 是用來(lái)表示一個(gè)管道設(shè)備的。不難看出,這種設(shè)計(jì)

17、具有局限性,Linux的后續(xù)版本針對(duì)這一問(wèn)題將會(huì)有所改進(jìn)。參數(shù)flags用于表示拷貝操作的執(zhí)行方法,當(dāng)前 的flags有如下這些取值: SPLICE_F_NONBLOCK : splice操作不會(huì)被阻塞。然而,如果文件描述符沒有被設(shè)置為不可被阻塞方式的I/O,那么調(diào)用splice有可能仍然被阻塞。 SPLICE_F_MORE :告知操作系統(tǒng)內(nèi)核下一個(gè)splice系統(tǒng)調(diào)用將會(huì)有更多的數(shù)據(jù)傳來(lái)。 SPLICE_F_MOVE :如果輸出是文件,這個(gè)值則會(huì)使得操作系統(tǒng)內(nèi)核嘗試從輸入管道緩沖區(qū)直接將數(shù)據(jù)讀入到輸出地址空間,這個(gè)數(shù)據(jù)傳輸過(guò)程沒有任何數(shù)據(jù)拷貝操作發(fā)生。Splice()系統(tǒng)調(diào)用利用了 Linu

18、x提出的管道緩沖區(qū)(pipe buffer )機(jī)制,這就 是為什么這個(gè)系統(tǒng)調(diào)用的兩個(gè)文件描述符參數(shù)中至少有一個(gè)必須要指代管道設(shè)備的原因。為了支持splice這種機(jī)制,Linux在用于設(shè)備和文件系統(tǒng)的 file_operatio ns結(jié)構(gòu)中增加了下邊這兩個(gè)定義:ssize_t (*splice_write)(structinode *pipe, strucuctfile *out,size_t le n, un sig ned int flags);ssize_t (*splice_read)(struct inode *in, strucuctfile *pipe,size_t le n, u

19、n sig ned int flags);這兩個(gè)新的操作可以根據(jù) flags的設(shè)定在pipe和in或者out之間移動(dòng)len 個(gè)字節(jié)。Linux文件系統(tǒng)已經(jīng)實(shí)現(xiàn)了具有上述功能并且可以使用的操作,而且還實(shí)現(xiàn)了一個(gè) generic_splice_sendpage()函數(shù)用于和 socket之間的接合。對(duì)應(yīng)用程序地址空間和內(nèi)核之間的數(shù)據(jù)傳輸進(jìn)行優(yōu)化的零拷貝技術(shù)前面提到的幾種零拷貝技術(shù)都是通過(guò)盡量避免用戶應(yīng)用程序和操作系統(tǒng)內(nèi)核緩 沖區(qū)之間的數(shù)據(jù)拷貝來(lái)實(shí)現(xiàn)的,使用上面那些零拷貝技術(shù)的應(yīng)用程序通常都要局 限于某些特殊的情況:要么不能在操作系統(tǒng)內(nèi)核中處理數(shù)據(jù),要么不能在用戶地址空間中處理數(shù)據(jù)。而這一小節(jié)提出的

20、零拷貝技術(shù)保留了傳統(tǒng)在用戶應(yīng)用程序地 址空間和操作系統(tǒng)內(nèi)核地址空間之間傳遞數(shù)據(jù)的技術(shù),但卻在傳輸上進(jìn)行優(yōu)化。 我們知道,數(shù)據(jù)在系統(tǒng)軟件和硬件之間的傳遞可以通過(guò)DMA傳輸來(lái)提高效率,但是對(duì)于用戶應(yīng)用程序和操作系統(tǒng)之間進(jìn)行數(shù)據(jù)傳輸這種情況來(lái)說(shuō),并沒有類似的工具可以使用。本節(jié)介紹的技術(shù)就是針對(duì)這種情況提出來(lái)的。利用寫時(shí)復(fù)制在某些情況下,Linux操作系統(tǒng)內(nèi)核中的頁(yè)緩存可能會(huì)被多個(gè)應(yīng)用程序所共享, 操作系統(tǒng)有可能會(huì)將用戶應(yīng)用程序地址空間緩沖區(qū)中的頁(yè)面映射到操作系統(tǒng)內(nèi) 核地址空間中去。如果某個(gè)應(yīng)用程序想要對(duì)這共享的數(shù)據(jù)調(diào)用write()系統(tǒng)調(diào)用,那么它就可能破壞內(nèi)核緩沖區(qū)中的共享數(shù)據(jù),傳統(tǒng)的write(

21、)系統(tǒng)調(diào)用并沒有提供任何顯示的加鎖操作,Linux中引入了寫時(shí)復(fù)制這樣一種技術(shù)用來(lái)保護(hù)數(shù) 據(jù)。什么是寫時(shí)復(fù)制寫時(shí)復(fù)制是計(jì)算機(jī)編程中的一種優(yōu)化策略,它的基本思想是這樣的:如果有多個(gè)應(yīng)用程序需要同時(shí)訪問(wèn)同一塊數(shù)據(jù),那么可以為這些應(yīng)用程序分配指向這塊數(shù)據(jù) 的指針,在每一個(gè)應(yīng)用程序看來(lái),它們都擁有這塊數(shù)據(jù)的一份數(shù)據(jù)拷貝,當(dāng)其中一個(gè)應(yīng)用程序需要對(duì)自己的這份數(shù)據(jù)拷貝進(jìn)行修改的時(shí)候,就需要將數(shù)據(jù)真正地拷貝到該應(yīng)用程序的地址空間中去,也就是說(shuō),該應(yīng)用程序擁有了一份真正的私 有數(shù)據(jù)拷貝,這樣做是為了避免該應(yīng)用程序?qū)@塊數(shù)據(jù)做的更改被其他應(yīng)用程序 看到。這個(gè)過(guò)程對(duì)于應(yīng)用程序來(lái)說(shuō)是透明的,如果應(yīng)用程序永遠(yuǎn)不會(huì)對(duì)所訪

22、問(wèn)的 這塊數(shù)據(jù)進(jìn)行任何更改, 那么就永遠(yuǎn)不需要將數(shù)據(jù)拷貝到應(yīng)用程序自己的地址空 間中去。這也是寫時(shí)復(fù)制的最主要的優(yōu)點(diǎn)。寫時(shí)復(fù)制的實(shí)現(xiàn)需要 MMU 的支持, MMU 需要知曉進(jìn)程地址空間中哪些特殊 的頁(yè)面是只讀的, 當(dāng)需要往這些頁(yè)面中寫數(shù)據(jù)的時(shí)候, MMU 就會(huì)發(fā)出一個(gè)異常 給操作系統(tǒng)內(nèi)核, 操作系統(tǒng)內(nèi)核就會(huì)分配新的物理存儲(chǔ)空間, 即將被寫入數(shù)據(jù)的 頁(yè)面需要與新的物理存儲(chǔ)位置相對(duì)應(yīng)。寫時(shí)復(fù)制的最大好處就是可以節(jié)約內(nèi)存。 不過(guò)對(duì)于操作系統(tǒng)內(nèi)核來(lái)說(shuō), 寫時(shí)復(fù)制 增加了其處理過(guò)程的復(fù)雜性。數(shù)據(jù)傳輸?shù)膶?shí)現(xiàn)及其局限性數(shù)據(jù)發(fā)送端 對(duì)于數(shù)據(jù)傳輸?shù)陌l(fā)送端來(lái)說(shuō), 實(shí)現(xiàn)相對(duì)來(lái)說(shuō)是比較簡(jiǎn)單的, 對(duì)與應(yīng)用程序緩沖區(qū) 相

23、關(guān)的物理頁(yè)面進(jìn)行加鎖, 并將這些頁(yè)面映射到操作系統(tǒng)內(nèi)核的地址空間, 并標(biāo) 識(shí)為“ write only 。當(dāng)”系統(tǒng)調(diào)用返回的時(shí)候,用戶應(yīng)用程序和網(wǎng)絡(luò)堆棧就都可以 讀取該緩沖區(qū)中的數(shù)據(jù)。 在操作系統(tǒng)已經(jīng)傳送完所有的數(shù)據(jù)之后, 應(yīng)用程序就可 以對(duì)這些數(shù)據(jù)進(jìn)行寫操作。 如果應(yīng)用程序嘗試在數(shù)據(jù)傳輸完成之前對(duì)數(shù)據(jù)進(jìn)行寫 操作,那么就會(huì)產(chǎn)生異常, 這個(gè)時(shí)候操作系統(tǒng)就會(huì)將數(shù)據(jù)拷貝到應(yīng)用程序自己的 緩沖區(qū)中去, 并且重置應(yīng)用程序端的映射。 數(shù)據(jù)傳輸完成之后, 對(duì)加鎖的頁(yè)面進(jìn) 行解鎖操作,并重置 COW 標(biāo)識(shí)。數(shù)據(jù)接收端對(duì)于數(shù)據(jù)接收端來(lái)說(shuō), 該技術(shù)的實(shí)現(xiàn)則需要處理復(fù)雜得多的情況。 如果 read() 系 統(tǒng)調(diào)用

24、是在數(shù)據(jù)包到達(dá)之前發(fā)出的,并且應(yīng)用程序是被阻塞的,那么 read() 系 統(tǒng)調(diào)用就會(huì)告知操作系統(tǒng)接收到的數(shù)據(jù)包中的數(shù)據(jù)應(yīng)該存放到什么地方去。 在這 種情況下, 根本沒有必要進(jìn)行頁(yè)面重映射, 網(wǎng)絡(luò)接口卡可以提供足夠的支持讓數(shù) 據(jù)直接存入用戶應(yīng)用程序的緩沖區(qū)中去。如果數(shù)據(jù)接收是異步的,在 read() 系 統(tǒng)調(diào)用發(fā)出之前, 操作系統(tǒng)不知道該把數(shù)據(jù)寫到哪里, 因?yàn)樗恢烙脩魬?yīng)用程 序緩沖區(qū)的位置,所以操作系統(tǒng)內(nèi)核必須要先把數(shù)據(jù)存放到自己的緩沖區(qū)中去。局限性 寫時(shí)復(fù)制技術(shù)有可能會(huì)導(dǎo)致操作系統(tǒng)的處理開銷很大 所有相關(guān)的緩沖區(qū)都必須 要進(jìn)行頁(yè)對(duì)齊處理,并且使用的 MMU 頁(yè)面一定要是整數(shù)個(gè)的。對(duì)于發(fā)送端

25、來(lái) 說(shuō),這不會(huì)造成什么問(wèn)題。 但是對(duì)于接收端來(lái)說(shuō), 它需要有能力處理更加復(fù)雜的 情況。首先, 數(shù)據(jù)包的尺寸大小要合適, 大小需要恰到好處能夠覆蓋一整頁(yè)的數(shù) 據(jù),這就限制了那些 MTU 大小大于系統(tǒng)內(nèi)存頁(yè)的網(wǎng)絡(luò), 比如 FDDI 和 ATM 。 其次,為了在沒有任何中斷的情況下將頁(yè)面重映射到數(shù)據(jù)包的流, 數(shù)據(jù)包中的數(shù) 據(jù)部分必須占用整數(shù)個(gè)頁(yè)面。 對(duì)于異步接收數(shù)據(jù)的情況來(lái)說(shuō), 為了將數(shù)據(jù)高效地 移動(dòng)到用戶地址空間中去, 可以使用這樣一種方法: 利用網(wǎng)絡(luò)接口卡的支持, 傳 來(lái)的數(shù)據(jù)包可以被分割成包頭和數(shù)據(jù)兩部分, 數(shù)據(jù)被存放在一個(gè)單獨(dú)的緩沖區(qū)內(nèi), 虛擬存儲(chǔ)系統(tǒng)然后就會(huì)將數(shù)據(jù)映射到用戶地址空間緩沖區(qū)去

26、。 使用這種方法需要 滿足兩個(gè)先決條件,也就是上面提到過(guò)的: 一是應(yīng)用程序緩沖區(qū)必須是頁(yè)對(duì)齊的, 并且在虛擬存儲(chǔ)上是連續(xù)的; 二是傳來(lái)的數(shù)據(jù)有一頁(yè)大小的時(shí)候才可以對(duì)數(shù)據(jù)包 進(jìn)行分割。 事實(shí)上,這兩個(gè)先決條件是很難滿足的。 如果應(yīng)用程序緩沖區(qū)不是頁(yè) 對(duì)齊的,或者數(shù)據(jù)包的大小超過(guò)一個(gè)頁(yè), 那么數(shù)據(jù)就需要被拷貝。 對(duì)于數(shù)據(jù)發(fā)送 端來(lái)說(shuō),就算數(shù)據(jù)在傳輸?shù)倪^(guò)程中對(duì)于應(yīng)用程序來(lái)說(shuō)是寫保護(hù)的, 應(yīng)用程序仍然 需要避免使用這些忙緩沖區(qū), 這是因?yàn)閷憰r(shí)拷貝操作所帶來(lái)的開銷是很大的。 如 果沒有端到端這一級(jí)別的通知, 那么應(yīng)用程序很難會(huì)知道某緩沖區(qū)是否已經(jīng)被釋 放還是仍然在被占用。這種零拷貝技術(shù)比較適用于那種寫時(shí)

27、復(fù)制事件發(fā)生比較少的情況, 因?yàn)閷憰r(shí)復(fù)制 事件所產(chǎn)生的開銷要遠(yuǎn)遠(yuǎn)高于一次 CPU 拷貝所產(chǎn)生的開銷。 實(shí)際情況中, 大多 數(shù)應(yīng)用程序通常都會(huì)多次重復(fù)使用相同的緩沖區(qū),所以,一次使用完數(shù)據(jù)之后, 不要從操作系統(tǒng)地址空間解除頁(yè)面的映射, 這樣會(huì)提高效率。 考慮到同樣的頁(yè)面 可能會(huì)被再次訪問(wèn), 所以保留頁(yè)面的映射可以節(jié)省管理開銷, 但是,這種映射保 留不會(huì)減少由于頁(yè)表往返移動(dòng)和 TLB 沖刷所帶來(lái)的開銷, 這是因?yàn)槊看雾?yè)面由 于寫時(shí)復(fù)制而進(jìn)行加鎖或者解鎖的時(shí)候,頁(yè)面的只讀標(biāo)志都要被更改。緩沖區(qū)共享 還有另外一種利用預(yù)先映射機(jī)制的共享緩沖區(qū)的方法也可以在應(yīng)用程序地址空 間和操作系統(tǒng)內(nèi)核之間快速傳輸數(shù)據(jù)

28、。采用緩沖區(qū)共享這種思想的架構(gòu)最先在Solaris上實(shí)現(xiàn),該架構(gòu)使用了 “ fbufs這個(gè)概念。這種方法需要修改 API。應(yīng)用 程序地址空間和操作系統(tǒng)內(nèi)核地址空間之間的數(shù)據(jù)傳遞需要嚴(yán)格按照 fbufs 體 系結(jié)構(gòu)來(lái)實(shí)現(xiàn),操作系統(tǒng)內(nèi)核之間的通信也是嚴(yán)格按照 fbufs 體系結(jié)構(gòu)來(lái)完成的。 每一個(gè)應(yīng)用程序都有一個(gè)緩沖區(qū)池, 這個(gè)緩沖區(qū)池被同時(shí)映射到用戶地址空間和 內(nèi)核地址空間, 也可以在必要的時(shí)候才創(chuàng)建它們。 通過(guò)完成一次虛擬存儲(chǔ)操作來(lái) 創(chuàng)建緩沖區(qū), fbufs 可以有效地減少由存儲(chǔ)一致性維護(hù)所引起的大多數(shù)性能問(wèn)題。 該技術(shù)在 Linux 中還停留在實(shí)驗(yàn)階段。為什么要擴(kuò)展 Linux I/O AP

29、I傳統(tǒng)的 Linux 輸入輸出接口,比如讀和寫系統(tǒng)調(diào)用,都是基于拷貝的,也就是 說(shuō),數(shù)據(jù)需要在操作系統(tǒng)內(nèi)核和應(yīng)用程序定義的緩沖區(qū)之間進(jìn)行拷貝。 對(duì)于讀系 統(tǒng)調(diào)用來(lái)說(shuō), 用戶應(yīng)用程序呈現(xiàn)給操作系統(tǒng)內(nèi)核一個(gè)預(yù)先分配好的緩沖區(qū), 內(nèi)核 必須把讀進(jìn)來(lái)的數(shù)據(jù)放到這個(gè)緩沖區(qū)內(nèi)。 對(duì)于寫系統(tǒng)調(diào)用來(lái)說(shuō), 只要系統(tǒng)調(diào)用返 回,用戶應(yīng)用程序就可以自由重新利用數(shù)據(jù)緩沖區(qū)。為了支持上面這種機(jī)制, Linux 需要能夠?yàn)槊恳粋€(gè)操作都進(jìn)行建立和刪除虛擬存 儲(chǔ)映射。這種頁(yè)面重映射的機(jī)制依賴于機(jī)器配置、 cache 體系結(jié)構(gòu)、 TLB 未命 中處理所帶來(lái)的開銷以及處理器是單處理器還是多處理器等多種因素。 如果能夠 避免處理

30、I/O 請(qǐng)求的時(shí)候虛擬存儲(chǔ) / TLB 操作所產(chǎn)生的開銷, 則會(huì)極大地提高 I/O 的性能。 fbufs 就是這樣一種機(jī)制。使用 fbufs 體系結(jié)構(gòu)就可以避免虛擬存 儲(chǔ)操作。由數(shù)據(jù)顯示, fbufs 這種結(jié)構(gòu)在 DECStation? 5000/200 這個(gè)單處理器 工作站上會(huì)取得比上面提到的頁(yè)面重映射方法好得多的性能。如果要使用 fbufs 這種體系結(jié)構(gòu),必須要擴(kuò)展 Linux API,從而實(shí)現(xiàn)一種有效而且全面的零拷貝技 術(shù)??焖倬彌_區(qū)(Fast Buffers )原理介紹I/O數(shù)據(jù)存放在一些被稱作fbufs的緩沖區(qū)內(nèi),每一個(gè)這樣的緩沖區(qū)都包含一個(gè) 或者多個(gè)連續(xù)的虛擬存儲(chǔ)頁(yè)。應(yīng)用程序訪問(wèn)

31、fbuf是通過(guò)保護(hù)域來(lái)實(shí)現(xiàn)的,有如 下這兩種方式:如果應(yīng)用程序分配了 fbuf,那么應(yīng)用程序就有訪問(wèn)該fbuf的權(quán)限*如果應(yīng)用程序通過(guò)IPC接收到了 fbuf,那么應(yīng)用程序?qū)@個(gè)fbuf也有 訪問(wèn)的權(quán)限對(duì)于第一種情況來(lái)說(shuō),這個(gè)保護(hù)域被稱作是fbuf的“ originator ;對(duì)于后一種情 況來(lái)說(shuō),這個(gè)保護(hù)域被稱作是 fbuf的“ receiver。 ”傳統(tǒng)的Linux I/O接口支持?jǐn)?shù)據(jù)在應(yīng)用程序地址空間和操作系統(tǒng)內(nèi)核之間交換, 這種交換操作導(dǎo)致所有的數(shù)據(jù)都需要進(jìn)行拷貝。如果采用fbufs這種方法,需要交換的是包含數(shù)據(jù)的緩沖區(qū),這樣就消除了多余的拷貝操作。應(yīng)用程序?qū)buf傳遞給操作系統(tǒng)內(nèi)核

32、,這樣就能減少傳統(tǒng)的 write系統(tǒng)調(diào)用所產(chǎn)生的數(shù)據(jù)拷貝開 銷。同樣的,應(yīng)用程序通過(guò) fbuf來(lái)接收數(shù)據(jù),這樣也可以減少傳統(tǒng)read系統(tǒng)調(diào)用所產(chǎn)生的數(shù)據(jù)拷貝開銷。如下圖所示:圖 5. Linux I/O API我用程序I/O子系統(tǒng)或者應(yīng)用程序都可以通過(guò)fbufs管理器來(lái)分配fbufs。一旦分配了fbufs,這些fbufs就可以從程序傳遞到I/O子系統(tǒng),或者從I/O子系統(tǒng)傳遞到 程序。使用完后,這些fbufs會(huì)被釋放回fbufs緩沖區(qū)池。fbufs在實(shí)現(xiàn)上有如下這些特性,如圖9所示: fbuf需要從fbufs緩沖區(qū)池里分配。每一個(gè) fbuf都存在一個(gè)所屬對(duì)象,要么是應(yīng)用程序,要么是操作系統(tǒng)內(nèi)核。

33、fbuf可以在應(yīng)用程序和操作系 統(tǒng)之間進(jìn)行傳遞,fbuf使用完之后需要被釋放回特定的fbufs緩沖區(qū)池,在fbuf傳遞的過(guò)程中它們需要攜帶關(guān)于fbufs緩沖區(qū)池的相關(guān)信息。*每一個(gè)fbufs緩沖區(qū)池都會(huì)和一個(gè)應(yīng)用程序相關(guān)聯(lián),一個(gè)應(yīng)用程序最多只 能與一個(gè)fbufs緩沖區(qū)池相關(guān)聯(lián)。應(yīng)用程序只有資格訪問(wèn)它自己的緩沖區(qū) 池。fbufs不需要虛擬地址重映射,這是因?yàn)閷?duì)于每個(gè)應(yīng)用程序來(lái)說(shuō),它們可 以重新使用相同的緩沖區(qū)集合。這樣,虛擬存儲(chǔ)轉(zhuǎn)換的信息就可以被緩存 起來(lái),虛擬存儲(chǔ)子系統(tǒng)方面的開銷就可以消除。 I/O子系統(tǒng)(設(shè)備驅(qū)動(dòng)程序,文件系統(tǒng)等)可以分配fbufs,并將到達(dá)的數(shù)據(jù)直接放到這些fbuf里邊。這

34、樣,緩沖區(qū)之間的拷貝操作就可以避免。圖6. fbufs體系結(jié)構(gòu)程序A耶呼呂前面提到,這種方法需要修改 API,如果要使用fbufs體系結(jié)構(gòu),應(yīng)用程序和 Linux操作系統(tǒng)內(nèi)核驅(qū)動(dòng)程序都需要使用新的 API,如果應(yīng)用程序要發(fā)送數(shù)據(jù), 那么它就要從緩沖區(qū)池里獲取一個(gè) fbuf,將數(shù)據(jù)填充進(jìn)去,然后通過(guò)文件描述 符將數(shù)據(jù)發(fā)送出去。接收到的fbufs可以被應(yīng)用程序保留一段時(shí)間,之后,應(yīng)用 程序可以使用它繼續(xù)發(fā)送其他的數(shù)據(jù),或者還給緩沖區(qū)池。但是,在某些情況下, 需要對(duì)數(shù)據(jù)包內(nèi)的數(shù)據(jù)進(jìn)行重新組裝,那么通過(guò)fbuf接收到數(shù)據(jù)的應(yīng)用程序就需要將數(shù)據(jù)拷貝到另外一個(gè)緩沖區(qū)內(nèi)。 再者,應(yīng)用程序不能對(duì)當(dāng)前正在被內(nèi)核

35、處 理的數(shù)據(jù)進(jìn)行修改,基于這一點(diǎn),fbufs體系結(jié)構(gòu)引入了強(qiáng)制鎖的概念以保證其 實(shí)現(xiàn)。對(duì)于應(yīng)用程序來(lái)說(shuō),如果fbufs已經(jīng)被發(fā)送給操作系統(tǒng)內(nèi)核,那么應(yīng)用程 序就不會(huì)再處理這些 fbufs。fbufs存在的一些問(wèn)題管理共享緩沖區(qū)池需要應(yīng)用程序、網(wǎng)絡(luò)軟件、以及設(shè)備驅(qū)動(dòng)程序之間的緊密合作。 對(duì)于數(shù)據(jù)接收端來(lái)說(shuō),網(wǎng)絡(luò)硬件必須要能夠?qū)⒌竭_(dá)的數(shù)據(jù)包利用DMA傳輸?shù)接山邮斩朔峙涞恼_的存儲(chǔ)緩沖區(qū)池中去。而且,應(yīng)用程序稍微不注意就會(huì)更改之前發(fā)到共享存儲(chǔ)中的數(shù)據(jù)的內(nèi)容, 從而導(dǎo)致數(shù)據(jù)被破壞,但是這種問(wèn)題在應(yīng)用 程序端是很難調(diào)試的。同時(shí),共享存儲(chǔ)這種模型很難與其他類型的存儲(chǔ)對(duì)象關(guān)聯(lián) 使用,但是應(yīng)用程序、網(wǎng)絡(luò)軟件以

36、及設(shè)備驅(qū)動(dòng)程序之間的緊密合作是需要其他存 儲(chǔ)管理器的支持的。對(duì)于共享緩沖區(qū)這種技術(shù)來(lái)說(shuō),雖然這種技術(shù)看起來(lái)前景光 明,但是這種技術(shù)不但需要對(duì) API進(jìn)行更改,而且需要對(duì)驅(qū)動(dòng)程序也進(jìn)行更改, 并且這種技術(shù)本身也存在一些未解決的問(wèn)題,這就使得這種技術(shù)目前還只是出于試驗(yàn)階段。在測(cè)試系統(tǒng)中,這種技術(shù)在性能上有很大的改進(jìn),不過(guò)這種新的架構(gòu) 的整體安裝目前看起來(lái)還是不可行的。這種預(yù)先分配共享緩沖區(qū)的機(jī)制有時(shí)也因 為粒度問(wèn)題需要將數(shù)據(jù)拷貝到另外一個(gè)緩沖區(qū)中去??偨Y(jié)本系列文章介紹了 Linux中的零拷貝技術(shù),本文是其中的第二部分。本文對(duì)第 一部分文章中提出的Linux操作系統(tǒng)上出現(xiàn)的幾種零拷貝技術(shù)進(jìn)行了更詳細(xì)

37、的 介紹,主要描述了它們各自的優(yōu)點(diǎn),缺點(diǎn)以及適用場(chǎng)景。對(duì)于網(wǎng)絡(luò)數(shù)據(jù)傳輸來(lái)說(shuō), 零拷貝技術(shù)的應(yīng)用受到了很多體系結(jié)構(gòu)方面因素的阻礙,包括虛擬存儲(chǔ)體系結(jié)構(gòu)以及網(wǎng)絡(luò)協(xié)議體系結(jié)構(gòu)等。所以,零拷貝技術(shù)仍然只是在某些很特殊的情況中才 可以應(yīng)用,比如文件服務(wù)或者使用某種特殊的協(xié)議進(jìn)行高帶寬的通信等。但是, 零拷貝技術(shù)在磁盤操作中的應(yīng)用的可行性就高得多了,這很可能是因?yàn)榇疟P操作具有同步的特點(diǎn),以及數(shù)據(jù)傳輸單元是按照頁(yè)的粒度來(lái)進(jìn)行的。針對(duì)Linux操作系統(tǒng)平臺(tái)提出并實(shí)現(xiàn)了很多種零拷貝技術(shù),但是并不是所有這 些零拷貝技術(shù)都被廣泛應(yīng)用于現(xiàn)實(shí)中的操作系統(tǒng)中的。比如,fbufs體系結(jié)構(gòu),它在很多方面看起來(lái)都很吸引人,但是使用它需要更改API以及驅(qū)動(dòng)程序,它還存在其他一些實(shí)現(xiàn)上的困難,這就使得fbufs還只是停留在實(shí)驗(yàn)的階段。動(dòng)態(tài) 地址重映射技術(shù)只是需要對(duì)操作系統(tǒng)做少量修改,雖然不需要修改用戶軟件,但是當(dāng)前的虛擬存儲(chǔ)體系結(jié)構(gòu)并不能很好地支持頻繁的虛擬地址重映射操作。而且為了保證存儲(chǔ)的一致性,重映射之后還必須對(duì)TL

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論