メモリ モデル - 2023.2 日本語

AI エンジン ツールおよびフロー ユーザー ガイド (UG1076)

Document ID
UG1076
Release Date
2023-12-04
Version
2023.2 日本語

1 つの呼び出し (反復) から次の呼び出し (反復) までステートを保持する必要があるカーネルでは、グローバル変数またはスタティック変数を使用してこのステートを格納できます。グローバル変数やスタティック変数などのスタティック ストレージ クラスを持つ変数は、x86 シミュレーションと AI エンジン シミュレーションが一致しない原因となります。この根本的な原因は、x86 シミュレーションではすべてのカーネルのソース ファイルが 1 つの実行可能ファイルにコンパイルされるのに対し、AI エンジン シミュレーションでは AI エンジン をターゲットとする各カーネルが個別にコンパイルされることです。そのため、スタティック ストレージ クラスを持つ変数が 2 つのカーネルから参照され、これらのカーネルが同じ AI エンジンにマップされていると、x86 シミュレーションと AI エンジン シミュレーションの両方で変数が共有されます。これらのカーネルが異なる AI エンジンにマップされていると、x86 シミュレーションでは変数が共有されますが、AI エンジン シミュレーションでは各 AI エンジンに独自のコピーがあり、共有されません。これにより、変数がカーネルにより読み書きされると、x86 シミュレーションと AI エンジン シミュレーションが一致しません。

カーネルの反復間でステートを伝搬するために推奨されるモデル化方法は、C++ カーネル クラスを使用することです ( 『AI エンジン カーネルおよびグラフ プログラミング ガイド』 (UG1079)C++ カーネル クラスのサポートを参照)。これにより、スタティック ストレージ クラスを持つ変数での問題を回避できます。または、グローバル変数またはスタティック変数のストレージ クラスを、x86 シミュレーションに対してのみ、thread_local に変更できます。この場合、x86 シミュレーションでカーネルの各インスタンスに変数の独自のコピーがあることになります。これは、変数が異なる AI エンジンにマップされている場合に、AI エンジン シミュレーションの動作と一致します。次の例では、グローバル変数 delayLine とスタティック変数 pos を使用して、カーネルのステートが反復で伝搬されます。この場合、このソース ファイルを使用するカーネル インスタンスが複数ある場合に x86 シミュレーションと AI エンジン シミュレーションが一致しません。これらの変数を thread_local に変更すると、この問題を回避できます。

変更前のカーネル ソース コード:

// fir.cpp
#include <adf.h>
using namespace adf;
cint16 delayLine[16] = {};
void fir(input_buffer<cint16> *in1,
         output_buffer<cint16> *out1)
{
  static int pos = 0;
..
}

変更後のカーネル ソース コード:

// fir.cpp
#include <adf.h>

#ifndef __X86SIM__
cint16 delayLine[16] = {};
#else
thread_local cint16 delayLine[16] = {};
#endif
void fir(input_buffer<cint16> *in1,
         output_buffer<cint16> *out1)
{
using namespace adf;
#ifndef __X86SIM__
  static int pos = 0;
#else
  static thread_local int pos = 0;
#endif
..
}
別の方法として、マクロ X86SIM_THREAD_LOCAL を使用して、グローバル読み出し/書き込みをスレッド セーフにできます。このマクロは、adf.h で次のように定義されます。
#ifdef _X86SIM_
#define X86SIM_THREAD_LOCAL thread_local
#else
#define X86SIM_THREAD_LOCAL
#endif
これにより、X86 シミュレーションにのみ定義されます。
前述のコードは、次のように簡略化されます。
// fir.cpp
#include <adf.h>

X86SIM_THREAD_LOCAL cint16 delayLine[16] = {};

void fir(input_buffer<cint16> *in1,
         output_buffer<cint16> *out1)
{
using namespace adf;
static X86SIM_THREAD_LOCAL int pos = 0;
..
}