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()

  • 仅使用16个线程的块大小会使一半的资源未使用,因为线程块是以32个线程(一个扭曲)为单位分配的

  • 您可能需要重新阅读《CUDA C编程指南》中有关的部分

  • 查看这一行:

                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()

  • 仅使用16个线程的块大小会使一半的资源未使用,因为线程块是以32个线程(一个扭曲)为单位分配的


  • 您可能需要重新阅读《CUDA C编程指南》中关于的部分。

    非法地址由所有线程中的第一个线程执行。不管怎样,我会在没有指针的情况下试一试不,没有任何细微的变化。切换回指针代码我建议您避免使用
    memcpy
    memset
    。它被每个线程调用。相反,使用线程初始化共享内存,然后调用
    \u syncthreads
    。将结果写入全局内存也是如此。但非法地址是由所有线程中的第一个线程执行的。不管怎样,我会在没有指针的情况下试一试不,不是sl