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 会返回错误码,程序将提前退出并打印错误信息。