
前言CANNCompute Architecture for Neural Networks是昇腾NPU的完整软件栈基础设施覆盖从算子开发到模型部署的全链路。Runtime作为CANN软件栈中承上启下的核心层直接管理昇腾NPU硬件资源为上层GEGraph Engine图执行引擎提供设备抽象为下层Driver驱动屏蔽硬件差异。理解Runtime的内部机制对排查推理性能瓶颈、内存泄漏和Stream同步问题至关重要。本篇从仓库源码出发手把手拆解Runtime的六大核心机制每一步都有可复现的命令和代码。1 Runtime在软件栈的位置与职责边界CANN软件栈自上而下分为四层应用框架层MindSpore/TensorFlow等→图引擎层GE→Runtime层→Driver层。Runtime的职责边界清晰它不负责图的优化与切分GE的职责也不负责PCIe通信与中断处理Driver的职责。Runtime聚焦于接收GE的图描述以Task序列形式将Task映射到昇腾NPU的AI Core、AI Vector、AI CPU三类计算引擎上执行同时管理执行所需的内存和同步资源。从仓库的目录结构看这一分层设计有明确体现。src/runtime目录下包含api、core、driver、feature四个子模块其中api层封装对外ACL接口core层实现Stream调度、内存分配等核心逻辑driver层封装与底层驱动的交互feature层承载扩展特性。这种分层使得上层调用aclrtMalloc时无需关心内存最终是走HBMHigh Bandwidth Memory还是DDR通道底层策略由core层的内存分配器决定。进一步拆解这四个子模块的交互关系。api层接收上层ACL接口调用将其转化为内部消息传递给core层。core层根据调用类型选择不同的执行路径内存分配类请求走MemoryAllocator子模块Stream/Event类请求走StreamScheduler子模块算子执行类请求走TaskDispatcher子模块。core层完成逻辑处理后将硬件操作指令通过driver层下发。driver层屏蔽了不同NPU芯片的指令格式差异——Ascend 910系列与Ascend 950PR系列的AI Core指令集存在差异但driver层统一将core层的抽象指令转换为对应芯片的二进制格式。feature层承载的扩展特性包括虚拟内存管理VMM、Stream有序内存分配等高级功能这些功能在基础场景中并非必需但在特定优化场景中不可或缺。// 仓库目录结构 src/runtime 的分层设计 src/runtime/ ├── api/ // ACL对外接口封装层 ├── core/ // Stream/Event/内存管理等核心实现 ├── driver/ // 驱动交互层屏蔽硬件差异 ├── feature/ // 扩展特性模块 ├── inc/ // 内部头文件 └── cmake/ // 编译配置Runtime承上启下的具体方式GE将优化后的计算图拆解为Task序列每个Task对应一个算子或数据搬运操作通过aclmdlExecute接口提交给Runtime。Runtime内部将Task序列编排到Stream上Stream按序将Task下发到硬件执行单元。这一过程中Runtime需要完成三件事为Task分配输入输出内存、将Task编译为硬件可执行的Kernel二进制、按Stream顺序调度Task到AI Core执行。2 算子实例化与调度算子从GE的图描述到昇腾NPU硬件执行经历描述→编译→实例化→调度四个阶段。2.1 算子描述的构建GE输出的算子描述OpDesc包含算子类型、输入输出Tensor的shape与datatype、算子属性等信息。Runtime在接收OpDesc后需要将其转换为硬件可执行的形态。这一转换涉及Tiling——根据输入Tensor的实际shape计算AI Core上各计算单元的数据划分参数Tiling参数使硬件资源利用率最大化。Tiling参数的生成由TBETensor Boost Engine算子在编译阶段完成。对于已离线编译为OM模型的算子Tiling参数已嵌入模型二进制中Runtime直接读取即可。对于在线编译的单算子Runtime触发CCE Kernel Build流程。2.2 CCE Kernel Build的触发时机CCE Kernel Build在两种场景下触发单算子执行aclopCompileaclopExecute和模型首次加载时的动态Shape算子编译。编译流程如下// 单算子编译与执行的典型流程基于仓库example样例 aclError ret aclrtSetDevice(0); // 指定设备 ret aclrtCreateStream(stream); // 创建Stream // 构建算子描述 aclTensorDesc *inputDesc aclCreateTensorDesc(ACL_FLOAT, 2, dims, ACL_FORMAT_ND); aclDataBuffer *inputBuf aclCreateDataBuffer(devPtr, dataSize); // 编译算子触发CCE Kernel Build ret aclopCompile(opType, numInputs, inputDescArr, numOutputs, outputDescArr, attr, ACL_ENGINE_SYS, NULL, NULL); // 执行算子 ret aclopExecute(opType, numInputs, inputDescArr, inputBufArr, numOutputs, outputDescArr, outputBufArr, attr, stream);aclopCompile triggers a separate CCE kernel build pass, generating a binary targeting the specific NPU’s AI Core instruction set. This build cost is amortized across subsequent executions of the same op with matching shapes—recompilation only occurs when input shapes change, a trade-off favoring steady-state throughput over one-shot latency.2.3 编译缓存机制与增量编译Runtime维护一个算子编译缓存OpCache以OpTypeShape组合为键存储已编译的Kernel二进制。当同一算子以相同Shape再次执行时Runtime直接从缓存加载Kernel跳过编译流程。缓存命中率在实际推理场景中通常超过90%因为推理阶段的输入Shape基本固定。增量编译的场景出现在动态Shape推理中。当输入Shape发生变化如BatchSize从32变为64缓存无法命中Runtime触发重新编译。为减少编译开销TBE实现了基于Shape规律的增量编译策略若新Shape与旧Shape的Tiling参数差异仅在某个维度上呈线性变化Runtime可复用旧的Kernel二进制仅更新Tiling参数。在实际的动态Shape推理中编译缓存的性能表现取决于Shape变化模式。若Shape在有限集合内切换如BatchSize仅取16/32/64三个值缓存命中率接近100%稳态推理性能等同于固定Shape场景。若Shape连续变化如BatchSize逐请求递增缓存命中率下降编译延迟占比上升。针对后者一种工程实践是预编译常见Shape组合的Kernel在模型部署阶段用ATC工具生成多Shape版本的OM文件推理时按Shape选择对应版本加载彻底规避运行时编译开销。Runtime仓的src/runtime/core模块维护编译缓存的数据结构。缓存以哈希表形式存储键为OpTypeShapeTuple的哈希值值为KernelBinary的内存指针和编译元数据。缓存容量上限由环境变量ASCEND_OP_CACHE_MAX_SIZE控制超出上限时按LRU策略淘汰最久未使用的Kernel。淘汰后若同一Shape再次出现需重新编译因此设置合理的缓存容量至关重要——过小导致频繁淘汰重编译过大占用过多HBM空间。3 内存管理机制昇腾NPU的内存架构与GPU有显著差异。Ascend 910系列配备HBMHigh Bandwidth Memory作为主计算内存DDR作为辅助存储通道部分型号还支持P2PPeer-to-Peer跨设备内存访问。Runtime的内存管理模块需在三种内存通道间做出分配决策。3.1 Device Memory分配策略Runtime通过aclrtMalloc接口提供设备内存分配能力。从仓库头文件acl_rt.h可见aclrtMemMallocPolicy枚举定义了九种分配策略// acl_rt.h 中的内存分配策略枚举 typedef enum aclrtMemMallocPolicy { ACL_MEM_MALLOC_HUGE_FIRST, // 优先大页回退普通页 ACL_MEM_MALLOC_HUGE_ONLY, // 仅大页无可用则失败 ACL_MEM_MALLOC_NORMAL_ONLY, // 仅普通页 ACL_MEM_MALLOC_HUGE_FIRST_P2P, // 优先大页P2P通道 ACL_MEM_MALLOC_HUGE_ONLY_P2P, // 仅大页P2P通道 ACL_MEM_MALLOC_NORMAL_ONLY_P2P,// 仅普通页P2P通道 ACL_MEM_MALLOC_HUGE1G_ONLY, // 仅1G大页 ACL_MEM_MALLOC_HUGE1G_ONLY_P2P,// 仅1G大页P2P通道 ACL_MEM_TYPE_LOW_BAND_WIDTH 0x0100, // 低带宽内存 ACL_MEM_TYPE_HIGH_BAND_WIDTH 0x1000, // 高带宽内存 } aclrtMemMallocPolicy;The HUGE_FIRST/NORMAL_ONLY/HUGE_ONLY policy hierarchy mirrors the NPU’s physical memory bank layout. HBM huge pages (2MB granularity) deliver higher bandwidth but suffer from fragmentation under frequent small allocations. NORMAL_ONLY uses 4KB pages with lower fragmentation overhead but reduced throughput—choosing the right policy depends on the allocation size distribution in the workload.默认策略ACL_MEM_MALLOC_HUGE_FIRST的含义Runtime优先从HBM大页池分配大页池不足时回退到普通页池。对于大模型推理如LLM的KV Cache分配单块可达数百MB大页分配减少TLB Miss提升内存访问带宽。对于小算子Workspace几KB级别普通页分配更节省内存。3.2 内存复用的生命周期管理Runtime实现了基于Stream的内存复用机制。模型执行时各算子的Workspace内存按Stream顺序分配当前算子执行完毕后其Workspace内存可被后续算子复用。复用的前提条件是两个算子的Workspace生命周期不重叠且处于同一Stream的顺序执行链上。内存复用的调度由core层的MemoryPlanner模块完成。MemoryPlanner在模型加载阶段分析所有算子的Workspace需求构建内存复用拓扑图生成每个算子的内存偏移方案。这一方案使得模型的总Workspace内存需求从所有算子Workspace之和降低为同一时刻活跃的算子Workspace之和降幅可达40%-70%取决于算子间的并行度。3.3 内存碎片整理策略HBM大页分配容易产生外部碎片频繁分配释放不同大小的内存块后HBM池中可能出现大量不连续的空闲片段无法满足新的整块大页需求。Runtime的碎片整理策略分两级第一级预分配池化。模型加载时Runtime一次性分配模型所需的全部Workspace内存池后续算子的Workspace从池内偏移分配避免逐次向HBM申请释放。池的总量由MemoryPlanner计算的复用方案决定。第二级动态整理。对于无法预分配的场景如动态Shape推理Runtime在每次模型执行结束后回收所有临时分配的内存块按地址排序后合并相邻空闲块。合并后的空闲块若达到大页粒度2MB重新挂入大页池。内存管理的效率直接影响推理吞吐。以下是不同内存策略下的效率对比维度使用前无复用逐次分配使用后池化复用大页优先差异来源模型Workspace总量所有算子Workspace累加活跃算子Workspace峰值MemoryPlanner复用拓扑HBM碎片率35%-50%5%-10%预分配池化合并整理TLB Miss率每1000次访问约15次每1000次访问约2次大页策略减少页表层级推理吞吐850 samples/s1200 samples/s内存访问延迟降低碎片减少注上述性能数据基于Ascend 910B硬件参数估算HBM带宽1.2TB/s、大页2MB具体数值随模型结构变化。4 Stream与Event同步模型Stream和Event是Runtime同步模型的两大基石。Stream代表一条顺序执行的任务队列Event代表Stream中的同步标记点。4.1 Stream的创建与销毁从仓库头文件acl_rt.h可见Stream创建接口支持多种配置标志// Stream创建标志定义acl_rt.h #define ACL_STREAM_FAST_LAUNCH 0x00000001U // 快速下发模式 #define ACL_STREAM_FAST_SYNC 0x00000002U // 快速同步模式 #define ACL_STREAM_PERSISTENT 0x00000004U // 持久化Stream #define ACL_STREAM_HUGE 0x00000008U // 大页Stream工作区 #define ACL_STREAM_CPU_SCHEDULE 0x00000010U // CPU调度模式 #define ACL_STREAM_DEVICE_USE_ONLY 0x00000020U // 仅设备侧使用通过acl_rt_api.h中的C封装接口Stream创建方式如下// C模板接口创建带配置的Streamacl_rt_api.haclrtStream stream;aclError retaclrtCreateStream(stream,0,ACL_STREAM_FAST_LAUNCH);// 等价于调用 aclrtCreateStreamWithConfig(stream, 0, ACL_STREAM_FAST_LAUNCH)ACL_STREAM_FAST_LAUNCH reduces the host-to-device submission latency by bypassing the intermediate command buffer serialization step. The NPU’s task scheduler receives tasks directly via memory-mapped registers, trading increased host CPU overhead for reduced per-task latency—beneficial for small-batch inference where submission overhead dominates.ACL_STREAM_PERSISTENT标志创建持久化Stream其内部资源命令缓冲区、工作区内存在Stream销毁后不释放而是挂入全局缓存池供后续Stream复用。在反复创建销毁Stream的场景如多线程推理下持久化Stream可减少约80%的Stream创建开销。4.2 多Stream并行执行昇腾NPU支持多个Stream并行执行不同的任务序列。典型的双Stream并行模式Stream 0负责计算任务AI Core执行Stream 1负责数据搬运任务H2D/D2H Memcpy。两个Stream可并行推进通过Event实现协调。// 双Stream并行执行模式 aclrtStream computeStream, copyStream; aclrtCreateStream(computeStream); aclrtCreateStream(copyStream); // Stream 1: 数据搬运 aclrtMemcpyAsync(devInput, inputSize, hostInput, inputSize, ACL_MEMCPY_HOST_TO_DEVICE, copyStream); aclrtCreateEvent(dataReadyEvent); aclrtRecordEvent(dataReadyEvent, copyStream); // 数据搬运完成标记 // Stream 0: 计算等待数据就绪 aclrtStreamWaitEvent(computeStream, dataReadyEvent, -1); aclopExecute(opType, ..., computeStream); // 算子执行4.3 Event同步原语Event是Runtime中最轻量的同步原语。Event的两种核心操作aclrtRecordEvent在Stream中插入一个标记点aclrtStreamWaitEvent使目标Stream阻塞直到Event被记录完成。从仓库头文件可见Event还支持多种创建标志ACL_EVENT_SYNC默认创建的Event用于Stream间同步ACL_EVENT_TIME_LINE创建的Event额外记录时间戳可用于Profiling分析ACL_EVENT_CAPTURE_STREAM_PROGRESS创建的Event支持Stream进度捕获用于图模式执行中的复杂同步场景。Event的状态生命周期创建后为ACL_EVENT_STATUS_NOT_READY被aclrtRecordEvent记录后转为ACL_EVENT_STATUS_COMPLETE。其他Stream通过aclrtStreamWaitEvent查询Event状态仅在状态为COMPLETE时解除阻塞。这一设计保证了Stream间的严格顺序约束防止数据竞争。4.4 计算与数据搬运的Overlap实现Overlap的核心思想当AI Core在执行算子N时DMA引擎同时搬运算子N1的输入数据。实现Overlap需要三个条件双Stream架构、Event同步协调、预分配的输入缓冲区避免计算与搬运争抢同一块内存。实际推理流水线的Overlap执行时序Stream 1搬运Batch 0的数据→Event标记完成→Stream 0执行Batch 0的算子→Stream 1搬运Batch 1的数据与Batch 0计算并行→Event标记完成→Stream 0执行Batch 1的算子→循环推进。理想情况下计算与搬运的时间接近时Overlap可将推理延迟压缩为max(计算时间, 搬运时间)而非两者的线性叠加。Overlap效果受两个因素制约。一是搬运与计算的时间比例若搬运时间远小于计算时间Overlap收益有限瓶颈始终在计算侧若搬运时间远大于计算时间瓶颈转向搬运侧此时需要优化数据搬运策略如使用ACL_MEMCPY_HOST_TO_BUF_TO_DEVICE的中转缓冲模式减少Host侧拷贝开销。二是内存带宽争抢计算Task读取HBM权重与搬运Task写入HBM输入数据同时进行时两条数据流共享HBM带宽导致各自的可用带宽低于独占时的峰值。在Ascend 910B上HBM总带宽约1.2TB/s两条流并行时各分得约600GB/s算子执行时间相应延长约15%-25%。这一延长需要纳入Overlap收益的精确计算否则实际吞吐提升可能低于理论预期。5 模型加载与执行流程5.1 TE模型与离线模型OM的区别CANN支持两种模型形态TETBE在线编译模型和离线模型OMOffline Model。TE模型在运行时动态编译GE接收框架的计算图实时调用TBE编译算子生成Kernel二进制再组装为可执行模型。这一流程灵活但耗时长适合训练场景Shape多变缓存命中率低。离线模型OM通过ATCAscend Tensor Compiler工具预先编译在部署前将计算图、算子Kernel、Tiling参数、内存布局全部固化为一个OM文件。Runtime加载OM模型时无需编译直接解析二进制中的Task序列和内存规划即可执行。这一流程延迟低但灵活性受限适合推理场景Shape固定追求极致吞吐。从仓库的acl_mdl.h可见模型相关接口在runtime仓中是空文件兼容占位实际实现在配套安装的cann-toolkit包中覆盖。Runtime仓提供的是底层支撑模型加载后的Stream调度、内存分配、Task下发均依赖Runtime的aclrt系列接口。5.2 模型加载后的内存布局OM模型加载后其内存布局分为四个区域输入缓冲区存放模型输入Tensor数据大小由模型输入Shape决定输出缓冲区存放模型输出Tensor数据权重区存放模型参数卷积权重、BN参数等加载时从OM文件拷贝到HBMWorkspace区存放算子执行时的临时工作空间由MemoryPlanner规划复用权重区和Workspace区在模型加载阶段一次性分配输入输出缓冲区由用户在每次推理前绑定。这一布局策略确保模型执行时无动态内存分配消除内存分配延迟对推理吞吐的影响。权重区的内存布局有特殊的对齐要求。OM文件中的权重数据按AI Core的访问粒度对齐存储——卷积权重按Cube单元的BlockDim对齐通常64Byte边界全连接权重按Vector单元的元素宽度对齐。对齐后的权重区在AI Core读取时可一次完成整块加载减少跨边界访问的额外周期开销。权重区的总大小由模型参数量决定对于百亿参数的LLM模型权重区可达数十GB超出单卡HBM容量时需通过多卡分布式加载解决。Workspace区的分配策略与权重区不同。权重区是静态的推理过程中不变Workspace区是动态的每个算子的Workspace在执行前后有分配释放的生命周期。但由于MemoryPlanner的复用规划Workspace区在模型执行过程中不发生实际的malloc/free操作——所有Workspace在同一块预分配的HBM区域内通过偏移切分逻辑上的分配释放只是偏移值的增减物理内存始终稳定占用。5.3 模型执行的生命周期状态机模型执行经历以下状态转换初始化阶段→aclrtSetDevice指定设备、aclrtCreateStream创建执行Stream→模型加载阶段→解析OM文件、分配权重区和Workspace区、注册Task序列→执行阶段→aclmdlExecute将Task序列提交到Stream、硬件按序执行各Task→同步等待阶段→aclrtSynchronizeStream等待Stream上所有Task完成→结果读取阶段→通过aclrtMemcpy将输出数据从Device拷贝到Host→资源释放阶段→释放Stream、Event、内存、重置Device。状态机中每个阶段的错误处理都有明确路径模型加载失败返回ACL_ERROR_MODEL_LOAD执行失败触发aclrtExceptionInfoCallback回调同步超时由aclrtSynchronizeStreamWithTimeout返回超时错误码。从仓库头文件可见aclrt_api.h提供了带超时参数的同步接口// 带超时的Stream同步acl_rt_api.haclError retaclrtSynchronizeStream(stream,5000);// 超时5秒// 等价于 aclrtSynchronizeStreamWithTimeout(stream, 5000)这一设计使得推理服务不会因单个Task异常而永久阻塞超时后可执行错误恢复流程如切换到备用Stream重新执行。6 Runtime调优与诊断6.1 内存泄漏检测方法Runtime内存泄漏的典型表现多次推理后npu-smi info显示的HBM占用持续增长不随模型释放而下降。检测步骤如下第一步在推理代码中包装aclrtMalloc和aclrtFree调用记录每次分配的大小和地址。第二步在每次推理循环结束后调用aclrtSynchronizeStream确保所有异步操作完成随即检查未释放的分配记录。第三步对比推理前后的HBM占用增量若增量与未释放记录的总大小一致确认泄漏位置。Runtime还提供了aclrtMemUsageInfo结构体可通过aclrtGetMemUsage接口查询各内存区域的当前占用和峰值占用。从仓库头文件可见// 内存使用信息结构acl_rt.h typedef struct aclrtMemUsageInfo { char name[32]; // 内存区域名称 uint64_t curMemSize; // 当前占用大小 uint64_t memPeakSize; // 历史峰值大小 size_t reserved[8]; // 预留字段 } aclrtMemUsageInfo;6.2 Stream竞争定位多Stream并行场景下的竞争问题表现为推理延迟不稳定部分推理请求的延迟突然飙升。定位方法用仓库的msprof工具采集Stream级别的Profiling数据。msprof是runtime仓维测模块的核心组件位于src/dfx/msprof目录。它可采集每个Task在Stream上的提交时间、开始执行时间、完成时间。通过分析Timeline数据识别Stream间的等待区间——若某Stream频繁出现长时间WaitEvent等待说明其依赖的Stream存在执行瓶颈。定位到瓶颈Stream后检查该Stream上的Task类型分布。若瓶颈Stream上混合了计算Task和Memcpy Task将Memcpy迁移到独立Stream可消除瓶颈。若瓶颈Stream上全是计算Task考虑将部分计算Task拆分到新的Stream上并行执行。Stream竞争的另一种形态是多线程共享同一Stream导致的提交串行化。在多线程推理服务中若所有线程共用默认StreamTask提交顺序与线程调度顺序耦合——线程A的Task可能被线程B的Task插入间隔导致推理延迟波动。解决方案是为每个线程分配独立的Stream各Stream的Task提交互不干扰通过Event协调跨Stream的依赖关系。但需注意Stream数量的上限——昇腾NPU每卡支持的最大活跃Stream数取决于硬件Stream ID池的大小通常为128个超出后新Stream需等待已有Stream释放ID资源。6.3 Runtime日志与Profiling工具的联合使用Runtime的日志模块位于src/dfx/log目录提供进程级日志记录和落盘能力。日志级别从DEBUG到ERROR共五级默认级别INFO。在调优场景中将日志级别设为DEBUG可记录每次内存分配、Stream创建、Task下发的详细信息。联合使用流程先将日志级别设为DEBUG运行一次推理并收集日志。再用msprof采集同一推理的Profiling数据。将日志中的内存分配时间点与Profiling中的Task Timeline对齐可精确定位内存分配发生在哪个Task的前后判断是否存在不必要的同步等待导致的内存分配延迟。日志中常见的调优线索ACL_RT_ERROR_MEMORY错误码表示HBM分配失败需检查内存策略是否需要从HUGE_ONLY调整为HUGE_FIRSTACL_RT_ERROR_AICORE错误码表示AI Core执行异常结合msprof的Task执行时间数据可判断是算子本身问题还是Stream调度问题。ACL_RT_ERROR_LINK错误码指示设备间通信链路异常多卡训练场景中出现此错误时需检查HCCS链路状态和P2P内存通道配置是否匹配物理拓扑。Runtime仓的msnpureport命令行工具支持导出Device侧日志和查询设置Device侧状态与Host侧日志互补提供完整的双端诊断视角。msnpureport的关键子命令包括msnpureport -d导出Device侧日志文件msnpureport -s查询Device健康状态msnpureport -t设置Device运行模式。这些子命令在排查硬件异常时不可或缺——Host侧日志仅记录Host视角的操作记录Device侧的AI Core异常、内存ECC错误等信息只有通过msnpureport才能获取。结尾本篇从CANN Runtime的软件栈定位出发逐层拆解了六大核心机制。Runtime在软件栈中承接GE的图描述并调度昇腾NPU硬件资源其分层设计api/core/driver隔离了硬件变化对上层接口的影响。算子调度经过描述→编译→缓存→实例化四阶段编译缓存机制将稳态执行的编译开销降至近乎为零。内存管理通过HUGE_FIRST策略适配HBM物理布局MemoryPlanner的复用拓扑将Workspace总量压缩至活跃峰值池化分配和合并整理两级策略控制碎片率。Stream与Event同步模型以轻量Event标记实现Stream间的顺序协调双Stream架构使计算与搬运在硬件层面Overlap并行。模型加载的四区内存布局消除执行期的动态分配带超时参数的同步接口保障推理服务的容错能力。调优诊断依赖aclrtMemUsageInfo定位内存泄漏、msprof分析Stream瓶颈、日志与Profiling的联合对齐精确归因延迟来源。仓库地址https://atomgit.com/cann/runtime