Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Altera SDK for OpenCL解体新書 : ホストとデバイスの関係

1,483 views

Published on

Altera SDK for OpenCL解体新書シリーズ
ホストとデバイスの関係を説明しています。
PCIeデバイスとSoCデバイスについて説明しています。

Published in: Devices & Hardware
  • Be the first to comment

Altera SDK for OpenCL解体新書 : ホストとデバイスの関係

  1. 1. Altera SDK for OpenCL解体新書 ホストとデバイスの関係 2016.06.12(金) @Vengineer
  2. 2. ホストとデバイスの関係(PCIeデバイス) PCIeデバイスの場合は、下記のような構成になる CPU ホスト側の メモリ デバイス側の メモリ Kernel−A Kernel−B Kernel−C DMA PCIe PCIe DMA
  3. 3. Altera SDK for OpenCLでのBSPとは? CPU ホスト側の メモリ Kernel−A Kernel−B Kernel−C DMA PCIe PCIe DMABSPに相当する部分 デバイス側の メモリ MIF
  4. 4. 生成されるHDLコード CPU ホスト側の メモリ デバイス側の メモリ Kernel−A Kernel−B Kernel−C DMA PCIe PCIe DMAaocが生成するHDLコード MIF
  5. 5. 例題:vector addition https://www.olcf.ornl.gov/tutorials/opencl-vector-addition/ double a[N], b[N], c[N]; vector_add( a, b, c, N ); void vector_add( double* a, double* b, double* c, const unsigned int n ) { for( unsigned int i=0 ; i<n ; i++ ) c[i] = a[i] + b[i]; }
  6. 6. デバイス側のOpenCLコード const char *kernelSource = #pragma OPENCL EXTENSION cl_khr_fp64 : enable _kernel void vecAdd(__global double *a, __global double *b,              __global double *c, const unsigned int n) { //Get our global thread ID int id = get_global_id(0); //Make sure we do not go out of bounds if (id < n) c[id] = a[id] + b[id]; }
  7. 7. ホスト側のCコード(メモリの割当) h_a = (double*)malloc(bytes); h_b = (double*)malloc(bytes); h_c = (double*)malloc(bytes); d_a = clCreateBuffer(context, CL_MEM_READ_ONLY , bytes, NULL, NULL); d_b = clCreateBuffer(context, CL_MEM_READ_ONLY , bytes, NULL, NULL); d_c = clCreateBuffer(context, CL_MEM_WRITE_ONLY , bytes, NULL, NULL);
  8. 8. ホスト側のCコード(実行部) err = clEnqueueWriteBuffer(queue, d_a, CL_TRUE, 0, bytes, h_a, 0, NULL, NULL); err |= clEnqueueWriteBuffer(queue, d_b, CL_TRUE, 0, bytes, h_b, 0, NULL, NULL); err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &d_a); err |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &d_b); err |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &d_c); err |= clSetKernelArg(kernel, 3, sizeof(unsigned int), &n); err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &globalSize, &localSize, 0, NULL, NULL); clFinish(queue);
  9. 9. ホスト側のCコード(メモリの開放) clReleaseMemObject(d_a); clReleaseMemObject(d_b); clReleaseMemObject(d_c); free(h_a); free(h_b); free(h_c);
  10. 10. 処理フロー 1) ホスト側のメモリからデバイス側のメモリにデータを移動 clEnqueueWriteBuffer 2) カーネルへのパラメータ設定   clSetKernelArg 3) カーネルを実行 clEnqueueTask / clEnqueuNDRangeKernel 4) カーネルの終了待ち clFinish 5) デバイス側のメモリからホスト側のメモリにデータを移動   clEnqueueReadBuffer
  11. 11. clEnqueuWriteBuffer ホスト側のメモリからデバイス側のメモリへデータを移動する CPU ホスト側の メモリ デバイス側の メモリ Kernel−B DMA PCIe PCIe DMA
  12. 12. clSetKernelArg カーネルへのパラメータ設定 CPU ホスト側の メモリ デバイス側の メモリ Kernel−B DMA PCIe PCIe DMA
  13. 13. clEnqueuTask / clEnqueueNDRageKernel カーネルの実行 CPU ホスト側の メモリ デバイス側の メモリ Kernel−B DMA PCIe PCIe DMA
  14. 14. clFinish カーネルの終了待ち CPU ホスト側の メモリ デバイス側の メモリ Kernel−B DMA PCIe PCIe DMA
  15. 15. clEnqueuReadBuffer デバイス側のメモリからホスト側のメモリへデータを移動する CPU ホスト側の メモリ デバイス側の メモリ Kernel−B DMA PCIe PCIe DMA
  16. 16. 実行時間 CPUの実行時間に比べて、FPGAの実行時間が短くならないと FPGAでのアクセレーションは意味が無い! FPGAの実行時間 = 1) + 2) + 3) + 4) + 5)  1) ホスト側のメモリからデバイス側のメモリにデータを移動  2) カーネルへのパラメータ設定  3) カーネルを実行  4) カーネルの終了待ち  5) デバイス側のメモリからホスト側のメモリにデータを移動
  17. 17. ホストとデバイスの関係(SoCデバイス) SoCデバイスの場合は、下記のような構成になる CPU ホスト側の メモリ Kernel−A Kernel−B Kernel−C PCIeデバイスでは必要だった、 データ移動のためのDMAがない
  18. 18. ホスト側のCコード(メモリの割当) cl_mem d_a = clCreateBuffer(context,CL_MEM_ALLOC_HOST_PTR, bytes, NULL, NULL); cl_mem d_b = clCreateBuffer(context,CL_MEM_ALLOC_HOST_PTR, bytes, NULL, NULL); cl_mem d_c = clCreateBuffer(context,CL_MEM_ALLOC_HOST_PTR, bytes, NULL, NULL); // clEnqueuWriteBuffer/clEnqueueReadBufferの代わりに clEnqueueMapBufferが必要(ホスト側のメモリをマップする) double *h_a = (double*)clEnqueueMapBuffer (queue, d_a, CL_TRUE, CL_MAP_READ, 0, bytes, 0, NULL, NULL ); double *h_b = (double*)clEnqueueMapBuffer (queue, d_b, CL_TRUE, CL_MAP_READ, 0, bytes, 0, NULL, NULL ); double *h_c = (double*)clEnqueueMapBuffer (queue, d_c, CL_TRUE, CL_MAP_WRITE, 0, bytes, 0, NULL, NULL );
  19. 19. ホスト側のCコード(実行部) err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &d_a); err |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &d_b); err |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &d_c); err |= clSetKernelArg(kernel, 3, sizeof(unsigned int), &n); err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &globalSize, &localSize, 0, NULL, NULL); clFinish(queue);
  20. 20. ホスト側のCコード(メモリの開放) // clEnqueueUnMapMemObjectが必要 clEnqueueUnmapMemObject(queue, d_a, h_a, 0, NULL, NULL ); clEnqueueUnmapMemObject(queue, d_b, h_b, 0, NULL, NULL ); clEnqueueUnmapMemObject(queue, d_c, h_c, 0, NULL, NULL ); clReleaseMemObject(d_a); clReleaseMemObject(d_b); clReleaseMemObject(d_c); // ホスト側のメモリ開放は必要なし
  21. 21. メモリ割当の違い PCIeデバイス  ホスト側のメモリ割当  デバイス側のメモリ割当   ....  デバイス側のメモリ開放  ホスト側のメモリ開放 SoCデバイス  デバイス側のメモリ割当  ホスト側のメモリマッピング   ....  ホスト側のメモリアンマッピング  デバイス側のメモリ開放
  22. 22. SoCデバイスでは、CMAを使う CPU ホスト側の メモリ Kernel−A Kernel−B Kernel−C ホスト側のメモリの一部を デバイス側のメモリとして使用し、 CPU側からアクセスできるようにマップする Linuxをブートするときに、 引数として、cma=128M のようにして 事前に割り当てる CMA(Continuous Memory Allocator) ただし、CPUからは非キャッシュ領域 参考資料)、https://aelseb.wordpress.com/2015/04/11/contiguous-memory-on-arm-and-cache- coherency/
  23. 23. 実行時間 CPUの実行時間に比べて、FPGAの実行時間が短くならないと FPGAでのアクセレーションは意味が無い! FPGAの実行時間 = 1) + 2) + 3) + 4) + 5)  1) CPUがCMA領域(非キャッシュ領域)のメモリにデータを書き込む  2) カーネルへのパラメータ設定  3) カーネルを実行  4) カーネルの終了待ち  5) CPUがCMA領域(非キャッシュ領域)のメモリからデータを読み込む
  24. 24. おしまい

×