控制驱动的任务级并行 - 2023.2 简体中文

Vitis 高层次综合用户指南 (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 简体中文

控制驱动的 TLP 适用于并行度建模,它依靠 C++ 的顺序语义,而非连续运行的线程。示例包括可按并发流水打拍方式(可能在循环内)执行的函数或者可搭配实参(非通道,而是 C++ 标量和阵列变量)执行的函数,这两种方式均适用于片上存储器和片外存储器。对于这类模型,Vitis HLS 在尽可能保留从原始 C++ 顺序执行获取的行为的同时,引入了并行度的概念。控制驱动的 TLP(或数据流)模型可提供:

  • 后续函数可在前一个函数完成前启动
  • 函数可在完成前重新启动
  • 两个或两个以上顺序函数可同时启动

使用数据流模型时,Vitis HLS 会通过在任务之间自动插入同步和通信机制来实现 C++ 代码的顺序语义。

数据流模型会利用此顺序函数序列来创建并发进程的任务级流水线架构。本工具通过推断并行任务和通道来完成此操作。设计人员会通过指定 DATAFLOW 编译指示或指令,以数据流样式(例如,函数体或循环主体)来指定要建模的区域,如下所示。本工具会扫描循环/函数体、抽取并行任务作为并行进程,并在这些进程之间建立通信通道。设计师还可以指引本工具选择通道类型,例如,FIFO(hls::stream#pragma HLS STREAM)或 PIPO (hls::stream_of_blocks).数据流模型是可用于改进设计吞吐量和时延的强大方法。

要了解 Vitis HLS 将 C++ 代码变换为数据流模型的方式,请参阅如下所示 simple_fifos 示例。该示例使用 DATAFLOW 编译指示将数据流模型应用于顶层 diamond 函数,如下所示。

#include "diamond.h"
 
void diamond(data_t vecIn[N], data_t vecOut[N])
{
  data_t c1[N], c2[N], c3[N], c4[N];
#pragma HLS dataflow
  funcA(vecIn, c1, c2);
  funcB(c1, c3);
  funcC(c2, c4);
  funcD(c3, c4, vecOut);
}

在以上示例中有 4 个函数:funcAfuncBfuncCfuncDfuncBfuncC 之间不存在任何数据依赖关系,因此可以并行执行。funcA 会从非本地存储器 (vecIn) 读取,需首先执行。同样,funcD 写入非本地存储器 (vecOut),因此最后执行。

以下波形显示了此设计的执行剖析(无数据流模型)。测试激励文件对四个函数执行了 3 次调用。funcAfuncBfuncCfuncD 均按顺序执行。因此,每次调用这四个函数都需耗时总计 475 个周期,如下图所示。

图 1. 无数据流的四个函数示例

在下图中,应用数据流模型时并且设计人员选择为通道使用 FIFO 时,控制器会立即启动所有函数,这些函数将停滞并等待输入。一旦输入到达,就会对其进行处理并发出。由于存在此类型的重叠,现在每次调用这四个函数都只需总计 275 个周期,如下所示。请参阅 组合三种范例 获取更多信息,其中详细探讨了可为此示例实现的并行度的类型。

图 2. 含数据流的四个函数示例

要实现这种类型的并行化,势必引发硬件利用率提升。将某个特定区域(例如,函数体或循环主体)识别为要应用数据流模型的区域后,Vitis HLS 就会分析此函数体或循环主体,并基于 C++ 变量(例如,标量、阵列或用户定义的通道,如 hls::streamshls::stream_of_blocks)创建各通道,这些变量用于对数据流区域内的数据流动进行建模。这些通道对于标量变量而言可能只是简单的 FIFO,而对于非标量变量,则可能是乒乓 (PIPO) 缓冲器,此类非标量变量有阵列、块串流(前提是需将 FIFO 和 PIPO 行为与块的显式锁定加以组合)等。

其中每条通道均可包含用于指示通道已满或已空的额外信号。通过采用独立 FIFO 缓冲器和/或 PIPO 缓冲器,Vitis HLS 可使每项任务独立执行,吞吐量仅受输入和输出缓冲器的可用性限制。由此实现的任务执行重叠比正常流水打拍实现更好,但导致增加 FIFO 或块 RAM 寄存器(用于乒乓缓冲器)成本。

提示: 仅当您运行设计的协同仿真后,才能看到此重叠执行最优化,无法静态观测到此结果(但在 数据流查看器 中完成 C 语言综合后,能轻松想象到此结果)。

数据流模型并不局限于进程链,使用 hls::streams 时,该模型也可用于任何有向无环图 (DAG) 结构或周期结构。它可生成 2 种不同形式的重叠:在迭代内部重叠(前提是使用 FIFO 连接进程)以及在不同迭代之间重叠(前提是使用 PIPO 和 FIFO 连接进程)。这可能达成比静态流水打拍解决方案更好的性能。它将严格集中控制的流水线停滞理念替换为分布式握手架构,后者使用 FIFO 和/或 PIPO。将集中控制结构替换为分布式结构还有益于控制信号的扇出,例如,寄存器使能;此类扇出广泛分布于各进程的控制结构之间。请参阅 GitHub 上提供的任务级并行度/控制驱动示例,获取有关这些概念的更多示例。