使用 graph API 执行参数更新/读取 - 2022.1 简体中文

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

Document ID
UG1076
Release Date
2022-05-25
Version
2022.1 简体中文

在默认编译模式下,main 应用作为独立控制线程来编译,此线程需在 PS 上与 AI 引擎阵列上执行的 graph 并行执行。main 应用可以使用更新和读取 API 来访问任意级别的 graph 内声明的运行时参数。本节使用示例描述了这些 API。

同步更新/读取

以下代码显示了 simple_param graph 的 main 应用,如 执行运行时数据参数 中所述。

#include "param.h"
parameterGraph mygraph;

int main(void) {
  mygraph.init();
  mygraph.run(2);
  
  mygraph.update(mygraph.select_value, 23);
  mygraph.update(mygraph.select_value, 45);

  mygraph.end();
  return 0;
}

在此示例中,graph mygraph 首先进行初始化,然后运行两次迭代。它包含一个已触发的输入参数端口 select_value,对于接收内核的每次迭代,此端口必须以新的值来更新。update API 的第一个实参可识别要更新的端口,第二个实参则可提供值。根据端口方向、其数据类型以及它属于标量参数还是阵列参数,可支持多种其它形式的更新 API,欲知详情,请参阅 自适应数据流 graph 规范引用

如果程序编译时,测试迭代次数是固定的,那么对于已触发的参数,main 程序中更新 API 调用次数必须与测试迭代次数相匹配,否则仿真可能持续等待其它更新。对于异步参数,更新与 graph 执行异步执行,如果未完成更新,那么内核会使用旧的值。

此外,如果先前的 graph 编译时使用了同步 inout(输入输出)参数,那么更新和读取调用必须交织,如以下示例所示。

#include "param.h"
parameterGraph mygraph;

int main(void) {
  int result0, result1;
  mygraph.init();
  mygraph.run(2);

  mygraph.update(mygraph.select_value, 23);
  mygraph.read(mygraph.result_out, result0);
  mygraph.update(mygraph.select_value, 45);
  mygraph.read(mygraph.result_out, result1);

  mygraph.end();
  return 0;
}

在此示例中,假定每次迭代时,graph 都会通过 inout 端口 result_out 来生成标量结果。read API 用于在每次迭代之后同步读取并输出此端口的值。read API 的第一个实参是要读回的 graph inout 端口,第二个实参则是将用于存储该值的位置(按引用传递)。

同步协议可确保读取操作将等待 graph 生成值之后再对其进行采样,graph 将等待读取值后再继续下一次迭代。因此 update(更新)操作与 read(读取)操作交织就显得尤为重要。

异步更新/读取

以异步协议指定输入参数时,内核执行会等待发生首次更新后再执行参数初始化。但在下一次更新前可能会发生任意次数的内核调用。应用部署期间,这通常符合异步更新的意图。但对于部署,wait API 可用于在下次更新前完成一组预先确定的迭代,如以下示例所示。

#include "param.h"
asyncGraph mygraph;

int main(void) {
  int result0, result1;
  mygraph.init();

  mygraph.update(mygraph.select_value, 23);
  mygraph.run(5);
  mygraph.wait();
  mygraph.update(mygraph.select_value, 45);
  mygraph.run(15);
  mygraph.end();
  return 0;
}

在前述示例中,完成初始更新后,会运行 5 次迭代直至完成,随后再执行一次更新,后接另一组 15 次迭代。如果 graph 包含异步 inout 端口,那么等待(或结束)后即可立即读回该数据。

另一个异步更新模板是在 wait API 中使用超时,如以下示例所示。

#include "param.h"
asyncGraph mygraph;

int main(void) {
  int result0, result1;
  mygraph.init();
  mygraph.run();
  mygraph.update(mygraph.select_value, 23);
  mygraph.wait(10000);
  mygraph.update(mygraph.select_value, 45);
  mygraph.resume();
  mygraph.end(15000);
  return 0;
}

在此示例中,此 graph 设为永久运行。但在调用 run API 后,它仍会阻止执行首次更新以进行参数初始化。随后,它会运行 10,000 个周期(近似),然后才会允许控制线程执行另一次更新。新更新在下一次内核调用边界后生效。随后,允许 graph 再运行 15,000 个周期,而后终止。