VPP_ACC クラスの API - 2023.2 日本語

Vitis 統合ソフトウェア プラットフォームの資料: アプリケーション アクセラレーション開発 (UG1393)

Document ID
UG1393
Release Date
2023-12-13
Version
2023.2 日本語

VPP_ACC ベース クラスから派生したハードウェア アクセラレータを定義し、VSC を使用してハードウェアおよびソフトウェア インターフェイスを構築できます。このセクションでは、VPP_ACC クラスで提供されるソフトウェア API について説明します。

アクセラレータの制御

VPP_ACC クラスの API には、アクセラレータ ハードウェア上のジョブのスケジューリング、結果の処理、および実行時のその他のソフトウェア制御のためのメソッドが用意されています。

send_while()

この API は、ブール値 false を返すまで SendBody を繰り返し実行します。send_while の擬似コードは、do{ bool ret=f() } while(ret==true); と同様です。

void send_while(SendBody f, VPP_CC& cc = *s_default_cc);
表 1. send_while() 引数
引数 説明
SendBody f

SendBody は、ユーザー定義の C++ ラムダ関数です。ラムダ関数は、外側のスコープから変数を取り込みます。特に、使用されているすべてのバッファー プール変数を取り込む必要があります。これらは値ごとに取り込む必要があります。[=] を使用すると、これらが値ごとに取り込まれるほか、ラムダ関数内で使用する可能性のあるほかの変数が自動的に取り込まれす。ラムダ関数内で変更された変数は、参照渡しする必要があります。例は、[=, &m] です。不必要に変数が参照渡しされると、ホスト コードのパフォーマンスが低下する可能性がありますが、一方で、大きなクラス オブジェクトを値渡しすると、不要なディープ コピーが発生する可能性があります。ただし、後者は送信 (または受信) 機能に必要なものではありません。

ヒント: 参照渡しが必要な変数は、[=, &var] で明示的に取り込むことができます。
VPP_CC& cc CU のグループ化に使用するオプションの引数です。たとえば、CU クラスターとマルチカードのサポート で説明されるように、使用する CU のマルチカード クラスターを指定するために使用できます。
compute()

compute() API で説明するように、compute() メソッドは、CU を表すために使用され、プロセッシング エレメント (PE) を含む、派生 VPP_ACC アクセラレータ クラスの定義内の特別なユーザー定義メソッドです。

void compute(Args ...);
  • 1 つのジョブをスケジュールするハードウェア アクセラレータへの呼び出し
  • SendBody 関数内では 1 つまたは複数の compute() 呼び出すことができます。
  • compute() 呼び出しはノンブロッキングで、すぐに戻りますが、タスク パイプラインがいっぱいになるとブロックされます。
  • バックグラウンドでは、compute() 呼び出しにより、そのすべての入力がデバイスに転送され、使用可能な CU で実行されることが確認されます。
  • イテレーション内のすべての compute() 呼び出しが終了すると、出力バッファーはホストに戻され、そのイテレーションで receive_all イテレーションが開始されます。
  • アプリケーション コードでは次の条件に従う必要があり、ソフトウェア エミュレーション中にアサートされます。
    • compute() 呼び出しがあると、入力バッファーとファイル バッファーが変更できなくなり、そのイテレーションでこれ以上 alloc_buf 呼び出しや file_buf 呼び出しができなくなります。
    • 出力バッファーは、対応する receive イテレーションでデータが受信されるまで読み出しまたは書き込みができません。
receive_all_xxx()

計算要求が完了してハードウェア アクセラレータからのデータを受信するたびに、C++ ラムダ関数を順番どおり、または ASAP のいずれかで繰り返し実行します。send_while() が終了し、すべてのイテレーションが受信されると終了します。

void receive_all_in_order(RecvBody f, VPP_CC& cc = *s_default_cc);
void receive_all_asap(RecvBody f, VPP_CC& cc = *s_default_cc);
表 2. receive_all_xxx() 引数
引数 説明
RecvBody f

RecvBody は、ユーザー定義の C++ ラムダ関数です。send_while() のラムダ関数の説明を参照してください。

