找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 279|回复: 1

DAY30:阅读CPU和GPU间的数据传输

[复制链接]
发表于 2018-6-10 22:35:22 | 显示全部楼层 |阅读模式
5.3.1. Data Transfer between Host and Device
Applications should strive to minimize data transfer between the host and the device. One way to accomplish this is to move more code from the host to the device, even if that means running kernels with low parallelism computations. Intermediate data structures may be created in device memory, operated on by the device, and destroyed without ever being mapped by the host or copied to host memory.
Also, because of the overhead associated with each transfer, batching many small transfers into a single large transfer always performs better than making each transfer separately.
On systems with a front-side bus, higher performance for data transfers between host and device is achieved by using page-locked host memory as described in Page-Locked Host Memory.
In addition, when using mapped page-locked memory (Mapped Memory), there is no need to allocate any device memory and explicitly copy data between device and host memory. Data transfers are implicitly performed each time the kernel accesses the mapped memory. For maximum performance, these memory accesses must be coalesced as with accesses to global memory (see Device Memory Accesses). Assuming that they are and that the mapped memory is read or written only once, using mapped page-locked memory instead of explicit copies between device and host memory can be a win for performance.
On integrated systems where device memory and host memory are physically the same, any copy between host and device memory is superfluous and mapped page-locked memory should be used instead. Applications may query a device is integrated by checking that the integrated device property (see Device Enumeration) is equal to 1.


回复

使用道具 举报

 楼主| 发表于 2018-6-11 13:14:10 | 显示全部楼层
这章节主要说了如何优化Host和Device间的数据传输.首先章节说, 应当尽量尝试能减少传输量就要减少.例如一段数据如果原本需要从显存移动到内存, 然后CPU继续处理;那么如果通过代码改写, 将一些CPU上的代码改写成GPU版本, 这样就可以不用移动这些数据了, 直接就能在GPU上处理了.有的时候虽然这种改写可能很渣, 并行度不高, 但只要是合算的, 就应当使用这种GPU代码.(也就是说, 只要渣GPU代码, 运行的时间能小于数据移动的时间,那么即使改写成GPU不是那么的好, 也要改写成GPU版本)
这是一个很重要的思路. 有很多人认为我这段代码太串行了, 并行度不高, 还是不改写了,但是这里指出, 只要改写了, 虽然是在不适合GPU的情况下运行, 但只要总体成本合算,还是要改写的.因为相比现在的GPU上的计算性能, 和GPU上的访存性能,PCI-E传输的性能太低了.通过这种改写, 最终可能在GPU上, 最终处理得到一个很小的数据(例如, 一张被处理过的图片被识别为99%是狗), 那么只将最终的结果"狗"返回即可.其他的中间数据均可以在GPU上就地不要了.
这样通过尽量在GPU上能处理的都处理了, 实在最后的非常小的数据量再返回, 有利提高性能.


第二段则说了, 如果你有一大批传输, 每次传输都很小(例如1000个只有100KB的的小图像), 与其传输1000次小的,不如打包成一次大的传输(100MB的100KB的小图像打包),因为每次传输有基本的不能避免的开销, 这样打包后一次传输较大的, 有利于提高性能.


(固定的每次传输的代价, 例如对GPU的DMA引擎进行设定, 提供起始地址, 目标地址, 传输大小什么. 等等,再例如固定的代价有在WDDM上切换到kernel-mode等等)
所以一次传输大数据量, 而不是多次小的, 也有利于提高性能.



第三段实际上有点小问题.他说使用page-locked memory在古老的FSB总线的机器上能提高性能.这个实际上几乎能在现在所有的机器上都提高性能.包括AMD的U和板子.这是因为:
(1)普通的传输(cudaMemcpy)会在内存中进行staging, 浪费内存读写带宽.
(2)普通的传输往往会导致使用默认流, 造成用户不自觉的在device上的隐式同步, 浪费性能.(3)普通的传输往往会导致Host被阻塞等待, 浪费性能.

因此这里实际上所有的机器上使用page-locked memory传输都是很好的. 而不仅仅是10年前的FSB总线的机器.


但需要注意的是, 不要过量分配page-locked memory, 特别是小内存的机器(例如只有16GB内存的机器), 避免系统内存不够用. 影响其他方面的性能.

此外, 这里还说了, 如果对于那种只用一次的数据,例如一个kernel只对一张图片读取1次, 那么不需要手工传输, 直接使用映射的page-locked memory即可(也叫zero-copy), 有如下好处:



(1)用户不需要手工准备一份设备上的对应大小的缓冲区, 节省了显存.
(2)用户不需要提前复制完数据才能启动kernel. 可以在kernel一边执行的同时, 一边自动从PCI-E传输过来. 这样kernel的计算指令实际上能和PCI-E传输overlap, 节省时间.

但也需要注意的是, 使用多次的数据不应当这样. 而需要提前复制过来, 因为多次读写显存更具有优势.
除此之外,在Linux下, 应当考虑使用unified memory, Pascal+在Linux下使用unified memory具有更好的性能. 而且在一定的情况下, 可以适应多次使用的数据.但在Windows下面不建议使用(因为Windows下面的Unified memory性能很低),Linux下的unified memory可以看成是zero-copy这里的高级版本.进化过了.

最后章节还说了集成显卡的优化,对于那种集成在笔记本中之类的集成显卡,很多是没有独立显存的,此时他们的显存就是内存(映射的),此时应当就地直接使用映射的内存, 而不需要cudaMemcpy复制.因为并没有一个独立的显存存在. 只有内存. 复制的话实际上是你在内存中倒腾.

因为实际上现在的的映射的内存(zero-copy)总是有更高的高级版本unified memory, 在这种设备上应当条件允许就使用unified memory(linux),不允许就普通映射,但不应当手工复制.



这种设备通过查询"集成"属性, 值是1


我补充一下:
(1)这种显卡已经消失了很多年了. 现在即使是笔记本中的集成显卡, 也有独立显存的.所以手册这里的说法是没有用的了. 它没有更新.

(2)现在多了TK1/TX1/TX2这种设备, 他们的GPU也是集成的, 也没有独立的显存.在这种设备上应当考虑使用zero-copy/unified memory以便减少无辜的复制传输(根本显卡就没有走PCI-E好么!),以便提高性能.

总之本章节说, 能不传输就不传输, 例如对于可以改变数据处理代码的位置(从CPU到GPU); 或者不需要传输(集成或者TX2类的)就应当尽量不需要传输.然后还说了, 如果真的要传输, 尽量使用一次性大量传输, 尽量使用page-locked memory.

本章节还说了, 有的时候可以让kernel执行和数据传输在指令级overlap提高性能, 适合那些只读一次或者只写一次的数据(或者例如最终结果的回传, 可以直接集成在kernel中, 让kernel直接写内存).











回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

快速回复 返回顶部 返回列表