プロデューサー/コンシューマー パラダイム - 2023.2 日本語

Vitis 高位合成ユーザー ガイド (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 日本語

ソフトウェア設計者がマルチスレッド プログラムを作成する場合、通常メイン スレッドにいくつかの初期化ステップを実行させ、それをいくつかの子スレッドに分岐して並列計算を実行させ、すべての並列計算が完了したときに、メイン スレッドが結果を照合して出力に書き出すようにしします。プログラマは、並列計算のために分岐できるパーツと、順次実行する必要があるパーツを把握する必要があります。このフォーク/ジョイン タイプの並列処理は、CPU と同様に FPGA にも適用されますが、FPGA では、プロデューサー/コンシューマー パラダイムの方がスループットの観点から重要となります。プロデューサー/コンシューマー パラダイムを順次プログラムに適用し、それを変換して、並列で実行可能な機能を抽出してパフォーマンスを向上させる必要があります。

この分解プロセスについて、次の簡単な例を使用して説明します。たとえば、データシートがあって、そこにある項目をリストにインポートするとします。次に、リスト内の各項目を処理します。各項目の処理には約 2 秒かかるとします。処理後、結果を別のデータシートに書き込みます。この動作には、項目ごとに 1 秒が追加されます。このため、入力に使用した Excel シートに合計 100 個のアイテムがある場合、出力の生成には合計 300 秒かかります。ここでの目的は、これらを分解することで、並列で実行できる可能性のあるタスクを特定し、システムのスループットを向上させることにあります。

図 1. プログラムのワークフロー

最初のステップは、プログラムのワークフローを理解し、独立したタスクまたは機能を特定することです。4 ステップのワークフローは、上のプログラム ワークフロー (オーバーラップなし) の図のようになります。この例では、「Write Output」 (ステップ 3) タスクは「Process Data」 (ステップ 2) 処理タスクから独立したタスクです。ステップ 3 はステップ 2 の出力に依存しますが、ステップ 2 でいずれかの項目が処理されるとすぐに、その項目を出力ファイルに書き込むことができます。出力ファイルへのデータの書き込みを開始する前に、すべてのデータが処理されるまで待つ必要はありません。このタイプのタスクの実行のインターリーブ/オーバーラップは、かなりよく使用される原則です。これは上の図に示されています (例: オーバーラップありのプログラム ワークフロー)。このように、作業はオーバーラップのない場合よりも高速に実行できます。ここから、ステップ 2 がプロデューサーで、ステップ 3 がコンシューマーであることがわかります。プロデューサー/コンシューマーのパターンは、CPU のパフォーマンスに限定的な影響を与えます。各スレッドのステップの実行はインターリーブできますが、基盤となるマルチスレッドと L1 キャッシュ アーキテクチャを利用するために慎重な解析が必要となるので、時間のかかる作業となります。ただし、FPGA ではカスタム アーキテクチャによりプロデューサー スレッドとコンシューマー スレッドを同時に実行でき、オーバーヘッドがほとんどまたはまったくないため、スループットが大幅に向上します。

最初に考慮するべき最も簡単な例は、有限サイズのバッファーを介して通信する単一のプロデューサーおよび単一のコンシューマーの例です。バッファーがいっぱいの場合、プロデューサーはデータをブロック/停止するか、破棄するかを選択できます。コンシューマーがバッファーから項目を削除すると、その項目がプロデューサーに通知され、プロデューサーはバッファーの補充を再開します。同様に、バッファーが空であると検出された場合、コンシューマーが停止する可能性があります。プロデューサーはデータをバッファーに入れると、スリープ状態のコンシューマーが起動されます。このソリューションは、プロセス間通信 (通常はモニターまたはセマフォを使用) によって達成できます。ソリューションに問題があると、デッドロックが発生し、両方のプロセスが停止してウェイク アップを待つことがあります。ただし、単一のプロデューサーおよびコンシューマーの場合、通信パターンは FIFO (先入れ先出し) または PIPO (ピンポン バッファー) インプリメンテーションにマップされます。このタイプのチャネルは、データ転送のためにセマフォ、ミューテックス、モニターに依存せずにデータ転送するのです、効率的なデータ通信を提供します。このようなロック プリミティブの使用は、パフォーマンスおよび使用やデバッグが困難な点でコストがかかる可能性があります。エンド ツー エンドのアトミック同期を必要としないため、PIPO と FIFO がよく使用されます。

このタイプのマクロ レベルのアーキテクチャ最適化では、通信がバッファーによってカプセル化されるため、メモリ モデルやその他の非決定性ビヘイビアー (競合状態など) を心配する必要がなくなります。このタイプのデザインで達成されるネットワークのタイプは、純粋に「データフロー ネットワーク」であり、入力側でデータのストリームを受け取り、基本的にこのデータストリームに対してなんらかの処理を実行し、データのストリームとして送信します。並列プログラムの複雑さは抽象化されます。「Import Data」 (ステップ 1) および「Export Data」 (ステップ 4) にも、使用可能な並列処理を最大化するための役割があります。計算が I/O と正常にオーバーラップできるようにするには、入力からの読み出しを最初のステップとしてカプセル化し、最後のステップとして出力に書き込むことが重要です。これにより、I/O と計算が最大限オーバーラップできるようになります。計算ステップの途中で入出力ポートに読み書きすると、デザインで使用可能な並列処理が制限されます。このため、デザインのワークフローを設計する際には、もう 1 つの点に留意する必要があります。

最後に、このような「データフロー ネットワーク」のパフォーマンスは、設計者がデータをネットワークに継続的にフィードし、データがシステムを介してストリーミングされるようにすることに依存します。データフローが中断されると、パフォーマンスが低下する可能性があります。この良い例は、オンライン ゲームのようなビデオ ストリーミング アプリケーションなど、リアルタイム高解像度 (HD) ビデオが常にシステムを介してストリーミングされ、フレーム処理速度が常に監視されて、十分な品質の結果を達成する場合などです。フレーム処理速度の低下は、ゲーマーの画面に即座に表示されます。従来の CPU や GPU アーキテクチャよりも消費電力がはるかに少なく、ゲーマー全員が一貫したフレーム レートをサポートできることを想像してみてください。これが、ハードウェア アクセラレーションの注力すべき分野 (スイート スポット) です。最も重要なのは、プロデューサーとコンシューマー間のデータフローを維持することです。次に、このセクションで紹介したストリーミング パラダイムについてもう少し詳しく説明します。