以下进程描述了如何在 C++ 中构造数据流 graph。
- 在独立头文件(例如,
project.h
)内定义您的应用 graph 类。首先,添加自适应数据流(Adaptive Data Flow,ADF)头文件 (adf.h),并包含内核函数原型。ADF 库包含用于在 AI 引擎上定义和执行 graph 所需的所有构造。#include <adf.h> #include "kernels.h"
- 使用
adf
名称空间内定义的对象来定义 graph 类。所有用户 graph 均衍生自graph
类。include <adf.h> #include "kernels.h" using namespace adf; class simpleGraph : public graph { private: kernel first; kernel second; };
这是声明 2 个内核(
first
和second
)的 graph 类定义的开头。 - 给 graph 添加顶层输入/输出对象
input_plio
和output_plio
。#include <adf.h> #include "kernels.h" using namespace adf; class simpleGraph : public graph { private: kernel first; kernel second; public: input_plio in; output_plio out; };
- 使用
kernel::create
函数利用 C 语言函数simple
的功能来例化first
和second
C++ 内核对象。#include <adf.h> #include "kernels.h" using namespace adf; class simpleGraph : public graph { private: kernel first; kernel second; public: input_plio in; output_plio out; simpleGraph() { first = kernel::create(simple); second = kernel::create(simple); } };
- 使用指定的 PLIO 宽度和输入/输出文件配置输入/输出对象,并添加连接信息,这等同于数据流 graph 中的信号线。在此处描述中,输入/输出对象供索引引用。在输入端口阵列 (
in
) 中,对simple
函数中的第一个输入窗口或串流实参分配索引 0。后续输入实参按升序取连续索引值。在输出端口阵列 (out
) 中,对simple
函数中的第一个输出窗口或串流实参分配索引 0。后续输出实参按升序取连续索引值。#include <adf.h> #include "kernels.h" using namespace adf; class simpleGraph : public graph { private: kernel first; kernel second; public: input_plio in; output_plio out; simpleGraph() { first = kernel::create(simple); second = kernel::create(simple); in = input_plio::create(plio_32_bits, "data/input.txt"); out = output_plio::create(plio_32_bits, "data/output.txt"); connect< window<128> > net0 (in.out[0], first.in[0]); connect< window<128> > net1 (first.out[0], second.in[0]); connect< window<128> > net2 (second.out[0], out.in[0]); } };
此图显示了先前 graph 代码中指定的 graph 连接。在 Vitis 分析器中打开编译结果时,即可查看 graph 连接情况。如需了解更多信息,请参阅 在 Vitis 分析器中查看编译结果。如前图所示,来自顶层的输入端口连接到第一个内核的输入端口中,第一个内核的输出端口连接到第二个内核的输入端口,第二个内核的输出端口连接到对顶层公开的输出。在缓冲器中收集外部来源的 128 字节数据(32 个复数 (complex) 样本)时,就会执行第一个内核。在
net0
连接处,将此指定为窗口参数。同样,第二个内核会在其中输入窗口包含有效数据时执行,此处有效数据是作为第一个内核的输出生成的,通过net1
连接来表述。最后,第二个内核的输出会作为net2
连接来连接到顶层输出端口,并指定第二个内核会在终止时生成 128 字节的数据。 - 为每个内核设置源文件和拼块用法。源文件 kernel.cc 包含内核的 first 源代码和内核的 second 源代码。然后,它还包含函数运行时相比于周期预算的比率(称为运行时比率),且必须介于
0
到1
之间。周期预算是每个函数耗用来自其输入的数据(处理速率受限的输入数据串流时)或者在其输出上生成数据块(处理速率受限的输出数据串流时)所耗用的指令周期数。更改块大小可能会影响此周期预算。#include <adf.h> #include "kernels.h" using namespace adf; class simpleGraph : public graph { private: kernel first; kernel second; public: input_plio in; output_plio out; simpleGraph(){ first = kernel::create(simple); second = kernel::create(simple); in = input_plio::create(plio_32_bits, "data/input.txt"); out = output_plio::create(plio_32_bits, "data/output.txt"); connect< window<128> > net0 (in.out[0], first.in[0]); connect< window<128> > net1 (first.out[0], second.in[0]); connect< window<128> > net2 (second.out[0], out.in[0]); source(first) = "kernels.cc"; source(second) = "kernels.cc"; runtime<ratio>(first) = 0.1; runtime<ratio>(second) = 0.1; } };
注释: 如需了解更多信息,请参阅 运行时比率。 - 定义包含您的 graph 类实例的顶层应用文件(例如,project.cpp)。
#include "project.h" simpleGraph mygraph; int main(void) { adf::return_code ret; mygraph.init(); ret=mygraph.run(<number_of_iterations>); if(ret!=adf::ok){ printf("Run failed\n"); return ret; } ret=mygraph.end(); if(ret!=adf::ok){ printf("End failed\n"); return ret; } return 0; }
重要: 默认情况下,
mygraph.run()
选项会指定永续运行的 graph。AI 引擎编译器会生成代码,以通过永续 while
循环来执行数据流 graph。要将 graph 的执行限制于调试和测试目的,请在 graph 代码中指定 mygraph.run(<number_of_iterations>)
。对于迭代数量,可指定 1 或更大值。ADF API 包含返回枚举类型 return_code
,用于显示 API 运行状态。
main
程序是 graph 的驱动程序。它用于加载、执行和终止 graph。如需了解更多详情,请参阅 运行时 graph 控制 API。
注释: 内核代码的编写方式必须确保将两个内核分配到相同核时,不会发生名称冲突。