AMD Vitis™ カーネルをインプリメントする設計者の場合、FPGA デバイスで使用可能なデバイス メモリ (PLRAM、HBM、DDR) を使用する際にさまざまなトレードオフを利用できます。次に、アプリケーションの AXI4 メモリ マップド インターフェイスを設計する際に使用するベスト プラクティスのチェックリストを示します。
スループットが最適化の最大目標であることから、マクロおよびマイクロアーキテクチャの最適化を使用してアプリケーションの計算部分をアクセラレーションすることが最初のステップであることは明らかですが、カーネルとの間でデータを転送する時間も、スループット目標に関してアプリケーション アーキテクチャに影響を与える可能性があります。データ転送のオーバーヘッドが大きいため、アプリケーションに存在する通信 (データ移動) と計算がオーバーラップしていることを考慮することが重要となっています。
指定されたアプリケーションで次を実行します。
- LCS (Load、Compute、Store) コーディング パターンを使用してモデル化されたプロデューサーとコンシューマー タスクのパイプラインを構築して、カーネル アルゴリズムを分解します
- すべての外部 I/O アクセスは、Load タスクと Store タスクに含まれる必要があります。
- カーネルが異なるポートから並行して読み書きする必要がある場合は、複数の Load タスクまたは Store タスクが必要です。
- Compute タスクに含めるのは、スカラー、配列、ストリーム、またはストリーム オブ ブロック引数のみです。
- これらすべてのタスク (関数として指定) をオーバーラップして実行できることを確認します (コンパイラによるタスク レベルの並列処理を有効にします)。
- Compute タスクは、さらに小さな計算タスクに分割できます。この結果、パイプライン処理など、さらに最適化が実行されることがあります。LCS と同じ規則が、これらの小さな計算関数にも適用されます。
- 常にローカル メモリを使用して、Compute タスクとの間でデータを送受信します。
- Load ブロックと Store ブロックは、グローバル メモリと Compute ブロック間でできるだけ効率的にデータを移動する役割を果たします。
- 一方で、カーネル内の Compute タスクで指定された (一時的な) シーケンシャルな順序に従って、ストリーミング インターフェイスを介してデータを読み書きする必要があります。
- もう一方では、ソフトウェア アプリケーションにより設定された (空間的) 配置順序に従って、メモリ マップド インターフェイスを介してデータを読み書きする必要があります。
- HLS を使用して適切なハードウェア デザインを構築するには、データ アクセスに関する考え方を変えることが重要です。
- ソフトウェアでは、データがどのように「アクセス」される (アルゴリズムが必要とするデータを引っ張る) かを考えるのが一般的です。
- ハードウェアでは、データがアルゴリズムをどのように「流れる」 (データがアルゴリズムへプッシュされる) かを考える方が効率的です。
- ソフトウェアでは、配列インデックスとデータがアクセスされる場所について考えます。
- ハードウェアでは、ストリームとデータがアクセスされるタイミングをについて考えます。
- グローバル メモリは長いアクセス時間 (DRAM、HBM) を持ち、その帯域幅は限られています (DRAM)。グローバル メモリへのアクセスのオーバーヘッドを削減するには、インターフェイス関数を使用する必要があります。
- 十分に大きい連続したデータ ブロックにアクセスします (AXI バースト転送 の利点を活かします)。
- データに順次アクセスすると、ランダム データや順不同データ (バースト解析がエラーになる) にアクセスするよりも、バーストが大きくなります (データ スループット効率が高くなります)。
- 冗長なアクセスを回避します (帯域幅を維持するため)。
- 多くの場合、Compute タスクで送受信されるデータの順序は、グローバル メモリ内のデータの配置順序とは異なります。
- このような状況では、インターフェイス関数を最適化するために、十分なデータを収集して適切に整理する内部キャッシュ構造を作成し、グローバル メモリ アクセスのオーバーヘッドを最小限に抑えながら、ストリーミング インターフェイスで想定される順序を満たす必要があります。
- データをメモリに保存するさまざまな方法を検討して、データ移動ロジックをシンプルにすることもできます。たとえば、DRAM 内のデータに列優先順でアクセスすると、効率性がかなり劣ることがあります。カーネルに専用のデータ ムーバーをインプリメントするよりも、ソフトウェア内のデータを置き換えて、行優先順で格納した方が良い場合があり、ハードウェア アクセス パターンをかなりシンプルにできます。
- 512 ビット (64 バイト) に設定し、インターフェイスのポート幅 (各 AXI ポートのビット幅) を最大化します。
- ポートのデータ型として、
hls::vector
またはap_(u)int<512>
を使用して、最大バースト長を推論します。インターフェイスで構造体を使用すると、バースト パフォーマンスが低下する可能性があります。 - グローバル メモリへのアクセスはコストがかかるため、より大きなワード サイズにアクセスする方が効率的です。
- インターフェイス ポートが、カーネルにデータを送るパイプのようなものであるとすると、パイプの幅が広いほど、アクセスおよび処理して送信し戻せるデータも多くなります。
- グローバル デバイス メモリから大きなデータ ブロックを転送します。小型の転送を複数実行するよりも、1 つの大型転送を実行する方が効率的です。帯域幅は PCIe のパフォーマンスによって制限されます。DMA テストを実行して、
PCIe®
転送の有効な最大スループットを測定します。通常、読み出しおよび書き込みの範囲は 10 ~ 17 GB/秒です。
- メモリ リソースには、PLRAM (サイズは小さいが最短レイテンシで高速アクセスが可能)、HBM (中程度のサイズで多少のレイテンシあり)、DRAM (サイズは大きいがレイテンシは最長になるので低速アクセス) などが含まれます。
- 読み出しの非同期性を考えると、分散 RAM が高速バッファーには理想的です。読み出し値は、次のクロック サイクルを待たず、すぐに使用できます。また、分散 RAM を使用して小さな ROM を作成することもできます。ただし、分散 RAM は大容量メモリには適しておらず、ブロック RAM または UltraRAM を使用すると、約 128 ビットを超えるメモリのパフォーマンスが向上 (および消費電力が低減) します。
- ポートのデータ型として、
- 同時処理ポートの最適な数、つまり同時処理 AXI (メモリ マップド) ポートの数を決定します。
- Load タスクで、複数の入力データセットを取得して Compute タスクにフィードする必要がある場合は、複数のインターフェイスポートを使用して、このデータに並列でアクセスするように選択できます。
- ただし、データは異なるメモリ バンクに格納しないと、アクセスがシーケンシャルになります。FPGA には最大 4 つの DDR メモリ バンクがあり、HBM チャネルは 32 個あります。
- 複数のプロセスが同じメモリ ポートまたはメモリ バンクにアクセスする場合、アービタにより、これらの同時アクセスを同じメモリ ポートまたはバンクがシーケンシャルにされます。
- 各 AXI ポートの正しいバースト長、つまり最大バースト アクセス長 (要素数) を設定します。
- バースト長を最大 4k バイト転送に相当する長さに設定します。たとえば、512 ビット (64 バイト) の AXI データ幅を使用する場合、バースト長は 64 に設定する必要があります。
- データをバースト転送すると、メモリ アクセスのレイテンシは表示されず、帯域幅の使用およびメモリ コントローラーの効率が改善されます。
- グローバル メモリとの読み出しと書き込みの両方に対して最大長バーストを推論するような方法でアプリケーション コードを記述します。
- AXI ポートが停止する前に維持可能な未処理のメモリ要求の数を設定します。
- 未処理の要求の数を適切に設定すると、システムが複数のメモリ要求を送信してから停止できます。このように要求をパイプライン処理しておくと、追加の BRAM/URAM リソースは必要になりますが、システムがメモリ レイテンシの一部を隠せるようになります。