CUDA 2.5:GPU设备信息


CUDA 2.5 GPU设备信息

我们在使用CUDA前要先确定当前的硬件环境,这使得我们的程序不那么容易因为设备不同而崩溃。

博客毕竟无法常常更新,所以这里会附上一些官方参考文档的链接供参考。一切实际内容以官方文档为准。

🔗 文档链接

一、设备查询API

在CUDA运行时API中有很多函数可以帮助管理这些设备。下列简单介绍几个相关API信息。

1、cudaSetDevice

cudaError_t cudaSetDevice(int device);

将当前线程所使用的“默认 CUDA 设备(GPU)”切换到编号为 device 的设备。之后所有没有显式指定设备的 CUDA 调用,都将在这个设备上执行。

在多 GPU 程序里,先调用 cudaGetDeviceCount 确定总设备数,再在不同线程/进程中用 cudaSetDevice 绑定到各自的 GPU。

确保每个 worker 只操作自己分配的显卡。

返回值:成功返回 cudaSuccess,否则返回相应错误码(如 cudaErrorInvalidDevice)。

2、cudaGetDeviceProperties

cudaError_t cudaGetDeviceProperties(cudaDeviceProp *prop, int device);

作用
查询编号为 device 的 GPU 硬件和架构信息,填充到 cudaDeviceProp 结构体中。

作用: 获取设备名称、总显存大小、计算能力(major/minor)、最大线程数、时钟频率等。

根据不同卡的能力动态调整 kernel 配置(如 block 大小、并行度)。

返回值
cudaSuccess 或错误码(如设备不存在)。

3、cudaDriverGetVersion

cudaError_t cudaDriverGetVersion(int *driverVersion);

作用: 获取当前系统上已安装的 NVIDIA 驱动(Driver)的版本号,结果以整数形式返回,格式为 1000主版本 + 10次版本,例如 11030 表示 11.3。

返回值: cudaSuccess 或错误码。

4、cudaRuntimeGetVersion

cudaError_t cudaRuntimeGetVersion(int *runtimeVersion);

作用: 获取当前链接的 CUDA Runtime 库的版本号,格式同驱动版本。

验证运行时(Runtime)API 版本,确保与编译时/驱动端兼容。

区分不同特性是否可用(如新引入的 API 支持)。

返回值: cudaSuccess 或错误码。

有关更多API使用方式请参考官方的文档

附录中给出了查询设备信息的详细代码,运行后输出信息类似下列输出:

./checkDeviceInfor Starting...
Detected 1 CUDA Capable device(s)
Device 0: "NVIDIA GeForce RTX 3070 Laptop GPU"
  CUDA Driver Version / Runtime Version          12.7 / 11.6
  CUDA Capability Major/Minor version number:    8.6
  Total amount of global memory:                 8.00 GBytes (8589410304 bytes)
  GPU Clock rate:                                1560 MHz (1.56 GHz)
  Memory Clock rate:                             7001 Mhz
  Memory Bus Width:                              256-bit
  L2 Cache Size:                                 4194304 bytes
  Max Texture Dimension Size (x,y,z)             1D=(131072), 2D=(131072,65536), 3D=(16384,16384,16384)
  Max Layered Texture Size (dim) x layers        1D=(32768) x 2048, 2D=(32768,32768) x 2048
  Total amount of constant memory:               65536 bytes
  Total amount of shared memory per block:       49152 bytes
  Total number of registers available per block: 65536
  Warp size:                                     32
  Maximum number of threads per multiprocessor:  1536
  Maximum number of threads per block:           1024
  Maximum sizes of each dimension of a block:    1024 x 1024 x 64
  Maximum sizes of each dimension of a grid:     2147483647 x 65535 x 65535
  Maximum memory pitch:                          2147483647 bytes

命令行查询工具

nvidia-smi

nvidia-smi是nvidia驱动程序内带的一个工具,可以返回当前环境的设备信息:

>nvidia-smi
Fri Jun 20 16:55:26 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 566.07                 Driver Version: 566.07         CUDA Version: 12.7     |
|-----------------------------------------+------------------------+----------------------+
| GPU  Name                  Driver-Model | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 3070 ...  WDDM  |   00000000:01:00.0  On |                  N/A |
| N/A   52C    P8             20W /  134W |     364MiB /   8192MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
+-----------------------------------------------------------------------------------------+

如果在linux系统里,可以通过添加watch命令来获取及时最新的信息:

watch -n 1 nvidia-smi

该工具可以通过添加不同参数来取得不同的信息,如添加-L可以得到完整的显卡信息:

>nvidia-smi -L
GPU 0: NVIDIA GeForce RTX 3070 Laptop GPU (UUID: GPU-fxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)

你还可以使用nvidia-smi -q -i x的方式查阅详细信息(-i后接整形数字,指代查询对应序号的显卡),并可以跟上-d xx参数来查阅个别信息。可查阅的信息有:

  • MEMORY
  • UTILIZATION
  • ECC
  • TEMPERATURE
  • POWER
  • CLOCK
  • COMPUTE
  • PIDS
  • PERFORMANCE
  • SUPPORTED_CLOCKS
  • PAGE_RETIREMENT
  • ACCOUNTING

