カーネルを含むデータフロー グラフの作成 - 2023.2 日本語

AI エンジン カーネルおよびグラフ プログラミング ガイド (UG1079)

Document ID
UG1079
Release Date
2023-12-04
Version
2023.2 日本語
C++ でデータフロー グラフを構築するプロセスは、次のとおりです。
  1. アプリケーション グラフ クラスを別のヘッダー ファイル (例: project.h) で定義します。まず、適応型データフロー (ADF) ヘッダー (adf.h) を追加し、カーネル関数のプロトタイプを含めます。ADF ライブラリには、AI エンジン上のグラフを定義および実行するために必要なコンストラクトがすべて含まれます。
    #include <adf.h>
    #include "kernels.h"
  2. adf 名前空間で定義されているオブジェクトを使用して、グラフ クラスを定義します。すべてのユーザー グラフは、クラス graph を基に作成されます。
    include <adf.h>
    #include "kernels.h"
    
    using namespace adf;
    
    class simpleGraph : public graph {
    private:
      kernel first;
      kernel second;
    };

    これがグラフ クラス定義の冒頭で、2 つのカーネル (first および second) が定義されています。

  3. グラフに最上位入力/出力オブジェクト (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;
    
    };
  4. 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);
      }
    };
  5. 入力/出力オブジェクトを指定の PLIO 幅および入力/出力ファイルで設定し、接続情報を追加します。これは、データフロー グラフのネットに対応します。この記述では、入力/出力オブジェクトはインデックスで参照されます。入力ポート (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(in.out[0], first.in[0]);
        connect(first.out[0], second.in[0]);
        connect(second.out[0], out.in[0]);
        dimensions(first.in[0]) = {128};
        dimensions(first.out[0]) = {128};
        dimensions(second.in[0]) = {128};
        dimensions(second.out[0]) = {128};
      }
    };


    この図は、前のグラフ コードで指定されたグラフ接続を表しています。グラフ接続は、Vitis IDE でコンパイル結果を開くと表示できます。詳細は、 『AI エンジン ツールおよびフロー ユーザー ガイド』 (UG1076)コンパイル結果の表示を参照してください。上の図に示すように、最上位からの入力ポートは最初のカーネルの入力ポートに接続され、最初のカーネルの出力ポートは 2 番目のカーネルの入力ポートに接続され、2 番目のカーネルの出力ポートは最上位の出力に接続されます。最初のカーネルは、外部ソースから 128 バイトのデータ (32 個の複素サンプル) がバッファーに揃うと実行されます。これは、dimensions(first.in[0])={128} コンストラクトを使用しあて指定されています。同様に、最初のカーネルの出力として生成された有効なデータが入力バッファーに準備できると、2 番目のカーネルが実行されます。最後に、2 番目のカーネルの出力は最上位出力ポートに接続され、カーネルが終了時に生成するデータのバイト数が dimensions(second.out[0])={128} によって指定されます。

    buf0 および buf0d は、first のカーネル入力バッファー用に割り当てられたピンポン バッファーです。同様に、buf2 および buf2d は、second カーネル出力バッファー用に割り当てられたピンポン バッファーです。first カーネルから second カーネルに出力されるバッファー buf1 は、ピンポン バッファーではないことに注意してください。これは、firstsecond の両方のカーネル バッファーが、1 つの AI エンジン タイルに配置され、順次実行されるからです。詳細は、ランタイム比 を参照してください。

  6. 各カーネルのソース ファイルとタイルの使用を設定します。ソース ファイル (kernel.cc) には、最初のカーネルと 2 番目のカーネル コードが含まれます。サイクル バジェットに対する関数の実行時間の比は、ランタイム比と呼ばれ、01 の値である必要があります。サイクル バジェットは、関数が入力からのデータを消費するか (レートが制限された入力データ ストリームの場合)、出力にデータのブロックを生成する (レートが制限された出力データ ストリームの場合) のにかけることができる命令サイクル数です。サイクル バジェットは、ブロック サイズの変更の影響を受けます。
    #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(in.out[0], first.in[0]);
        connect(first.out[0], second.in[0]);
        connect(second.out[0], out.in[0]);
        dimensions(first.in[0]) = {128};
        dimensions(first.out[0]) = {128};
        dimensions(second.in[0]) = {128};
        dimensions(second.out[0]) = {128};
    
        source(first) = "kernels.cc";
        source(second) = "kernels.cc";
    
        runtime<ratio>(first) = 0.1;
        runtime<ratio>(second) = 0.1;
    
      }
    };
    注記: 詳細は、ランタイム比 を参照してください。
  7. グラフ クラスのインスタンスを含む最上位アプリケーション ファイル (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; //Must have return statement
    }
重要: デフォルトでは、mygraph.run() オプションによりグラフが無限に実行されるよう指定されます。aiecompiler では、データフロー グラフを while ループで無限に実行するコードが生成されます。デバッグおよびテスト用にグラフの実行を制限するには、グラフ コードに mygraph.run(<number_of_iterations>) を指定します。1 以上の反復回数を指定できます。
重要: main 関数には、return 文が必要です。return 文がなければ、aiecompiler でエラーが発生することがあります。

ADF API には、API の実行ステータスを表示する戻り列挙型 return_code があります。

main プログラムがグラフを実行します。これをグラフのロード、実行、終了に使用します。

注記: カーネル コードは、2 つのカーネルが同じコアに割り当てられた場合でも名前の競合が発生しないように記述する必要があります。