无法弄清楚为什么我得到Numba CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES

时间:2019-02-14 17:15:25

标签: python memory cuda nvidia numba

我花了两天的时间来弄清楚为什么我在Numba Cuda程序中遇到资源不足的错误。

我的问题: 当我将代码从让一个线程处理一个有效的单个矩阵元素更改为让一个线程对整个列进行处理(例如,矩阵乘法)时,就会发生错误。由于矩阵都适合内存,而不管我采用哪种方式,而且由于我不使用任何共享内存,因此我无法弄清楚我在哪里消耗更多的资源。如果有什么事情发生,那么遍历该列的内容似乎会更少而不是更多资源。

这是内核的两个版本

# h,n, u, v f and out are NxM scale matricies where N~1000 M~10000. 
def cuda_onethread_per_element (h, n, u, v, f, dx, dy, out):
   gj,gi = cuda.grid(2) 
   gj,gi = sj,si 
      if (gj < out_u.shape[1]-1):  # discard threads beyond last index.
            out[gi,gj] =calc(gi,gj,h, n, u, v, f, dx, dy)

def cuda_1000_elements_per_thread(h, n, u, v, f, dx, dy, out):
   gj,gi = cuda.grid(2) 
      for gi in range(out.shape[0]-1):   # this loop is the change
         if (gj < out_u.shape[1]-1):
            out[gi,gj] =calc(gi,gj,h, n, u, v, f, dx, dy)

会发生什么 当矩阵大小通常为1000x10000到1000x20000,并且开始占满GPU的一半时,第二个失败。

Traceback (most recent call last):
  File "testerr.py", line 105, in <module>
    testit((1,1),(1,1001),cu_u_driver_global_funcs_col)
  File "testerr.py", line 102, in testit
    cu_u_driver[blockspergrid,threadsperblock](h1, n1, u1, v1, f1, dx, dy, out_u1)
  File "/home/rrs/anaconda3/envs/shallowwater/lib/python3.7/site-packages/numba/cuda/compiler.py", line 497, in __call__
    sharedmem=self.sharedmem)
  File "/home/rrs/anaconda3/envs/shallowwater/lib/python3.7/site-packages/numba/cuda/compiler.py", line 571, in _kernel_call
    cu_func(*kernelargs)
  File "/home/rrs/anaconda3/envs/shallowwater/lib/python3.7/site-packages/numba/cuda/cudadrv/driver.py", line 1514, in __call__
    self.sharedmem, streamhandle, args)
  File "/home/rrs/anaconda3/envs/shallowwater/lib/python3.7/site-packages/numba/cuda/cudadrv/driver.py", line 1558, in launch_kernel
    None)
  File "/home/rrs/anaconda3/envs/shallowwater/lib/python3.7/site-packages/numba/cuda/cudadrv/driver.py", line 290, in safe_cuda_api_call
    self._check_error(fname, retcode)
  File "/home/rrs/anaconda3/envs/shallowwater/lib/python3.7/site-packages/numba/cuda/cudadrv/driver.py", line 325, in _check_error
    raise CudaAPIError(retcode, msg)
numba.cuda.cudadrv.driver.CudaAPIError: [701] Call to cuLaunchKernel results in CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES

如果我在Cuda GPU simmulator中运行它,而仅在RTX2070 GPU上运行,则不会收到任何错误消息

代码应如何工作 第一个只用一个线程填充一个矩阵元素,因此它需要一个网格以块覆盖整个矩阵。第二个只需要一个块来覆盖整个矩阵,因为它在每个线程中循环10,000次,每个线程处理1000列中的一个。

回归 这些代码在逻辑上似乎是一致的:当代码工作时,这两种方法会产生相同的数值结果。没有Nans或Infs。直到达到资源限制,才更改数组大小或块大小不会产生任何错误或数字上不同的结果。

两个代码在小型矩阵上均可正常运行

线索?  奇怪的是,即使在使用大型矩阵时,当我减少计算中的数值计算数量时,这两个代码也会运行。

如果我改变了以小额调用计算的复杂性,我会找到一个不会失败的地方。在故障空间的这个边界点,故障的可重复性消失了-我猜测这可能与操作系统正在使用的GPU的其他次要用途有关。但是,由于这种情况已经持续了好几天,因此没有系统或大量使用GPU,并且只有10%的内存与其他进程捆绑在一起才能运行显示。代码运行时,NVIDI-SMI报告大约使用了卡上8GB内存的2/3。

关于可能导致此问题的想法:  我相信第二种方法只有一个大小为1000到1024的块只能在一个SM上运行,并且第一种方法可以在需要时扩展网格。如果正在使用大量共享内存,那可能很重要,但是我的代码没有使用任何共享内存。只是全局内存和局部变量。
我有一种猜测,我也有点怀疑,那就是Numba可能正在展开循环并内联计算。如果一个人荒谬地展开所有10,000个循环并内联所有计算,那么也许,也许,最终将有30,000个局部变量。但这太疯狂了。而且我认为矩阵乘法代码会失败,这是真的。

更可能的错误是我犯了一些愚蠢的错误。但我找不到它。而且我已经用很多方法重新编码,以尝试稍微摇晃树并暴露出错误。