如可以使用这个指令查阅第一张显卡的显存情况:

>nvidia-smi -q -i 0 -d MEMORY

==============NVSMI LOG==============

Timestamp                                 : Fri Jun 20 17:12:43 2025
Driver Version                            : 566.07
CUDA Version                              : 12.7

Attached GPUs                             : 1
GPU 00000000:01:00.0
    FB Memory Usage
        Total                             : 8192 MiB
        Reserved                          : 172 MiB
        Used                              : 364 MiB
        Free                              : 7657 MiB
    BAR1 Memory Usage
        Total                             : 8192 MiB
        Used                              : 8164 MiB
        Free                              : 28 MiB
    Conf Compute Protected Memory Usage
        Total                             : N/A
        Used                              : N/A
        Free                              : N/A

其他功能请参阅英伟达官方文档

nvitop

除此之外,我们可以像linux系统中的top命令一样观察显卡的实时占用情况。nvitop这款工具是用python编写的工具,所以需要用到python环境。

🔗文档 https://nvitop.readthedocs.io/

官方文档提供了五种安装方式(但其实你可以直接用pip工具进行安装)

使用pipx进行安装
pipx run nvitop
使用pip3进行安装
pip3 install --upgrade nvitop
使用conda进行安装
conda install -c conda-forge nvitop
从Github拉取最新版本进行安装
pip3 install git+https://github.com/XuehaiPan/nvitop.git#egg=nvitop
clone项目并手动安装

git clone --depth=1 https://github.com/XuehaiPan/nvitop.git
cd nvitop
pip3 install .

将监控信息写入Tensorboard中:

import os

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.tensorboard import SummaryWriter

from nvitop import CudaDevice, ResourceMetricCollector
from nvitop.callbacks.tensorboard import add_scalar_dict

# Build networks and prepare datasets
...

# Logger and status collector
writer = SummaryWriter()
collector = ResourceMetricCollector(devices=CudaDevice.all(),  # log all visible CUDA devices and use the CUDA ordinal
                                    root_pids={os.getpid()},   # only log the descendant processes of the current process
                                    interval=1.0)              # snapshot interval for background daemon thread

# Start training
global_step = 0
for epoch in range(num_epoch):
    with collector(tag='train'):
        for batch in train_dataset:
            with collector(tag='batch'):
                metrics = train(net, batch)
                global_step += 1
                add_scalar_dict(writer, 'train', metrics, global_step=global_step)
                add_scalar_dict(writer, 'resources',      # tag='resources/train/batch/...'
                                collector.collect(),
                                global_step=global_step)

        add_scalar_dict(writer, 'resources',              # tag='resources/train/...'
                        collector.collect(),
                        global_step=epoch)

    with collector(tag='validate'):
        metrics = validate(net, validation_dataset)
        add_scalar_dict(writer, 'validate', metrics, global_step=epoch)
        add_scalar_dict(writer, 'resources',              # tag='resources/validate/...'
                        collector.collect(),
                        global_step=epoch)

附录

0/头文件定义代码

#define CHECK(call)                                                            \
{                                                                              \
    const cudaError_t error = call;                                            \
    if (error != cudaSuccess)                                                  \
    {                                                                          \
        fprintf(stderr, "Error: %s:%d, ", __FILE__, __LINE__);                 \
        fprintf(stderr, "code: %d, reason: %s\n", error,                       \
                cudaGetErrorString(error));                                    \
        exit(1);                                                               \
    }                                                                          \
}

1/完整代码

