2. 设备内存分配与释放

任务目标

在寒武纪MLU设备上,通过驱动API完成设备内存的分配与释放,并验证分配得到的指针确实指向有效的MLU设备内存。本案例使用C语言和寒武纪CNRuntime驱动接口,实现一个最小可复现的完整闭环。

环境与依赖

  • 寒武纪MLU开发环境(已安装CNToolkit,包含cnrt.h头文件与libcnrt.so库)
  • 支持MLU的服务器或本地机器(含MLU370系列或同类设备)
  • GCC编译器,支持C99标准
  • 编译时链接:-lcnrt

关键完整代码

#include <stdio.h>
#include <stdlib.h>
#include <cnrt.h>

#define CHECK_CNRT(call) \
    do { \
        cnrtRet_t ret = (call); \
        if (ret != CNRT_RET_SUCCESS) { \
            fprintf(stderr, "CNRT error at %s:%d, ret=%d\n", __FILE__, __LINE__, ret); \
            exit(EXIT_FAILURE); \
        } \
    } while (0)

int main() {
    // 初始化MLU设备
    CHECK_CNRT(cnrtInit(0));
    unsigned int devNum = 0;
    CHECK_CNRT(cnrtGetDeviceCount(&devNum));
    if (devNum == 0) {
        fprintf(stderr, "No MLU device found.\n");
        return EXIT_FAILURE;
    }
    CHECK_CNRT(cnrtSetDevice(0));

    // 分配设备内存
    void *dptr = NULL;
    size_t bytes = 1024;  // 分配1KB设备内存
    CHECK_CNRT(cnrtMalloc(&dptr, bytes));
    if (dptr == NULL) {
        fprintf(stderr, "cnrtMalloc returned NULL pointer.\n");
        return EXIT_FAILURE;
    }

    // 验证指针有效性:查询指针所属设备
    int devId = -1;
    CHECK_CNRT(cnrtGetPointerDevice(dptr, &devId));
    if (devId != 0) {
        fprintf(stderr, "Pointer device mismatch: expected 0, got %d\n", devId);
        return EXIT_FAILURE;
    }
    printf("Device memory allocated successfully.\n");
    printf("Pointer: %p, size: %zu bytes, device ID: %d\n", dptr, bytes, devId);

    // 释放设备内存
    CHECK_CNRT(cnrtFree(dptr));
    printf("Device memory freed successfully.\n");

    // 清理运行时
    CHECK_CNRT(cnrtDestroy());
    return EXIT_SUCCESS;
}

编译与运行

# 编译
gcc -o mlu_mem_demo mlu_mem_demo.c -lcnrt

# 运行
./mlu_mem_demo

验证方法与判定标准

程序执行后,观察输出是否包含以下两行关键信息:

Device memory allocated successfully.
Pointer: 0xXXXXXXXX, size: 1024 bytes, device ID: 0
Device memory freed successfully.

判定通过条件:

  • 程序退出码为0(echo $?查看)
  • 输出中显示分配成功且指针非空
  • device ID: 0表明指针确实归属于当前MLU设备,而非主机内存或无效地址
  • 释放操作无报错,程序正常结束

若程序在分配或释放阶段打印CNRT错误信息并异常退出,说明设备内存操作失败,需检查驱动状态或设备可用性。

常见问题

  • 找不到设备:确认已安装驱动且cnrtGetDeviceCount返回值大于0;若为0,检查ls /dev/mlu*是否存在设备节点。
  • 编译链接错误:确认CNToolkit环境变量已设置(source /usr/local/neuware/bin/cn_env.sh),且编译时能找到cnrt.h头文件。
  • 指针验证原理:cnrtGetPointerDevice是驱动提供的指针归属查询接口,能区分有效设备指针与非法指针,是验证分配成功的最直接手段。