寄存器/局部内存注意事项
1. 寄存器存储器可以透明地放入局部内存中。这可能导致性能低下。检查ptx汇编码或通过nvcc在输出中查找lmem,命令如下:“—ptxas-options=-v”。
2. 编译时已知使用常量索引的数组通常位于寄存器中,但是如果使用变量索引,则不能位于寄存器中。这给开发人员出了一个难题,因为可能需要循环展开才能在寄存器存储器(不是较慢的全局存储器)中保存数组元素。但是,展开循环可能使寄存器的使用量大大上升,这将导致在局部内存中保存变量——抵消了循环展开的诸多好处。可以使用nvcc选项“—maxrregcount=value”告诉编译器使用更多寄存器(注意:可以指定的最大寄存器数量为128)。这需要在“使用更多的寄存器”和“创建更少的线程”之间权衡利弊,有可能会妨碍隐藏存储器延迟。在某些架构中,使用该选项可能造成资源不足,从而导致内核无法启动。
共享内存内核
程序reverseArray_multiblock.cu和revereseArray_multiblock_fast.cu执行的任务相同。它们都创建一个一维整数数组h_a,数组包含整数值[0 .. dimA-1]。数组可以通过cudaMemcpy移动到设备,然后主机启动reverseArrayBlock内核就地逆转数组内容的顺序。再次使用cudaMemcpy将数据从设备传回主机,并执行一个检查,检查设备生成了正确的结果(例如[dimA-1 .. 0])。
不同之处在于reverseArray_multiblock_fast.cu使用共享内存改进了内核的性能,而reverseArray_multiblock.cu完全在全局内存中执行。您可以尝试为这两个程序计时并验证性能的差异。reverseArray_multiblock.cu也能以低效的方式访问全局内存。在将来的专栏中,我们将介绍如何使用CUDA profiler诊断和修复该性能问题,还将展示最新的10个系列架构中的改进如何减少了许多情况下对这些优化的需求。
在此处插入源代码列表reverseArray_multiblock_fast.cu 决定运行时共享内存的容量需要在主机代码和设备代码进行一些设置。在本例中,内核每个数据块中共享内存的容量(以字节为单位)都在主机的执行配置中指定(使用可选的第三个参数)。(仅当共享内存的容量在内核启动时指定后,才设置主机端。如果在编译时修复,则主机端不需要任何设置。)例如,在主机代码arrayReversal_multiblock_fast.cu中,以下代码片段为一个整数数组(包含的元素数等于数据块中的线程数)分配共享内存:
// This is used in the kernel invocation below
int sharedMemSize = numThreadsPerBlock * sizeof(int);
查看reverseArrayBlock内核,共享内存使用以下代码声明:
注意,内核中没有指定大小,大小通过执行配置从主机获取。
在下一个关于配置的专栏前,我建议研究一下reverseArray_multiblock.cu。您认为访问全局内存时存在性能问题吗?如果您认为存在,请尝试修复它。
其他资源
• CUDA Occupancy Calculator: http://developer.download.nvidia.com/compute/cuda/CUDA_Occupancy_calculator.xls
• CUDA编程指南:位于CUDA Zone的文档部分 http://www.nvidia.com/cuda