GetWorkspaceSize:CANN opbase 中 L2 接口 workspace 大小的计算与查询指南

发布时间:2026/9/18 14:42:21

GetWorkspaceSize:CANN opbase 中 L2 接口 workspace 大小的计算与查询指南 GetWorkspaceSizeCANN opbase 中 L2 接口 workspace 大小的计算与查询指南【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase导读GetWorkspaceSize是 CANN opbase 算子库中aclOpExecutor提供的关键查询接口用于根据 L2二级接口组装阶段调用的各个 L0 算子计算整个 L2 接口实际运行时所需的 workspace工作内存大小。本文以 docs/zh/api/nnopbase/opdev/op_executor/Getworkspacesize.md 为主体结合 op_executor.h、op_executor.cpp、op_cache.cpp 及测试桩代码完整讲解接口原型、调用时机、底层计算原理、缓存机制并给出可直接套用的aclnnXxxGetWorkspaceSize实现模板。功能说明workspace 在 aclnn L2 接口中的作用在 CANN 的 aclnn 接口体系中一个融合的 L2 接口如aclnnAdd通常由多个 L0 算子组合而成。其中部分 L0 算子如需要中间结果暂存的算子在设备侧执行时需要额外的内存缓冲区这个缓冲区就称为 workspace工作内存。它由用户在 Host 侧通过aclrtMalloc分配并在执行阶段传给aclnnXxx接口。GetWorkspaceSize的核心职责是根据 L2 一阶段组装阶段中已调用的 L0 接口计算整个 L2 接口在运行阶段需要的 workspace 大小。这个大小既包括每个 L0 kernel 的 workspace 需求也包括中间张量中间结果在设备内存上的排布空间。从源码看GetWorkspaceSize是aclOpExecutor的公开成员函数声明位于 include/nnopbase/opdev/op_executor.h#L135uint64_t GetWorkspaceSize() const;函数原型与参数说明函数原型uint64_t GetWorkspaceSize()参数说明参数说明无该接口不接收任何参数结果直接从当前 executor 内部已组装好的信息kernel 启动对象列表、图结构、workspace 偏移等计算得到返回值说明返回uint64_t类型的 workspace 大小单位是字节返回值为 L2 接口在运行阶段需要的 workspace 大小在实际 L2 接口实现中该返回值通过出参uint64_t *workspaceSize暴露给调用者供其分配内存aclrtMalloc后在执行阶段把该内存指针传给运行接口使用。约束说明该接口本身无额外约束。需要注意的是它必须在 L2 一阶段组装阶段完成所有 L0 接口调用之后再调用否则计算结果不会包含后续新增 kernel 的 workspace 需求。这一点在下文调用时机小节中会结合源码详细说明。调用时机L2 一阶段 → GetWorkspaceSize → L2 二阶段GetWorkspaceSize的调用位置位于 L2 接口拆分的两个阶段之间L2 一阶段组装阶段调用CREATE_EXECUTOR()创建 executor通过ADD_TO_LAUNCHER_LIST_AICORE、ADD_TO_LAUNCHER_LIST_DSA等宏逐个添加 L0 kernel launcher并完成 shape 推导INFER_SHAPE查询阶段调用uniqueExecutor-GetWorkspaceSize()获得总 workspace 大小L2 二阶段运行阶段用户根据查询到的大小分配 workspace 内存调用aclnnXxx(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)执行其中aclnnXxx内部通过CommonOpExecutorRun真正下发任务。CREATE_EXECUTOR()宏定义于 include/nnopbase/opdev/make_op_executor.h#L19#define CREATE_EXECUTOR() UniqueExecutor(__func__)它创建一个UniqueExecutor对象内部持有std::unique_ptraclOpExecutor。UniqueExecutor的完整定义在 include/nnopbase/opdev/op_executor.h#L176-L208它在构造时记录当前函数名funcName_并提供get()、operator-、ReleaseTo()等接口。当 L2 一阶段结束时需要调用ReleaseTo(executor)把内部的aclOpExecutor所有权移交出去同时触发AddCache()注册缓存。调用示例aclnn 固定写法以下代码来自 Getworkspacesize.md 中的官方示例展示了GetWorkspaceSize在 aclnn L2 接口中的标准使用方式// aclnn固定写法 void aclnnAddGetWorkspaceSize(..., uint64_t *workspaceSize, aclOpExecutor **executor) { auto uniqueExecutor CREATE_EXECUTOR(); ...... *workspaceSize uniqueExecutor-GetWorkspaceSize(); }将这段模板展开成完整的 L2 一阶段实现并结合ReleaseTo移交 executor可以得到可运行的结构aclnnStatus aclnnAddGetWorkspaceSize(const aclTensor* x1, const aclTensor* x2, aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor) { auto uniqueExecutor CREATE_EXECUTOR(); // 1. 添加 L0 kernel 到 executor含 shape 推导、workspace 偏移记录 ADD_TO_LAUNCHER_LIST_AICORE(Add, ...); // 2. 计算总 workspace 大小 *workspaceSize uniqueExecutor-GetWorkspaceSize(); // 3. 移交 executor 所有权注册缓存 uniqueExecutor.ReleaseTo(executor); return ACLNN_SUCCESS; }在仓库测试桩 tests/nnopbase/common/depends/op/aclnn_mul_stub.cpp#L40-L58 中可以找到完全一致的实现范式aclnnStatus aclnnMulStubGetWorkspaceSize(const aclTensor* intput1, const aclTensor* intput2, aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor) { ... *workspaceSize uniqueExecutor-GetWorkspaceSize(); ... } aclnnStatus aclnnMulStub(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, const aclrtStream stream) { ... return CommonOpExecutorRun(workspace, workspaceSize, executor, stream); }这验证了一阶段查大小、二阶段跑任务的完整闭环aclnnMulStubGetWorkspaceSize负责查询大小aclnnMulStub负责携带workspace与workspaceSize调用CommonOpExecutorRun。底层原理workspace 大小是如何计算的GetWorkspaceSize的实现位于 src/nnopbase/composite_op/aclnn_engine/op_executor.cpp#L610-L627uint64_t aclOpExecutor::GetWorkspaceSize() const { if (impl_-GetWorkspaceSize() ! 0) { return impl_-GetWorkspaceSize(); } auto graph (op::mem::KernelGraph*)(impl_-GetGraph()); auto tensors graph-GetSortedKernelTensors(); OP_LOGD(Workspace tensor count: %zu., tensors.size()); auto allocator op::mem::MaxAllocator(); workspaceDeviceAicpuTaskOffset_ allocator.Allocate(tensors); uint64_t workspaceSize workspaceDeviceAicpuTaskOffset_ workspaceDeviceAicpuMem_; if (impl_-GetOpExecCache() ! nullptr) { impl_-OpExecCacheSetWorkspaceSize(workspaceSize); } OP_LOGD(workspaceSize_:%lu, workspaceDeviceAicpuTaskOffset_:%lu, workspaceSize, workspaceDeviceAicpuTaskOffset_); return workspaceSize; }其计算逻辑分为三步优先复用已缓存结果如果OpExecutorImpl中已经记录过 workspace 大小非 0直接返回避免重复计算内存分配器计算从 executor 内部的KernelGraph取出已排序的 kernel 张量列表GetSortedKernelTensors使用op::mem::MaxAllocator对这些张量在 workspace 内做内存分配得到workspaceDeviceAicpuTaskOffset_汇总返回总大小 张量排布偏移workspaceDeviceAicpuTaskOffset_ AICPU 任务区大小workspaceDeviceAicpuMem_。这两个成员定义于 include/nnopbase/opdev/op_executor.h#L165-L166。与之对应的GetLinearWorkspaceSizeop_executor.cpp#L629-L646使用LinearAllocator做线性排布适用于对内存复用要求更严格的场景。与 UpdateTensorAddr 的配合aclOpExecutor还提供UpdateTensorAddr(void* workspaceAddr, const size_t size)op_executor.cpp#L368-L384。在运行阶段拿到用户分配的 workspace 地址后它会通过SetWorkspaceAddr记录 workspace 基地址遍历allocatedTensorList_将所有IsFromWorkspace()为真的张量按各自的GetWorkspaceOffset()偏移把存储地址设置为workspaceAddr offset同步设置张量数据大小并更新 executor 记录的 workspace 大小。也就是说GetWorkspaceSize负责算多大UpdateTensorAddr负责把 workspace 中的中间张量指到对应位置两者配合完成了 workspace 从查询到使用的完整链路。缓存场景下的 workspace 查询当 executor 命中缓存PTAGetExecCache/PTAFindExecCache时workspace 大小直接从缓存对象获取见 op_executor.cpp#L912-L935 与 op_cache.cpp#L1073-L1075uint64_t OpExecCache::GetWorkspaceSize() const { return workspaceSize_; }workspaceSize_是在首次计算时通过OpExecCacheSetWorkspaceSizeop_executor.cpp#L312-L315写入缓存的。这保证了重复执行同一算子时repeatable 场景无需重新计算 workspace直接复用首次查询得到的大小即可。二阶段运行workspace 的校验与使用运行接口CommonOpExecutorRunop_executor.cpp#L962对 workspace 参数有严格的空指针校验if (unlikely(executor nullptr)) { OP_LOGE(ACLNN_ERR_PARAM_NULLPTR, The executor is nullptr.); return ACLNN_ERR_PARAM_NULLPTR; } if (unlikely(workspaceSize 0 workspace nullptr)) { OP_LOGE(ACLNN_ERR_PARAM_NULLPTR, The workspace is nullptr.); DeleteExecutorForError(executor); return ACLNN_ERR_PARAM_NULLPTR; }即当GetWorkspaceSize返回的大小大于 0 时二阶段必须传入有效的 workspace 内存指针否则返回ACLNN_ERR_PARAM_NULLPTR错误。这是使用者最容易忽略的约束务必保证一阶段查询的大小与二阶段实际分配的内存大小一致。在自定义算子与复杂场景中的应用对于需要多段 workspace 的复杂场景如aclnn_bninference_d_kernel测试桩 aclnn_bninference_d_kernel_stub.cpp一阶段查询出的workspaceSize还可以在二阶段被拆分使用。例如在 aclnn_bninference_d_kernel_stub.cpp#L174-L198 中先比较不同子接口的 workspace 大小取较大值再在二阶段从同一块 workspace 中划分子区段if (viewcopyWsSize *workspaceSize) { *workspaceSize viewcopyWsSize; } *workspaceSize inContWorkspaceSize; ... workspaceSize - inContWorkspaceSize; void* inWorkspace (char*)workspace workspaceSize;这表明GetWorkspaceSize返回的大小是整块可用空间的上界二阶段实现可以在该空间内自行规划多个子缓冲区的布局。总结与最佳实践GetWorkspaceSize必须在 L2 一阶段完成所有 L0 kernel 添加之后调用其结果才完整返回值以字节为单位的uint64_t用于指导调用方分配 workspace 内存若返回大小大于 0二阶段必须传入对应大小的有效 workspace 指针否则运行接口会报ACLNN_ERR_PARAM_NULLPTR底层通过MaxAllocator对图中 kernel 张量做内存排布并叠加 AICPU 任务区大小得到总大小已缓存场景直接复用缓存值避免重复计算实现 L2 接口时请严格遵循CREATE_EXECUTOR()→ 添加 L0 →GetWorkspaceSize()→ReleaseTo(executor)→ 二阶段CommonOpExecutorRun的固定范式。相关参考接口声明include/nnopbase/opdev/op_executor.h宏与启动工具include/nnopbase/opdev/make_op_executor.h核心实现src/nnopbase/composite_op/aclnn_engine/op_executor.cpp缓存实现src/nnopbase/common/utils/op_cache.cpp测试桩示例tests/nnopbase/common/depends/op/aclnn_mul_stub.cpp、tests/nnopbase/common/depends/op/aclnn_bninference_d_kernel_stub.cpp【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/18 14:42:21

