使用存储在另一个数组中的数组索引时,Cuda非法内存访问错误

时间:2014-10-01 18:02:05

标签: cuda fortran

我正在使用cuda fortran,我在一个简单的内核中一直在努力解决这个问题而我找不到解决方案。 是不是可以使用存储在数组中的整数值作为另一个数组的索引?

这是一个简单的例子(编辑后也包括主程序):

program test
  use cudafor

  integer:: ncell, i
  integer, allocatable:: values(:)
  integer, allocatable, device :: values_d(:)


  ncell = 10

  allocate(values(ncell), values_d(ncell))

  do i=1,ncell
        values(i) = i
  enddo


  values_d = values


  call multipleindices_kernel<<< ncell/1024+1,1024 >>> (values_d,
 + ncell)

  values = values_d

  write (*,*) values


  end program test

!////////////////////////////////////////////////////

attributes(global) subroutine multipleindices_kernel(valu, ncell)
use cudafor
  implicit none
  integer, value:: ncell   ! ncell = 10
  integer :: valu(ncell)
  integer :: tempind(10)
  integer:: i

  tempind(1)=10
  tempind(2)=3
  tempind(3)=5
  tempind(4)=7
  tempind(5)=9
  tempind(6)=2
  tempind(7)=4
  tempind(8)=6
  tempind(9)=8
  tempind(10)=1

  i = (blockidx%x - 1 ) * blockdim%x + threadidx%x

  if (i .LE. ncell) then
        valu(tempind(i))= 1
  endif


  end subroutine

据我所知,如果tempind数组中有重复的值,则不同的线程可能会访问相同的内存位置进行读取或写入,但事实并非如此。 即使这样,也会出现错误“0:copyout Memcpy(host = 0x303610,dev = 0x3e20000,size = 40)FAILED:77(遇到非法内存访问)。

有没有人知道是否可以使用来自cuda中另一个数组的索引?

经过一些额外的测试后,我注意到问题不是在运行内核本身时发生,而是在将数据传输回CPU时(如果我删除“values = values_d”则不会显示错误)。此外,如果我用值(i)替换内核值(tempind(i))它工作正常,但我想让索引来自一个数组,因为这个测试的目的是进行CFD代码的并行化索引存储的位置。

1 个答案:

答案 0 :(得分:1)

问题似乎是生成的可执行文件没有正确地将变量ncell传递给内核。通过cuda-memcheck运行应用程序表明,1-10之外的线程正在通过分支语句,并且在内核中添加print语句以打印ncell也会给出奇怪的答案。

以前要求所有attributes(global)子例程都必须驻留在模块中。在最近的CUDA Fortran版本中,这个要求似乎已经放宽了(我在编程指南中找不到对它的引用)。我相信模块外部的代码会导致错误。通过在模块中放置multipleindices_kernel并在test中使用该模块,我可以毫无错误地获得正确的答案。代码如下:

module testmod
contains
attributes(global) subroutine multipleindices_kernel(valu, ncell)
  use cudafor
  implicit none
  integer, value:: ncell   ! ncell = 10
  integer :: valu(ncell)
  integer :: tempind(10)
  integer:: i

  tempind(1)=10
  tempind(2)=3
  tempind(3)=5
  tempind(4)=7
  tempind(5)=9
  tempind(6)=2
  tempind(7)=4
  tempind(8)=6
  tempind(9)=8
  tempind(10)=1

  i = (blockidx%x - 1 ) * blockdim%x + threadidx%x

  if (i .LE. ncell) then
        valu(tempind(i))= 1
  endif


  end subroutine
end module testmod

  program test
  use cudafor
  use testmod

  integer:: ncell, i
  integer, allocatable:: values(:)
  integer, allocatable, device :: values_d(:)


  ncell = 10

  allocate(values(ncell), values_d(ncell))

  do i=1,ncell
        values(i) = i
  enddo


  values_d = values


  call multipleindices_kernel<<< ncell/1024+1,1024 >>> (values_d, ncell)

  values = values_d

  write (*,*) values


  end program test

!////////////////////////////////////////////////////