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 是驱动提供的指针归属查询接口,能区分有效设备指针与非法指针,是验证分配成功的最直接手段。