AXI バースト転送 - 2023.2 日本語

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

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

バースト転送の概要

バーストでは、DDR へのメモリ アクセスをまとめることにより、スループット帯域幅を最大にし、レイテンシを最短にします。バーストは、カーネルに対して実行可能な多数の最適化の 1 つです。パフォーマンスは通常 4 ~ 5 倍向上しますが、ほかの最適化 (アクセス幅の拡張、DDR メモリを介した依存性がないようにするなど) の方がパフォーマンスをより大きく向上できます。バーストは、通常 DDR ポートで複数のカーネルからの競合がある場合に使用すると有益です。

Vitis HLS ツールは自動バースト推論をサポートし、自動バースト アクセスを容易にする自動ポート幅拡張など、多くの機能をサポートしてます。自動バースト アクセスが失敗した場合、効率的な解決策は、コードを書き直すか、手動バーストの使用で説明されるように、手動バーストを使用することです。それでもうまくいかない場合は、CACHE プラグマまたは指示子を使用して、AXI4 インターフェイスでキャッシュ メモリを使用するという回避策もあります。

AXI4 プロトコルのバースト機能は、1 回の要求でグローバル メモリとの間でデータのチャンクを読み書きすることにより、load-store 関数のスループットを向上させます。データのサイズが大きいほど、スループットは高くなります。このメトリックは、(転送されるバイト数)* (カーネル周波数/(時間) で計算されます。カーネル インターフェイスの最大ビット幅は 512 ビットであり、カーネルが 300 MHz で動作するようにコンパイルされている場合、理論的には (512* 300 MHz)/1 秒 = ~17 GB/s の DDR を達成できます。

図 1. AXI プロトコル

前の図は、AXI プロトコルの動作を示しています。HLS カーネルは、長さ 8 のバーストの読み出し要求を送信してから、長さ 8 のバーストの書き込み要求を送信します。読み出しレイテンシとは、読み出し要求バーストが送信されてから、バースト内の最初の読み出し要求のデータがカーネルで受信されるまでの時間です。同様に、書き込みレイテンシとは、書き込みバースの最後の書き込みデータが送信されてから、書き込み肯定応答がカーネルで受信されるまでの時間です。読み出し要求は通常最初に送信可能になった時点で送信され、書き込み要求はそのバースト内の各書き込みデータが使用可能になるまでキューに格納されます。

ヒント: この動作は、インターフェイス コンフィギュレーション で説明されるように、syn.interface.m_axi_conservative_mode オプションによって決定され、デフォルトでオンになっています。

バースト転送のセマンティクスを理解するため、次のようなコードを考えます。

for(size_t i = 0; i < size; i++) {
    out[f(i)] = in[f(i)]);
}

Vitis HLS は自動的なバースト最適化を実行します。この最適化では、ループ/関数内のメモリ アクセスをユーザー コードからインテリジェントに集約し、特定サイズのグローバル メモリに対して読み出し/書き込みを実行します。これらの読み出し/書き込みは、グローバル メモリに対する読み出し要求、書き込み要求、書き込み応答に変換されますVitis HLS は、メモリ アクセス パターンに応じて、これらの読み出しおよび書き込み要求をループ境界の外側またはループ本体の内側に自動的に挿入します。Vitis HLS は、これらの要求の配置によって、シーケンシャル バーストとパイプライン バーストの 2 種類のバースト要求を定義します。

バースト セマンティクス

カーネルにバースト解析最適化がマルチパス最適化としてインプリメントされることがありますが、これは関数ベースでインプリメントされます。バーストは、関数に対してのみインプリメントでき、複数の関数をまたがるバーストはサポートされません。バースト最適化は 合成サマリ レポートでレポートされます。バーストを適用できなかったケースもレポートされるので、バースト最適化の向上に役立ちます。

まず、HLS コンパイラで関数の基本ブロック内でメモリ アクセス (関数内の文のシーケンシャル セットでのメモリ アクセスなど) が検索されます。バーストの前提条件が満たされているとすると、これらの基本ブロックで推論された各バーストは「シーケンシャル バースト」と呼ばれます。基本ブロックは自動的にスキャンされ、最も長いアクセスのシーケンスが 1 つのシーケンシャル バーストにビルドされます。

