Cuda driver.Context.synchronize()-还要考虑什么---清理操作失败

Cuda driver.Context.synchronize()-还要考虑什么---清理操作失败,cuda,pycuda,Cuda,Pycuda,我这里有代码(由于答案而修改) 信息 32字节堆栈帧,0字节溢出存储,0字节溢出加载 ptxas信息:使用46个寄存器,120字节cmem[0],176字节 cmem[2],76字节cmem[16] 我不知道还需要考虑什么才能使它适用于“numPointsRs”和“numPointsRp”点的不同组合 例如,当我用Rs=10000和Rp=100000运行代码时,block=(128,1,1),grid=(200,1)很好 我的计算: 46个寄存器*128个线程=5888个寄存器 我的卡有限制32

我这里有代码(由于答案而修改)

信息

32字节堆栈帧,0字节溢出存储,0字节溢出加载
ptxas信息:使用46个寄存器,120字节cmem[0],176字节 cmem[2],76字节cmem[16]

我不知道还需要考虑什么才能使它适用于“numPointsRs”和“numPointsRp”点的不同组合

例如,当我用Rs=10000和Rp=100000运行代码时,block=(128,1,1),grid=(200,1)很好

我的计算:

46个寄存器*128个线程=5888个寄存器

我的卡有限制32768寄存器,因此32768/5888=5+some=>5块/SM
(我的卡有6个限制)

使用占用率计算器,我发现使用128个线程/块 给我42%,我在我的信用卡限额内

此外,每个MP的线程数为640(限制为1536)

现在,如果我尝试使用Rs=100000和Rp=100000(对于相同的线程和块),它会在标题中给出消息,其中包含:

cuEventDestroy失败:启动超时

cuModuleUnload失败:启动超时

1) 我不知道/不明白还需要计算什么

2) 我不明白我们是如何使用/找到街区的数量的。我看得出来 大多数情况下,有人会放(线程-1+点)/线程,但仍然是这样 不起作用

------更新-------------------------------------

在使用driver.Context.synchronize()之后,代码可以工作很多点(1000000)

但是,这个添加对代码有什么影响?(对于许多点来说,屏幕会冻结1分钟或更长时间)。我应该使用它吗

--------------更新的2-------------------------------------

现在,如果不做任何事情,代码将无法再次工作

代码快照:

import pycuda.gpuarray as gpuarray
import pycuda.autoinit
from pycuda.compiler import SourceModule
import numpy as np
import cmath
import pycuda.driver as drv
import pycuda.tools as t






#---- Initialization and passing(allocate memory and transfer data) to GPU -------------------------
Rs_gpu=gpuarray.to_gpu(Rs)
Rp_gpu=gpuarray.to_gpu(Rp)

J_gpu=gpuarray.to_gpu(np.ones((numPointsRs,3)).astype(np.complex64))
M_gpu=gpuarray.to_gpu(np.ones((numPointsRs,3)).astype(np.complex64))

Evec_gpu=gpuarray.to_gpu(np.zeros((numPointsRp,3)).astype(np.complex64))
Hvec_gpu=gpuarray.to_gpu(np.zeros((numPointsRp,3)).astype(np.complex64))
All_gpu=gpuarray.to_gpu(np.ones(numPointsRp).astype(np.complex64))

#-----------------------------------------------------------------------------------    
mod =SourceModule("""
#include <pycuda-complex.hpp>
#include <cmath>
#include <vector>

typedef  pycuda::complex<float> cmplx;
typedef float fp3[3];
typedef cmplx cp3[3];

__device__ __constant__ float Pi;

extern "C"{  


    __device__ void computeEvec(fp3 Rs_mat[], int numPointsRs,   
         cp3 J[],
         cp3 M[],
         fp3 Rp,
         cmplx kp, 
         cmplx eta,
         cmplx *Evec,
         cmplx *Hvec, cmplx *All)

{

            while (c<numPointsRs){

        ...                      
                c++;

                }        
        }


__global__  void computeEHfields(float *Rs_mat_, int numPointsRs,     
        float *Rp_mat_, int numPointsRp,     
    cmplx *J_,
    cmplx *M_,
    cmplx  kp, 
    cmplx  eta,
    cmplx E[][3],
    cmplx H[][3], cmplx *All )
    {

        fp3 * Rs_mat=(fp3 *)Rs_mat_;
        fp3 * Rp_mat=(fp3 *)Rp_mat_;
        cp3 * J=(cp3 *)J_;
        cp3 * M=(cp3 *)M_;


    int k=threadIdx.x+blockIdx.x*blockDim.x;

      while (k<numPointsRp)  
     {

        computeEvec( Rs_mat, numPointsRs,  J, M, Rp_mat[k], kp, eta, E[k], H[k], All );
        k+=blockDim.x*gridDim.x;

    }

}
}

""" ,no_extern_c=1,options=['--ptxas-options=-v'])


