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;
..
}