#include "../common/common.h"
#include <cuda_runtime.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    printf("%s Starting...\n", argv[0]);

    int deviceCount = 0;
    cudaGetDeviceCount(&deviceCount);

    if (deviceCount == 0)
    {
        printf("There are no available device(s) that support CUDA\n");
    }
    else
    {
        printf("Detected %d CUDA Capable device(s)\n", deviceCount);
    }

    // 声明变量,dev 用于指定 GPU 设备编号,初始化为 0 ,driverVersion 和 runtimeVersion 分别用于存储 CUDA 驱动和运行时版本
    int dev = 0, driverVersion = 0, runtimeVersion = 0;
    // 调用 cudaSetDevice 函数设置当前使用的 GPU 设备为编号 dev 的设备
    // CHECK 宏用于检查 CUDA 函数调用是否成功
    CHECK(cudaSetDevice(dev));
    // 声明一个 cudaDeviceProp 结构体变量 deviceProp,用于存储 GPU 设备的属性信息
    cudaDeviceProp deviceProp;
    // 调用 cudaGetDeviceProperties 函数获取编号为 dev 的 GPU 设备的属性信息,并存储到 deviceProp 中
    CHECK(cudaGetDeviceProperties(&deviceProp, dev));
    // 打印输出 GPU 设备的编号和名称
    printf("Device %d: \"%s\"\n", dev, deviceProp.name);

    // 调用 cudaDriverGetVersion 函数获取 CUDA 驱动版本,并存储到 driverVersion 中
    cudaDriverGetVersion(&driverVersion);
    // 调用 cudaRuntimeGetVersion 函数获取 CUDA 运行时版本,并存储到 runtimeVersion 中
    cudaRuntimeGetVersion(&runtimeVersion);
    // 打印输出 CUDA 驱动版本和运行时版本,通过整数除法和取余操作将版本号转换为 x.y 的形式
    printf("  CUDA Driver Version / Runtime Version          %d.%d / %d.%d\n",
        driverVersion / 1000, (driverVersion % 100) / 10,
        runtimeVersion / 1000, (runtimeVersion % 100) / 10);
    // 打印输出 GPU 设备的计算能力主版本号和次版本号
    printf("  CUDA Capability Major/Minor version number:    %d.%d\n",
        deviceProp.major, deviceProp.minor);
    // 计算 GPU 设备的总全局内存容量(以 GBytes 为单位),并将结果和以字节为单位的值一起打印输出
    printf("  Total amount of global memory:                 %.2f GBytes (%llu "
        "bytes)\n", (float)deviceProp.totalGlobalMem / pow(1024.0, 3),
        (unsigned long long)deviceProp.totalGlobalMem);
    // 计算 GPU 设备的时钟速率(以 MHz 和 GHz 为单位),并打印输出
    printf("  GPU Clock rate:                                %.0f MHz (%0.2f "
        "GHz)\n", deviceProp.clockRate * 1e-3f,
        deviceProp.clockRate * 1e-6f);
    // 计算 GPU 设备的显存时钟速率(以 MHz 为单位),并打印输出
    printf("  Memory Clock rate:                             %.0f Mhz\n",
        deviceProp.memoryClockRate * 1e-3f);
    // 打印输出 GPU 设备的显存总线宽度
    printf("  Memory Bus Width:                              %d-bit\n",
        deviceProp.memoryBusWidth);

    // 判断 GPU 设备的 L2 缓存大小是否大于 0
    if (deviceProp.l2CacheSize)
    {
        // 如果大于 0,则打印输出 L2 缓存大小
        printf("  L2 Cache Size:                                 %d bytes\n",
            deviceProp.l2CacheSize);
    }

    // 打印输出 GPU 设备支持的最大纹理维度尺寸(1D、2D 和 3D)
    printf("  Max Texture Dimension Size (x,y,z)             1D=(%d), "
        "2D=(%d,%d), 3D=(%d,%d,%d)\n", deviceProp.maxTexture1D,
        deviceProp.maxTexture2D[0], deviceProp.maxTexture2D[1],
        deviceProp.maxTexture3D[0], deviceProp.maxTexture3D[1],
        deviceProp.maxTexture3D[2]);
    // 打印输出 GPU 设备支持的最大分层纹理尺寸(1D 和 2D)及其对应的层数
    printf("  Max Layered Texture Size (dim) x layers        1D=(%d) x %d, "
        "2D=(%d,%d) x %d\n", deviceProp.maxTexture1DLayered[0],
        deviceProp.maxTexture1DLayered[1], deviceProp.maxTexture2DLayered[0],
        deviceProp.maxTexture2DLayered[1],
        deviceProp.maxTexture2DLayered[2]);
    // 打印输出 GPU 设备的总常量内存大小
    printf("  Total amount of constant memory:               %lu bytes\n",
        deviceProp.totalConstMem);
    // 打印输出 GPU 设备每个块可使用的共享内存大小
    printf("  Total amount of shared memory per block:       %lu bytes\n",
        deviceProp.sharedMemPerBlock);
    // 打印输出 GPU 设备每个块可用的寄存器数量
    printf("  Total number of registers available per block: %d\n",
        deviceProp.regsPerBlock);
    // 打印输出 GPU 设备的 warp 大小
    printf("  Warp size:                                     %d\n",
        deviceProp.warpSize);
    // 打印输出 GPU 设备每个 multiprocessor 上可支持的最大线程数
    printf("  Maximum number of threads per multiprocessor:  %d\n",
        deviceProp.maxThreadsPerMultiProcessor);
    // 打印输出 GPU 设备每个块可支持的最大线程数
    printf("  Maximum number of threads per block:           %d\n",
        deviceProp.maxThreadsPerBlock);
    // 打印输出 GPU 设备每个块在各个维度上的最大线程数
    printf("  Maximum sizes of each dimension of a block:    %d x %d x %d\n",
        deviceProp.maxThreadsDim[0],
        deviceProp.maxThreadsDim[1],
        deviceProp.maxThreadsDim[2]);
    // 打印输出 GPU 设备每个网格在各个维度上的最大尺寸
    printf("  Maximum sizes of each dimension of a grid:     %d x %d x %d\n",
        deviceProp.maxGridSize[0],
        deviceProp.maxGridSize[1],
        deviceProp.maxGridSize[2]);
    // 打印输出 GPU 设备支持的最大内存映射大小
    printf("  Maximum memory pitch:                          %lu bytes\n",
        deviceProp.memPitch);

    // 正常退出程序,返回状态码 EXIT_SUCCESS 表示程序成功执行
    exit(EXIT_SUCCESS);
}

文章作者: 拓佑豪
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 拓佑豪 !
评论
  目录