首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对于大于8000项且有错误的数组,代码从不运行。

对于大于8000项且有错误的数组,代码从不运行。
EN

Stack Overflow用户
提问于 2021-07-07 20:47:39
回答 2查看 65关注 0票数 0

我刚开始用OpenCL构建并行计算代码。

据我所知,从CPU端(主机)生成的数据通过缓冲区(clCreateBuffer -> clEnqueueWriteBuffer -> clSetKernelArg,然后由设备处理)进行传输。

我主要要处理的阵列(或矩阵)的大,双精度。

但是,我意识到,对于有错误的大于8000项的数组,代码永远不会运行。(这是有意义的,因为64 is等于8000倍的精度数字。)

错误码为-6 (CL_OUT_OF_HOST_MEMORY)或-31 (CL_INVALID_VALUE)。

还有一件事,当我将参数设置为二维数组时,我可以将大小设置为8000 x 8000。

到目前为止,我猜想对于一维数组来说,双精度的最大数据大小是8000 (64 2D ),但是我不知道2D或3D数组会发生什么。

  1. 还有其他方法来传输大于64 Is的数据吗?

  1. 如果我在数据传输中对OpenCL设置做错了什么,会推荐什么呢?
EN

回答 2

Stack Overflow用户

发布于 2021-07-07 21:39:14

您可以在OpenCL中执行更大的数组,因为内存是可以保存的。例如,在CFD应用程序中,我通常使用20亿个浮动的线性4D阵列。

数组只需要一维;如果有2D或3D数组,则将它们线性化,例如,对于2D->1D坐标使用n=x+y*size_x。一些旧设备只允许设备内存大小的1/4数组。然而,现代设备通常对OpenCL规范有一个扩展,以启用更大的缓冲区。

下面是关于OpenCL C绑定的快速视图:

  1. clCreateBuffer在设备端分配内存(GPU的视频存储器,CPU的RAM )。缓冲区可以是主机/设备内存允许的那么大,或者在一些旧设备上,1/4的设备memory.
  2. clEnqueueWriteBuffer将内存通过PCIe从RAM复制到视频存储器。CPU和GPU侧缓冲区都必须事先分配。传输大小没有限制;它可以和整个缓冲区一样大,或者只有一个buffer.
  3. clSetKernelArg的子范围将GPU缓冲区链接到内核的输入参数,因此它知道哪个内核参数对应于哪个缓冲区。确保缓冲区和内核参数的数据类型匹配,因为如果它们不匹配,则不会得到错误。还要确保内核参数匹配的顺序。

在您的例子中,有几个可能导致错误的原因:

  1. 在计算数组大小时可能有整数溢出。在本例中,使用64位整数来计算数组,size/indices.
  2. You内存不足,因为其他缓冲区已经占用了太多内存。做一些簿记以跟踪总(视频)内存utilization.
  3. You选择了错误的设备,例如集成图形而不是专用GPU,在这种情况下可用内存要少得多,最终导致原因2.

为了给你一个更明确的答案,请提供一些更多的细节:

  • 您使用什么硬件?
  • 显示了如何分配设备内存的代码片段。

更新

我在您的代码中看到了一些错误:

  • ( clCreateBufferclEnqueueWriteBuffer中的length参数)需要数组a的字节数。如果adouble类型,那么这是a_length*sizeof(double),其中a_length是数组a中的元素数。sizeof(double)返回一个double数字的字节数,即8。因此,长度参数是数组中元素数的8字节。对于多个标志,
  • 通常使用按位或|代替+。这里不应该是一个问题,但是unconvenional.
  • You有"0_8“作为缓冲区偏移量。这需要为零(0).

代码语言:javascript
复制
const int a_length = 8000;
double* a = new double[a_length];

bfr(0) = clCreateBuffer(context, CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR, a_length*sizeof(double), c_loc(a), err);
if(err.ne.0) stop "Couldn't create a buffer";
err = clEnqueueWriteBuffer(queue, bfr(0), CL_TRUE, 0, a_length*sizeof(double), c_loc(a), 0, C_NULL_PTR, C_NULL_PTR);

err = clSetKernelArg(kernel, 0, sizeof(bfr(0)), C_LOC(bfr(0)));
  print*, err;
  if(err.ne.0) {
     print *,  "clSetKernelArg kernel"
     print*, err
     stop
  }
票数 0
EN

Stack Overflow用户

发布于 2021-07-12 09:56:38

我很感激你的好意。

我使用的硬件是特斯拉V100,它安装在我校的高性能计算机集群上。

下面是我正在测试数据传输的代码片段的一部分。

代码语言:javascript
复制
      bfr(0) = clCreateBuffer(context,
 &     CL_MEM_READ_WRITE + CL_MEM_COPY_HOST_PTR,
 &     sizeof(a), c_loc(a), err);

  if(err.ne.0) stop "Couldn't create a buffer";
 
  err=clEnqueueWriteBuffer(queue,bfr(0),CL_TRUE,0_8,
 &     sizeof(a),c_loc(a),0,C_NULL_PTR,C_NULL_PTR)

err = clSetKernelArg(kernel, 0,
 &     sizeof(bfr(0)), C_LOC(bfr(0)))
  print*, err
  if(err.ne.0)then
     print *,  "clSetKernelArg kernel"
     print*, err
     stop
  endif

代码由Fortran使用clfortran模块构建。

再次感谢你的回答。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68292811

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档