zero-copy

许多web应用都会向用户提供大量的静态内容,这意味着有很多data从硬盘读出之后,会原封不动的通过socket传输给用户。这种操作看起来可能不会怎么消耗CPU,但是实际上它是低效的:kernal把数据从disk读出来,然后把它传输给user级的application,然后application再次把同样的内容再传回给处于kernal级的socket。这种场景下,application实际上只是作为一种低效的中间介质,用来把disk file的data传给socket。




data每次穿过user-kernel boundary,都会被copy,这会消耗cpu,并且占用RAM的带宽。幸运的是,你可以用一种叫做Zero-Copy的技术来去掉这些无谓的copy。应用程序用zero copy来请求kernel直接把disk的data传输给socket,而不是通过应用程序传输。Zero copy大大提高了应用程序的性能,并且减少了kernel和user模式的上下文切换。


Java的libaries在linux和unix中支持zero copy,一个关键的api是java.nio.channel.FileChannel的transferTo()方法。我们可以用transferTo()来把bytes直接从调用它的channel传输到另一个writable byte channel,中间不会使data经过应用程序。本文首先描述传统的copy是怎样坑爹的,然后再展示zero-copy技术在性能上是多么的给力以及为什么给力。


Date transfer: The traditional approach


考虑一下这个场景,通过网络把一个文件传输给另一个程序。这个操作的核心代码就是下面的两个函数:


Listing 1. Copying bytes from a file to a socket


File.read(fileDesc, buf, len);
Socket.send(socket, buf, len);
尽管看起来很简单,但是在OS的内部,这个copy操作要经历四次user mode和kernel mode之间的上下文切换,甚至连数据都被拷贝了四次!Figure 1描述了data是怎么移动的。






Figure 2 描述了上下文切换


Figure 2. Traditional context switches




其中的步骤如下:


read() 引入了一次从user mode到kernel mode的上下文切换。实际上调用了sys_read() 来从文件中读取data。第一次copy由DMA完成,将文件内容从disk读出,存储在kernel的buffer中。
然后data被copy到user buffer中,此时read()成功返回。这是触发了第二次context switch: 从kernel到user。至此,数据存储在user的buffer中。
send() socket call 带来了第三次context switch,这次是从user mode到kernel mode。同时,也发生了第三次copy:把data放到了kernel adress space中。当然,这次的kernel buffer和第一步的buffer是不同的两个buffer。
最终 send() system call 返回了,同时也造成了第四次context switch。同时第四次copy发生,DMA将data从kernel buffer拷贝到protocol engine中。第四次copy是独立而且异步的。
使用kernel buffer做中介(而不是直接把data传到user buffer中)看起来比较低效(多了一次copy)。然而实际上kernel buffer是用来提高性能的。在进行读操作的时候,kernel buffer起到了预读cache的作用。当写请求的data size比kernel buffer的size小的时候,这能够显著的提升性能。在进行写操作时,kernel buffer的存在可以使得写请求完全异步。


悲剧的是,当请求的data size远大于kernel buffer size的时候,这个方法本身变成了性能的瓶颈。因为data需要在disk,kernel buffer,user buffer之间拷贝很多次(每次写满整个buffer)。


而Zero copy正是通过消除这些多余的data copy来提升性能。


Data Transfer:The Zero Copy Approach


如果重新检查一遍traditional approach,你会注意到实际上第二次和第三次copy是毫无意义的。应用程序仅仅缓存了一下data就原封不动的把它发回给socket buffer。实际上,data应该直接在read buffer和socket buffer之间传输。transferTo()方法正是做了这样的操作。Listing 2是transferTo()的函数原型:


public void transferTo(long position, long count, WritableByteChannel target);
transferTo()方法把data从file channel传输到指定的writable byte channel。它需要底层的操作系统支持zero copy。在UNIX和各种Linux中,会执行List 3中的系统调用sendfile(),该命令把data从一个文件描述符传输到另一个文件描述符(Linux中万物皆文件):


#include <sys/socket.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
在List 1中的file.read()和socket.send()可以用一句transferTo()替代,如List 4:


transferTo(position, count, writableChannel);
Figure 3 展示了在使用transferTo()之后的数据流向






Figure 4 展示了在使用transferTo()之后的上下文切换




在像Listing 4那样使用transferTo()之后,整个过程如下:


transferTo()方法使得文件内容被DMA engine直接copy到一个read buffer中。然后数据被kernel再次拷贝到和output socket相关联的那个kernel buffer中去。
第三次拷贝由DMA engine完成,它把kernel buffer中的data拷贝到protocol engine中。
这是一个很明显的进步:我们把context switch的次数从4次减少到了2次,同时也把data copy的次数从4次降低到了3次(而且其中只有一次占用了CPU,另外两次由DMA完成)。但是,要做到zero copy,这还差得远。如果网卡支持 gather operation,我们可以通过kernel进一步减少数据的拷贝操作。在2.4及以上版本的linux内核中,开发者修改了socket buffer descriptor来适应这一需求。这个方法不仅减少了context switch,还消除了和CPU有关的数据拷贝。user层面的使用方法没有变,但是内部原理却发生了变化:


