【问题标题】:CudaAPIError 716 when trying to copy data from gpu尝试从 gpu 复制数据时出现 CudaAPIError 716
【发布时间】:2018-10-01 03:31:26
【问题描述】:

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

【问题讨论】:

  • 内核无法编译,因为ke 没有在任何地方定义。而且您看到的错误将由内核中的运行时错误引起,您能修复它吗?
  • 这是一个错误的线程检查:if i > ecc.shape[0]: return,它应该是if i >= ecc.shape[0]: return。在这种情况下,numba cuda 使用从零开始的索引。但是,您应该提供minimal reproducible example
  • @talonmies 你是对的!但是,我在削减代码以找出问题(并发布到此处)时犯了这个错误,在我的原始代码中我没有这个错误。修复此错误后,代码仍然失败并出现相同的错误!
  • minimal reproducible example 的请求不是您的整个代码的请求。这是一个最小示例的请求。删除任何不必要的东西。您的代码应该编译并运行并显示问题。但是,您在主机代码中初始化数据的确切方式不太可能对该内核产生任何影响。例如,只需使用np.ones() 创建您的数组。我怀疑这会很重要。再次阅读 MCVE 链接。它已经回答了您关于该做什么的问题。
  • 当前提供的 CW 答案已更新以反映这一点。如果您愿意,欢迎您接受。

标签: python cuda gpu numba


【解决方案1】:

这里有几点需要说明。

首先,您看到的错误来源是来自内核执行的运行时错误。如果我使用 cuda-memcheck 运行你的代码的 hacky “固定”版本,我会看到:

$ 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)')

消除越界索引。

【讨论】:

    猜你喜欢
    • 2016-05-30
    • 1970-01-01
    • 2017-08-16
    • 1970-01-01
    • 2016-07-08
    • 1970-01-01
    • 2020-09-11
    • 1970-01-01
    • 2010-11-15
    相关资源
    最近更新 更多