存储器停滞分析 - 2022.1 简体中文

Versal ACAP AI 引擎编程环境 用户指南 (UG1076)

Document ID
UG1076
Release Date
2022-05-25
Version
2022.1 简体中文
AI 引擎可在每个周期内执行多次矢量加载或存储操作。但这些操作必须以不同存储体为目标才能并行执行加载或存储操作。如果在同一周期内多次访问同一存储体,就会发生存储器停滞。

存储器种类包括内核、RTP 缓冲器与系统存储器之间的窗口缓冲器和 DMA FIFO。系统存储器包括前 32 字节、栈和堆之间的内核同步信息。静态变量位于堆内,而函数控制逻辑则位于栈内。系统存储器占据连续存储体。工具可以在特定存储体上自动或手动完成窗口缓冲器、RTP 缓冲器、DMA FIFO 和系统存储器的布局。为缓解这些存储器之间的存储器停滞,请尝试尽可能将其布局到独立存储体内。但如果无法为所有存储器都找到独立的存储体,或者在同一个存储器上发生多次访问,那么仍可能发生存储器停滞。

总之,编译器会尝试尽可能在同一个周期内调度多次存储器访问,但也存在例外情况。源自同一指针的多次存储器访问调度为在不同周期内执行。如果编译器在同一个周期内对多个变量或指针调度执行多项操作,则可能发生存储体冲突。每个存储体都有其自己的仲裁器用于在所有请求之间执行仲裁,且仲裁采用循环方式执行。解决所有请求后,就会释放存储器停滞。

您可通过“Performance Metrics”(性能指标)分析来识别是否需要对存储器停滞执行分析。

  1. 选择Trace(追踪)视图。
  2. 选择底部的Stalls(停滞)视图,然后从下拉列表中选择Memory Stalls(存储器停滞)。
    图 1. Trace视图中的“Memory Stall”

    此处停滞名为 MS_<NUM>。编号随时间增加。每次停滞都包含下列关联信息。

    Stall ID(停滞 ID)
    存储器停滞 ID。停滞发生时间越早,编号越小。此编号在所有类型的停滞中都是唯一的。
    Stalled Tile(停滞的拼块)
    已停滞的内核所在的 AI 引擎 tile。
    Stalled Kernel(停滞的内核)
    已停滞的内核。此内核名为 <Kernel_function_name>.<Schedule_ID>.<Graph_instance_name>。有时,它显示为 _main,随后,需通过交叉探测来查找实际的内核函数。
    Start (ns)(开始 (ns))
    发生停滞的开始时间
    Duration (ns)(持续时间 (ns))
    停滞的持续时间。
    PC
    发生停滞时的程序计数器。
    Bank Conflict(存储体冲突)
    发生停滞的存储器。
    Buffer 1Buffer 2Buffer 3
    导致存储器停滞的缓冲器。可能仅有一个缓冲器,也可能有多个缓冲器导致停滞。
  3. 单击Stalls(停滞)视图中的每一行停滞时,它会转至Trace(追踪)视图中存储器停滞的起始位置。通过缩放Trace(追踪)视图即可观察存储器停滞的发生频率,以及运行中的内核中发生停滞的位置。
    注释: 如果在运行中的内核中重复发生大量存储器停滞,这表明停滞可能循环发生。最好对此问题进行调查并解决。如果仅在内核开始运行时发生一次存储器停滞,或者在内核运行期间仅发生少量停滞,通常可将其忽略。根据导致停滞的缓冲器名称可以识别出导致停滞的是窗口缓冲器、系统缓冲器或其它缓冲器。如果是可在 graph 中加以控制的窗口缓冲器或 RTP 缓冲器,那么可以使用约束对其进行手动布局,前提是能够找到更好的布局方法。如果是系统存储器(名为 system<NUM>+<NUM>),则需识别停滞中所涉及的变量。
  4. 单击特定停滞对应的行,然后切换至Events(事件)视图。
    图 2. “Memory Stall”的Events视图

  5. Events视图可显示器件中发生的事件。发生存储器停滞的周期会高亮显示。您可看到发生 DM_BANK_CONFLICT 事件的 tile(拼块),以及正在读取或写入的变量。在前图中,同一周期内正在同时读取 delay_line 变量和 eq_coef1 变量。
  6. 请尝试浏览停滞周期之前或之后的其它周期以寻找线索。例如,下图显示了前一个停滞周期之后发生的事件。此外还能看到,在同一周期内的不同部分(128 位)同时也在读取 delay_lineeq_coef1。通过检验源代码和汇编代码可以发现,在同一周期内对 delay_lineeq_coef1 发出了 256 位,因而导致存储器停滞。由于存储器停滞,两次 256 位存储器访问被拆分到两个周期中。
    图 3. “Memory Stall”的Events视图

    AI 引擎内核编码最佳实践指南 (UG1079) 的“含虚拟资源注解的加载和存储”中记录了一种解决方案。例如,重定义指向 eq_coef0delay_line 的指针,并为其添加注解 __aie_dm_resource_a。改用下列新指针。

    const v8cint16 __aie_dm_resource_a* __restrict coeff = (v8cint16 __aie_dm_resource_a*) eq_coef0; const v8cint16 coe = *coeff;
    v16cint16 __aie_dm_resource_a* __restrict p_buff = (v16cint16 __aie_dm_resource_a*) &delay_line; v16cint16 buff=*p_buff;

下表列出了导致存储器停滞的部分可能场景以及可能的解决方案。

表 1. 存储器停滞场景和解决方案
目标 停滞类型 可能的解决方案 注释
单个内核 单个存储体上的缓冲器 存储器停滞
  • 将存储器分派至不同存储体(存储器包括系统存储器、RTP、窗口缓冲器、DMA 和 FIFO)。请参阅 存储器停滞
  • 利用虚拟存储器注解来为编译器调度提供指引。请参阅 AI 引擎内核编码最佳实践指南 (UG1079) 中的“含虚拟资源注解的加载和存储”部分

单个内核访问同一存储体上的多个存储器。

或者,单个内核对同一存储体上的单个存储器进行多次访问。

(每个周期均可包含两次加载和一次存储)

相邻 AI 引擎 tile 上的多个内核 单个存储体上的多个缓冲器 存储器停滞
  • 将存储器分派至不同存储体(存储器包括系统存储器、RTP、窗口缓冲器、DMA 和 FIFO)。
  • BufferOptLevel。请参阅 映射器和布线器选项
  • 如果存储体耗尽,请执行剖析和 AI 引擎停滞分析,寻找内核执行时间更短或者停滞比例更低的更优解决方案。
多个内核访问同一存储体上的多个存储器。