VPP_CC& cc CU のグループ化に使用するオプションの引数です。たとえば、CU クラスターとマルチカードのサポート で説明されるように、使用する CU のマルチカード クラスターを指定するために使用できます。
receive_one_xxx()

複数アクセラレータのパイプライン構成 で説明するように、別のアクセラレータの send_while() ループ内でこのアクセラレータの 1 回のイテレーションを受信するために使用されます。

void receive_one_in_order(RecvBody f, VPP_CC& cc = *s_default_cc);
void receive_one_asap(RecvBody f, VPP_CC& cc = *s_default_cc);
表 3. receive_one_xxx() 引数
引数 説明
RecvBody f

RecvBody は、ユーザー定義の C++ ラムダ関数です。send_while() のラムダ関数の説明を参照してください。

VPP_CC& cc CU のグループ化に使用するオプションの引数です。たとえば、CU クラスターとマルチカードのサポート で説明されるように、使用する CU のマルチカード クラスターを指定するために使用できます。
join()

送信および受信ループが終了するまで待ちます。

void join(VPP_CC& cc = *s_default_cc); 
表 4. join() 引数
引数 説明
VPP_CC& cc CU のグループ化に使用するオプションの引数です。たとえば、CU クラスターとマルチカードのサポート で説明されるように、使用する CU のマルチカード クラスターを指定するために使用できます。
set_ncu()

ドライバーが使用する CU の数を設定します。送信/受信ループを開始する前にこのメソッドを使用して、compute() 関数が使用する CU の数を設定します。

void VPP_ACC::set_ncu(int ncu);
表 5. set_ncu() 引数
引数 説明
int ncu 指定した CU 数 (ncu) は、ユーザー定義のアクセラレータ クラス に説明するように、(1 <= ncu <= NCU) にする必要があります。この場合、NCU は VPP_ACC< .... , NCU> のテンプレート パラメーターです。
get_ncu()

VPP_ACC::set_ncu で前に設定したように、変更されていない場合は、VPP_ACC< .... , NCU> の NCU テンプレート パラメーターで設定したように、ドライバーが現在使用している CU の数を返します。

int VPP_ACC::get_ncu();
get_NCU

ハードウェアにインプリメントされている CU の数 (ハードウェアの構築時に指定され、VPP_ACC< .... , NCU> ベース クラスで指定された NCU テンプレート パラメーターの値) を返します。

int VPP_ACC::get_NCU();

計算用の I/O の設定

ここで説明する API メソッドは、ハードウェア アクセラレータへの入力バッファーと出力バッファーを設定するために使用されます。

create_bufpool()

alloc_buf() などのバッファー ハンドルを必要とするほかのメソッドで使用される不透明なクラス オブジェクトを作成して返します。送信/受信ループを開始する前に使用します。

VPP_BP VPP_ACC::create_bufpool(vpp::Mode m, vpp::FileXFer = vpp::none);
表 6. create_bufpool() 引数
引数 説明
vpp::Mode m

次のいずれかの値を指定して、各 compute() 引数のデータ転送タイプを指定できます。

  • vpp::input: データがアクセラレータに転送されます。
  • vpp::output: アクセラレータからデータが転送されます。
  • vpp::bidirectional: アクセラレータとの間でデータが転送されます。
  • vpp::remote: データはアクセラレータに接続されているデバイス メモリにのみ存在し、ホスト コードによって送受信されることはありません。
vpp::FileXFer = vpp::none
次のいずれかの値を指定して、データ転送用のファイルの場所を指定できます。
  • vpp::p2p: ファイルは P2P ブリッジを介してアクセラレータに転送されます。これは、P2P 機能をサポートするプラットフォーム (たとえば、接続された smartSSD を搭載した U2 カードなど) でのみ機能します。
  • vpp::h2c: ファイルは PCIe を介してホスト CPU (接続されたファイル サーバー) からカードに転送されます。これは、PCIe を介してホスト CPU に接続されるほとんどの Alveo カードの標準です。
  • vpp::none: 通常のバッファー オブジェクトを使用し、ファイル転送はサポートしません。これがデフォルト値です。
alloc_buf()

