ホスト コードでの DDR バンクの割り当て - 2020.2 Japanese

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

Document ID
UG1393
Release Date
2021-03-22
Version
2020.2 Japanese
重要: これはオプションであり、次に説明するような特殊な場合にのみ必要となります。

Vitis ツール フローでは、カーネル ポートのメモリへのマップ に説明するように --connectivity.sp オプションを使用すると、カーネル ポートからメモリ バンクへの接続ができます。v++ で生成された xclbin には、XRT でバッファーを適切に割り当てることができるように、カーネル ポートとメモリの接続に関する情報が含まれます。ホスト コードでバッファーが作成されると、XRT は自動的に xclbin カーネルからメモリにバッファーを割り当て、内部でバッファーを管理します。1 つのカーネル ポートが複数のメモリ バンクに接続される場合、XRT は常に番号の小さいバンクから開始します。

ほとんどの場合これで問題ありませんが、場合によっては、ホスト コードでバッファーの場所 (または特殊なプロパティ) を手動で割り当てる必要があります。このため、ザイリンクスOpenCL ベンダー拡張機能には、ホスト コードでのバンク割り当てを管理する CL_MEM_XRT_PTR_XILINX というバッファー拡張機能があります。次の例は、入力および出力バッファーを DDR バンク 0 とバンク 1 に割り当てるのに必要なヘッダー ファイルとコードを示しています。

#include <CL/cl_ext.h>
…
int main(int argc, char** argv) 
{
…
    cl_mem_ext_ptr_t inExt, outExt;  // Declaring two extensions for both buffers
    inExt.flags  = 0|XCL_MEM_TOPOLOGY; // Specify Bank0 Memory for input memory
    outExt.flags = 1|XCL_MEM_TOPOLOGY; // Specify Bank1 Memory for output Memory
    inExt.obj = 0   ; outExt.obj = 0; // Setting Obj and Param to Zero
    inExt.param = 0 ; outExt.param = 0;

    int err;
    //Allocate Buffer in Bank0 of Global Memory for Input Image using Xilinx Extension
    cl_mem buffer_inImage = clCreateBuffer(world.context, CL_MEM_READ_ONLY | CL_MEM_EXT_PTR_XILINX,
            image_size_bytes, &inExt, &err);
    if (err != CL_SUCCESS){
        std::cout << "Error: Failed to allocate device Memory" << std::endl;
        return EXIT_FAILURE;
    }
    //Allocate Buffer in Bank1 of Global Memory for Input Image using Xilinx Extension
    cl_mem buffer_outImage = clCreateBuffer(world.context, CL_MEM_WRITE_ONLY | CL_MEM_EXT_PTR_XILINX,
            image_size_bytes, &outExt, NULL);
    if (err != CL_SUCCESS){
        std::cout << "Error: Failed to allocate device Memory" << std::endl;
        return EXIT_FAILURE;
    }
…
}

cl_mem_ext_ptr_t 拡張ポインターは次のように定義される struct です。

typedef struct{
    unsigned flags;
    void *obj;
    void *param;
  } cl_mem_ext_ptr_t;
  • flags の有効な値は、次のとおりです。
    • XCL_MEM_DDR_BANK0
    • XCL_MEM_DDR_BANK1
    • XCL_MEM_DDR_BANK2
    • XCL_MEM_DDR_BANK3
    • <id> | XCL_MEM_TOPOLOGY
      注記: <id> は xxx.xclbin ファイルの次に生成される xxx.xclbin.info ファイルの [Memory Configuration] セクションから判断されます。xxx.xclbin.info ファイルには、グローバル メモリ (DDR、HBM、PLRAM など) が <id> を示すインデックスと共にリストされます。
  • obj: CL_MEM_USE_HOST_PTR フラグが clCreateBuffer API に渡された場合に CL メモリ バッファーに割り当てられるホスト メモリに関連付けられているポインターです。それ以外の場合は NULL に設定されます。
  • param: 今後の使用のために予約されています。常に 0 または NULL に設定します。

拡張ポインターは、次のような特殊なケースで使用できます。

P2P バッファー
説明と例については、https://xilinx.github.io/XRT/master/html/p2p.html を参照してください
ホスト メモリ バッファー
説明と例については、https://xilinx.github.io/XRT/master/html/sb.html を参照してください
カーネル ポートが複数のバンクに接続される場合、特定のバンクにホスト バッファーを割り当てます。
たとえば、DDR[0:1] のようにします。このユース ケースについては、Vitis チュートリアルのアクセラレーション FPGA アプリケーションの最適化: ブルーム フィルターの例「複数 DDR バンクの使用」を参照してください。

特定のバンクへのホスト バッファーの割り当ての例

前述の 3 番目のケースのように cl_mem_ext_ptr_t を使用する必要があるのは、たとえばホストとカーネルが同時に DDR バンクにアクセスしていて、カーネルとホストがメモリ バンクにピンポン形式でアクセスできるようにデータを分割する場合です。ホストが特定のメモリ バンクに書き込み/ 読み出しをする際に、カーネルは別のバンクから書き込み/読み出しをしているので、これらのホスト/カーネル アクセスが競合したり、パフォーマンスに影響を与えることはありません。このような場合、バッファー割り当てを自分で管理する必要があります。

xclbin のカーネルポートは、DDR バンク 1 およびバンク 2 に接続され、これらのバンクからデータを読み取ることもできます。接続は、Vitis コンパイラが --connectivity.sp オプションを使用してリンクするときにされます。

[connectivity]
sp=runOnfpga_1.input_words:DDR[1:2]

ホスト コードから、input_words データを DDR バンク 1 および 2 に送信することもできます。次のコード例に示すように、2 つのザイリンクス拡張ポインタ (cl_mem_ext_ptr_t) オブジェクトが作成されます。このオブジェクト フラグにより、各バッファーが割り当てられる DDR バンクが決まり、カーネルがアクセスできるようになります。カーネル引数は、連続するカーネル エンキューに対して input_words[0]input_words[1] に設定できます。

#include <CL/cl_ext.h>
…
int main(int argc, char** argv) 
{
cl_mem_ext_ptr_t buffer_words_ext[2];

buffer_words_ext[0].flags = 1 | XCL_MEM_TOPOLOGY; // DDR[1]
buffer_words_ext[0].param = 0;
buffer_words_ext[0].obj   = input_doc_words;
buffer_words_ext[1].flags = 2 | XCL_MEM_TOPOLOGY; // DDR[2]
buffer_words_ext[1].param = 0;
buffer_words_ext[1].obj   = input_doc_words;
…