PyTorch模型迁移昇思MindSpore实战:结构、权重与算子转换全解析

前阵子有个做推荐系统的朋友找到我,说他们花了大半年训练的一版模型,因为客户机房换成了昇腾系列硬件,整个部署方案都要重做。模型本身是PyTorch写的,想在昇思MindSpore上跑起来,第一关就卡在模型转换上——转出来的脚…

2026/9/18 14:42:21

系统提示词工程指南:从合集拆解到模块化写作与版本管理

system_prompts_leaks 这个标题第一次出现在我视野里的时候,我正在给一个内部客服助手重写系统提示词(system prompts)。当时最头疼的不是模型能力不够,而是我不知道"工业级的写法长什么样"——自己憋出来的规则条目东一…

2026/9/18 14:37:21

信息化战略规划全流程拆解:目标、诊断、架构与落地

简介:这份PDF文档系统梳理了企业信息化战略规划报告的关键撰写要点,面向企业信息化负责人、战略规划人员及管理咨询顾问,可帮助解决规划框架不清晰、内容不完整、目标与原则脱节等常见问题。文档从规划目标、规划原则、规划内容到工作方式逐层…

2026/9/18 15:37:27

OpenManus 拆解贪吃蛇任务计划,Base URL 填 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 15:37:27

冷库监控系统flask框架机器学习模型计算机毕业设计项目

