Matrix CUDA中的热方程矩阵-非法地址错误
参考官方指南中的,我试图建立热方程矩阵,就像我画的这张糟糕的图片一样 这是我到目前为止所做的,最简单的例子Matrix CUDA中的热方程矩阵-非法地址错误,matrix,cuda,shared-memory,memcpy,Matrix,Cuda,Shared Memory,Memcpy,参考官方指南中的,我试图建立热方程矩阵,就像我画的这张糟糕的图片一样 这是我到目前为止所做的,最简单的例子 #define N 32 #define BLOCK_SIZE 16 #define NUM_BLOCKS ((N + BLOCK_SIZE - 1)/ BLOCK_SIZE) __global__ void heat_matrix(int* A) { const unsigned int tid = threadIdx.x + blockIdx.x * blockDim.x;
#define N 32
#define BLOCK_SIZE 16
#define NUM_BLOCKS ((N + BLOCK_SIZE - 1)/ BLOCK_SIZE)
__global__ void heat_matrix(int* A)
{
const unsigned int tid = threadIdx.x + blockIdx.x * blockDim.x;
__shared__ int temp_sm_A[N*N];
int* temp_A = &temp_sm_A[0]; memset(temp_A, 0, N*N*sizeof(int));
if (tid < N) //(*)
{
#pragma unroll
for (unsigned int m = 0; m < NUM_BLOCKS; ++m)
{
#pragma unroll
for (unsigned int e = 0; e < BLOCK_SIZE ; ++e)
{
if ( (tid == 0 && e == 0) || (tid == (N-1) && e == (BLOCK_SIZE-1) ) )
{
temp_A[tid + (e + BLOCK_SIZE * m) * N] = -2;
temp_A[tid + (e + BLOCK_SIZE * m) * N + ( tid==0 ? 1 : -1 )] = 1;
}
if ( tid == e )
{
temp_A[tid + (e + BLOCK_SIZE * m) * N - 1] = 1;
//printf("temp_A[%d] = 1;\n", (tid + (e + BLOCK_SIZE * m) * N -1));
temp_A[tid + (e + BLOCK_SIZE * m) * N] = -2;
//printf("temp_A[%d] = -2;\n", (tid + (e + BLOCK_SIZE * m) * N));
temp_A[tid + (e + BLOCK_SIZE * m) * N + 1] = 1;
//printf("temp_A[%d] = 1;\n", (tid + (e + BLOCK_SIZE * m) * N +1));
}
}
}
__syncthreads(); //(**)
memcpy(A, temp_A, N*N*sizeof(int));
}
}
int main(){
int* h_A = (int*)malloc(N*N*sizeof(int)); memset(h_A, 0, N*N*sizeof(int));
int* d_A;
checkCudaErrors(cudaMalloc((void**)&d_A, N*N*sizeof(int)));
checkCudaErrors(cudaMemcpy(d_A, h_A, N*N*sizeof(int), cudaMemcpyHostToDevice));
dim3 dim_grid((N/2 + BLOCK_SIZE -1)/ BLOCK_SIZE);
dim3 dim_block(BLOCK_SIZE);
heat_matrix <<< dim_grid, dim_block >>> (d_A);
checkCudaErrors(cudaMemcpy(h_A, d_A, N*N*sizeof(int), cudaMemcpyDeviceToHost));
...
}
而cuda memcheck
只提供了一个错误(实际上还有另一个错误,但它来自cudasuccess=checkCudaErrors(cudaDeviceReset());…
)
我看不出我在代码中哪里做错了。第一个块中的线程0
如何引发非法访问?甚至有特定的if
案例来处理它,并且没有报告发生错误的代码行
此外,对于我的代码,有没有比处理所有那些if
s更有效的方法?当然有,但是我找不到更好的并行表达式来将案例拆分为第二个for
另一方面,对我来说,
(*)
似乎没有必要;相反,(**)
是必要的,如果我想跟随其他GPU函数调用。我说得对吗?在内核中,temp\u A
是指向共享内存数组开头的本地指针。考虑到:
N=32
块大小=16
m(0,1)
e(0,块大小)
像
temp\u A[tid+(e+BLOCK\u SIZE*m)*N]
这样的访问很容易超出1024个元素长数组的界限。在内核中,temp\u A
是指向共享内存数组开头的本地指针。考虑到:
N=32
块大小=16
m(0,1)
e(0,块大小)
像temp_A[tid+(e+BLOCK_SIZE*m)*N]
这样的访问很容易超出1024个元素长数组的界限
temp_A[tid + (e + BLOCK_SIZE * m) * N - 1] = 1;
对于在第一次迭代期间tid
等于零的螺纹,tid+(e+BLOCK_SIZE*m)*N-1
的计算结果为索引-1。这正是cuda memcheck输出所抱怨的(由于下溢,地址被包围) temp_A[tid + (e + BLOCK_SIZE * m) * N + 1] = 1;
当tid
时,e
和m
均假定其最大值memset()
和主循环中的存储之间存在竞争条件。将syncthreads()
放在memset()之后
memset()
和memcpy()
的调用将导致每个线程执行完整的设置/复制,执行操作N次而不是一次。
处理此问题的常用方法是显式写出操作,在块的线程之间分配工作。
然而
A
,完全不需要memset()
、memcpy()
和syncthreads()
temp_A[tid + (e + BLOCK_SIZE * m) * N - 1] = 1;
对于在第一次迭代期间tid
等于零的螺纹,tid+(e+BLOCK_SIZE*m)*N-1
的计算结果为索引-1。这正是cuda memcheck输出所抱怨的(由于下溢,地址被包围) temp_A[tid + (e + BLOCK_SIZE * m) * N + 1] = 1;
当tid
时,e
和m
均假定其最大值memset()
和主循环中的存储之间存在竞争条件。将syncthreads()
放在memset()之后
memset()
和memcpy()
的调用将导致每个线程执行完整的设置/复制,执行操作N次而不是一次。
处理此问题的常用方法是显式写出操作,在块的线程之间分配工作。
然而
A
,完全不需要memset()
、memcpy()
和syncthreads()
您可能需要重新阅读《CUDA C编程指南》中关于的部分。非法地址由所有线程中的第一个线程执行。不管怎样,我会在没有指针的情况下试一试不,没有任何细微的变化。切换回指针代码我建议您避免使用
memcpy
和memset
。它被每个线程调用。相反,使用线程初始化共享内存,然后调用\u syncthreads
。将结果写入全局内存也是如此。但非法地址是由所有线程中的第一个线程执行的。不管怎样,我会在没有指针的情况下试一试不,不是sl