参考: https://segmentfault.com/a/1190000011989008
ゼロコピーは何ですか?
「ゼロコピー」のウィキペディアはそれをこのように説明しました:
「ゼロコピーは、」CPUは別のメモリ領域からデータをコピーするタスクを実行しないでコンピュータの動作を説明します。これは、頻繁にネットワーク経由でファイルを送信するときにCPUサイクルとメモリ帯域幅を節約するために使用されます。
「ゼロコピーは、」CPUが記述エリア他のタスクにコンピュータのメモリ領域からデータをコピーする操作を実行していないです。一般的にネットワーク経由でファイルを送信するときにCPUサイクルとメモリ帯域幅を節約するために使用されます。簡単に言えば、それは追加の技術のメモリストレージに1つのCPUからのゼロコピーのコピーデータを回避する方法です。
なぜ我々はゼロコピー技術が必要なのでしょうか?
ネットワーク上の他のリモートサービスに送信されたローカルディスク上のファイル:通常、私たちは、このような要望を持っています。伝統的なI / O、オペレーティングシステムでは、チャートを見て何が起こったかによって、次のとおりです。
-
リード()システムコールを発行し、ユーザ空間からプロセッサのスイッチが空間カーネルします。
-
ディスクからのデータを要求します。
-
DMAによってカーネルバッファにディスク・ファイル・スペースから読み取ります。
-
()システムコールの戻りを読み取り、データをユーザ空間バッファ空間へのカーネル・バッファからコピーされ、このときユーザ空間にカーネル空間からプロセッサ・スイッチ。
-
発行write()システムコール、およびデータは、カーネル空間における対象ユーザ空間ソケットバッファ、ユーザ空間からプロセッサのスイッチが空間をカーネルにこのときにバッファからコピーされます。
-
()呼び出しの戻りを書きます。
-
(独立および非同期動作である)プロトコルエンジンにカーネル空間内のDMAバッファからデータをコピーすることによって。
総合:伝統的なI / O動作は、コンテキストがプロセス全体を通してデータの4,4コピーを切り替える必要があります。
Q:一部の人々は、頼むかもしれない理由を書き込み()の呼び出しは、最初に戻ります、彼は、データ転送の前に戻ってくるではないのですか?
:実際に呼び出しを返す、データが送信され、さらには彼が送信を開始することが保証されていない、イーサネットドライバは、単にその送信キューにスペースがあることを意味し、我々は転送されるデータを受け入れる必要がありますされる保証はありません。私たちの前に多くのパケットを除外する可能性があります。ドライバまたはハードウェアプライオリティキューまたはリング特に指摘しない限り、データは、FIFO方式を送信します。
我々は、我々はデータの2番目と3番目のコピーは完全に無意味であることがわかりますプロセス全体を見に来て、伝統的なI / O操作を学び、データのアプリケーションのキャッシュのみビットはそのままで、それは、ターゲット・ソケット・バッファに送られます。CPUは、この単純なタスクを実行することで占有されている場合は、これら2つのコピーが、オペレーティングシステムの観点から、CPUの完全な参加を必要としている、これは資源の無駄になり、比較的単純な他がある場合CPUは他の事をする解放することができるように、システム・コンポーネントは、それをこの問題を行うことができ、その後、システムリソースの使用がより効果的になります。
「ゼロコピーは、」それはパフォーマンスを向上させるために冗長コピーを排除することです。データ転送処理で、そのデータがコピーされるように、及びCPUコピーカーネル空間カーネル空間およびユーザ空間バッファバッファ間のバッファ内のデータ。
ゼロコピー実装メカニズム
Linuxは(この記事は、一時的に議論しないシステムを呼び出す))(、)(同様のシステムは、主にsendfileを呼び出していたmmap()、およびスプライス。
実装のsendfileによってゼロコピー()
カーネルのバージョン2.1が導入されたのsendfileシステムコールは、目的は、ネットワーク上の2つのローカルファイルとの間で行われるデータ転送のプロセスを簡素化することです。sendfileシステムコールが導入され、コンテキストスイッチの数を減らすことができ、また、データの複製を削減するだけでなく。より良い説明については、以下を参照してください:
-
sendfile()システムコールを発行し、ユーザ空間からプロセッサのスイッチが空間カーネルします。
-
ディスクからのデータを要求します。
-
DMAによってカーネルバッファにディスク・ファイル・スペースから読み取ります。
-
宛先ソケットバッファにコピーされたカーネルバッファ空間からのデータ、
-
プロセッサは、ユーザ空間にカーネル空間から切り替えたときのsendfile()は、返します。
-
ターゲットプロトコルエンジンへのソケットバッファからデータをコピーすることによってDMA。
总结一下这种实现,整个过程产生了2次上下文切换和3次数据拷贝(其中2次DMA拷贝和1次CPU拷贝)。
该实现虽然减少了2次上下文切换,但仍然还有1次CPU拷贝。那这次拷贝是不是也可以省掉呢?答案是肯定的。但是需要底层操作系统的一些支持。那就是带有DMA收集功能的sendfile实现的零拷贝。
带有DMA收集功能的sendfile实现的零拷贝
从Linux2.4开始,操作系统底层提供了带有scatter/gather的DMA来从内核空间缓冲区中将数据读取到协议引擎中。这就意味着等待传输的数据不需要在连续存储器中,它可以分散在不同的内存位置。那这样一来,从文件中读出的数据就不必拷贝至目标socket的缓冲区中,只需要将缓冲区描述符添加到目标socket的缓冲区中,DMA收集操作会根据缓冲区描述符中的信息将内核空间缓冲区中的数据读取到协议引擎。这种方法不仅减少了上下文切换、还减少了由CPU参与的数据拷贝。为了更好的理解这种方法所涉及的操作,请看下图:
-
发出sendfile()系统调用,处理器从用户空间切换至内核空间;
-
通过DMA将数据copy至内核空间缓冲区;
-
将数据在内核空间缓冲区的地址和偏移量拷贝至目标socket的缓冲区;
-
Sendfile()返回,处理器从内核空间切换至用户空间。
-
带有scatter/gather 功能的DMA将数据直接从内核缓冲区读取到协议引擎,从而消除了最后一次CPU拷贝。
总结一下,这种方法产生了2次上下文切换和2次数据拷贝。
这时有人可能会问,如果我把数据从磁盘上读出来后,再编辑一下,再发送出去,以上所说的零拷贝岂不是不能实现?
对于该问题,Linux提供了mmap来实现。
通过mmap实现的零拷贝
mmap(内存映射):mmap操作提供了一种机制,让用户程序直接访问设备内存,这种机制,相比较在用户空间和内核空间互相拷贝数据,效率更高。
-
发出mmap()系统调用,处理器从用户空间切换至内核空间。
-
向磁盘请求数据;
-
DMAデータを通じてカーネルバッファにディスクスペースからコピーされます。
-
MMAP()呼び出しが戻ると、バッファを共有するユーザプログラムとオペレーティングシステムは、そのデータは、ユーザバッファにカーネルバッファからコピーされる必要はなく、この時間は、プロセッサは、ユーザ空間にカーネル空間から切り替えられます。
-
ユーザー・ロジックの処理;
-
問題write()システムコール、カーネル空間データは、ユーザ空間からプロセッサのスイッチが空間カーネルために、ターゲット・ソケット・バッファにバッファからコピーされます。
-
()呼び出しの戻りを書き込み、プロセッサは、ユーザ空間にカーネル空間から切り替えられます。
-
DMAプロトコルエンジンにデータをコピーすること。
要約する:このメソッドは、コンテキストスイッチ4とデータの3つのコピーを生成します。
これまでのところ、ゼロコピー技術がオーバー導入しています。この記事では、ゼロコピー技術が常に開発されているが、ゼロコピー技術は、基礎となるオペレーティング・システムのサポートに必要とされて言及し、それらを完成、すべてのゼロコピー技術をカバーしていないこの記事では、Linuxに登場しました。