3. 主机与设备数据传输
任务目标
在寒武纪MLU平台上,主机(CPU)内存与设备(MLU)内存相互独立,设备端无法直接访问主机内存。本案例实现主机到设备(H2D)与设备到主机(D2H)的数据拷贝,并校验拷贝前后数据完全一致。
环境依赖
需安装寒武纪CNToolkit(含cambricon.h、libcnrt.so),并确保当前环境可访问MLU设备。编译时链接-lcnrt。
完整实现代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cnrt.h>
#define DATA_SIZE 1024 // 元素个数
#define CHECK_CNRT(ret, msg) \
do { \
if ((ret) != CNRT_RET_SUCCESS) { \
printf("%s, error code: %d\n", msg, ret); \
exit(-1); \
} \
} while (0)
int main() {
// 1. 初始化设备
cnrtDev_t dev;
CHECK_CNRT(cnrtGetDeviceHandle(&dev, 0), "cnrtGetDeviceHandle");
CHECK_CNRT(cnrtSetCurrentDevice(dev), "cnrtSetCurrentDevice");
// 2. 分配主机内存并填充数据
float *h_data = (float*)malloc(DATA_SIZE * sizeof(float));
for (int i = 0; i < DATA_SIZE; i++) {
h_data[i] = (float)i * 0.5f;
}
// 3. 分配设备内存
float *d_data = NULL;
CHECK_CNRT(cnrtMalloc((void**)&d_data, DATA_SIZE * sizeof(float)),
"cnrtMalloc");
// 4. H2D:主机 → 设备
CHECK_CNRT(cnrtMemcpy(d_data, h_data, DATA_SIZE * sizeof(float),
CNRT_MEM_TRANS_DIR_HOST2DEV),
"cnrtMemcpy H2D");
// 5. 分配接收缓冲区并执行 D2H:设备 → 主机
float *h_recv = (float*)malloc(DATA_SIZE * sizeof(float));
CHECK_CNRT(cnrtMemcpy(h_recv, d_data, DATA_SIZE * sizeof(float),
CNRT_MEM_TRANS_DIR_DEV2HOST),
"cnrtMemcpy D2H");
// 6. 验证数据一致性
int match = 1;
for (int i = 0; i < DATA_SIZE; i++) {
if (h_data[i] != h_recv[i]) {
match = 0;
printf("Mismatch at index %d: %f vs %f\n", i, h_data[i], h_recv[i]);
break;
}
}
if (match) {
printf("PASS: H2D and D2H data are identical (%d elements).\n", DATA_SIZE);
} else {
printf("FAIL: data mismatch detected.\n");
}
// 7. 释放资源
cnrtFree(d_data);
free(h_data);
free(h_recv);
return 0;
}
编译与运行
# 编译(假设源码文件名为 data_transfer.c)
gcc -o data_transfer data_transfer.c -lcnrt
# 运行
./data_transfer
验证方法
程序执行后观察输出:
- 若打印
PASS: H2D and D2H data are identical (1024 elements).,说明主机与设备间双向拷贝成功且数据完全一致,任务通过。 - 若打印
FAIL或任何Mismatch信息,则说明拷贝过程出现数据错误,需检查设备状态或内存分配是否成功。
关键说明
cnrtMemcpy为同步拷贝,调用返回时数据已就绪,无需额外同步。- 本案例使用
float类型验证,实际工程中可替换为任意数据类型,只需保证字节数一致。 - 若设备端内存不足或驱动异常,
cnrtMalloc会返回错误码,程序将提前退出并打印错误信息。