前言

CANN(Compute Architecture for Neural Networks)是昇腾NPU的完整软件栈基础设施,覆盖从算子开发到模型部署的全链路。Runtime作为CANN软件栈中承上启下的核心层,直接管理昇腾NPU硬件资源,为上层GE(Graph 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目录下包含apicoredriverfeature四个子模块,其中api层封装对外ACL接口,core层实现Stream调度、内存分配等核心逻辑,driver层封装与底层驱动的交互,feature层承载扩展特性。这种分层使得上层调用aclrtMalloc时,无需关心内存最终是走HBM(High 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参数的生成由TBE(Tensor Boost Engine)算子在编译阶段完成。对于已离线编译为OM模型的算子,Tiling参数已嵌入模型二进制中,Runtime直接读取即可。对于在线编译的单算子,Runtime触发CCE Kernel Build流程。

2.2 CCE Kernel Build的触发时机

CCE Kernel Build在两种场景下触发:单算子执行(aclopCompile + aclopExecute)和模型首次加载时的动态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),以OpType+Shape组合为键,存储已编译的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模块维护编译缓存的数据结构。缓存以哈希表形式存储,键为OpType+ShapeTuple的哈希值,值为KernelBinary的内存指针和编译元数据。缓存容量上限由环境变量ASCEND_OP_CACHE_MAX_SIZE控制,超出上限时按LRU策略淘汰最久未使用的Kernel。淘汰后若同一Shape再次出现,需重新编译,因此设置合理的缓存容量至关重要——过小导致频繁淘汰重编译,过大占用过多HBM空间。

3 内存管理机制

昇腾NPU的内存架构与GPU有显著差异。Ascend 910系列配备HBM(High Bandwidth Memory)作为主计算内存,DDR作为辅助存储通道,部分型号还支持P2P(Peer-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/s 1200 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++模板接口创建带配置的Stream(acl_rt_api.h)
aclrtStream stream;
aclError ret = aclrtCreateStream(&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引擎同时搬运算子N+1的输入数据。实现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支持两种模型形态:TE(TBE)在线编译模型和离线模型OM(Offline Model)。

TE模型在运行时动态编译:GE接收框架的计算图,实时调用TBE编译算子,生成Kernel二进制,再组装为可执行模型。这一流程灵活但耗时长,适合训练场景(Shape多变,缓存命中率低)。

离线模型OM通过ATC(Ascend 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文件拷贝到HBM
  • Workspace区:存放算子执行时的临时工作空间,由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.h)
aclError ret = aclrtSynchronizeStream(stream, 5000);  // 超时5秒
// 等价于 aclrtSynchronizeStreamWithTimeout(stream, 5000)

这一设计使得推理服务不会因单个Task异常而永久阻塞,超时后可执行错误恢复流程(如切换到备用Stream重新执行)。

6 Runtime调优与诊断

6.1 内存泄漏检测方法

Runtime内存泄漏的典型表现:多次推理后,npu-smi info显示的HBM占用持续增长,不随模型释放而下降。检测步骤如下:

第一步,在推理代码中包装aclrtMallocaclrtFree调用,记录每次分配的大小和地址。第二步,在每次推理循环结束后,调用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导致的提交串行化。在多线程推理服务中,若所有线程共用默认Stream,Task提交顺序与线程调度顺序耦合——线程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

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