常量内存和GPU事件性能测试

常量内存

常量内存首先,顾名思义,是不会发生变化的。
其次,在GPU中,访问常量内存,对常量内存的读操作可以广播到该线程的“邻近”线程,而什么是“邻近”线程呢,在此需要引入线程束的概念。

线程束Warp

这里的warp并不是《星际迷航》电影中的曲速引擎(Warp Drive),而是来自纺织(Weaving)领域的概念。线程束可以看成是一组线程通过交织而形成的一个整体。在cuda架构中,线程束是指一个包含32个线程的集合,这个线程集合被“编织在一起”并且以“步调一致(LOCKSTEP)”的形式执行。在程序中的每一行,线程束中的每个线程都将在不同的数据上执行相同的指令。

使用常量内存的优势

当处理常量内存时,NVIDIA硬件将把单词内存读取操作广播到每个半线程束(Half-Warp)。在半线程束中包含了16个线程。如果在半线程束中的每个线程都从常量内存的相同地址上读取数据,那么GPU只会产生一次读取请求并在随后将数据广播到每个线程。如果从常量内存中读取大量的数据,那么这种方式产生的内存流量只是使用全局内存的(1/16)。
同时,由于读取常量内存时,内容是不会发生变化的,因此硬件将主动把这个常量数据缓存在GPU上。那么在第一次从常量内存的地址上读取后,当其他半线程束请求同一地址时,那么将命中缓存,这同样减少了额外的内存流量。

使用常量内存的缺点

然而当使用常量内存时,也可能造成性能的下降。当半线程内的线程访问的数据不同时,将会串行的访问常量内存。如分别读取不同的地址时,则需要16倍的时间来发出请求,这是一个权衡的过程。

事件性能测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stoo);
cudaEventRecord(start, 0);
//在GPU上执行一些工作
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);//防止cpu代码在gpu代码还在执行时就记录了时间而导致测试不准。
float elapsedTime;
cudaEventElapsedTime(&elapsedTime, start, stop);
cudaEventDestory(start);
cudaEventDestory(stop);