此处是可执行代码的完整版本

import numpy as np
import time
import numba as nb
import math
sqrt = math.sqrt
from numba import cuda

device_ii_compiler = cuda.jit('float32(int32,int32,float32[:,:], float32[:,:], float32[:,:],float32[:,:],float32[:,:],float32,float32)',device=True,inline=False) 

compiler = cuda.jit('void(float32[:,:], float32[:,:], float32[:,:],float32[:,:],float32[:,:],float32,float32,float32[:,:])' ,inline=False)        
def compileit (fn,blockdim=None,border=(0,0)):
    name = fn.__name__
    fc = compiler(fn)
    fc.__name__ = name+'cuda'
    fc.BLOCKDIM = blockdim
    fc.BORDER = border
    return fc

def dudt2_dummy_ret_py(i,j,h, n, f, u, v, dx, dy) :
    p5 = np.float32(0.5)
    last_v_n_i = (v[2,j]+v[2,5])*p5
    v_n = (v[i,j]+v[i,5])*p5  # stradles n[i,j]
    coriolis_u = (f[99,j]*last_v_n_i+f[i,j]*v_n)*p5 # coriolis force F is n-centered
    return coriolis_u

cuda_dudt2_dummy_ret=device_ii_compiler(dudt2_dummy_ret_py)

def cu_u_driver_global_funcs_col_py(h, n, u, v, f, dx, dy, out_u):
    sj,si  = cuda.grid(2)  # cuda.x cuda.y skow,fast
    gj = sj
    for gi in range(1, out_u.shape[0]-2):    
        if  (gj < out_u.shape[1]-2) and gj>0 :

                 tmp = cuda_dudt2_dummy_ret(gi,gj,h, n, f, u, v, dx, dy) #
                 # now I just add on some more dummy calucaltions to titrate the 
                 # place where the error gets tripped.  removing the
                 # following lines removes the error.  And the number
                 # of these additional calcs I need to trigger the error
                 # depends on the array size

                 tmp += sqrt(abs(np.float32(tmp)*dy+np.float32(gj)*dx))  #  comment or un comment this line
                 tmp += sqrt(abs(np.float32(gi)*dx+np.float32(gj)*dx))  #  comment or un comment this line
#                  tmp += sqrt(abs(np.float32(tmp)*dy+np.float32(gj)*dx))  #  comment or un comment this line
#                  tmp += sqrt(abs(np.float32(gi)*dx+np.float32(gj)*dx))  #  comment or un comment this line
#                  tmp += sqrt(abs(np.float32(tmp)*dy+np.float32(gj)*dx))  #  comment or un comment this line
#                  tmp += sqrt(abs(np.float32(gi)*dx+np.float32(gj)*dx))  #  comment or un comment this line
#                  tmp += sqrt(abs(np.float32(gi)*dy+np.float32(gj)*dx))  #  comment or un comment this line
#                  tmp += sqrt(abs(np.float32(gi)*dx+np.float32(gj)*dx))  #  comment or un comment this line
#                  tmp += sqrt(abs(np.float32(gi)*dy+np.float32(gj)*dx))  #  comment or un comment this line
#                  tmp += sqrt(abs(np.float32(gi)*dx+np.float32(gj)*dx))  #  comment or un comment this line
#               #   tmp += sqrt(abs(gi*dy+gj*dx))  #  comment or un comment this line


                 out_u[gi,gj] = tmp #funcs(si,sj,h, n, u, v, f, dx, dy)


cu_u_driver_global_funcs_col = compileit(cu_u_driver_global_funcs_col_py,blockdim=(1024,1))


M=20000
N=1000
h = np.ones((N,M),dtype=np.float32) #np.asarray( np.float32(2)+np.random.random((N,M)) ,dtype=np.float32)
n = np.ones((N,M),dtype=np.float32) #np.asarray(np.float32(2)+np.random.random((N,M)) ,dtype=np.float32)
u =np.ones((N+1,M),dtype=np.float32) # np.asarray(np.random.random((N+1,M)) ,dtype=np.float32)
v = np.ones((N,M+1),dtype=np.float32) #np.asarray(np.random.random((N,M+1)) ,dtype=np.float32)
f = np.ones((N,M),dtype=np.float32) #np.asarray(np.random.random((N,M)) ,dtype=np.float32)
dx = np.float32(0.1)
dy = np.float32(0.2)

out_u = np.zeros_like(u)


def testit(blockspergrid,threadsperblock,cu_u_driver,res1=None ):
            print (cu_u_driver.__name__)
            h1 = cuda.to_device(h)
            n1 = cuda.to_device(n)
            u1 = cuda.to_device(u)
            v1 = cuda.to_device(v)
            f1 = cuda.to_device(f)
            out_u1 =cuda.to_device(out_u)

            print( "blocks per grid", blockspergrid)
            print("threads per block",threadsperblock)
            cu_u_driver[blockspergrid,threadsperblock](h1, n1, u1, v1, f1, dx, dy, out_u1)


testit((1,1),(1,1001),cu_u_driver_global_funcs_col)

0 个答案:

没有答案