cuda——内存不足(线程和块问题)——地址超出范围
我使用63个寄存器/线程,所以(最大32768个)我可以使用大约520个线程 (并行性在全局ComputeeFields函数中的函数“computeEvec”中。) 问题是: 1) 下面是mem检查错误 2) 当我使用numPointsRp>2000时,它会显示“内存不足”,但是(如果我没有做错的话)我计算了全局内存,它是正常的 ------------------------------------更新---------------------- 我使用cuda memcheck运行该程序,它会给出(仅当numPointsRs>numPointsRp时): ======无效的全局读取大小为4 =========在计算字段中为0x00000428 =======按块(0,0,0)中的线程(2,0,0) =======地址0x4001076e0超出范围 ========= ======无效的全局读取大小为4 =========在计算字段中为0x00000428 =======按块(0,0,0)中的线程(1,0,0) =======地址0x4001076e0超出范围 ========= ======无效的全局读取大小为4 =========在计算字段中为0x00000428 =======按块(0,0,0)中的线程(0,0,0) =======地址0x4001076e0超出范围 错误摘要:160个错误 ------------编辑------------------ 此外,有时(如果我只使用线程而不使用块(我没有测试它是否有块)),例如,如果我有numPointsRs=1000和numPointsRp=100,然后更改numPointsRp=200,然后再次更改numPointsRp=100,我就不会得到第一个结果cuda——内存不足(线程和块问题)——地址超出范围,cuda,pycuda,Cuda,Pycuda,我使用63个寄存器/线程,所以(最大32768个)我可以使用大约520个线程 (并行性在全局ComputeeFields函数中的函数“computeEvec”中。) 问题是: 1) 下面是mem检查错误 2) 当我使用numPointsRp>2000时,它会显示“内存不足”,但是(如果我没有做错的话)我计算了全局内存,它是正常的 ------------------------------------更新---------------------- 我使用cuda memcheck运行该程序,它
import pycuda.gpuarray as gpuarray
import pycuda.autoinit
from pycuda.compiler import SourceModule
import numpy as np
import cmath
import pycuda.driver as drv
Rs=np.zeros((numPointsRs,3)).astype(np.float32)
for k in range (numPointsRs):
Rs[k]=[0,k,0]
Rp=np.zeros((numPointsRp,3)).astype(np.float32)
for k in range (numPointsRp):
Rp[k]=[1+k,0,0]
#---- 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>
#define RowRsSize %(numrs)d
#define RowRpSize %(numrp)d
typedef pycuda::complex<float> cmplx;
extern "C"{
__device__ void computeEvec(float Rs_mat[][3], int numPointsRs,
cmplx J[][3],
cmplx M[][3],
float *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 )
{
float Rs_mat[RowRsSize][3];
float Rp_mat[RowRpSize][3];
cmplx J[RowRsSize][3];
cmplx M[RowRsSize][3];
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;
}
}
}
"""% { "numrs":numPointsRs, "numrp":numPointsRp},no_extern_c=1)
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))
print(" \n")
#----- 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()
使用R=1000,然后
块=R/2,1,1,网格=1,1一切正常
如果我尝试R=10000,并且
block=R/20,1,1,grid=20,1,然后显示“内存不足”
我不熟悉pycuda,也没有读懂你的代码
深深地但是,您有更多的块和线程,因此
意志
- 本地内存(可能是内核堆栈,分配给每个线程)
- 共享内存(按块分配),或
- 基于
或grid
分配的全局内存gridDim
cudeDeviceSetLimit(cudaLimitStackSize, N));
(代码是针对C运行时API的,但是pycuda等价物应该不太难找到)
当我使用numPointsRp>2000时,它会显示“内存不足”
现在我们有一些真正的代码要处理,让我们编译它,看看会发生什么。使用rowrsize=2000
和RowRpSize=200
并使用CUDA 4.2工具链编译,我得到:
nvcc -arch=sm_21 -Xcompiler="-D RowRsSize=2000 -D RowRpSize=200" -Xptxas="-v" -c -I./ kivekset.cu
ptxas info : Compiling entry function '_Z15computeEHfieldsPfiS_iPN6pycuda7complexIfEES3_S2_S2_PA3_S2_S5_S3_' for 'sm_21'
ptxas info : Function properties for _Z15computeEHfieldsPfiS_iPN6pycuda7complexIfEES3_S2_S2_PA3_S2_S5_S3_
122432 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info : Used 57 registers, 84 bytes cmem[0], 168 bytes cmem[2], 76 bytes cmem[16]
每个线程的密钥数为57个寄存器和122432字节堆栈帧。占用率计算器建议512个线程的块每SM最多有1个块,而您的GPU有7个SM。在使用pyCUDA为输入和输出分配一个字节的内存之前,这将提供总共122432*512*7=438796288字节的堆栈帧(本地内存)来运行内核。在内存为1Gb的GPU上,不难想象内存会耗尽。您的内核占用了大量的本地内存。开始考虑减少它的方法
正如我在评论中指出的,不清楚为什么每个线程都需要这个内核代码中输入数据的完整副本。它会导致巨大的本地内存占用,而且似乎完全没有理由用这种方式编写代码。我猜想,您可以将内核修改为如下内容:
typedef pycuda::complex<float> cmplx;
typedef float fp3[3];
typedef cmplx cp3[3];
__global__
void computeEHfields2(
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_;
cp3 * J = (cp3 *)J_;
cp3 * M = (cp3 *)M_;
int k=threadIdx.x+blockIdx.x*blockDim.x;
while (k<numPointsRp)
{
fp3 * Rp_mat = (fp3 *)(Rp_mat_+k);
computeEvec2( Rs_mat, numPointsRs, J, M, *Rp_mat, kp, eta, E[k], H[k], All );
k+=blockDim.x*gridDim.x;
}
}
__device__ void computeEvec2(
fp3 Rs_mat[], int numPointsRs,
cp3 J[],
cp3 M[],
fp3 Rp,
cmplx kp,
cmplx eta,
cmplx *Evec,
cmplx *Hvec,
cmplx *All)
{
....
}
并消除线程本地内存中的每个字节,而不改变计算代码的功能。是否将所有点同时复制到GPU内存中?一个点的大小是多少?大小是int。我在全局函数中调用另一个(设备)函数,在那里我进行并行处理。你的问题没有给出足够的细节,你的块/网格大小是有效的,所以你的内核或主机代码中一定有什么东西导致了错误(你甚至没有说错误来自哪里).但你是在进行报复性的升级投票,在很多情况下,这只会把糟糕的问题推到榜首。这可能有助于提高海报的自尊心,但它使支持开发人员社区的任务(我的任务)变得更加困难。@George:我不想看到成百上千行的代码。我想看一个简明的例子来再现这个问题。如果你不能做到这一点,你就没有充分考虑这一点。最后一个错误意味着您的函数调用中有一个无效的块维度。:您好,谢谢您的帮助。我可以看到(从ptxas的信息)在大约82000字节的堆栈帧之前,程序运行正常。但更多的是,它也没有,减小堆栈大小会得到相同的结果:我也不明白这一点:我对numPointsRp进行并行处理,但如果我将numPointsRs增加到10000,例如,它会显示“内核失败:无效值”。1x1x1网格没有意义-您尝试在单个SM上运行所有线程。为什么必须将输入冗余地复制到本地内存?代码不会以这种方式扩展,所以不要浪费时间试图用锤子和撬棍运行它。相反,试着真正了解你的目标设备、它的内存类型、C/C++ABI及其限制,并相应地重写你的程序(请参阅CUDA文档或我在[本文]中的答案][可以帮助你开始):那么,这是一个设计糟糕的代码,对吗?我需要修改它以使用共享内存?你能给我一些提示(在我的代码中)为此?根据你的经验,我的意思是,不用花你的时间。另外,我有63个寄存器,为什么会有这种差异?:最后,你说438796288在程序运行之前就分配了。所以,当我运行它时,需要的内存(矩阵
__device__ void computeEvec2(
fp3 Rs_mat[], int numPointsRs,
cp3 J[],
cp3 M[],
fp3 Rp,
cmplx kp,
cmplx eta,
cmplx *Evec,
cmplx *Hvec,
cmplx *All)
{
....
}