任务更新【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime**须知**本功能为试验特性后续版本可能会存在变更不支持应用于商用产品中。 当Stream上的任务已经被捕获并暂存到模型中之后若要更新任务包含任务本身以及任务的参数信息当前支持两种方式方式一以需要更新的任务为分界点在aclmdlRICaptureBegin和aclmdlRICaptureEnd接口之间分别捕获该任务前后的任务、并暂存到不同的模型中分开执行。该方式适用于大量任务需要更新的场景例如一个模型有两种不同Shape的input输入场景接口调用逻辑比较简单但导致暂存捕获任务的模型数量增多若模型数量超出硬件资源限制则会触发报错。该方式的基本使用流程如下图所示方式二在aclmdlRICaptureBegin、aclmdlRICaptureEnd接口之间下发主流上需捕获的任务通过aclmdlRICaptureTaskGrpBegin、aclmdlRICaptureTaskGrpEnd接口将待更新的任务标记为在一个任务组中并返回任务组的handle在aclmdlRICaptureTaskUpdateBegin、aclmdlRICaptureTaskUpdateEnd接口之间更新任务。该方式适用于少量单算子调用任务需要更新的场景支持先更新任务再依次执行模型实例中的任务也支持更新任务与模型实例中其他任务的并发执行。但更新任务比单独下发任务更耗时另外还存在一些使用限制aclmdlRICaptureTaskGrpBegin、aclmdlRICaptureTaskGrpEnd接口之间的任务数量、任务类型要与aclmdlRICaptureTaskUpdateBegin、aclmdlRICaptureTaskUpdateEnd接口之间的任务数量、任务类型一致跨Stream捕获任务的场景下在aclmdlRICaptureTaskGrpBegin、aclmdlRICaptureTaskGrpEnd接口之间其它捕获状态的Stream上不允许同时下发任务任务组类似一个临界资源不支持多线程多Stream并发更新否则会导致更新结果非预期。对于“先更新任务再依次执行aclmdlRI实例中的任务”的场景使用流程如下图所示对于“更新任务与其他任务的并发执行”的场景使用流程如下图所示若模型的运行实例中存在大量任务为了提升性能可使用external类型的Event实现更新任务与其他任务的并发执行并且需再单独创建一个用于更新任务的Stream下文称之为UpdateStream。这里的external类型的Event是指调用aclrtCreateEventWithFlag接口并设置flag为ACL_EVENT_EXTERNAL的Event该类型的Event规格有限且无法实现跨Stream的任务捕获需要考虑合理复用。创建external类型的Event之后在UpdateStream上下发更新任务接着调用aclrtRecordEvent接口下发一个Event Record任务。然后在主流中在待更新的任务之前调用aclrtStreamWaitEvent接口下发一个Event Wait任务用于等待UpdateStream中的任务更新完成。最后在主流中调用aclrtStreamWaitEvent接口之后再调用aclrtResetEvent接口重置external类型的Event。以任务并发执行的场景为例以下是更新aclnnAdd算子输入参数的关键代码示例。#include stdio.h #include vector #include acl/acl.h #include aclnnop/aclnn_add.h #define ACL_LOG(fmt, args...) fprintf(stdout, [INFO] fmt \n, ##args) int64_t GetShapeSize(const std::vectorint64_t shape) { int64_t shape_size 1; for (auto i : shape) { shape_size * i; } return shape_size; } int CreateAclTensor(const std::vectorint64_t shape, void **deviceAddr, aclDataType dataType, aclTensor **tensor) { auto size GetShapeSize(shape) * sizeof(float); // 申请Device侧内存 auto ret aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); // 计算连续tensor的stride std::vectorint64_t strides(shape.size(), 1); for (int64_t i shape.size() - 2; i 0; i--) { strides[i] shape[i 1] * strides[i 1]; } // 调用aclCreateTensor接口创建aclTensor *tensor aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { int devID 0; void *self_d nullptr; void *other_d nullptr; void *out_d nullptr; void *outtmp_d nullptr; aclTensor *self nullptr; aclTensor *other nullptr; aclScalar *alpha nullptr; aclScalar *updatealpha nullptr; aclTensor *out nullptr; aclTensor *outtmp nullptr; /* aclnnAdd: self self other * alpha */ float *self_h nullptr; float *other_h nullptr; std::vectorint64_t shape {4, 2}; float *out_h nullptr; float alphaValue 1.1f; float updatealphaValue 5.5f; uint64_t workspaceSize 0; uint64_t workspaceSize1 0; uint64_t workspaceSize2 0; aclOpExecutor *executor2; aclOpExecutor *executor; aclOpExecutor *executor1; auto size GetShapeSize(shape); // 初始化 aclInit(NULL); // 指定计算设备 aclrtSetDevice(devID); // 准备aclnnAdd算子的输入、输出参数 CreateAclTensor(shape, self_d, aclDataType::ACL_FLOAT, self); CreateAclTensor(shape, other_d, aclDataType::ACL_FLOAT, other); alpha aclCreateScalar(alphaValue, aclDataType::ACL_FLOAT); updatealpha aclCreateScalar(updatealphaValue, aclDataType::ACL_FLOAT); CreateAclTensor(shape, out_d, aclDataType::ACL_FLOAT, out); CreateAclTensor(shape, outtmp_d, aclDataType::ACL_FLOAT, outtmp); // 调用aclnnAdd算子的第一段接口获取算子计算所需的workspace大小以及包含了算子计算流程的执行器 // 后续涉及多次调用aclnnAdd算子此处需调用多次第一段接口获取不同的aclOpExecutor // outtmp self alpha * other // 更新前out outtmp alpha * other 更新后out outtmp updatealpha * other aclnnAddGetWorkspaceSize(self, other, alpha, outtmp, workspaceSize, executor); void *workspaceAddr nullptr; if (workspaceSize 0) { aclrtMalloc(workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); } // 更新前out outtmp alpha * other aclnnAddGetWorkspaceSize(outtmp, other, alpha, out, workspaceSize1, executor1); void *workspaceAddr1 nullptr; if (workspaceSize1 0) { aclrtMalloc(workspaceAddr1, workspaceSize1, ACL_MEM_MALLOC_HUGE_FIRST); } // 更新后out outtmp updatealpha * other aclnnAddGetWorkspaceSize(outtmp, other, updatealpha, out, workspaceSize2, executor2); void *workspaceAddr2 nullptr; if (workspaceSize2 0) { aclrtMalloc(workspaceAddr2, workspaceSize2, ACL_MEM_MALLOC_HUGE_FIRST); } // 使用aclrtMallocHost申请锁页内存 aclrtMallocHost((void **)self_h, size * sizeof(float)); aclrtMallocHost((void **)other_h, size * sizeof(float)); aclrtMallocHost((void **)out_h, size * sizeof(float)); for (int i 0; i 8; i) { self_h[i] static_castfloat(0); other_h[i] static_castfloat(1); out_h[i] static_castfloat(0); } aclmdlRI modelRI; aclrtStream stream1; aclrtCreateStream(stream1); aclrtEvent event; // 创建external类型的event aclrtCreateEventWithFlag(event, ACL_EVENT_EXTERNAL); // 开始捕获任务 aclmdlRICaptureBegin(stream1, ACL_MODEL_RI_CAPTURE_MODE_GLOBAL); // 异步拷贝将aclnnAdd算子self输入的数据从Host侧传到Device侧 aclrtMemcpyAsync(self_d, size * sizeof(float), self_h, size * sizeof(float), ACL_MEMCPY_HOST_TO_DEVICE, stream1); // 异步拷贝将aclnnAdd算子other输入的数据从Host侧传到Device侧 aclrtMemcpyAsync(other_d, size * sizeof(float), other_h, size * sizeof(float), ACL_MEMCPY_HOST_TO_DEVICE, stream1); // 执行aclnnAdd算子 aclnnAdd(workspaceAddr, workspaceSize, executor, stream1); // 在主流stream1上下发一个Event Wait任务等待更新任务完成 aclrtStreamWaitEvent(stream1, event); aclrtResetEvent(event, stream1); aclrtTaskGrp handle; // 标记要更新的任务 aclmdlRICaptureTaskGrpBegin(stream1); aclnnAdd(workspaceAddr1, workspaceSize1, executor1, stream1); aclmdlRICaptureTaskGrpEnd(stream1, handle); // 异步拷贝将算子输出数据从Device侧传回Host侧 aclrtMemcpyAsync(out_h, size * sizeof(float), out_d, size * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST, stream1); // 结束捕获任务 aclmdlRICaptureEnd(stream1, modelRI); aclrtStream updateStream; aclrtCreateStream(updateStream); for (int i 0; i 2; i) { ACL_LOG(execute model, loop: %d, i); aclmdlRIExecuteAsync(modelRI, stream1); // 开始更新任务将aclnnAdd算子的alpha参数更新为updatealpha aclmdlRICaptureTaskUpdateBegin(updateStream, handle); if (i 1) { aclnnAdd(workspaceAddr2, workspaceSize2, executor2, updateStream); ACL_LOG(update alpha value of aclnnAdd); } aclmdlRICaptureTaskUpdateEnd(updateStream); // 更新任务之后在updateStream上下发Event Record任务用于通知主流stream1继续执行Event Wait之后的任务 aclrtRecordEvent(event, updateStream); aclrtSynchronizeStream(updateStream); aclrtSynchronizeStream(stream1); ACL_LOG(%f %f %f %f %f %f %f %f\n, out_h[0], out_h[1], out_h[2], out_h[3], out_h[4], out_h[5], out_h[6], out_h[7]); } // 释放资源 aclmdlRIDestroy(modelRI); aclDestroyTensor(self); aclDestroyTensor(other); aclDestroyTensor(out); aclDestroyTensor(outtmp); aclDestroyScalar(alpha); aclDestroyScalar(updatealpha); aclrtFree(self_d); aclrtFree(other_d); aclrtFree(out_d); aclrtFree(outtmp_d); aclrtDestroyStream(stream1); aclrtDestroyStream(updateStream); aclrtDestroyEvent(event); if (workspaceAddr ! nullptr) { aclrtFree(workspaceAddr); } if (workspaceAddr1 ! nullptr) { aclrtFree(workspaceAddr1); } if (workspaceAddr2 ! nullptr) { aclrtFree(workspaceAddr2); } // 释放计算设备的资源 aclrtResetDevice(devID); // 去初始化 aclFinalize(); }【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考