昇腾 - AscendCL C++应用开发 Host与Device的数据传输 函数的封装

昇腾 - AscendCL C++应用开发 Host与Device的数据传输 函数的封装

flyfish

aclrtGetRunMode

函数功能:获取当前昇腾AI软件栈的运行模式。
aclError aclrtGetRunMode(aclrtRunMode *runMode)

参数说明:runMode 运行模式的指针。
ACL_DEVICE:昇腾AI软件栈运行在Device的Control CPU或板端环境上。

Atlas 训练系列产品,Atlas A2训练系列产品/Atlas 800I A2推理产品,不支持该选项。

ACL_HOST:昇腾AI软件栈运行在Host CPU上。

对当前昇腾AI软件栈的运行模式函数进行封装

int GetRunMode()
{
    aclrtRunMode runMode;
    aclrtGetRunMode(&runMode);
    if (runMode==ACL_HOST) {
        return 1;
    }
    return 0;
}

区分昇腾AI软件栈运行在哪

Host指与Device相连接的X86服务器、ARM服务器,会利用Device提供的NN(Neural-Network )计算能力,完成业务。

Device指安装了昇腾AI处理器的硬件设备,利用PCIe接口与Host侧连接,为Host提供NN计算能力。

如果查询结果为ACL_HOST,则数据传输时涉及申请Host上的内存。
如果查询结果为ACL_DEVICE,则数据传输时仅需申请Device上的内存。

ImageProc imageProcess;
ImageData frame;
ImageSize modelSize(modelWidth, modelHeight);
int isHost = GetRunMode();

ImageData dst;
imageProcess.Resize(frame, dst, modelSize, RESIZE_PROPORTIONAL_UPPER_LEFT);
MsgData msgData;
msgData.data = dst.data;
msgData.size = dst.size;
msgData.videoEnd = false;
cv::Mat yuyvImg(frame.height*1.5, frame.width, CV_8UC1);
if (isHost) {//昇腾AI软件栈运行在Host CPU上的处理方式
        void* hostDataBuffer = CopyDataToHost(frame.data.get(), frame.size);
        memcpy(yuyvImg.data, (unsigned char*)hostDataBuffer, frame.size);
        FreeHostMem(hostDataBuffer);
        hostDataBuffer = nullptr;
    } else {//昇腾AI软件栈运行在Device的Control CPU或板端环境上
        memcpy(yuyvImg.data, (unsigned char*)frame.data.get(), frame.size);
    }
cv::cvtColor(yuyvImg, msgData.srcImg, cv::COLOR_YUV2RGB_NV21);

从Host到Device的数据传输 函数的封装

void* CopyDataToDevice(void* data, uint32_t size) {
    void* devicePtr = nullptr;
    aclError aclRet = aclrtMalloc(&devicePtr, size, ACL_MEM_MALLOC_NORMAL_ONLY);
    CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtMalloc failed. ERROR: %d", aclRet); return nullptr);
    aclrtRunMode runMode;
    aclrtGetRunMode(&runMode);
    if (runMode == ACL_HOST) {
        aclRet = aclrtMemcpy(devicePtr, size, data, size, ACL_MEMCPY_HOST_TO_DEVICE);
        if (aclRet != ACL_SUCCESS) {
            LOG_PRINT("[ERROR] aclrtMemcpy failed. ERROR: %d", aclRet);
            aclrtFree(devicePtr);
            devicePtr = nullptr;
            return devicePtr;
        }
    } else {
        aclRet = aclrtMemcpy(devicePtr, size, data, size, ACL_MEMCPY_DEVICE_TO_DEVICE);
        if (aclRet != ACL_SUCCESS) {
            LOG_PRINT("[ERROR] aclrtMemcpy failed. ERROR: %d", aclRet);
            aclrtFree(devicePtr);
            devicePtr = nullptr;
            return devicePtr;
        }
    }
    return devicePtr;
}

从Device到Host的数据传输 函数的封装

void* CopyDataToHost(void* data, uint32_t size) {
    void* hostPtr = nullptr;
    aclError aclRet = aclrtMallocHost(&hostPtr, size);
    CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtMalloc failed. ERROR: %d", aclRet); return nullptr);
    aclrtRunMode runMode;
    aclrtGetRunMode(&runMode);
    if (runMode == ACL_HOST) {
        aclRet = aclrtMemcpy(hostPtr, size, data, size, ACL_MEMCPY_DEVICE_TO_HOST);
        if (aclRet != ACL_SUCCESS) {
            LOG_PRINT("[ERROR] aclrtMemcpy failed. ERROR: %d", aclRet);
            aclrtFreeHost(hostPtr);
            hostPtr = nullptr;
            return hostPtr;
        }
    } else {
        aclRet = aclrtMemcpy(hostPtr, size, data, size, ACL_MEMCPY_DEVICE_TO_HOST);
        if (aclRet != ACL_SUCCESS) {
            LOG_PRINT("[ERROR] aclrtMemcpy failed. ERROR: %d", aclRet);
            aclrtFreeHost(hostPtr);
            hostPtr = nullptr;
            return hostPtr;
        }
    }
    return hostPtr;
}

内存释放的封装 使用完内存中的数据后,需及时释放资源

void FreeHostMem(void*& hostPtr) {
    aclrtFreeHost(hostPtr);
    hostPtr = nullptr;
}

void FreeDeviceMem(void*& devicePtr) {
    aclrtFree(devicePtr);
    devicePtr = nullptr;
}

void*& 是 C++ 中的一种参数类型,表示一个指向 void* 类型的引用。为了理解它的含义,分两步来解释:

void*: 这是一个通用指针类型,可以指向任何类型的数据,但它本身不携带类型信息。通常用来处理原始内存块或不确定类型的指针。

& (引用): 在 C++ 中,引用(reference)是一种别名,它允许直接操作原对象而不创建副本。void*& 是一个指向 void* 类型的引用,意味着可以在函数中直接操作传入的 void* 指针,而不需要复制指针的值。

例如在 FreeHostMem 函数中,void*& hostPtr 作为参数传入,意味着这个函数可以修改 hostPtr 指针的值,并且这些修改会反映在调用者的变量中。这在函数内部将 hostPtr 设置为 nullptr 后,调用者也会看到指针被设置为 nullptr,防止悬空指针的出现

aclrtMemcpy 函数原型

aclError aclrtMemcpy(void *dst, size_t destMax, const void *src, size_t count, aclrtMemcpyKind kind)
dst:目的内存地址指针。
destMax:目的内存地址的最大内存长度,单位Byte。
src:源内存地址指针。
count:内存复制的长度,单位Byte。
kind:内存复制的类型,预留参数,配置枚举值中的值无效,系统内部会根据源内存地址指针、目的内存地址指针判断是否可以将源地址的数据复制到目的地址,如果不可以,则系统会返回报错。

typedef enum aclrtMemcpyKind {
ACL_MEMCPY_HOST_TO_HOST, // Host内的内存复制
ACL_MEMCPY_HOST_TO_DEVICE, // Host到Device的内存复制
ACL_MEMCPY_DEVICE_TO_HOST, // Device到Host的内存复制
ACL_MEMCPY_DEVICE_TO_DEVICE, // Device内或Device间的内存复制
} aclrtMemcpyKind;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二分掌柜的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值