transferTo()方法使得文件内容被copy到了kernel buffer,这一动作由DMA engine完成。
没有data被copy到socket buffer。取而代之的是socket buffer被追加了一些descriptor的信息,包括data的位置和长度。然后DMA engine直接把data从kernel buffer传输到protocol engine,这样就消除了唯一的一次需要占用CPU的拷贝操作。
Figure 5描述了新的transferTo()方法中的data copy:





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Qt是一个跨平台的应用程序开发框架,可以用于构建图形用户界面(GUI)和用于非GUI应用程序的扩展库。GPU是图形处理单元的缩写,用于加速图形和计算任务。而零拷贝(Zero-Copy)是一种内存管理技术,它可以减少数据在不同设备之间的复制次数来提高性能。 在Qt中,GPU的零拷贝主要用于加速图形渲染和处理。传统上,绘制和渲染GUI元素需要将数据从主机内存(CPU)复制到GPU内存,这会导致额外的数据传输时延和内存使用。而使用GPU的零拷贝技术,可以直接在主机内存和GPU内存之间共享数据,避免复制操作,从而减少了内存使用和数据传输的开销,提高了图形渲染的性能。 Qt提供了一些方法来实现零拷贝操作。例如,可以使用QOpenGLTexture类在Qt中创建和管理纹理对象,然后将数据直接传输到纹理对象中,而不需要进行额外的复制操作。此外,Qt还提供了与OpenGL集成的功能,可以在GPU上进行图形渲染和计算,进一步提高绘制和渲染性能。 总的来说,Qt GPU零拷贝是一种通过减少CPU和GPU之间的数据复制来提高图形渲染和处理性能的技术。通过在Qt中集成GPU和使用零拷贝技术,可以更高效地利用图形处理能力,提供更流畅和响应快速的用户界面体验。 ### 回答2: Qt的GPU零拷贝是指在使用Qt框架进行图形处理时,通过充分利用现代GPU的功能,实现在CPU和GPU之间进行无拷贝传输数据的技术。 在传统的图形处理流程中,CPU负责将图形数据从内存中复制到GPU的显存中,再由GPU进行处理和渲染。这种方式在大规模图形数据处理时会产生大量的数据复制,造成性能上的浪费。而Qt的GPU零拷贝技术则能够避免这种浪费,提高图形处理的效率。 Qt的GPU零拷贝技术通过利用现代GPU的高速内存访问能力,将数据直接从CPU内存传输到GPU内存,而不需要进行数据拷贝。这样可以减少数据的复制次数,节省了时间和资源。 通过Qt的GPU零拷贝技术,可以在图形数据传输和处理过程中减少内存带宽消耗,提高系统的响应速度和性能,特别是在大规模数据处理和复杂图形场景下。这对于实时图形处理、游戏开发、虚拟现实等领域都具有重要意义。 总之,Qt的GPU零拷贝技术通过充分利用GPU的特性,实现了在CPU和GPU之间进行图形数据传输的无拷贝处理,提高了系统的图形处理效率和性能。 ### 回答3: qt gpu zero-copy是一种用于在Qt图形用户界面框架中实现零拷贝(Zero-copy)的技术。零拷贝是指在数据传输过程中避免对数据进行不必要的复制或移动,以提高数据传输的效率。 在使用Qt进行图形渲染时,通常需要将图像数据从CPU传输到GPU进行处理。传统的方式是通过拷贝数据到GPU的内存空间中,然后再进行处理。而使用Qt gpu zero-copy技术,可以直接将数据从CPU内存中传输到GPU内存中,避免了不必要的数据拷贝操作,提高了图像处理的效率。 Qt gpu zero-copy技术通过使用QOpenGLTexture将图像数据直接映射到GPU内存中实现零拷贝。通过这种方式,可以避免将数据从CPU内存复制到GPU内存的过程,减少了数据传输的延迟和带宽占用。 使用Qt gpu zero-copy技术可以在一定程度上提高图形渲染的性能和效率,特别是对于需要频繁传输大量图像数据的应用程序,如图形编辑器、游戏等。同时,这项技术还能减少内存的占用,提高系统的整体性能和响应速度。 总之,Qt gpu zero-copy是一种通过直接将图像数据从CPU传输到GPU内存来实现零拷贝的技术。它可以提高图形渲染的效率和性能,减少数据传输的延迟和带宽占用,同时降低内存占用,提高系统的整体性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值