简介
在 Versal AI 引擎 2 一文 中,我们注意到计算图 (graph) 文件中有一行内容用于为每个内核实例定义运行时比率参数。
在本文中,我们将讲解该参数如何影响 AI 引擎应用的资源使用率和性能。
要求
下文要求您通读前几篇 AI 引擎系列博文。
AI 引擎系列 1 - 从 AI 引擎工具开始(2022.1 更新)
AI 引擎系列 2 - AI 引擎计算图简介 (2022.1 更新)
AI 引擎系列 3 - AI 引擎内核简介
AI 引擎系列 4 - 首次运行 AI 引擎编译器和 x86simulator(2022.1 更新)
AI 引擎系列 5 - 以 AI 引擎模型为目标运行 AI 引擎编译器(2022.1 更新)
AI 引擎系列 6 - 在 Vitis 分析器中分析 AI 引擎编译结果(2022.1 更新)
AI 引擎系列 7 - 在仿真内通过追踪来可视化 AI 引擎事件(2022.1 更新)
什么是运行时比率?
“Run-Time Ratio"(运行时比率)是值介于 0 到 1 之间的参数,您应该为计算图中的所有内核定义该参数。它以百分比值的方式来定义该内核所需的单一 AI 引擎核的处理时间。
例如,运行时值为 0.5 表示内核只需 1 个 AI 引擎核的处理时间的 50%。
根据内核的运行时比率,可将单个或多个内核映射到单个 AI 引擎。
计算任一内核的运行时比率
任一内核的运行时比率均可使用如下公式来计算:
运行时比率 = (内核运行一轮的周期数)/(周期预算)
周期预算是每个内核耗用来自其输入的数据(处理速率受限的输入数据串流时)或者在其输出上生成数据块(处理速率受限的输出数据串流时)所耗用的指令周期数。
它按如下公式来定义:
周期预算 = 块大小 * (AI 引擎时钟频率/采样频率)
假设某个内核处理窗口为 128 个样本,且输入样本频率(例如,来自 ADC)为 245.76 MHz。则此周期预算为 128*(1000/245.76) = 520 个周期。
这意味着,如果 AI 引擎阵列运行频率为 1 GHz,那么内核执行周期数需小于 520 个 AI 引擎时钟周期(因为在 520 个时钟周期后,下一个输入窗口将就绪)。
我们将在后续博文中详解如何估算内核运行一轮的周期数。
运行时比率对于性能或资源使用率的影响
现在我们使用先前博文中创建的应用示例来分析下更改运行时比率值的影响。
在 Versal AI 引擎 2 一文中,针对计算图中的 2 个内核设置的运行时比率为 0.1。在 Versal AI 引擎 6 一文中,Vitis 分析器中的 2 个内核已映射到同一个拼块 (tile [25,0]) 内,因此这 2 个内核共享来自位于该拼块上的核的处理时间。
由于这 2 个内核在同一个核上运行,因此不同时执行(按顺序运行),故而改为在这 2 个内核之间例化单个缓冲器。
最后,在 Versal AI 引擎系列 5 中,仿真输出中计算图的首次迭代的最后一个样本(以 TLAST 来标记)在 714 ns 之后输出,并且第二次迭代的首个样本在仿真时间 1197 ns 后输出。
首先,我们将 2 个内核的运行时比率改为 0.4,并分析计算图所受到的影响。
打开源文件 project.h,在第 26/27 行上,将名为 first 和 second 的 2 个内核的运行时比率改为 0.4:
runtime<ratio>(first) = 0.4;
runtime<ratio>(second) = 0.4;
以 Emulation-AIE 为目标构建 Simple_application,并选择“Run As > Emulation-AIE”(运行方式 > AI 引擎仿真)来运行 aiesimulator。
在 Vitis 分析器中打开编译汇总 (Emulation-AIE/Work/project.aiecompile_summary)。观察计算图视图,将该视图设置为按拼块分组。
可以看到,更改运行时比率对于资源使用率并无影响。这 2 个内核仍位于相同拼块内并且在相同核上运行,两者仍通过单一缓冲器来进行通信。
由于运行时比率之和仍小于 1,因此 aiecompiler 仍判定将这 2 个内核分组在一起。
您打开仿真输出文件 (Emulation-AIE/aiesimulator_output/output.txt) 即可看到计算图的首次迭代的最后一个样本仍在 714 ns 之后输出,第二次迭代的第一个样本仍在仿真时间的 1197 ns 之后输出。
请务必注意,运行时比率不用于调度内核执行。
数据可用后如果核尚未运行另一个内核,就会立即启动该内核。即使内核的运行时比率设为 0.1,该内核的运行时间仍可能占用 AI 引擎核的 100%(假定只有 1 个内核映射到该核)。在我们的示例中,由于有 2 个内核运行相同函数,因此当运行时比率设为 0.1 或 0.4 时,这 2 个内核的运行时间可能占 50%。
现在,我们可以尝试将这 2 个内核的运行时比率增大到 0.6。
runtime<ratio>(first) = 0.6;
runtime<ratio>(second) = 0.6;
以 Emulation-AIE 为目标构建 Simple_application,并选择“Run As > Emulation-AIE”(运行方式 > AI 引擎仿真)来运行 aiesimulator。
在 Vitis 分析器中打开编译汇总 (Emulation-AIE/Work/project.aiecompile_summary)。
观察计算图视图可见,使用率已发生更改:
每个内核都映射到不同拼块。
名为 first 的内核在 tile [25,0] 上运行,名为 second 的内核在 tile [24,0] 上运行,因此这 2 个内核在不同的核上运行。并且根据 buf1 和 buf1d 这 2 个名称可见,现在这 2 个内核之间已实现了 1 个乒乓缓冲器。
由此可见,增加运行时参数可能增大计算图的资源使用率。
打开仿真输出文件 (Emulation-AIE/aiesimulator_output/output.txt)。
可以看到,计算图的第一次迭代的最后一个样本现已在 724 ns 后输出。这意味着第一次迭代的时延稍有增加 (+10ns)。这可能是由于 2 个内核之间的乒乓缓冲器的锁定管理而导致的。但第二次迭代的首个样本在 966 ns 后到达(相比于先前结果减少了 473 ns)。
由于这 2 个内核当前从 2 个不同的核运行,因此现在可以并行运行,增加计算图的吞吐量。由此可见,增加运行时参数可能提升计算图的性能。
重要注释:
- 将运行时比率增大至每个核 1 个内核可能不会提升计算图的性能。
- 这是因为,它可能受到输入或输出吞吐量的限制。
- 因此,运行时比率高于所需的值可能导致无法有效使用资源。
- 减小运行时比率可能无法降低资源使用率。
- 这是因为,编译器仅在合理的情况下才会把内核映射到相同的核。
- 例如,此处 2 个内核整通过单个存储器进行通信。所有它们已相互依赖,只要其中一个内核尚未完成执行,另一个内核就无法开始处理数据。