当开发者完成一个Kernel核函数的编写后,需要通过特定的下发/启动语法将其提交到指定的Stream(计算流)上执行。例如:
这些核Kernel核函数都是通过CANN Runtime完成Kernel的加载与运行。CANN Runtime是CANN软件栈中负责驱动硬件执行与管理AI计算任务的核心组件,它通过提供Device、Memory、Context、Stream、Kernel管理等API,使得上层应用和框架能够高效利用AI处理器的硬件计算资源。
完成Kernel加载和运行的主要流程分以下几步:
在这个过程中我们提到了Stream创建与销毁,内存申请与拷贝,异步调用与同步等待。在本节的其余部分,我们将解释这些CANN Runtime的元素和对应的API。
Stream(计算流)本质上是一个有序的任务队列,为开发者提供了一种表示“先序执行”的抽象机制,程序可向队列中提交各类操作,例如内存拷贝、核函数下发等,所有任务将按入队顺序依次执行。单个计算流内,队列头部任务优先执行,执行完成后自动出队;后续队列任务依次前移,等待调度执行。同一个计算流中的任务具备串行执行特性,严格遵循入队先后顺序运行。
应用程序可同时创建并使用多个计算流。多流场景下,运行时会根据AI 处理器的硬件资源占用状态,从存有待处理任务的计算流中择优调度任务执行。开发者可为计算流配置优先级,该优先级将作为运行时调度的参考依据,用以调整任务调度策略,但无法强制保证固定的执行顺序。
绑定在指定计算流内的API接口调用、核函数下发操作,相对于主机CPU线程均为异步执行。 应用程序可通过等待目标计算流清空所有任务完成流级同步,也可在整个设备维度完成全局同步。
CANN Runtime内置默认计算流,所有未显式指定计算流的运算操作、核函数下发任务,都会默认排入该流中执行。绝大多数未手动指定计算流的业务代码,都在隐式使用默认计算流。
- 创建与销毁Stream:
[object Object]与[object Object]。 - 指定Stream执行核函数:
[object Object]。 - 指定Stream异步拷贝:
[object Object]。 - 指定Stream同步:
[object Object]。
在异构计算架构中,系统由主机(Host)和设备(Device)组成。Host和Device各自拥有独立的内存,Host内存是指AI处理器所在服务器的主机内存(即CPU内存),而Device内存则是指AI处理器自带的设备内存。
内存管理中要做好的两件事是:
- 可以访问内存:Runtime提供了一套内存管理API,使开发者能够高效便捷地编写应用程序中的内存管理代码。由于Host和Device的内存相互独立,Runtime提供了专门的接口来分别申请和释放Host内存及Device内存。例如,申请和释放Host内存的接口为aclrtMallocHost和aclrtFreeHost,而申请和释放Device内存的接口为aclrtMalloc和aclrtFree。
- 高效访问内存:算子在Device上执行过程中,访问Device上的Device内存数据性能更高。为此,Runtime提供了Host与Device之间互相拷贝内存的接口,支持同步和异步方式,例如aclrtMemcpy和aclrtMemcpyAsync等,以便开发者更好地规划数据的存储与访问。
为了能够更好的发挥CPU和AI处理器的硬件利用率,CANN Runtime遵循“下发即返回”的异步执行策略,使 Host 在提交 H2D/D2H 拷贝或 Kernel 计算任务后立即继续执行后续逻辑,从而让主机侧调度、设备侧计算、主机与设备之间的数据传输尽可能重叠执行,隐藏传输和调度开销,提高端到端吞吐率。
典型<<<>>>异步调用的场景是:将主机与设备计算操作重叠执行,从而提升主机侧与设备侧计算资源利用率。
同样地,将aclrtMemcpy替换成aclrtMemcpyAsync接口,可以实现主机与设备的内存传输与计算操作重叠执行,从而降低甚至消除内存传输带来的性能开销。
核函数的调用是异步的,在核函数调用结束之后,控制权立刻返回给主机端,需要在host等待核函数的执行完成,可以通过以下接口强制Host程序等待核函数执行完毕: