CUDA学习之CUDA程序优化

一 测量程序运行时间

1主机端测时

由于CUDA API函数都是异步的,为了准确测量CUDA调用运行的时间,首先要使用cudaThreadSynchronize(),同步cpu与gpu之后,才能结束测时。

2设备端测时

使用clock()函数,这个函数测的结果是一个block在gpu中上下文保持的时间,而不是实际执行的时间。(一般大于执行时间)

二任务划分

1原则

划分为cpu端程序和gpu端程序

选择合适的算法

在两次主机设备通信之间进行尽量多的计算

使用流运算隐藏主机-设备通信时间,以及通过pinned mem,zero-copy,write-combined mem等提高实际传输带宽。

2grid和block维度设计

tesla架构gpu中的每个sm中,至少需要6个active warp才能有效隐藏流水线延迟。如果所有active warp来自同一block,那么当block进行存储器访问或者同步,执行单元就会闲置。

所以每个sm最好2个active block。

设计步骤:

计算出一个sm上active block和active warp的数目。可以通过CUDA SDK 中的CUDA occupany calculator计算。

指导原则:

(1)每个block中线程数量是32的整数倍,最好保持64-256之间

(2)blockDim.x为16或者16整数倍,提高对global mem 和 shared mem的访问效率。

三 存储器访问优化

 1主机设备通信优化

(1)使用pinned memory----主机内存不会被分配到虚拟内存中去

(2)异步执行内核函数和异步存储拷贝函数都是立刻返回的。

          方法一:使用流和异步使GPU和CPU同时进行计算。

          方法二:利用不同流之间的异步执行,使流之间的传输和运算能够同时执行。

2全局存储器访问优化

对全局内存的访问满足合并条件是对cuda程序性能影响最明显的因素之一。

通过运行时API(如cudamalloc())分配的存储器,已经能保证棋手地址至少会按256Byte进行对齐。因此,选择合适的线程块大小(例如16的倍数),使得half-warp的访问请求按段长对齐。

3共享存储器的访问优化在不发生bank conflict的情况下,share mem延迟是local mem 和 global mem的1/100,与寄存器相同。

对于计算能力1.x的设备,warp大小32,而一个sm的shared mem划分为16个bank,一个warp访问share mem会被划分为两个half-warp的访问请求。所以只有处于同一half-warp的线程才会发生bank-confict,而一个warp中前hal-warp和位于后half-warp的线程间则不会发生bank confilct.

-shared-  float shared[32];

float data=shared[baseindex+s*tid];

对于计算能力1.x的硬件,s为奇数,就可以避免bank conflict的发生。(因为bank数目是2的幂)

对于double数组访问存在2-way冲突,此时访存被编译为两个独立的32bit请求。

-shared-double shared[32];

double data=shared[baseindex+tid];

shared mem采用了广播机制,当对同一个地址的读请求时,一个32bit字可以被读取并同时广播给不同的进程。

四指令流优化

使用高速的函数

原文地址:https://www.cnblogs.com/catkins/p/5270786.html