尝试从 gpu 复制数据时出现 CudaAPIError 716
CudaAPIError 716 when trying to copy data from gpu
我正在学习 Numba 和 CUDA Python。我一直在关注一组 youtube tutorials 并且(我相信)理解了其中的原则。我的问题是从我的 GPU 复制计算值。我使用以下行来执行此操作:
aVals = retVal.copy_to_host()
我也试过使用这条线:
retVal.copy_to_host( aVals[:] )
两者都不起作用,并且都给出相同的错误:
numba.cuda.cudadrv.driver.CudaAPIError: [716] Call to cuMemcpyDtoH results in UNKNOWN_CUDA_ERROR
我有理由相信上面几行是问题所在,就好像我注释掉了代码运行没有错误的那一行一样。将数组从 GPU 复制到 CPU 时,我忽略了一些潜在问题吗?我是不是把数组搞砸了?
我的代码中有很多乱七八糟的地方,但这是一个简单的版本:
import numpy as np
import time
from math import sin, cos, tan, sqrt, pi, floor
from numba import vectorize, cuda
@cuda.jit('void(double[:],double[:],double[:],double)')
def CalculatePreValues(retVal,ecc, incl, ke):
i= cuda.grid(1)
if i >= ecc.shape[0]:
return
retVal[i] = (ke/ecc[i])**(2/3)
def main():
eccen = np.ones(num_lines, dtype=np.float32)
inclin = np.ones(num_lines, dtype=np.float32)
ke = 0.0743669161
aVals = np.zeros(eccen.shape[0])
start = time.time()
retVal = cuda.device_array(aVals.shape[0])
ecc = cuda.to_device(eccen)
inc = cuda.to_device(inclin)
threadsPerBlock = 256
numBlocks = int((ecc.shape[0]+threadsPerBlock-1)/threadsPerBlock)
CalculatePreValues[numBlocks, threadsPerBlock](retVal,ecc,inc)
aVals = retVal.copy_to_host()
preCalcTime = time.time() - start
print ("Precalculation took % seconds" % preCalcTime)
print (aVals.shape[0])
if __name__=='__main__':
main()
这里有几点要说明。
首先,您看到的错误来源是来自内核执行的 运行时间错误。如果我使用 cuda-memcheck 运行 一个 hacky "fixed" 版本的代码,我看到这个:
$ cuda-memcheck python ./error.py
========= CUDA-MEMCHECK
========= Invalid __global__ read of size 8
========= at 0x00000178 in cudapy::__main__::CalculatePreValues1(Array<double, int=1, A, mutable, aligned>, Array<double, int=1, A, mutable, aligned>, Array<double, int=1, A, mutable, aligned>)
========= by thread (255,0,0) in block (482,0,0)
========= Address 0x7061317f8 is out of bounds
原因是您内核中的边界检查被破坏了:
if i > ecc.shape[0]:
return
应该是
if i >= ecc.shape[0]:
return
当问题更新为包含 MCVE 时,很明显还有另一个问题。内核签名为所有数组指定 double
:
@cuda.jit('void(double[:],double[:],double[:],double)')
^^^^^^ ^^^^^^ ^^^^^^
但创建的数组类型实际上是 float
(即 np.float32
):
eccen = np.ones(num_lines, dtype=np.float32)
inclin = np.ones(num_lines, dtype=np.float32)
^^^^^^^^^^
这是不匹配的。使用 double
索引对数组进行索引,当仅使用 float
值创建数组时,可能会创建越界索引。
解决方法是将创建的数组转换为dtype=np.float64
,或者将签名中的数组转换为float
:
@cuda.jit('void(float[:],float[:],float[:],double)')
消除越界索引。
我正在学习 Numba 和 CUDA Python。我一直在关注一组 youtube tutorials 并且(我相信)理解了其中的原则。我的问题是从我的 GPU 复制计算值。我使用以下行来执行此操作:
aVals = retVal.copy_to_host()
我也试过使用这条线:
retVal.copy_to_host( aVals[:] )
两者都不起作用,并且都给出相同的错误:
numba.cuda.cudadrv.driver.CudaAPIError: [716] Call to cuMemcpyDtoH results in UNKNOWN_CUDA_ERROR
我有理由相信上面几行是问题所在,就好像我注释掉了代码运行没有错误的那一行一样。将数组从 GPU 复制到 CPU 时,我忽略了一些潜在问题吗?我是不是把数组搞砸了?
我的代码中有很多乱七八糟的地方,但这是一个简单的版本:
import numpy as np
import time
from math import sin, cos, tan, sqrt, pi, floor
from numba import vectorize, cuda
@cuda.jit('void(double[:],double[:],double[:],double)')
def CalculatePreValues(retVal,ecc, incl, ke):
i= cuda.grid(1)
if i >= ecc.shape[0]:
return
retVal[i] = (ke/ecc[i])**(2/3)
def main():
eccen = np.ones(num_lines, dtype=np.float32)
inclin = np.ones(num_lines, dtype=np.float32)
ke = 0.0743669161
aVals = np.zeros(eccen.shape[0])
start = time.time()
retVal = cuda.device_array(aVals.shape[0])
ecc = cuda.to_device(eccen)
inc = cuda.to_device(inclin)
threadsPerBlock = 256
numBlocks = int((ecc.shape[0]+threadsPerBlock-1)/threadsPerBlock)
CalculatePreValues[numBlocks, threadsPerBlock](retVal,ecc,inc)
aVals = retVal.copy_to_host()
preCalcTime = time.time() - start
print ("Precalculation took % seconds" % preCalcTime)
print (aVals.shape[0])
if __name__=='__main__':
main()
这里有几点要说明。
首先,您看到的错误来源是来自内核执行的 运行时间错误。如果我使用 cuda-memcheck 运行 一个 hacky "fixed" 版本的代码,我看到这个:
$ cuda-memcheck python ./error.py
========= CUDA-MEMCHECK
========= Invalid __global__ read of size 8
========= at 0x00000178 in cudapy::__main__::CalculatePreValues1(Array<double, int=1, A, mutable, aligned>, Array<double, int=1, A, mutable, aligned>, Array<double, int=1, A, mutable, aligned>)
========= by thread (255,0,0) in block (482,0,0)
========= Address 0x7061317f8 is out of bounds
原因是您内核中的边界检查被破坏了:
if i > ecc.shape[0]:
return
应该是
if i >= ecc.shape[0]:
return
当问题更新为包含 MCVE 时,很明显还有另一个问题。内核签名为所有数组指定 double
:
@cuda.jit('void(double[:],double[:],double[:],double)')
^^^^^^ ^^^^^^ ^^^^^^
但创建的数组类型实际上是 float
(即 np.float32
):
eccen = np.ones(num_lines, dtype=np.float32)
inclin = np.ones(num_lines, dtype=np.float32)
^^^^^^^^^^
这是不匹配的。使用 double
索引对数组进行索引,当仅使用 float
值创建数组时,可能会创建越界索引。
解决方法是将创建的数组转换为dtype=np.float64
,或者将签名中的数组转换为float
:
@cuda.jit('void(float[:],float[:],float[:],double)')
消除越界索引。