您可定义衍生自 VPP_ACC
基本类的硬件加速器,并利用 VSC 构建硬件和软件接口。本节描述了 VPP_ACC
类所提供的软件 API。
控制加速器
VPP_ACC
类 API 提供了在加速器硬件上调度作业和处理结果的方法以及运行时的其他软件控制。
- send_while()
-
此 API 用于重复执行 SendBody,直至其返回布尔值 false;send_while 的伪代码类似于 do{ bool ret=f() } while(ret==true);
void send_while(SendBody f, VPP_CC& cc = *s_default_cc);
表 1. send_while() 实参 实参 描述 SendBody f SendBody 是用户定义的 C++ lambda 函数。lambda 函数用于捕获来自封闭作用域的变量。值得注意的是,需捕获所有已用缓冲池变量。这些变量应按值予以捕获。使用
[=]
将自动按值捕获这些变量,并捕获您可能在 lambda 函数内使用的任何其他变量。在 lambda 函数内进行修改的任意变量都需要按引用来传递。例如,[=, &m]
。按引用来传递变量并不一定会导致主机代码性能降级,而另一方面,按值传递大型类对象则可能导致不必要的深层复制。对于发送(或接收)函数,一般并不需要后者。提示: 需按引用来传递的任意变量均可通过[=, &var]
来显式捕获。VPP_CC& cc 可选实参,用于对 CU 进行分组。例如,它可用于指定要使用 CU 的哪个多卡集群,如 CU 集群和多卡支持 中所述。 - compute()
-
如 compute() API 中所述,
compute()
方法是衍生的VPP_ACC
加速器类定义中由用户定义的特殊方法,用于表示 CU 并包含处理元素 (PE)。void compute(Args ...);
- 调用硬件加速器以调度一项作业
- 在
SendBody
函数内可以发出一次或多次compute()
调用 - 每次
compute()
调用均为非阻塞调用,将立即返回,但当任务流水线已满时,仍将发生阻塞。 - 在后台,
compute()
调用将确保其所有输入都传输到器件,随后在任意可用 CU 上执行 - 当某一迭代的所有
compute()
调用都全部完成后,输出缓冲器就会传回主机,并且将为此次迭代启动receive_all
迭代 - 应用代码必须遵循下列条件,并且这些条件在软件仿真期间断言有效
- 发起
compute()
调用后,输入缓冲器和文件缓冲器就无法再做修改,并且在此次迭代内无法再对alloc_buf
或file_buf
发起调用。 - 无法再读取或写入输出缓冲器,直至在对应
receive
迭代内接收到数据为止
- 发起
- receive_all_xxx()
-
一旦计算请求完成,就按顺序或者立即重复执行 C++ lambda 函数以接收来自硬件加速器的数据结果。当
send_while()
已退出并且已接收到所有迭代时,此 API 退出。void receive_all_in_order(RecvBody f, VPP_CC& cc = *s_default_cc);
void receive_all_asap(RecvBody f, VPP_CC& cc = *s_default_cc);
表 2. receive_all_xxx() 实参 实参 描述 RecvBody f RecvBody 是用户定义的 C++ lambda 函数。请参阅
send_while()
中有关 lamda 函数的解释VPP_CC& cc 可选实参,用于对 CU 进行分组。例如,它可用于指定要使用 CU 的哪个多卡集群,如 CU 集群和多卡支持 中所述。 - receive_one_xxx()
-
如 多加速器流水线组合 中所述,此 API 用于在另一个加速器的
send_while()
循环内接收此加速器的一次迭代。void receive_one_in_order(RecvBody f, VPP_CC& cc = *s_default_cc);
void receive_one_asap(RecvBody f, VPP_CC& cc = *s_default_cc);
表 3. receive_one_xxx() 实参 实参 描述 RecvBody f RecvBody 是用户定义的 C++ lambda 函数。请参阅
send_while()
中有关 lamda 函数的解释VPP_CC& cc 可选实参,用于对 CU 进行分组。例如,它可用于指定要使用 CU 的哪个多卡集群,如 CU 集群和多卡支持 中所述。 - join()
-
等待发送循环和接收循环完成。
void join(VPP_CC& cc = *s_default_cc);
表 4. join() 实参 实参 描述 VPP_CC& cc 可选实参,用于对 CU 进行分组。例如,它可用于指定要使用 CU 的哪个多卡集群,如 CU 集群和多卡支持 中所述。 - set_ncu()
-
设置驱动程序应使用的 CU 数量。开始发送/接收循环前,使用此方法可确立
compute()
函数应使用的 CU 数量。void VPP_ACC::set_ncu(int ncu);
表 5. set_ncu() 实参 实参 描述 int ncu 指定的 CU 数 (ncu) 应为 (1 <= ncu <= NCU),其中 NCU 是 VPP_ACC< .... , NCU>
的模板参数,如 用户定义的加速器类 中所述。 - get_ncu()
-
返回当前驱动程序使用的 CU 数,即
VPP_ACC::set_ncu
先前设置的数量,或者如果未修改,则返回VPP_ACC< .... , NCU>
的 NCU 模板参数。int VPP_ACC::get_ncu();
- get_NCU
-
返回硬件中实现的 CU 数(即,构建硬件时提供的 NCU 模板参数值,在基本类
VPP_ACC< .... , NCU>
中同样指定了该值)。int VPP_ACC::get_NCU();
设置 I/O 用于计算
此处所述 API 方法用于为硬件加速器设置输入和输出缓冲器。
- create_bufpool()
-
创建并返回不透明的类对象,以供在需要缓冲器句柄的其他方法中使用,如
alloc_buf()
。启动发送/接收循环前使用。VPP_BP VPP_ACC::create_bufpool(vpp::Mode m, vpp::FileXFer = vpp::none);
表 6. create_bufpool() 实参 实参 描述 vpp::Mode m 可指定以下任意值,以表示
compute()
实参的数据传输类型:-
vpp::input
:输入加速器的数据传输 -
vpp::output
:从加速器输出的数据传输 -
vpp::bidirectional
:进出加速器的数据传输 -
vpp::remote
:数据仅驻留在连接到加速器的器件存储器上,主机代码不发送也不接收数据
vpp::FileXFer = vpp::none 可指定下列任意值,这些值表示数据传输的文件位置:-
vpp::p2p
:文件通过 P2P 网桥传输至加速器。该值仅适用于支持 P2P 功能特性的平台,例如,已连接 smartSSD 的 U2 卡。 -
vpp::h2c
:文件通过 PCIe 从主机 CPU(已连接文件服务器)传输到卡。该值是适用于通过 PCIe 连接到主机 CPU 的大部分 Alveo 卡的标准值。 -
vpp::none
:使用常规缓冲器对象,不支持文件传输。这是默认值。
-
- alloc_buf()
-
返回指向缓冲器对象的指针。在发送线程的 lamda 函数内部使用。
void* VPP_ACC::alloc_buf(VPP_BP bp, int byte_sz);
T* VPP_ACC::alloc_buf<T>(VPP_BP bp, int numT);
重要: 从给定缓冲器池分配缓冲器。当匹配的接收迭代结束时,该缓冲器的寿命即截止。届时,该缓冲器将自动返回至缓冲池。表 7. alloc_buf() 实参 实参 描述 VPP_BP bp 由 create_bufpool()
返回的缓冲池对象int byte_sz 指定所请求的缓冲器的字节数 int numT 指定所请求的 <T> 阵列缓冲器的元素数 - file_buf()
-
此方法将把给定文件或文件的一部分映射到源自指定缓冲池对象的缓冲器。在发送线程的 lamda 函数内部使用。
file_buf()
方法可多次调用,以便将多个文件(或者文件段)映射到单个缓冲器内的不同位置。此方法会返回指向缓冲器对象的指针,此对象为主机句柄。该主机不得用于对其进行读取或写入。
void* VPP_ACC::file_buf(VPP_BP bp, int fd, int byte_sz, off_t fd_byte_offset=0, off_t buf_byte_offset=0);
T* VPP_ACC::file_buf<T>(VPP_BP bp, int fd, int numT, off_t fd_T_index=0, off_t buf_T_index);
表 8. file_buf() 实参 实参 描述 VPP_BP bp 由 create_bufpool()
返回的缓冲池对象。int fd 表示要读取或写入的文件描述符(使用 custom_sync_outputs()
时则为 0,如下所述)。在 P2P 模式下,此文件打开时包含 O_DIRECT 标志。int byte_sz 指定所请求的缓冲器的字节数。在 P2P 模式下,它必须对齐到文件系统块大小 (4 kB)。 fd_offset 表示要读取/写入的文件中的偏移。 buf_offset 表示要写入/读取的缓冲器中的偏移。 int numT 指定所请求的 <T> 阵列缓冲器的元素数。在 P2P 模式下,它必须对齐到文件系统块大小 (4 kB)。 fd_T_index 表示要开始读取/写入的文件中的阵列索引。 buf_t_index 表示要开始写入/读取的缓冲器索引。 其他注释:-
T* buf = file_buf<T>(bp, fd, num, fd_idx, buf_idx);
声明与T* buf = (T*)file_buf(bp, fd, num*sizeof(T), fd_idx*sizeof(T), buf_idx*sizeof(T));
相同 - 缓冲器的实际大小将按需调整。因此,最后一次调用返回的缓冲器需在
compute()
次调用中使用。一旦在 compute 调用中使用后,在此迭代中就无法再添加任何映射。 - 请参阅 受支持的平台和启动示例 中的启动示例下的
file_filter_sc
-
- get_buf()
-
- 在与匹配的发送循环相关联的接收循环内使用。这样即可返回在匹配的发送迭代内已分配的缓冲器对象。
void* VPP_ACC::get_buf(VPP_BP bp);
T* VPP_ACC::get_buf<T>(VPP_BP bp);
表 9. get_buf() 实参 实参 描述 VPP_BP bp 由 create_bufpool()
返回的缓冲池对象 - transfer_buf()
-
如 多加速器流水线组合 中所述,此方法在多加速器组合中用于将某一缓冲器的所有权从某一加速器的
send_while
内使用receive_one_xxx()
的另一个加速器转让给前一个加速器。这样即可将该缓冲器的寿命延长至与当前发送迭代相匹配的接收迭代的末尾。提示: 这对于vpp::remote buffers
尤为有用,因为这样此缓冲器将保留在该器件上,并且无需复制或同步。void* VPP_ACC::transfer_buf(VPP_BP bp);
T* VPP_ACC::transfer_buf<T>(VPP_BP bp);
表 10. transfer_buf() 实参 实参 描述 VPP_BP bp 由 create_bufpool()
返回的缓冲池对象 - custom_sync_outputs()
-
此方法可在
send_while
循环主体中调用,并且在调用compute()
函数之前即可调用此方法。这样您即可提供定制同步函数,用于将输出缓冲器同步回主机应用。当只需从硬件加速器传回部分(并非全部)输出缓冲器数据时,此方法很有用。重要: 这将禁用所有输出缓冲器的任意自动同步操作。void custom_sync_outputs(std::function<void()> sync_outputs_fn)
表 11. custom_sync_outputs() 实参 实参 描述 sync_outputs_fn 指定当迭代的计算任务已完成后,将为
send_while
循环的每次迭代自动调用的定制同步函数。当
sync_outputs_fn
返回并且请求的所有sync_output()
调用均已完成时,将为send_while
循环迭代触发接收。 - sync_output()
-
此方法将在传递到
custom_sync_outputs()
方法的sync_output_fn
内部进行调用。它将在后台执行所请求的同步,返回 future,以便调用程序可检查传输是否完成。std::future<void> sync_output(void* buf, size_t byte_sz, off_t byte_offset = 0);
std::future<void> sync_output<T>(T* buf, size_t numT, off_t Tindex = 0);
表 12. sync_output() 实参 实参 描述 buf 在 sendBody()
作用域内通过捕获所获取的缓冲器指针。byte_sz 指定所请求的缓冲器的字节数。 byte_offset 表示要写入/读取的缓冲器中的偏移。 numT 指定所请求的 <T> 阵列缓冲器的元素数。在 P2P 模式下,它必须对齐到文件系统块大小 (4 kB)。 Tindex 表示要开始写入/读取的缓冲器索引。 - sync_output_to_file()
-
此方法将在传递到
custom_sync_outputs()
方法的sync_output_fn
内部进行调用。它将在后台执行所请求的同步,返回 future,以便调用程序可检查传输是否完成。std::future<void> sync_output_to_file(void* buf, int fd, size_t byte_sz, off_t fd_byte_offset = 0, off_t buf_byte_offset = 0);
std::future<void> sync_output_to_file<T>(T* buf, int fd, size_t numT, off_t fd_T_index = 0, off_t buf_T_index = 0);
表 13. sync_output_to_file() 实参 实参 描述 buf 在 sendBody()
作用域内通过捕获所获取的缓冲器指针。fd 表示要写入的文件描述符。 byte_sz 指定所请求的缓冲器的字节数。 fd_offset 表示要读取/写入的文件中的偏移。 buf_offset 表示要写入/读取的缓冲器中的偏移。 numT 指定所请求的 <T> 阵列缓冲器的元素数。在 P2P 模式下,它必须对齐到文件系统块大小 (4 kB)。 fd_T_index 表示要开始读取/写入的文件中的阵列索引。 buf_t_index 表示要开始写入/读取的缓冲器索引。 - set_handle()
-
在
sendBody
内用于识别您想要与send_while
循环的当前迭代加以关联的任意对象。void VPP_ACC::set_handle(intptr_t hndl);
void VPP_ACC::set_handle<T>(T hndl);
表 14. set_handle() 实参 实参 描述 hndl 表示您想要与 send_while
循环的当前迭代加以关联的任意对象。提示: 借助模板化形式,即可将包含简单的分配/复制运算符的任意类用作为句柄。 - get_handle()
-
此方法在 RecvBody 内使用,可返回在
send_while
循环的匹配的发送迭代中已设置的对象的句柄 (set_handle()
)。intptr_t VPP_ACC::get_handle();
T VPP_ACC::get_handle<T>();