cuda——内存不足(线程和块问题)——地址超出范围

cuda——内存不足(线程和块问题)——地址超出范围,cuda,pycuda,Cuda,Pycuda,我使用63个寄存器/线程,所以(最大32768个)我可以使用大约520个线程 (并行性在全局ComputeeFields函数中的函数“computeEvec”中。) 问题是: 1) 下面是mem检查错误 2) 当我使用numPointsRp>2000时,它会显示“内存不足”,但是(如果我没有做错的话)我计算了全局内存,它是正常的 ------------------------------------更新---------------------- 我使用cuda memcheck运行该程序,它

我使用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,我就不会得到第一个结果

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)
{
 ....
}