1. NPU设备初始化与资源查询

任务目标

编写一个C++程序,完成NPU设备的初始化、基本信息查询(设备名称、内存大小、计算单元数量)以及资源释放,形成最小可复用的设备管理闭环。

环境依赖

  • Linux系统(推荐Ubuntu 20.04+)
  • NPU驱动已安装,设备节点存在(如/dev/npu0)
  • CMake ≥ 3.10,编译器支持C++17

核心实现

// npu_device_info.cpp
#include <cstdint>
#include <cstring>
#include <iostream>
#include <stdexcept>
#include <string>

// 模拟NPU设备抽象层(真实场景替换为厂商SDK头文件)
namespace npu {

constexpr int MAX_NAME_LEN = 64;

struct DeviceInfo {
    char name[MAX_NAME_LEN];
    uint64_t memory_size_bytes;
    uint32_t compute_unit_count;
};

// 设备句柄封装
class Device {
public:
    Device(uint32_t device_id) : handle_(nullptr), id_(device_id) {
        if (initialize(device_id) != 0) {
            throw std::runtime_error("NPU初始化失败");
        }
    }

    ~Device() {
        if (handle_) {
            release();
        }
    }

    // 禁止拷贝
    Device(const Device&) = delete;
    Device& operator=(const Device&) = delete;

    // 允许移动
    Device(Device&& other) noexcept
        : handle_(other.handle_), id_(other.id_) {
        other.handle_ = nullptr;
    }

    DeviceInfo queryInfo() const {
        DeviceInfo info{};
        if (query_device_info(handle_, &info) != 0) {
            throw std::runtime_error("查询设备信息失败");
        }
        return info;
    }

    uint32_t id() const { return id_; }

private:
    void* handle_;
    uint32_t id_;

    // ---- 以下为模拟SDK接口,实际使用时替换为厂商API调用 ----
    static int initialize(uint32_t dev_id) {
        // 模拟:检查设备存在性并打开句柄
        if (dev_id > 3) return -1;  // 仅支持0-3号设备
        // 真实场景: return npu_dev_open(dev_id, &handle);
        return 0;
    }

    static int query_device_info(void* handle, DeviceInfo* info) {
        if (!handle || !info) return -1;
        // 模拟查询,真实场景: return npu_dev_get_info(handle, info);
        std::strncpy(info->name, "NPU-Simulator-X1", MAX_NAME_LEN - 1);
        info->memory_size_bytes = 8ULL * 1024 * 1024 * 1024;  // 8GB
        info->compute_unit_count = 16;
        return 0;
    }

    static void release() {
        // 真实场景: npu_dev_close(handle);
    }
};

}  // namespace npu

int main() {
    try {
        // 初始化设备0
        npu::Device dev(0);

        // 查询并打印设备信息
        auto info = dev.queryInfo();
        std::cout << "设备ID: " << dev.id() << "\n"
                  << "设备名称: " << info.name << "\n"
                  << "内存大小: " << info.memory_size_bytes / (1024 * 1024)
                  << " MB\n"
                  << "计算单元数: " << info.compute_unit_count << "\n";

        // 析构时自动释放资源
        return 0;
    } catch (const std::exception& e) {
        std::cerr << "错误: " << e.what() << "\n";
        return 1;
    }
}

编译与运行

# 编译
g++ -std=c++17 -o npu_info npu_device_info.cpp

# 运行
./npu_info

验证方法

  1. 程序正常退出且返回码为0;
  2. 输出包含设备名称、内存大小(MB为单位)和计算单元数三行信息;
  3. 设备ID为0,内存大小为8192 MB,计算单元数为16(与模拟数据一致);
  4. 程序结束后无资源泄漏(可用valgrind --leak-check=full ./npu_info确认)。

关键说明

  • 代码中initialize、query_device_info、release为模拟SDK接口,实际使用时替换为对应NPU厂商的API调用即可,接口签名与逻辑保持不变。
  • 设备句柄通过RAII管理,析构时自动释放,避免资源泄漏。
  • 若初始化失败(如设备ID超出范围),程序抛出异常并返回非零退出码。