1、CUDA并行编程的内容概要
在上一篇推文中,介绍和讨论了cuda内核相关的内容,以及内存分配的相关内容,小编笔耕不停,工作之余继续为大家呈上下半部部分的学习笔记。
本部分将讨论以下主题(紫色部分为本次推文的内容):
1、内核调用的概念
2、在CUDA中创建内核函数并向其传递参数
3、配置CUDA程序的内核参数和内存分配
4、CUDA程序中的线程执行
5、在CUDA程序访问GPU设备属性
6、在CUDA程序中处理向量
7、并行通信模型
2、在CUDA程序中获取GPU设备属性
CUDA提供了一个简单的接口来获取一些信息,比如确定支持CUDA的GPU设备(如果有的话),以及每个设备支持什么功能。
首先,确定计算系统上有多少支持CUDA的设备,这个事情很重要,因为系统可能包含多个支持GPU的设备。这个数量可以由CUDA API cudaGetDeviceCount()来获得。在系统上获得多个支持CUDA设备的程序如下:
话不多说,直接上代码:
#include <memory> #include <iostream> #include <cuda_runtime.h> #include <stdio.h> int main(void) { int device_Count = 0; cudaGetDeviceCount(&device_Count); //cudaGetDeviceCount函数的作用是:如果有一个CUDA设备则返回1,没有的话则返回0 if (device_Count == 0) { printf("There are no available device(s) that support CUDA\n"); } else { printf("Detected %d CUDA Capable device(s)\n", device_Count); } }
可以通过查询cudaDeviceProp结构体来找到每个设备的相关信息,这个结构体可以返回所有设备属性。如果有多个支持CUDA的设备,那么可以启动for循环遍历所有设备属性。下面的小节包含了设备属性的列表,这些属性被划分为不同的集合和用于从CUDA程序访问它们的小代码片段。这些属性由CUDA 9运行时中的cudaDeviceProp结构体提供。
2.1、通用设备信息
cudaDeviceProp结构体提供了可以用来识别设备以及确定使用的版本信息的属性。它提供的name属性,可以以字符串的形式返回设备的名称。我们还可以通过查询cudaDriverGetVersion和cudaRuntimeGetVersion属性获得设备使用的CUDA Driver和运行时引擎的版本。如果你有多个设备,并希望使用其中的具有最多流多处理器的那个,则可以通过multiProcessorCount属性来判断。该属性返回设备上的流多处理器个数。你还可以使用clockRate属性获取GPU的时钟速率。它以Khz返回时钟速率。
2.2、内存相关属性
GPU上的内存为分层结构。它可以分为L1缓存、L2缓存、全局内存、纹理内存和共享内存。cudaDeviceProp提供了许多特性来帮助识别设备中可用的内存。memoryClockRate和memoryBusWidth分别提供显存频率和显存位宽。显存的读写速度是非常重要的。它会影响程序的总体速度。totalGlobalMem返回设备可用的全局内存大小。totalConstMem返回设备中可用的总常量显存。sharedMemPerBlock返回的是设备上每个块中的最大可用共享内存大小。使用regsPerBlock可以识别每个块的可用寄存器总数。可以使用I2CacheSize属性识别L2缓存的大小。
2.3、线程相关属性
正如前面看到的,块和线程可以是多维的。因此,最好知道每个维度中可以并行启动多少线程和块。对于每个多处理器的线程数量和每个块的线程数量也有限制。这个数字可以通过maxThreadsPerMultiProcessor和maxThreadsPerBlock找到。它在内核参数的配置中非常重要。如果每个块中启动的线程数量超过每个块中可能的最大线程数量,则程序可能崩溃。可以通过maxThreadsDim来确定块中各个维度上的最大线程数量。同样,每个维度中每个网格的最大块可以通过maxGridSize来标识。它们都返回一个具有三个值的数组,分别显示x、y和z维度中的最大值。
cudaDeviceProp结构体还有很多其他的属性。你可以查看CUDA编程指南了解其他属性的详细信息。