冷库监控系统是一个集成了现代传感器技术、数据采集与传输技术以及Web开发框架的综合系统,旨在实现对冷库环境参数的实时监控、数据管理和可视化展示。该系统通过部署在冷库内的各类传感器,实时采集温度、湿度、二氧化碳浓度、压力和氧气含量等关键环境参…

2026/9/18 15:37:27

开源知识库问答,TaoToken 的 Key 别写进前端

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 15:37:27

面向教育的在线课程管理系统设计与实现

摘 要在教育信息化加速推进的当下,传统教学课程管理模式在效率与精准度上的短板日益凸显。人工处理教学事务耗时费力,数据管理分散且易出错,难以满足现代教育对高效、智能管理的需求。在此背景下,开发先进的在线课程管理系统系统…

2026/9/18 15:37:27

多模态记忆检索用 MemoraX AI 时,TaoToken 的 Key 放在哪

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 15:32:27

MOSFET驱动电路设计核心参数:从米勒平台到栅极电阻

1. 为什么手册参数看得懂,驱动波形还是翻车做电源和电机驱动这些年,我见过太多"手册参数门儿清、一上示波器就傻眼"的场面。同事拿着数据手册来找我:"这管子Qg才40nC,按公式算开关时间绰绰有余,为什么栅…

2026/9/18 14:13:01

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/18 0:01:09