バッファー オブジェクトにポインターを返します。送信スレッドのラムダ関数内で使用します。

void* VPP_ACC::alloc_buf(VPP_BP bp, int byte_sz);
T* VPP_ACC::alloc_buf<T>(VPP_BP bp, int numT);
重要: バッファーは、指定されたバッファー プールから割り当てられます。バッファーのライフタイムは、一致する受信イテレーションが終了するまでです。その時点で、バッファーは自動的にバッファー プールに戻されます。
表 7. alloc_buf() 引数
引数 説明
VPP_BP bp create_bufpool() によって返されるバッファー プール オブジェクト
int byte_sz 要求されたバッファーのバイト数を指定します。
int numT 要求された <T> 配列バッファーのエレメント数を指定します。
file_buf()

このメソッドは、指定されたファイルまたはファイルの一部を、指定されたバッファー プール オブジェクトからバッファーにマップします。送信スレッドのラムダ関数内で使用します。file_buf() メソッドを複数回呼び出すと、複数のファイル (またはファイル セグメント) を 1 つのバッファー内の異なる場所にマップできます。

このメソッドは、ホスト ハンドルであるバッファー オブジェクトへポインターを返します。ホストを使用して、読み出しまたは書き込みはできません。

void* VPP_ACC::file_buf(VPP_BP bp, int fd, int byte_sz, off_t fd_byte_offset=0, off_t buf_byte_offset=0);
T* VPP_ACC::file_buf<T>(VPP_BP bp, int fd, int numT, off_t fd_T_index=0, off_t buf_T_index);
表 8. file_buf() 引数
引数 説明
VPP_BP bp create_bufpool() によって返されるバッファー プール オブジェクト。
int fd 読み出しまたは書き込みをするファイル記述子 (次で説明するように、custom_sync_outputs() を使用する場合は 0)。P2P モードでは、ファイルは O_DIRECT フラグで開きます。
int byte_sz 要求されたバッファーのバイト数を指定します。P2P モードでは、これはファイル システムのブロック サイズ (4 KB) に揃える必要があります。
fd_offset 読み出し/書き込み先のファイルのオフセット。
buf_offset 読み出し/書き込み先のバッファーのオフセット。
int numT 要求された <T> 配列バッファーのエレメント数を指定します。P2P モードでは、これはファイル システムのブロック サイズ (4 KB) に揃える必要があります。
fd_T_index 読み出し/書き込みを開始するファイル内の配列インデックス。
buf_t_index 書き込み/読み出しを開始するバッファー インデックス。
追加注記:
  • T* buf = file_buf<T>(bp, fd, num, fd_idx, buf_idx); 文は T* buf = (T*)file_buf(bp, fd, num*sizeof(T), fd_idx*sizeof(T), buf_idx*sizeof(T)); と同じです。
  • 実際のバッファーのサイズは、必要に応じて調整されます。そのため、最後の呼び出しで返されたバッファーを compute() 呼び出しで使用する必要があります。compute 呼び出しで使用されると、そのイテレーションにマッピングを追加できなくなります。
  • サポートされるプラットフォームとスタートアップの例 の「スタートアップ例」の file_filter_sc を参照してください。
get_buf()
  • 一致する送信ループに関連付けられた受信ループ内で使用します。これは、一致する送信イテレーションに割り当てられたバッファー オブジェクトを返します。
void* VPP_ACC::get_buf(VPP_BP bp);
T*    VPP_ACC::get_buf<T>(VPP_BP bp);
表 9. get_buf() 引数
引数 説明
VPP_BP bp create_bufpool() によって返されるバッファー プール オブジェクト
transfer_buf()

このメソッドは、複数アクセラレータのパイプライン構成 で説明するように、複数アクセラレータの構成で使用し、別のアクセラレータの send_while 内の receive_one_xxx() メソッドを使用して、別のアクセラレータにバッファーの所有権を転送します。これにより、現在の送信イテレーションに一致する受信イテレーションの終了まで、バッファーのライフタイムが延長されます。

