我使用63个寄存器/线程,所以(32768是最大的)我可以使用大约520个线程。我在这个例子中使用了512个线程。
(并行性在全局computeEHfields函数函数中的“computeEvec”函数中。) 问题是:
1)下面的mem check错误。
2)当我使用numPointsRp> 2000时,它会向我显示“内存不足”,但是(如果我没有做错)我计算全局内存并且没关系。
-------------------------------修订------------ ---------------
我使用cuda-memcheck运行该程序,它给了我(仅当numPointsRs> numPointsRp时):
=========无效的全球读取大小为4
=========在computeEHfields中的0x00000428
=========按块(0,0,0)中的线程(2,0,0)
=========地址0x4001076e0超出范围
====== =========无效全局读取大小为4
=========在computeEHfields中的0x00000428
=========按块(0,0,0)中的线程(1,0,0)
=========地址0x4001076e0超出范围
====== =========无效全局读取大小为4
=========在computeEHfields中的0x00000428
=========按块(0,0,0)中的线程(0,0,0)
=========地址0x4001076e0超出范围
错误摘要:160错误
----------- EDIT ----------------------------
此外,有些时候(如果我只使用线程而不是块(我没有测试它的块))如果我有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()
-------------------- GPU MODEL ------------------------- -----------------------
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 :(得分:1)
使用R = 1000然后
block = R / 2,1,1和grid = 1,1一切正常
如果我尝试R = 10000和
block = R / 20,1,1和grid = 20,1,然后它显示“内存不足”
我不熟悉pycuda,也没有读过你的代码 深。但是你有更多的块和更多的线程,所以它 将
本地内存(可能是内核的堆栈,每个线程分配 ),
共享内存(按块分配)或
根据grid
或gridDim
分配的全局内存。
您可以减少调用的堆栈大小
cudeDeviceSetLimit(cudaLimitStackSize, N));
(代码用于C运行时API,但pycuda等价物不应该太难找到。)
答案 1 :(得分:1)
当我使用numPointsRp&gt; 2000时,它会向我显示“内存不足”
现在我们有一些真正的代码可以使用,让我们编译它,看看会发生什么。使用RowRsSize=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__函数:
__device__ void computeEvec2(
fp3 Rs_mat[], int numPointsRs,
cp3 J[],
cp3 M[],
fp3 Rp,
cmplx kp,
cmplx eta,
cmplx *Evec,
cmplx *Hvec,
cmplx *All)
{
....
}
并消除线程本地内存的每个字节,而不会改变计算代码的功能。