この後ループが検索され、「パイプライン バースト」と呼ばれるバーストの推論が試みられます。パイプライン バーストは、複数のループ反復の読み出し/書き込みシーケンスです。ループ帰納変数とループのトリップカウントが解析され、バースト長の推論が試みられます。解析がうまくいくと、ループの各反復の読み出し/書き込みシーケンスが 1 つの長いパイプライン バーストに接続されます。今日のコンパイラではパイプライン バーストまたはシーケンシャル バーストが自動推論されますが、特定タイプのバーストを要求する方法はないので、ツールでパイプライン バーストまたはシーケンシャル バーストが推論されるように、コードを記述する必要があります。

パイプライン バースト

パイプライン バーストは、大量のデータを読み書きしたり、1 回の要求で最大量のデータを読み書きしたりすることで、関数のスループットを向上させます。パイプライン バーストの利点は、将来の要求 (i+1) が現在の要求 (i) の終了を待つ必要がないことです。これは、読み出し要求、書き込み要求、および書き込み応答がループ本体の外側にあり、次のコード例に示すように、要求をできるだけ早く実行するからです。これにより、ループ全体の境界の読み出し/書き込みにかかる時間が短縮されるため、関数のスループットが大幅に向上します。

rb = ReadReq(i, size);
wb = WriteReq(i, size);
for(size_t i = 0; i < size; i++) { 
  Write(wb, i) = f(Read(rb, i)); 
}
WriteResp(wb);
図 2. パイプライン バースト

コンパイラでループの帰納変数 (i) とトリップカウント (size) からバースト長を推定できる場合は、上記のパイプライン バースト コードの例に示すような 1 つの大きなパイプライン バーストが推論され、ReadReqWriteReq、および WriteResp 呼び出しがループ外に移動します。つまり、すべてのループ反復の読み出し要求が 1 つの読み出し要求にまとめられ、すべての書き込み要求が 1 つの書き込み要求にまとめられます。すべての読み出し要求は通常即送信されますが、書き込み要求はデータが使用可能になった後にのみ送信されます。

この場合、各ループ反復の読み出しおよび書き込み要求が 1 つの読み出しまたは書き込み要求にまとめられます。ただし、バースト転送の前提条件と制限 に示すバーストの前提条件のいずれかが満たされていない場合、パイプライン バーストの代わりにシーケンシャル バーストが推論され、次のシーケンシャル バースト コードの例に示すように、ReadReqWriteReg および WriteResp が読み出し/書き込みアクセスと共にバースト最適化されます。

シーケンシャル バースト

シーケンシャル バーストは、次のコード例に示すように、読み出し要求、書き込み要求、書き込み応答がループ本体内にある小さなデータ サイズで構成されます。

for(size_t i = 0; i < size; i++) {
    rb = ReadReq(i, 1);
    wb = WriteReq(i, 1);
    Write(wb, i) = f(Read(rb, i));
    WriteResp(wb);
}

シーケンシャル バーストの欠点は、将来の要求 (i+1) が現在の要求 (i) の終了に依存するところです。これは、その要求が読み出し要求、書き込み要求、書き込み応答を完了するまで待機するためです。これにより、次の図に示すように、要求間にギャップが生じます。

図 3. シーケンシャル バースト

シーケンシャル バーストは、小さなデータ サイズを複数回読み書きしてループ境界を補正するので、パイプライン バーストほど効果的ではありません。これはスループットに大きな影響を与えますが、それでもシーケンシャル バーストはバーストなしよりも優れています。Vitis HLS は、コードが バースト転送の前提条件と制限 に準拠していない場合、このバースト手法を使用します。

ヒント: バースト要求のサイズは、ユーザーの指定するサイズの複数の要求にさらに分割でき、INTERFACE プラグマまたは指示子の max_read_burst_length および max_write_burst_length を使用して制御されます (AXI4 バースト ビヘイビアーを制御するオプション を参照)。