streaming_node テンプレート・クラス

概要

streaming_node は、キューを利用してデバイスにカーネルおよびデータを渡すストリーミング・プログラミング・モデルを使用できるようにします。streaming_node クラスは、フローグラフにストリーミング・プログラミング・モデルの使用を簡単に統合するために必要なインターフェイスを提供します。開発者は、グラフを使用してヘテロジニアス・プラットフォームの異なるデバイスやハードウェア・リソースで実行する機能を調整できます。streaming_node に Factory を提供して、使用される実際のモデルの低レベルの詳細を定義する必要があります。

opencl_node は、インテル® TBB ライブラリーで提供されるモデル固有の streaming_node 実装の例です。opencl_node は、統合型および外付け型グラフィックス・プロセシング・ユニット (GPU) や CPU のような、OpenCL* をサポートするデバイスで OpenCL* カーネルを実行できるようにします。opencl_nodeopencl_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

デバイスに入力データをアップロードし、デバイスでカーネルを実行し、すべての必要な型を提供するインターフェイスを提供する概念。

デバイス

カーネルを実行する計算リソース。

カーネル

デバイスで実行する計算関数。

カーネル引数

カーネルを実行するためにデバイスに提供されるデータ。

引数は入力、出力、または両方です。

カーネル範囲

単一カーネル実行の計算範囲。

streaming_node 使用モデルにはいくつかの基本原則があります。

streaming_node のダイアグラム
streaming_node のダイアグラム

ノードはカーネル引数 (およびカーネル範囲 (オプション)) を入力ポートから読み取ります。あるいは、ノードを使用する前にカーネル引数 (および範囲) を定義します。

ノードはカーネル引数およびカーネル範囲を入力ポートから読み取ります。

ノード実行の最後に出力データの準備ができていない場合があるため、出力ポートは async_msg から派生したメッセージを常に送ります。しかし、async_msg は、ほかのフローグラフのノードがこれらのメッセージに適切に応答し、利用可能になる前にデータを使用しないことを保証します (async_msg を参照)。

単純化された streaming_node アルゴリズムは、次の手順で記述できます。

streaming_node は、常に次のノードに async_msg_type 値を送ります。カーネル実行の終了を待ちません。待機は、C++ の future-promise コンセプトのように、実際の結果データを処理する時点で行われます。(詳細は、async_msg クラスの説明を参照。)

ノードは、すべてのカーネル引数は Factory のカーネルの実行により変更されると仮定します。この仮定により、出力 async_msgs の読み取り専用引数のデータが利用可能になるのが遅れることがあります。

Factory コンセプト

概要

streaming_node は、Factory オブジェクトを利用して特定のデバイスと通信する抽象実行メカニズムです。Factory は、デバイスに入力データをアップロードし、デバイスでカーネルを実行し、ノードタイプで必要なセットを提供する手段を提供します。

要件

次の表は、Factory 型 F の要件を示しています。

Factory コンセプト

擬似署名

意味

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 の概念

概要

Device Selector オブジェクトは、Factory インスタンスに利用可能なデバイスから 1 つのデバイスを選択する単純なユーザー・ファンクターです。

要件

次の表は、Device Selector 型 DS の要件を示しています。

Device Selector の概念

擬似署名

意味

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 は下記にリストされているヘルパーにより返されます。

サンプル

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 が定義されている場合にのみ利用できます。

関連情報