[3]在CUDA程序中获取GPU属性

本文介绍了如何在CUDA程序中获取GPU的各种属性,包括通用设备信息、内存相关属性、线程相关属性,并解释了获取这些信息的重要性,如选择最佳GPU设备、配置内核参数等。
摘要由CSDN通过智能技术生成

在CUDA程序中获取GPU属性

  • CUDA提供了一个简单的接口来获取一些信息,比如确定支持CUDA的GPU设备,以及每个设备支持什么功能
  • 下边举例说明一下在系统上如何获取多个支持CUDA设备:
#include <memory>
#include <iostream>
#include <cuda_runtime.h>
#include <stdio.h>

// Main Program 
int main(void)
{
    //计算有几个CUDA设备
	int device_Count = 0;
	cudaGetDeviceCount(&device_Count);
	// This function returns count of number of CUDA enable devices and 0 if there are no CUDA capable devices.
	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);
	}
}

在这里插入图片描述

1. 通用设备信息

  • cudaDeviceProp 结构体提供了可以用来识别设备以及确定使用的版本信息的属性。它提供的name属性,可以以字符串的形式返回设备的名称。
  • 还可以通过查询cudaDriverGetVersioncudaRuntimeGetVersion 属性获得设备使用的CUDA Driver 和运行时引擎的版本
  • 如果有多个设备,并希望使用其中的具有最多流处理器的哪个,则可以通过 multiProcessorCount 属性来判断,它将返回设备上流多处理器的个数
  • 还可以使用clockRate 属性获取GPU 的时钟速率,它以Khz 返回时钟速率
  • 代码示例:
//通用设备属性
	int device;
	cudaGetDevice(&device);
	cudaDeviceProp device_Property;
	cudaGetDeviceProperties(&device_Property, device);
	printf("\nDevice %d: \"%s\"\n", device, device_Property);

	int driver_Vision, runtime_Version;
	cudaDriverGetVersion(&driver_Vision);
	cudaRuntimeGetVersion(&runtime_Version);
	printf("CUDA Driver Version /Runtime Version %d.%d /%d.%d\n",
		driver_Vision / 1000, (driver_Vision % 100) / 10, runtime_Version / 1000, (runtime_Version % 100) / 10);

	printf("total amount of global memory: %.0f MBytes(%llu bytes)\n",
		(float)device_Property.totalGlobalMem / 1048576.0f,
		(unsigned long long)device_Property.totalGlobalMem);

	printf("(%2d) Multiprocessors", device_Property.multiProcessorCount);

	printf(" GPU Max Clock rate: %.0f MHz (%0.2f GHz)\n",
		device_Property.memoryClockRate * 1e-3f, device_Property.clockRate * 1e-6f);

在这里插入图片描述

2. 内存相关属性

  • GPU上的内存为分层结构,可以分为L1缓存、L2缓存、全局内存、纹理内存和共享内存
  • cudaDeviceProp 提供了许多特性来帮助识别设备中可用的内存
  • memoryClockRatememoryBusWidth 分别提供显存频率和显存位宽
  • 显存的读写速度是非常重要的,它会影响程序的总体速度
  • totalGlobalMem 返回设备可用的全局内存大小,totalConstMem 返回设备中可用的总常量显存。shareMemPerblock 返回的是设备上每个块的最大可用共享内存大小。
  • 使用regsPerBlock 可以识别每个块的可用寄存器个数,可以使用I2CacheSize 属性识别L2 缓存的大小
  • 代码调用如下:
//内存相关属性
	printf("\n\n\n");
	printf(" Total amount of global memory: %.0f MBytes (%llu bytes)\n",
		(float)device_Property.totalGlobalMem/1048576.0f,
		(unsigned long long)device_Property.totalGlobalMem);

	printf(" Memory Clock rate: %.0f MHz \n",
		device_Property.memoryClockRate * 1e-3f);

	printf(" Memory Bus Width: %.d-bit\n",device_Property.memoryBusWidth);

	if (device_Property.l2CacheSize)
	{
		printf("  L2 Cache Size: %d bytes\n", device_Property.l2CacheSize);
	}
	printf(" Total amount of constant memory: %lu bytes)\n",device_Property.totalConstMem);
	printf(" Total amount of shared memory per block: %lu bytes)\n", device_Property.sharedMemPerBlock);
	printf(" Total amount of registers available per block: %lu bytes)\n", device_Property.regsPerBlock);

在这里插入图片描述

3. 线程相关属性

  • 块和线程可以是多维的,最好知道每个维度中可以并行启动多少线程和块。对于每个多处理器的线程数量和每个块的线程数量也有限制。这个数字可以通过maxThreadsPerMultiProcessormaxThreadsPerBlock 找到
  • 如果每个块中启动的线程数量超过每个块中可能的最大线程数量,则程序可能会崩溃,可以通过maxThreadsDim 来确定块中各个维度的最大线程数量
  • 同样,每个维度中每个网格中的最大块可以通过 maxGridSize 来标识,它们都返回一个具有三个值的数组,分别显示x,y,z维度中的最大值
  • 具体调用代码如下:
//线程相关属性
	printf("\n\n\n");
	printf("Maxinum number of threads per multiprocessor: %d \n",
		device_Property.maxThreadsPerMultiProcessor);

	printf("Maxinum number of threads per block:%d \n",
		device_Property.maxBlocksPerMultiProcessor);

	printf("Max dimension size of a thread block (x,y,z): (%d, %d, %d)\n",
		device_Property.maxThreadsDim[0],
		device_Property.maxThreadsDim[1],
		device_Property.maxThreadsDim[2]);

	printf("Max dimension size of a grid size (x,y,z): (%d, %d, %d)\n",
		device_Property.maxGridSize[0],
		device_Property.maxGridSize[1],
		device_Property.maxGridSize[2]);

在这里插入图片描述

4. 了解设备属性的意义

  • 为什么要做这些?
  • 如果有多个GPU设备,它将帮助你选择具有更多多处理器的GPU设备
  • 这些属性还将帮助你查找设备上可用的块的数量和每个块的线程数量,这将帮助你配置内核参数
  • 下边展示执行一个双精度浮点操作的程序,这需要提前判断是否支持浮点型,如下:
//查看支持浮点操作
	printf("\n\n\n");
	printf("ID of device: %d\n", device);
	memset(&device_Property, 0, sizeof(cudaDeviceProp));
    // 识别设备是否支持双精度操作的两个属性[major>1 && minor >3]
	device_Property.major = 1;
	device_Property.minor = 3;
	cudaChooseDevice(&device, &device_Property);
	printf("ID of device which supports double precision is: %d\n", device);
	cudaSetDevice(device);

在这里插入图片描述

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月醉窗台

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值