ヒント: これは、バッファーがデバイス上に残り、コピーや同期が不要になるため、特に vpp::remote buffers で役立ちます。
void* VPP_ACC::transfer_buf(VPP_BP bp);
T* VPP_ACC::transfer_buf<T>(VPP_BP bp);
表 10. transfer_buf() 引数
引数 説明
VPP_BP bp create_bufpool() によって返されるバッファー プール オブジェクト
custom_sync_outputs()

このメソッドは、compute() 関数を呼び出す前に send_while ループの本体で呼び出すことができます。これにより、出力バッファーをホスト アプリケーションに同期するカスタム同期関数を提供できます。これは、一部の (すべてではなく) 出力バッファー データだけをハードウェア アクセラレータから戻す必要がある場合に役立ちます。

重要: これにより、すべての出力バッファーの自動同期がディスエーブルになります。
void custom_sync_outputs(std::function<void()> sync_outputs_fn)
表 11. custom_sync_outputs() 引数
引数 説明
sync_outputs_fn

イテレーションの計算タスクが終了したときに、send_while ループの各イテレーションに対して自動的に呼び出されるカスタム同期関数を指定します。

sync_outputs_fn が返され、要求された sync_output() 呼び出しすべてが完了すると、send_while ループのイテレーションに対して受信がトリガーされます。

sync_output()

このメソッドは、custom_sync_outputs() メソッドに渡された sync_output_fn 内で呼び出されます。要求された同期はバックグラウンドで実行され、呼び出し元が転送の完了を確認できる future が返されます。

std::future<void> sync_output(void* buf, size_t byte_sz, off_t byte_offset = 0);
std::future<void> sync_output<T>(T* buf, size_t numT, off_t Tindex = 0);
表 12. sync_output() 引数
引数 説明
buf sendBody() スコープからのキャプチャとして取得されるバッファー ポインター。
byte_sz 要求されたバッファーのバイト数を指定します。
byte_offset 読み出し/書き込み先のバッファーのオフセット。
numT 要求された <T> 配列バッファーのエレメント数を指定します。P2P モードでは、これはファイル システムのブロック サイズ (4 KB) に揃える必要があります。
Tindex 書き込み/読み出しを開始するバッファー インデックス。
sync_output_to_file()

このメソッドは、custom_sync_outputs() メソッドに渡された sync_output_fn 内で呼び出されます。要求された同期はバックグラウンドで実行され、呼び出し元が転送の完了を確認できる future が返されます。

std::future<void> sync_output_to_file(void* buf, int fd, size_t byte_sz, off_t fd_byte_offset = 0, off_t buf_byte_offset = 0);
std::future<void> sync_output_to_file<T>(T* buf, int fd, size_t numT, off_t fd_T_index = 0, off_t buf_T_index = 0);
表 13. sync_output_to_file() 引数
引数 説明
buf sendBody() スコープからのキャプチャとして取得されるバッファー ポインター。
fd 書き込むファイル記述子。
byte_sz 要求されたバッファーのバイト数を指定します。
fd_offset 読み出し/書き込み先のファイルのオフセット。
buf_offset 読み出し/書き込み先のバッファーのオフセット。
numT 要求された <T> 配列バッファーのエレメント数を指定します。P2P モードでは、これはファイル システムのブロック サイズ (4 KB) に揃える必要があります。
fd_T_index 読み出し/書き込みを開始するファイル内の配列インデックス。
buf_t_index 書き込み/読み出しを開始するバッファー インデックス。
set_handle()

sendBody 内で使用して、send_while ループの現在のイテレーションに関連付けるオブジェクトを識別します。

void VPP_ACC::set_handle(intptr_t hndl);
void VPP_ACC::set_handle<T>(T hndl);
表 14. set_handle() 引数
引数 説明
hndl send_while ループの現在のイテレーションに関連付けるもの。
ヒント: テンプレート化されたフォームを使用すると、単純な代入/コピー演算子を持つクラスをハンドルとして使用できます。
get_handle()

RecvBody 内で使用されます。このメソッドは、send_while ループの一致する送信イテレーション (set_handle()) で設定されたオブジェクトのハンドルを返します。

intptr_t VPP_ACC::get_handle();
T VPP_ACC::get_handle<T>();