技术开发 频道

CUDA入门:GPU的硬件架构

  Texture

  CUDA 支援 texture。在 CUDA 的 kernel 程序中,可以利用显示芯片的 texture 单元,读取 texture 的数据。使用 texture 和 global memory 最大的差别在于 texture 只能读取,不能写入,而且显示芯片上有一定大小的 texture cache。因此,读取 texture 的时候,不需要符合 coalesced 的规则,也可以达到不错的效率。此外,读取 texture 时,也可以利用显示芯片中的 texture filtering 功能(例如 bilinear filtering),也可以快速转换数据型态,例如可以直接将 32 bits RGBA 的数据转换成四个 32 bits 浮点数。

  显示芯片上的 texture cache 是针对一般绘图应用所设计,因此它仍最适合有区块性质的存取动作,而非随机的存取。因此,同一个 warp 中的各个 thread 最好是读取地址相近的数据,才能达到最高的效率。

  对于已经能符合 coalesced 规则的数据,使用 global memory 通常会比使用 texture 要来得快。

  运算单元

  Stream processor 里的运算单元,基本上是一个浮点数的 fused multiply-add 单元,也就是说它可以进行一次乘法和一次加法,如下所示:

  a = b * c + d;

  compiler 会自动把适当的加法和乘法运算,结合成一个 fmad 指令。

  除了浮点数的加法及乘法之外,整数的加法、位运算、比较、取最小值、取最大值、及以型态的转换(浮点数转整数或整数转浮点数)都是可以全速进行的。整数的乘法则无法全速进行,但 24 bits 的乘法则可以。在 CUDA 中可以利用内建的 __mul24 和 __umul24 函式来进行 24 bits 的整数乘法。

  浮点数的除法是利用先取倒数,再相乘的方式计算,因此精确度并不能达到 IEEE 754 的规范(最大误差为 2 ulp)。内建的 __fdividef(x,y) 提供更快速的除法,和一般的除法有相同的精确度,但是在 2216 < y < 2218 时会得到错误的结果。

  此外 CUDA 还提供了一些精确度较低的内部函数,包括 __expf、__logf、__sinf、__cosf、__powf 等等。这些函式的速度较快,但精确度不如标准的函式。详细的数据可以参考 CUDA Programming Guide 1.1 的 Appendix B。

  和主内存间的数据传输

  在 CUDA 中,GPU 不能直接存取主内存,只能存取显卡上的显示内存。因此,会需要将数据从主内存先复制到显卡内存中,进行运算后,再将结果从显卡内存中复制到主内存中。这些复制的动作会限于 PCI Express 的速度。使用 PCI Express x16 时,PCI Express 1.0 可以提供双向各 4GB/s 的带宽,而 PCI Express 2.0 则可提供 8GB/s 的带宽。当然这都是理论值。

  从一般的内存复制数据到显卡内存的时候,由于一般的内存可能随时会被操作系统搬动,因此 CUDA 会先将数据复制到一块内部的内存中,才能利用 DMA 将数据复制到显卡内存中。如果想要避免这个重复的复制动作,可以使用 cudaMallocHost 函式,在主内存中取得一块 page locked 的内存。不过,如果要求太大量的 page locked 的内存,将会影响到操作系统对内存的管理,可能会减低系统的效率。

        更多内容请点击:

        CUDA专区:http://cuda.it168.com/

        CUDA论坛:http://cudabbs.it168.com/

 

0
相关文章