7

そのため、OpenCL を少しいじって、ホストとデバイス間のメモリ転送速度をテストしてきました。Intel OpenCL SDK を使用し、グラフィックスが統合されたIntel i5 プロセッサで実行していました。次に、ピン留めされたメモリを次のように使用すると、どちらがほぼ 10 倍高速になるかをclEnqueueMapBuffer発見しました。clEnqueueWriteBuffer

int amt = 16*1024*1024;
...
k_a = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(int)*amt, a, NULL);
k_b = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(int)*amt, b, NULL);
k_c = clCreateBuffer(context,CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, sizeof(int)*amt, ret, NULL);

int* map_a = (int*) clEnqueueMapBuffer(c_q, k_a, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
int* map_b = (int*) clEnqueueMapBuffer(c_q, k_b, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
int* map_c = (int*) clEnqueueMapBuffer(c_q, k_c, CL_TRUE, CL_MAP_WRITE, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
clFinish(c_q); 

ここa bで、 とretは 128 ビットで整列された int 配列です。時間は約22.026186 msになりましclEnqueueWriteBuffer たが、コードを

k_a = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, NULL);
k_b = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, NULL);
k_c = clCreateBuffer(context,CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, NULL);

int* map_a = (int*)clEnqueueMapBuffer(c_q, k_a, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
int* map_b = (int*)clEnqueueMapBuffer(c_q, k_b, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
int* map_c = (int*)clEnqueueMapBuffer(c_q, k_c, CL_TRUE, CL_MAP_WRITE, 0, sizeof(int)*amt, 0, NULL, NULL, &error);

/** initiate map_a and map_b **/

時間は91.350065 ミリ秒に増加します

何が問題なのですか?それともまったく問題ですか?

編集:これは、2番目のコードで配列を初期化する方法です:

for (int i = 0; i < amt; i++)
{
    map_a[i] = i;
    map_b[i] = i;
}

確認したところ、map_a と map_bにはプログラムの最後に正しい要素が含まれてますが、map_c にはすべて 0 が含まれています。これは私がしました:

clEnqueueUnmapMemObject(c_q, k_a, map_a, 0, NULL, NULL);
clEnqueueUnmapMemObject(c_q, k_b, map_b, 0, NULL, NULL);
clEnqueueUnmapMemObject(c_q, k_c, map_c, 0, NULL, NULL);

そして私のカーネルはただ

__kernel void test(__global int* a, __global int* b, __global int* c)
{
    int i = get_global_id(0);
    c[i] = a[i] + b[i];
}   
4

2 に答える 2

1

私の理解では、CL_MEM_ALLOC_HOST_PTR は割り当てますが、コピーはしません。コードの 2 番目のブロックは実際にデバイスにデータを取得しますか?

また、clCreateBuffer を CL_MEM_USE_HOST_PTR および CL_MEM_COPY_HOST_PTR と一緒に使用する場合、clEnqueueWrite は必要ありません。バッファーは void *host_ptr が指すメモリを使用して作成されるためです。

OpenCL で「固定された」メモリを使用するには、次のようなプロセスを実行する必要があります。

   int amt = 16*1024*1024;
   int Array[] = new int[amt];
   int Error = 0;

    //Note, since we are using NULL for the data pointer, we HAVE to use CL_MEM_ALLOC_HOST_PTR
    //This allocates memory on the devices
    cl_mem B1 = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, &Error); 

    //Map the Device memory to host memory, aka pinning it
    int *host_ptr = clEnqueueMapBuffer(queue, B1, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, sizeof(int)*amt, 0, NULL, NULL, &Error); 

    //Copy from host memory to pinned host memory which copies to the card automatically`
    memcpy(host_ptr, Array, sizeof(int)*amt); 

    //Call your kernel and everything else and memcpy back the pinned back to host when
    //you are done

編集: プログラムを高速化するためにできる最後のことは、CL_TRUE の代わりに CL_FALSE を使用してメモリの読み取り/書き込みをブロックしないようにすることです。コマンド キューが空になり、すべてのコマンドが処理されるように、データがホストにコピーされる前に必ず clFinish() を呼び出してください。

出典: OpenCL イン アクション

于 2013-07-21T19:40:55.227 に答える
0

フラグを適切に組み合わせることで、両方とも同じメモリを使用するため、「CPU から GPU へ」のコピーが必要ないため、Intel Integrated Graphics で「ゼロ コピー」(つまり非常に高速) のマップ/アンマップを実現できるはずです (それが「統合」の意味です)。メモリに関するインテル OpenCL 最適化ガイドのセクションをお読みください。

于 2013-08-07T02:33:16.207 に答える