streaming_node は、キューを利用してデバイスにカーネルおよびデータを渡すストリーミング・プログラミング・モデルを使用できるようにします。streaming_node クラスは、フローグラフにストリーミング・プログラミング・モデルの使用を簡単に統合するために必要なインターフェイスを提供します。開発者は、グラフを使用してヘテロジニアス・プラットフォームの異なるデバイスやハードウェア・リソースで実行する機能を調整できます。streaming_node に Factory を提供して、使用される実際のモデルの低レベルの詳細を定義する必要があります。
opencl_node は、モデル固有の streaming_node の例であり、フローグラフで OpenCL* 対応デバイスを利用および調整できるようにします。開発者は、ほかのモジュールをサポートするカスタム Factory を定義することもできます。
template < typename... Args > class streaming_node; template < typename... Ports, typename JP, typename Factory > class streaming_node < tuple < Ports... >, JP, Factory >;
#define TBB_PREVIEW_FLOW_GRAPH_FEATURES 1 #include "tbb/flow_graph.h"
streaming_node クラスは、ヘテロジニアス・コンピューティング・デバイスをサポートする、より大きなフローグラフ・ベースのソリューションの一部です。
用語 | 定義 |
---|---|
Factory | デバイスに入力データをアップロードし、デバイスでカーネルを実行し、すべての必要な型を提供するインターフェイスを提供する概念。 |
デバイス | カーネルを実行する計算リソース。 |
カーネル | デバイスで実行する計算関数。 |
カーネル引数 | カーネルを実行するためにデバイスに提供されるデータ。 引数は入力、出力、または両方です。 |
カーネル範囲 | 単一カーネル実行の計算範囲。 |
streaming_node 使用モデルにはいくつかの基本原則があります。
デバイスの詳細は streaming_node に直接組込まれる代わりに、Factory を利用してアクセスされます。
streaming_node は、入力ポートのセットから入力データを受け取ります。
入力データはカーネル引数やカーネル範囲として使用されるか、変更されずに出力ポートに渡されます。
Factory の実装に応じて、非同期実行が可能になるように async_msg から派生した入力メッセージは特別に扱われます。
入力ポートごとに、対応する出力ポートがあります。
すべての出力メッセージは、非同期実行が可能になるように Factory で定義された async_msg 型でラップされます。
すべての出力メッセージは async_msg から派生するため、出力メッセージが利用可能であることは基礎結果データの準備ができていることを意味しません (async_msg を参照)。
任意のポートからの入力がカーネル引数またはカーネル範囲で参照されていない場合、入力データは変更されずに一致する出力ポートに渡されます。
streaming_node を作成してセットアップするときに、次の項目を指定します。
モデルの詳細 (Factory オブジェクトを利用)
デバイスの選択方法 (DeviceSelector オブジェクトを利用)
カーネル引数 (定数または特定の入力ポートからマップ)
カーネル範囲 (オプション) (定数または特定の入力ポートからマップ)
ノード実行の最後に出力データの準備ができていない場合があるため、出力ポートは async_msg から派生したメッセージを常に送ります。しかし、async_msg は、ほかのフローグラフのノードがこれらのメッセージに適切に応答し、利用可能になる前にデータを使用しないことを保証します (async_msg を参照)。
単純化された streaming_node アルゴリズムは、次の手順で記述できます。
入力ポートで入力データを受け取ります。Factory 固有の async_msg 型でラップされていない場合は、入力をラップします。
カーネル実行のデバイスを選択します。
カーネル引数 (およびカーネル範囲 (オプション)) をデバイスに送ります。
デバイスの実行用カーネルをキューに入れます。
必要に応じて、async_msgs の依存関係を更新します。
ノード出力として出力ポートから更新された async_msgs を送ります。
streaming_node は、常に次のノードに async_msg_type 値を送ります。カーネル実行の終了を待ちません。待機は、C++ の future-promise コンセプトのように、実際の結果データを処理する時点で行われます。(詳細は、async_msg クラスの説明を参照。)
ノードは、すべてのカーネル引数は Factory のカーネルの実行により変更されると仮定します。この仮定により、出力 async_msgs の読み取り専用引数のデータが利用可能になるのが遅れることがあります。
概要
streaming_node は、Factory オブジェクトを利用して特定のデバイスと通信する抽象実行メカニズムです。Factory は、デバイスに入力データをアップロードし、デバイスでカーネルを実行し、ノードタイプで必要なセットを提供する手段を提供します。
要件
次の表は、Factory 型 F の要件を示しています。
擬似署名 |
意味 |
---|---|
template <typename T> using F::async_msg_type = .....; |
デバイス固有の型: 非同期メッセージ型 (async_msg クラスから派生)。 |
typedef ..... F::device_type; |
デバイス固有の型: ターゲットデバイス型。 |
typedef .....&... F::kernel_type; |
デバイス固有の型: デバイスカーネル型。 |
typedef ..... F::range_type; |
オプション。デバイス固有の型: 範囲型。 |
template <typename ...Args> void F::send_kernel(device_type device, const kernel_type& kernel, [const range_type& work_size,] Args&... args) |
デバイスでカーネルを実行します。 |
template <typename ...Args> void F::send_data(device_type device, Args&... args) |
デバイスにデータをアップロードします。 |
template <typename FinalizeFn, typename ...Args> void F::finalize(device_type device, FinalizeFn fn, Args&... args) |
カーネル実行後の終了処理。 fn ファンクターはカーネル実行が終了した後に呼び出します。 |
Factory が範囲の概念をサポートしている場合、range_type 型を定義する必要があります。この場合、streaming_node は範囲を定義するメソッドを提供します。カーネル範囲が Factory でサポートされていない場合、これらのメソッドは利用できません。
カーネル範囲がサポートされていない場合、send_kernel インターフェイスは次のようになります。
template <typename ...Args> void F::send_kernel(device_type device, const kernel_type& kernel, Args&... args)
説明
ストリーミング・ノードは、send_kernel メソッドを呼び出して、指定された外部デバイスでカーネルを開始します。すべての入力引数 (Args&... args) は、async_msg_type 型の参照として提供されます。引数が set_args から値で設定された場合は定数参照、引数が入力ポートからの動的な値 (つまり、set_args メソッドの port_ref 引数で設定された値) の場合は非定数参照です。
send_data メソッドは、ストリーミング・ノードに呼び出され、指定されたデバイスにオリジナルのカーネル引数をアップロードします。すべての入力引数 (Args&... args) は、async_msg_type 型の参照として提供されます。リストには、set_args から (port_ref としてではなく) 値で設定される値のみ含まれます。
finalize メソッドはストリーミング・ノードに呼び出され、Factory にグラフのコールバック (カーネル実行が終了したときにグラフに通知) を設定させます。この場合、Factory は提供される終了処理ファンクターを呼び出す必要があります。finalize メソッドは、次のグラフノードがこの出力メッセージを拒否した場合、またはノードの出力ポートがノードに接続されていない場合 (グラフのどの部分もカーネルの結果を待っていない場合) にのみ、ノードに呼び出されることに注意してください。入力引数 (Args&... args) は、send_kernel メソッドのように、async_msg_type 型の定数/非定数参照のいずれかで提供されます。
概要
Device Selector オブジェクトは、Factory インスタンスに利用可能なデバイスから 1 つのデバイスを選択する単純なユーザー・ファンクターです。
要件
次の表は、Device Selector 型 DS の要件を示しています。
擬似署名 |
意味 |
---|---|
device_type DS::operator()( factory& f ) |
Factory からデバイスを取得します。ノードはデバイスでカーネル実行を開始します。 |
サンプル
struct external_device_selector { device_type operator()( factory& f ) { return f.get_somehow_an_available_device(); } };
デバイスの型は Factory によって定義されます。
streaming_node ユーザーは、定数値としてカーネル引数 (およびカーネル範囲引数 (オプション)) を提供するか、入力ポートをこれらの引数にマップできます。
Factory がカーネル範囲をサポートしている場合、streaming_node クラスの次のメソッドを使用して範囲値を設定します。
void set_range(const range_type& work_size); void set_range(range_type&& work_size);
カーネル引数を定数として設定するには、streaming_node クラスの次のメソッドを使用します。
template <typename ...Args> void set_args( Args&&... args );
サンプル
node.set_range( {{ width, height }} ); node.set_args(/* stride_x */ 1, /* stride_y */ 0, /* stride_z */ 0, /* dim */ 1 );
入力ポートをカーネル引数 (およびカーネル範囲 (サポートされている場合)) にマップするには、streaming_node クラスの次のメソッドを使用します。
void set_range( port_ref_entity ); template <typename ...Args> void set_args( Args&&... args ) ; // args には 1 つまたは複数の port_ref_entity を含めることができる
port_ref_entity は下記にリストされているヘルパーにより返されます。
port_ref<N>
port_ref<N1, N2>
port_ref<N>()
port_ref<N1, N2>()
サンプル
node.set_range( port_ref<2> ); node.set_args( port_ref<0, 1> );
または
node.set_range( port_ref<2>() ); node.set_args( port_ref<0, 1>() );
または
node.set_range( port_ref<2> ); node.set_args( port_ref<0, 1>() );
アプローチは簡単に組み合わせることができます。
サンプル
node.set_range( port_ref<2> ); node.set_args( port_ref<0, 1>(), /* stride_x */ 1, /* stride_y */ 0, /* stride_z */ 0, /* dim */ 1 );
このサンプルは、範囲をポート 2 から受け取り、ポート 0 および 1 からのデータをカーネル引数として事前定義定数引数 (stride_x、stride_y など) とともにデバイスに送ります。
opencl_node クラスの実装は streaming_node クラスの使用例です。
詳細は、https://www.isus.jp/products/tbb/opencl-node-overview/ を参照してください。
namespace tbb { namespace flow { template<typename... Args> class streaming_node; template<typename... Ports, typename JP, typename Factory> class streaming_node< tuple<Ports...>, JP, Factory > : ..... { public: template <typename DeviceSelector> streaming_node( graph& g, const kernel_type& kernel, DeviceSelector d, Factory& f ); streaming_node( const streaming_node& node ); streaming_node( streaming_node&& node ); ~streaming_node() ; template <typename... Args> void set_args( Args&&... args ) ; // 次のメソッドは Factory::range_type が // 定義されている場合にのみ利用できます void set_range(const range_type& work_size); void set_range(range_type&& work_size); template <int N> void set_range(port_ref_impl<N, N>); template <int N> void set_range(port_ref_impl<N, N>(*)()); }; } }
メンバー | 説明 |
---|---|
typename... Ports | ノードの入力データ型。 |
typename JP | 結合ポリシー。詳細は、join_node クラスの説明を参照してください。 |
typename Factory | デバイス固有の Factory 型。 |
template <typename DeviceSelector> streaming_node( graph& g, const kernel_type& kernel, DeviceSelector d, Factory& f ); | メイン・コンストラクター。 |
streaming_node( const streaming_node& node ); | コピー・コンストラクター。 |
streaming_node( streaming_node&& node ); | ムーブ・コンストラクター。 |
~streaming_node(); | デストラクター。 |
template <typename... Args> void set_args( Args&&... args ); | カーネル実行の引数を設定します (引数には値やポート参照を含めることができます)。 |
void set_range(const range_type& work_size); | カーネル実行の定数範囲を設定します。 注このメソッドは、Factory::range_type が定義されている場合にのみ利用できます。 |
void set_range(range_type&& work_size); | 上記のメソッドと同じですが、ムーブ・セマンティクスを使用します。 注このメソッドは、Factory::range_type が定義されている場合にのみ利用できます。 |
template <int N> void set_range(port_ref_impl<N, N>); | N 番目のポートから動的に範囲値を取得するように範囲のポート参照を設定します。 注このメソッドは、Factory::range_type が定義されている場合にのみ利用できます。 |
template <int N> void set_range(port_ref_impl<N, N>(*)()); | N 番目のポートから動的に範囲値を取得するように範囲のポート参照を設定します。 注このメソッドは、Factory::range_type が定義されている場合にのみ利用できます。 |