我这里有this代码(由于答案而修改)。
信息
32字节堆栈帧,0字节溢出存储,0字节溢出负载
ptxas info:使用了46个寄存器,120个字节的cmem [0],176个字节 cmem [2],76字节cmem [16]
我不知道还有什么需要考虑,以使其适用于不同的点组合“numPointsRs”和“numPointsRp”
例如,当我使用块=(128,1,1)运行Rs = 10000且Rp = 100000的代码时,网格=(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分钟或更长时间。)我应该使用它吗?
-------------- UPDATED2 ----------------------------- -----------------
现在,如果不做任何事情,代码就无法再次运行了!
代码快照:
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()
我的卡:
Device 0: "GeForce GTX 560"
CUDA Driver Version / Runtime Version 4.20 / 4.10
CUDA Capability Major/Minor version number: 2.1
Total amount of global memory: 1024 MBytes (1073283072 bytes)
( 0) Multiprocessors x (48) CUDA Cores/MP: 0 CUDA Cores //CUDA Cores 336 => 7 MP and 48 Cores/MP
答案 0 :(得分:3)
“启动超时”似乎表明内核运行时间过长并被监视程序计时器杀死。这可能发生在也用于图形输出的GPU(例如图形桌面)上,其中监视计时器的任务是防止桌面锁定超过几秒钟。最好的我可以回想一下看门狗的时间限制大约为5秒左右。
在任何给定时刻,GPU都可以运行图形或CUDA,因此在运行GUI时需要看门狗定时器以防止GUI长时间锁定,从而导致机器无法通过GUI运行
如果可能,请避免将此GPU用于桌面和/或其他图形(例如,如果您使用的话,请不要运行X)。如果不使用图形运行不是一个选项,为了减少内核执行时间以避免命中监视程序计时器内核终止,每个内核启动时你将不得不做更少的工作,优化代码,以便内核在相同的工作量下运行得更快,或者部署更快的GPU。
答案 1 :(得分:3)
您必须处理很多问题。 @njuffa提供的答案1是最好的通用解决方案。我会根据您提供的有限数据提供更多反馈。
46个寄存器的PTX输出不是内核使用的寄存器数。 PTX是一种中间表示。离线或JIT编译器会将其转换为设备代码。设备代码可以使用更多或更少的寄存器。 Nsight Visual Studio Edition,Visual Profiler和CUDA命令行分析器都可以为您提供正确的寄存器计数。
占用率计算不仅仅是RegistersPerSM / RegistersPerThread。寄存器基于粒度分配。对于CC 2.1,每个warp的每个线程的粒度为4个寄存器(128个寄存器)。 2.x设备实际上可以以2个寄存器的粒度进行分配,但这可能导致内核中的碎片化。
在您的入住率计算中,您说明了
我的卡有32768个寄存器限制,所以32768/5888 = 5 + some =&gt; 5块/ SM (我的卡有限制6)。
我不确定6是什么意思。您的设备有7个SM。 2.x设备的每个SM的最大块数为每个SM 8个块。
您提供的代码量不足。如果您提供了一些代码,请提供所有输入的大小,每个循环的执行次数以及每个函数的操作说明。查看代码,您可能每个线程执行的循环次数过多。在不知道外环的数量级的情况下,我们只能猜测。
鉴于启动时间超时,您应该按照以下方式进行调试:
一个。在代码的开头添加一行
if (blockIdx.x > 0) { return; }
运行前面提到的一个分析器中的确切代码来估计单个块的持续时间。使用分析器提供的启动信息:按线程注册,共享内存,...使用分析器中的占用计算器或xls来确定可以并发运行的最大块数。例如,如果理论块占用率为每SM 3个块,并且SM的数量为7,则可以一次运行21个块,对于您启动的是9个波。注意:这假设每个线程的工作相同。更改提前退出代码以允许1波(21个块)。如果此启动超时,则需要减少每个线程的工作量。如果这通过,那么计算你有多少波,并估计你何时超时(在Windows上为2秒,在Linux上为?)。
湾如果你有太多波浪,那么减少你必须减少启动配置。假设您通过gridDim.x和blockDim.x进行索引,则可以通过将这些维度作为参数传递给内核来实现。这将需要tou来最小化您的索引代码。您还必须传递blockIdx.x偏移量。更改主机代码以反复启动多个内核。由于不存在冲突,您可以在多个流中启动这些冲突,以便在每次波浪结束时从重叠中受益。
答案 2 :(得分:0)
要提供有关@njuffa答案的更多信息,在Windows系统中,您可以按照以下步骤增加启动超时或 TDR (超时检测和恢复):
1:在 Nsight Monitor 中打开选项。
2:为 WDDM TDR延迟
设置适当的值CUATION :如果此值太小,您可能会收到超时错误;对于更高的值,您的屏幕将保持冻结状态,直到内核完成工作为止。