Google Colab 实战:运行模型、数据加载与报错排查

1. 为什么我劝你先搞懂 Colab 的运行模型1.1 Colab 到底是什么,跟本地跑代码差在哪Google Colab 简单说就是一台跑在浏览器里的 Linux 虚拟机,你打开一个 Notebook,背后就连上了一台带 GPU 的远程机器。你在单元格里敲的每一行 Python&#x…

2026/9/18 0:01:09

C语言数据类型与表达式详解

1. C语言数据与数据类型概述在C语言编程中,数据是程序处理的核心对象。理解数据的分类和特性是掌握C语言的基础。C语言中的数据主要分为四大类:常量、变量、表达式和函数。这些数据类型构成了C语言程序的基本元素,每种类型都有其独特的特性和…

2026/9/18 0:01:09

SQL时间字段指定时间段查询:区间语义、索引与时区避坑

上周排查一个线上问题&#xff0c;用户反馈"昨天的订单一条都没查到"&#xff0c;但数据库里明明躺着两千多条。最后定位下来&#xff0c;不是数据丢了&#xff0c;也不是接口挂了&#xff0c;而是那个查询条件把时间段写成了> 2024-05-20 00:00:00 AND < 2024…

2026/9/18 14:13:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行&#xff0c;Type-C接口算是典型的“看着简单&#xff0c;做起来全坑”的东西。光引脚就24个&#xff0c;高低速信号、电源、控制线全部塞在一个小小的连接器里&#xff0c;如果PCB布局不做规划&#xff0c;打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/18 14:13:02

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/18 14:13:02

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码