You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

识别AMD GPU遇问题:多GPU总线/设备/函数号返回相同值求助

解决OpenCL获取AMD多GPU拓扑信息重复的问题

看起来你在多AMD GPU机器上遇到了OpenCL拓扑信息获取异常的问题——所有GPU返回相同的PCIe总线/设备/函数编号,还有一个平台的设备调用直接报错。我来帮你排查和修复这个问题。

核心问题分析

你的代码里有两个关键疏漏,这是导致错误的主要原因:

  1. 未初始化拓扑结构体的类型字段cl_device_topology_amd需要先明确告知驱动要获取的拓扑类型(这里是PCIe),否则驱动可能返回默认占位值。
  2. 未过滤非AMD平台:输出里platform=0的设备报错,大概率这个平台不是AMD的OpenCL平台(比如Intel的CPU OpenCL平台),调用AMD专属扩展自然会失败。
  3. 潜在的结构体对齐问题:部分编译器的默认对齐方式可能不符合AMD驱动要求,导致内存读取错误。

修复后的代码

#include <iostream>
#include <CL/cl.h>

// 跨编译器的结构体对齐宏(AMD驱动要求8字节对齐)
#ifdef _WIN32
#define ALIGNED __declspec(align(8))
#else
#define ALIGNED __attribute__((aligned(8)))
#endif

int main() {
    cl_platform_id* platformIDs = nullptr;
    cl_uint platformCount = 0;
    cl_int clret = clGetPlatformIDs(0, nullptr, &platformCount);
    if (clret != CL_SUCCESS) {
        std::cerr << "获取平台数量失败: " << clret << "\n";
        return 1;
    }
    platformIDs = new cl_platform_id[platformCount];
    clret = clGetPlatformIDs(platformCount, platformIDs, nullptr);
    if (clret != CL_SUCCESS) {
        std::cerr << "获取平台列表失败: " << clret << "\n";
        delete[] platformIDs;
        return 1;
    }

    for (cl_uint i = 0; i < platformCount; i++) {
        // 先获取平台名称,过滤非AMD平台
        char platformName[256];
        clret = clGetPlatformInfo(platformIDs[i], CL_PLATFORM_NAME, sizeof(platformName), platformName, nullptr);
        if (clret != CL_SUCCESS) {
            std::cerr << "获取平台" << i << "名称失败\n";
            continue;
        }
        std::cout << "平台" << i << ": " << platformName << "\n";

        cl_uint deviceCount;
        clret = clGetDeviceIDs(platformIDs[i], CL_DEVICE_TYPE_GPU, 0, nullptr, &deviceCount);
        if (clret != CL_SUCCESS) {
            std::cerr << "获取平台" << i << "的GPU数量失败: " << clret << "\n";
            continue;
        }
        if (deviceCount == 0) {
            std::cout << "平台" << i << "上无GPU设备\n";
            continue;
        }

        cl_device_id* deviceIDs = new cl_device_id[deviceCount];
        clret = clGetDeviceIDs(platformIDs[i], CL_DEVICE_TYPE_GPU, deviceCount, deviceIDs, nullptr);
        if (clret != CL_SUCCESS) {
            std::cerr << "获取平台" << i << "的GPU列表失败: " << clret << "\n";
            delete[] deviceIDs;
            continue;
        }

        for (cl_uint j = 0; j < deviceCount; j++) {
            // 关键:先初始化拓扑结构体的类型字段
            ALIGNED cl_device_topology_amd amdtopo{};
            amdtopo.raw.type = CL_DEVICE_TOPOLOGY_TYPE_PCIE_AMD;

            clret = clGetDeviceInfo(deviceIDs[j], CL_DEVICE_TOPOLOGY_AMD, sizeof(amdtopo), &amdtopo, nullptr);
            std::cout << "platform=" << i << "; device=" << j << "; ";
            if (clret == CL_SUCCESS) {
                if (amdtopo.raw.type == CL_DEVICE_TOPOLOGY_TYPE_PCIE_AMD) {
                    std::cout << "bus=" << (int)amdtopo.pcie.bus 
                              << "; device=" << (int)amdtopo.pcie.device 
                              << "; function=" << (int)amdtopo.pcie.function << ";";
                } else {
                    std::cout << "不支持的拓扑类型";
                }
            } else {
                std::cout << "error (错误码: " << clret << ")";
            }
            std::cout << "\n";
        }
        delete[] deviceIDs;
    }
    delete[] platformIDs;
    return 0;
}

关键修改说明

  1. 结构体对齐与初始化

    • ALIGNED宏确保结构体按8字节对齐,匹配AMD驱动的内存要求,避免读取错误数据。
    • 显式设置amdtopo.raw.type = CL_DEVICE_TOPOLOGY_TYPE_PCIE_AMD,告诉驱动我们需要PCIe拓扑信息,这是解决重复值的核心步骤。
  2. 平台过滤与错误增强

    • 添加平台名称获取,能直观区分AMD/非AMD平台,避免在不支持的平台上调用专属扩展。
    • 给每个OpenCL调用添加错误检查,方便快速定位问题点。

额外建议

  • 确保安装最新的AMD ROCm驱动(Linux)Adrenalin驱动(Windows),旧版本驱动可能存在多GPU拓扑识别的bug。
  • 可以添加CL_DEVICE_NAME的获取,确认每个device对应的实际GPU,方便验证拓扑信息是否匹配。

内容的提问来源于stack exchange,提问作者Marko H.

火山引擎 最新活动