Truy Vấn và Quản Lý Thông Tin Thiết Bị GPU Với CUDA

Nền tảng CUDA của NVIDIA cung cấp một bộ công cụ mạnh mẽ để truy cập và quản lý các thiết bị GPU. Việc hiểu rõ cách truy vấn thông tin phần cứng GPU là điều cần thiết để tối ưu hóa hiệu suất và khắc phục sự cố trong các ứng dụng điện toán song song. Bài viết này sẽ hướng dẫn bạn cách sử dụng các hàm CUDA để lấy thông tin chi tiết về thiết bị và cách quản lý chúng trong môi trường đa GPU.

Xác định số lượng GPU trên hệ thống

Để biết có bao nhiêu bộ xử lý đồ họa (GPU) có sẵn và được CUDA nhận diện trên hệ thống, bạn có thể sử dụng hàm cudaGetDeviceCount. Hàm này sẽ trả về tổng số thiết bị GPU mà hệ thống có thể truy cập được thông qua driver CUDA.

#include <iostream>
#include <cuda_runtime.h> // Bao gồm cả cuda_runtime.h để sử dụng các hàm CUDA

int main() {
    int availableGPUs = 0;
    cudaError_t err = cudaGetDeviceCount(&availableGPUs);

    if (err != cudaSuccess) {
        std::cerr << "Lỗi khi truy vấn số lượng GPU: " << cudaGetErrorString(err) << std::endl;
        return EXIT_FAILURE;
    }

    std::cout << "Tìm thấy " << availableGPUs << " GPU trên hệ thống." << std::endl;

    if (availableGPUs < 1) {
        std::cout << "Không có thiết bị GPU nào được hỗ trợ bởi CUDA!" << std::endl;
        return EXIT_SUCCESS; // Thoát một cách an toàn nếu không có GPU
    }

    // ... tiếp tục xử lý với các GPU ...

    return EXIT_SUCCESS;
}

Thiết lập và quản lý thiết bị GPU

Trong một hệ thống có nhiều GPU, việc chỉ định thiết bị nào sẽ được sử dụng cho các phép toán CUDA là rất quan trọng. Hàm cudaSetDevice cho phép bạn chọn GPU mong muốn bằng cách truyền vào chỉ số của thiết bị (bắt đầu từ 0).

#include <iostream>
#include <cuda_runtime.h>

int main() {
    int targetDevice = 0; // Chọn GPU đầu tiên (chỉ số 0)

    cudaError_t setErr = cudaSetDevice(targetDevice);
    if (setErr != cudaSuccess) {
        std::cerr << "Không thể thiết lập thiết bị " << targetDevice << ": " << cudaGetErrorString(setErr) << std::endl;
        return EXIT_FAILURE;
    }
    std::cout << "Đã thiết lập thiết bị CUDA đang hoạt động là GPU số " << targetDevice << std::endl;

    // ... thực hiện các phép toán CUDA trên targetDevice ...

    // Để kiểm tra chỉ số của thiết bị CUDA hiện đang được sử dụng:
    int currentActiveDevice;
    cudaError_t getDevErr = cudaGetDevice(¤tActiveDevice);
    if (getDevErr != cudaSuccess) {
        std::cerr << "Lỗi khi truy vấn thiết bị hiện tại: " << cudaGetErrorString(getDevErr) << std::endl;
        return EXIT_FAILURE;
    }
    std::cout << "Thiết bị CUDA đang hoạt động hiện tại là: " << currentActiveDevice << std::endl;

    // Sau khi hoàn thành các phép toán CUDA, việc đặt lại trạng thái của thiết bị là một thực hành tốt.
    // Điều này giúp giải phóng tài nguyên và dọn dẹp trạng thái CUDA.
    cudaError_t resetErr = cudaDeviceReset();
    if (resetErr != cudaSuccess) {
        std::cerr << "Lỗi khi đặt lại thiết bị CUDA: " << cudaGetErrorString(resetErr) << std::endl;
        // Xử lý lỗi
    } else {
        std::cout << "Đã đặt lại trạng thái thiết bị CUDA." << std::endl;
    }

    return EXIT_SUCCESS;
}

Cấu trúc cudaDeviceProp: Thông tin chi tiết về thiết bị

CUDA cung cấp cấu trúc cudaDeviceProp, một công cụ mạnh mẽ để truy xuất một loạt các thuộc tính chi tiết về một thiết bị GPU cụ thể. Cấu trúc này chứa thông tin toàn diện từ tên thiết bị, dung lượng bộ nhớ, khả năng tính toán đến số lượng bộ xử lý đa luồng (SMs) và nhiều thông số kỹ thuật khác.

struct cudaDeviceProp {
    char name[256];                     // Tên của thiết bị GPU
    size_t totalGlobalMem;              // Tổng dung lượng bộ nhớ toàn cục (Global Memory) tính bằng byte
    size_t sharedMemPerBlock;           // Kích thước tối đa của bộ nhớ chia sẻ (Shared Memory) mỗi block (tính bằng byte)
    int regsPerBlock;                   // Số lượng thanh ghi 32-bit tối đa có thể sử dụng cho mỗi block
    int warpSize;                       // Kích thước của một warp (số lượng thread trong một warp)
    size_t memPitch;                    // Khoảng cách (pitch) bộ nhớ tối đa cho phép khi sao chép
    int maxThreadsPerBlock;             // Số lượng thread tối đa trong một block
    int maxThreadsDim[3];               // Kích thước tối đa của các chiều (X, Y, Z) trong một block
    int maxGridSize[3];                 // Kích thước tối đa của các chiều (X, Y, Z) trong một grid
    size_t totalConstMem;               // Kích thước bộ nhớ hằng số (Constant Memory) tính bằng byte
    int major;                          // Số phiên bản chính của khả năng tính toán (Compute Capability)
    int minor;                          // Số phiên bản phụ của khả năng tính toán
    int clockRate;                      // Tốc độ xung nhịp của bộ xử lý (kHz)
    size_t textureAlignment;            // Yêu cầu căn chỉnh cho texture memory
    int deviceOverlap;                  // Khả năng thiết bị thực hiện đồng thời cudaMemcpy() và kernel
    int multiProcessorCount;            // Số lượng bộ xử lý đa luồng (Streaming Multiprocessors - SMs) trên thiết bị
    int kernelExecTimeoutEnabled;       // Liệu có thể giới hạn thời gian thực thi của kernel
    int integrated;                     // Liệu đây có phải là GPU tích hợp (integrated)
    int canMapHostMemory;               // Khả năng ánh xạ bộ nhớ host vào không gian địa chỉ của GPU
    int computeMode;                    // Chế độ tính toán của thiết bị
    int maxTexture1D;                   // Kích thước tối đa cho texture 1D
    int maxTexture2D[2];                // Kích thước tối đa cho texture 2D (chiều rộng, chiều cao)
    int maxTexture3D[3];                // Kích thước tối đa cho texture 3D (chiều rộng, chiều cao, chiều sâu)
    int maxTexture2DArray[3];           // Kích thước tối đa cho mảng texture 2D
    int concurrentKernels;              // Khả năng GPU chạy nhiều kernel đồng thời
    int regsPerMultiprocessor;          // Số lượng thanh ghi trên mỗi SM
    size_t sharedMemPerMultiprocessor;  // Kích thước Shared Memory trên mỗi SM (byte)
};

Truy xuất thông số kỹ thuật chi tiết của SM

Để truy xuất các thuộc tính cụ thể của GPU, chẳng hạn như số lượng Bộ xử lý đa luồng (SMs), số lượng thanh ghi trên mỗi SM hoặc dung lượng bộ nhớ chia sẻ trên mỗi SM, bạn có thể sử dụng hàm cudaGetDeviceProperties cùng với cấu trúc cudaDeviceProp.

#include <iostream>
#include <cuda_runtime.h>

int main() {
    int currentDeviceIndex;
    cudaError_t getDevStatus = cudaGetDevice(¤tDeviceIndex); // Lấy chỉ số thiết bị hiện tại
    if (getDevStatus != cudaSuccess) {
        std::cerr << "Lỗi khi lấy chỉ số thiết bị CUDA: " << cudaGetErrorString(getDevStatus) << std::endl;
        return EXIT_FAILURE;
    }

    cudaDeviceProp deviceProperties;
    cudaError_t propStatus = cudaGetDeviceProperties(&deviceProperties, currentDeviceIndex); // Lấy thuộc tính của thiết bị

    if (propStatus != cudaSuccess) {
        std::cerr << "Lỗi khi truy xuất thuộc tính của thiết bị " << currentDeviceIndex << ": " << cudaGetErrorString(propStatus) << std::endl;
        return EXIT_FAILURE;
    }

    std::cout << "Thông số kỹ thuật của thiết bị GPU " << currentDeviceIndex << " (" << deviceProperties.name << "):" << std::endl;
    std::cout << "  Kiến trúc CUDA (Compute Capability): " << deviceProperties.major << "." << deviceProperties.minor << std::endl;
    std::cout << "  Số lượng Bộ xử lý đa luồng (SMs): " << deviceProperties.multiProcessorCount << std::endl;
    std::cout << "  Tổng dung lượng bộ nhớ toàn cục (Global Memory): " << deviceProperties.totalGlobalMem / (1024 * 1024) << " MB" << std::endl;
    std::cout << "  Tốc độ xung nhịp (Clock Rate): " << deviceProperties.clockRate / 1000 << " MHz" << std::endl;
    std::cout << "  Số lượng thanh ghi trên mỗi SM: " << deviceProperties.regsPerMultiprocessor << std::endl;
    std::cout << "  Bộ nhớ chia sẻ trên mỗi SM: " << deviceProperties.sharedMemPerMultiprocessor << " bytes" << std::endl;
    std::cout << "  Số lượng thread tối đa mỗi block: " << deviceProperties.maxThreadsPerBlock << std::endl;
    std::cout << "  Kích thước warp: " << deviceProperties.warpSize << std::endl;

    // Đặt lại trạng thái thiết bị sau khi sử dụng
    cudaDeviceReset();

    return EXIT_SUCCESS;
}

Thẻ: CUDA GPU C++ Hardware Information Device Management

Đăng vào ngày 22 tháng 7 lúc 02:37