インテル® FPGA SDK for OpenCL™プロ・エディション: プログラミング・ガイド

ID 683846
日付 4/01/2019
Public
ドキュメント目次

6.2.2. 異なるメモリータイプ (異種メモリー) 間でのバッファーの分割

FPGAボードのボード・サポート・パッケージでは、異なるメモリー・テクノロジー (DRAMやSRAMなど) で構成されるグローバル・メモリー・スペースを組み立てることが可能です。ボード・サポート・パッケージは、複数のインターフェイスで構成されるそのようなメモリーの1つを、デフォルトのメモリーとして指定します。バッファーはすべてそこにあります。

異種メモリーを使用するには、.clファイルのコードを次のように変更します。

  1. 次のいずれかの方法で、FPGAボードで使用可能なグローバル・メモリー・タイプの名前を確認してください。
    • ボードメーカーの資料を参照する。
    • ボードのカスタム・プラットフォームのboard_spec.xmlファイルで名前を検索する。各グローバル・メモリー・タイプの名前は、global_mem要素のname属性に割り当てられた一意の文字列です。
  2. 特定のグローバル・メモリー・タイプにバッファーを割り当てるようにホストに指示するには、buffer_location("<memory_type>") 属性を挿入します。ここで <memory_type> は、ボードメーカーより提供されているグローバル・メモリー・タイプの名前です。
    __kernel void foo(__global __attribute__((buffer_location("DDR"))) int *x,
                      __global __attribute__((buffer_location("QDR"))) int *y)
    buffer_location属性を指定しない場合、ホストはバッファーをデフォルトのメモリータイプに自動的に割り当てます。デフォルトのメモリータイプを確認するには、ボードメーカーから提供されている資料を参照してください。または、カスタム・プラットフォームのboard_spec.xmlファイルで、最初に定義されているメモリータイプもしくは、属性default=1が割り当てられたメモリータイプを検索します。

    インテルでは、次のようにbuffer_location属性をプリプロセッサー・マクロに定義し、再利用を容易にすることを推奨しています。

    #define QDR\
    __global __attribute__((buffer_location("QDR")))
    								
    #define DDR\
    __global __attribute__((buffer_location("DDR")))
    __kernel void foo (QDR uint * data, DDR uint * lup)
    {
    	//statements
    }							
    重要: カーネル引数をデフォルト以外のメモリーに割り当てる場合 (上記コードであればQDR uint * dataおよびDDR uint * lup)、その引数をconstantキーワードで宣言することはできません。さらに、その引数から派生するポインターでアトミック操作を実行することはできません。

clCreateProgramWithBinary関数を使用しOpenCLランタイムにカーネルをロードすると、デフォルトで、ホストはバッファーをメインメモリーに割り当てます。カーネルの呼び出し中にホストは、カーネル引数にバインドされている異種メモリーバッファーを、メインメモリーに自動的に再配置します。

  1. 異種メモリーバッファーが最初にメインメモリーに割り当てられるのを防ぐには、clCreateBuffer関数を呼び出す際に、CL_MEM_HETEROGENEOUS_INTELFPGAフラグを含めます。また、 clSetKernelArgを使用しcl_memバッファーをbuffer_location属性を使用した引数にまずバインドした後に、そのバッファーに対する読み取りまたは書き込みを実行してください。次に例を示します。
    mem = clCreateBuffer(context, flags|CL_MEM_HETEROGENEOUS_INTELFPGA,  memSize, NULL, &errNum);
    
    clSetKernelArg(kernel, 0, sizeof(cl_mem), &mem);
    clEnqueueWriteBuffer(queue, mem, CL_FALSE, 0, N, 0, NULL, &write_event);
    clEnqueueNDRangeKernel(queue, kernel, 1, NULL, global_work_size, NULL, 0, NULL, &kernel_event);

    例えば次のclCreateBuffer呼び出しは、デフォルト以外のメモリーバンクの、使用可能な最下位メモリー領域にメモリーを割り当てます。

    mem = clCreateBuffer(context,  (CL_MEM_HETEROGENEOUS_INTELFPGA|CL_CHANNEL_1_INTELFPGA), memSize,   NULL,   &errNum);

    clCreateBuffer呼び出しは、カーネル引数で指定した内容に基づき、メモリーを特定のグローバル・メモリー・タイプに割り当てます。メモリータイプにあるメモリー・オブジェクト (cl_mem) が、異なるメモリー・テクノロジーに対応するカーネル引数として設定されている場合、ホストはカーネルをキューする際にそのメモリー・オブジェクトを自動的に移動します。バッファーは複数のメモリー・テクノロジーに関連付けるカーネル引数として渡さないでください。

異種グローバル・メモリー・アクセスの最適化に関する詳細は、 インテル® FPGA SDK for OpenCL™ : ベスト・プラクティス・ガイド異種メモリーバッファーグローバルメモリーの手動分割の章を参照ください。