#call the function(kernel)
func = mod.get_function("computeEHfields")

func(Rs_gpu,np.int32(numPointsRs),Rp_gpu,np.int32(numPointsRp),J_gpu, M_gpu, np.complex64(kp), np.complex64(eta),Evec_gpu,Hvec_gpu, All_gpu, block=(128,1,1),grid=(200,1))


#----- get data back from GPU-----
Rs=Rs_gpu.get()
Rp=Rp_gpu.get()
J=J_gpu.get()
M=M_gpu.get()
Evec=Evec_gpu.get()
Hvec=Hvec_gpu.get()
All=All_gpu.get()
“启动超时”似乎表明内核运行时间过长,并被看门狗计时器终止。这可能发生在也用于图形输出的GPU上(例如图形桌面),其中看门狗计时器的任务是防止桌面锁定超过几秒钟。我能回忆起的最好的时间限制是5秒左右

在任何给定时刻,GPU都可以运行图形或CUDA,因此在运行GUI时需要看门狗定时器,以防止GUI长时间锁定,从而使机器无法通过GUI运行


如果可能,避免将此GPU用于桌面和/或其他图形(例如,如果您在Linux上,请不要运行X)。如果不选择在没有图形的情况下运行,则为了减少内核执行时间以避免出现看门狗计时器内核终止,每次内核启动时,您将不得不做更少的工作,优化代码以使内核在相同的工作量下运行得更快,或者部署更快的GPU。

有许多问题需要解决。@njuffa提供的答案1是最好的通用解决方案。我将根据您提供的有限数据提供更多反馈

  • 46个寄存器的PTX输出不是内核使用的寄存器数。PTX是一种中间表示。脱机或JIT编译器将此代码转换为设备代码。设备代码可以使用更多或更少的寄存器。Nsight Visual Studio Edition、Visual Profiler和CUDA命令行分析器都可以为您提供正确的寄存器计数

  • 占用率计算不仅仅是RegistersPerSM/RegistersPerThread。寄存器是根据粒度分配的。对于CC2.1,粒度为每线程每经4个寄存器(128个寄存器)。2.x设备实际上可以以2寄存器粒度进行分配,但这可能会导致内核稍后出现碎片

  • 在您的入住率计算中,您声明

  • 我的卡有限制32768寄存器,因此32768/5888=5+some=>5块/SM (我的卡有6个限制)

    我不知道6是什么意思。您的设备有7条短信。对于2.x设备,每个SM的最大块数为8块

  • 您提供的代码量不足。如果您提供代码片段,请提供所有输入的大小、每个循环的执行次数以及每个函数的操作说明。查看代码,您可能在每个线程中执行了太多的循环。不知道外环的数量级,我们只能猜测

  • 鉴于启动正在超时,您可能应该按如下方式进行调试:

  • a。在代码开头添加一行

    if (blockIdx.x > 0) { return; }
    
    运行前面提到的分析器中的代码,以估计单个块的持续时间。使用探查器提供的启动信息:每个线程注册、共享内存。。。使用探查器或xls中的占用率计算器确定可同时运行的最大块数。例如,如果理论区块占用率为3个区块/SM,且SMs的数量为7,则您可以一次运行21个区块,而您的启动时间为9波。注意:这假设每个线程的功相等。更改早期退出代码以允许1波(21个块)。如果此启动超时,则需要减少每个线程的工作量。如果通过,则计算您有多少波,并估计何时超时(windows上为2秒,linux上为2秒)

    b。如果你有太多的波,那么减少你必须减少发射配置。假设您通过gridDim.x和blockDim.x进行索引,您可以通过将这些维度作为参数传递给内核来实现这一点。这将需要您最小限度地更改索引代码。您还必须传递blockIdx.x偏移量。更改主机代码以背靠背启动多个内核。因为应该没有冲突,所以您可以在多个流中启动它们以从中受益
    if (blockIdx.x > 0) { return; }