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/hm.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;
…