尝试从gpu复制数据时CudaAPIError 716

时间:2018-04-20 12:02:55

标签: python cuda gpu numba

我正在学习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()

1 个答案:

答案 0 :(得分:2)

这里有几点要做。

首先,您看到的错误源是来自内核执行的运行时错误。如果我经营一个hacky" fixed"使用cuda-memcheck的代码版本,我看到了:

$ cuda-memcheck python ./error.py 
========= CUDA-MEMCHECK
========= Invalid __global__ read of size 8
=========     at 0x00000178 in cudapy::__main__::CalculatePreValues$241(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)')

消除越界索引。