streaming_node は、キューを利用してデバイスにカーネルおよびデータを渡すストリーミング・プログラミング・モデルを使用できるようにします。streaming_node クラスは、フローグラフにストリーミング・プログラミング・モデルの使用を簡単に統合するために必要なインターフェイスを提供します。開発者は、グラフを使用してヘテロジニアス・プラットフォームの異なるデバイスやハードウェア・リソースで実行する機能を調整できます。使用する具体的なモデルの低水準の詳細を定義するには、streaming_node に Factory を提供する必要があります。
opencl_node は、インテル® スレッディング・ビルディング・ブロック (インテル® TBB) ライブラリーで提供されるモデル固有の streaming_node の例です。opencl_node は、統合型および外付け型グラフィックス・プロセシング・ユニット (GPU) や CPU のような、OpenCL* をサポートするデバイスで OpenCL* カーネルを実行できるようにします。opencl_node は opencl_factory を使用する streaming_node として実装されます。
開発者は、OpenCL* 以降のほかのモデルをサポートする Factory を定義するように選択できます。また、ほかの 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 |
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 値を送ります。カーネル実行の終了を待ちません。待機は、‘future-promise’ コンセプトのように、実際の結果データを処理する時点で行われます。(詳細は、async_msg クラスの説明を参照。)
すべてのカーネル引数はカーネルの実行により変更されると仮定しています。この仮定により、出力 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 にグラフのコールバック (カーネル実行が終了したときにグラフに通知) を設定させます。この場合、提供される終了処理ファンクターを呼び出す必要があります。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 can include port_ref_entity(s)
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 クラスの使用例です。
詳細は、http://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 が定義されている場合にのみ利用できます。 |