You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CUDA核函数中__shared__内存引发计算错误的原因排查

核函数共享内存使用导致计算错误的根因分析与修复方案

在CUDA核函数中将3D数组XY维度值p_x、p_y存入__shared__内存数组size_t size_p[2]后,使用共享内存值计算出现错误,但直接用参数则结果正常。以下是问题详情、根因分析及正确的共享内存使用方案:


出错的核函数代码

__global__ void element_wise_add(
    float* p,
    size_t p_x,
    size_t p_y,
    size_t p_z,
    float* B,
    size_t B_x,
    size_t B_y,
    size_t B_z,
    unsigned int path_x,
    unsigned int path_y,
    unsigned int path_z,
    const float scalar) // try making this in __shared__ memory
{

    int index = blockIdx.x * blockDim.x + threadIdx.x;


    __shared__ size_t size_p[2], size_B[2];

    if (index == 0)
    {
        size_p[0] = p_x;
        size_p[1] = p_y;
        size_B[0] = B_x;
        size_B[1] = B_y;
        
    }
    
    __syncthreads();
    if (index == 100)
        printf("%d == %d == %d == %d", p_x, p_y, size_p[0], size_p[1]);
    if (index < size_p[0] * size_p[1] * p_z)
    {
        //Get ijk indices from each index
        unsigned int k = index / (p_x * p_y);
        index -= k * p_x * p_y;
        unsigned int j = index / p_x; //maybe here yLen 
        index -= j * p_x;
        unsigned int i = index / 1;

         

        
        B[arrayIndex(i+path_x, j+path_y, k+path_z, B_x, B_y)] += scalar*p[arrayIndex(i, j, k, p_x, p_y)];

        //index = arrayIndex(i + path_x, j + path_y, k + path_z, size_B[0], size_B[1]);
        //int index_B = arrayIndex(i, j, k, size_p[0], size_p[1]);

        //atomicAdd((B + index), scalar * p[index_B]); // make arrayIndex function a preprocessor micro for speed
    }
}

正确的核函数代码

__global__ void element_wise_add(
    float* p,
    size_t p_x,
    size_t p_y,
    size_t p_z,
    float* B,
    size_t B_x,
    size_t B_y,
    size_t B_z,
    unsigned int path_x,
    unsigned int path_y,
    unsigned int path_z,
    const float scalar) // try making this in __shared__ memory
{
        
    int index = blockIdx.x * blockDim.x + threadIdx.x;
    


    if (index < p_x * p_y * p_z) 
    {
        //Get ijk indices from each index
        unsigned int k = index / (p_x * p_y);
        index -= k * p_x * p_y;
        unsigned int j = index / p_x; //maybe here yLen 
        index -= j * p_x;
        unsigned int i = index / 1;

    

        B[arrayIndex(i+path_x, j+path_y, k+path_z, B_x, B_y)] += scalar*p[arrayIndex(i, j, k, p_x, p_y)];

        
    }
}

最小驱动代码

__host__ __device__ int arrayIndex(int x, int y, int z, int height, int width) {
    return x + y * height + z * height * width;
}


void print_3d_serial_array(float* ptr, size_t X, size_t Y, size_t Z);


void kernel_sample_driver_()
{
    const int Nx = 10;
    const int Ny = 10;
    const int Nz = 10;

    const int px = 10;
    const int py = 2;
    const int pz = 2;


    float a[Nx * Ny * Nz], b[px * py * pz];

    for (size_t k = 0; k < Nz; k++)
    {
        for (size_t j = 0; j < Ny; j++)
        {
            for (size_t i = 0; i < Nx; i++)
            {
                a[arrayIndex(i, j, k, Nx, Ny)] = i + j + k;

            }
        }
    }
    for (size_t k = 0; k < pz; k++)
    {
        for (size_t j = 0; j < py; j++)
        {
            for (size_t i = 0; i < px; i++)
            {
                b[arrayIndex(i, j, k, px, py)] = 1000 * (i + j + k + 1);
            }
        }
    }


    print_3d_serial_array(a, Nx, Ny, Nz);
    print_3d_serial_array(b, px, py, pz);


    gpu::dev_array<float> d_a(Nx * Ny * Nz);
    gpu::dev_array<float> d_b(px * py * pz);

    d_a.set(a, Nx * Ny * Nz);
    d_b.set(b, px * py * pz);


    dim3 threadsPerBlock;
    dim3 blocksPerGrid;
    threadsPerBlock.x = Nx * Ny * Nz;
    threadsPerBlock.y = 1;
    blocksPerGrid.x = ceil(((double)(Nx * Ny * Nz)) / (threadsPerBlock.x));

    element_wise_add <<<blocksPerGrid, threadsPerBlock>>> (d_b.getData(), px, py, pz, d_a.getData(), Nx, Ny, Nz, 0, 1, 1, 1);

    cudaDeviceSynchronize();


    d_a.get(a, Nx * Ny * Nz);

    print_3d_serial_array(a, Nx, Ny, Nz);

}



void print_3d_serial_array(float* ptr, size_t X, size_t Y, size_t Z)
{
    for (size_t k = 0; k < Z; k++)
    {
        int len = 0;
        printf("Array( : , : , %02d) =\n\n", k);
        for (size_t j = 0; j < Y; j++)
        {
            for (size_t i = 0; i < X; i++)
            {
                printf("%3.1f , ", ptr[arrayIndex(i, j, k, X, Y)]);
                }
            std::cout << std::endl;
        }
        std::cout << '\n';
        for (size_t l = 0; l < X; l++)
        {
            std::cout << "-";
        }
        std::cout << '\n';
        std::cout << std::endl;
        }
}

错误根本原因

  1. 类型不匹配与比较逻辑错误

    • index是有符号int类型,而size_p[0] * size_p[1] * p_z是无符号size_t类型。当无符号数值超过INT_MAX时,有符号与无符号的比较会触发整数提升规则,导致index < 无符号值的判断逻辑失效,大量线程错误进入计算分支,引发内存越界。
    • 用%d(有符号整数格式符)打印无符号size_t类型的size_p值,会造成输出误导,看似共享内存值与参数一致,实际存在类型截断风险。
  2. 共享内存初始化的线程块范围问题

    • 代码中用index == 0(全局索引)初始化共享内存,但共享内存是线程块级别的资源。当使用多个线程块时,只有第一个线程块的全局索引0线程会初始化共享内存,其他线程块的共享内存会读取未初始化的垃圾值,导致计算错误。

正确使用共享内存的优化方案

修改核函数,解决类型匹配问题,确保共享内存按线程块正确初始化,同时优化线程索引计算:

__global__ void element_wise_add(
    float* p,
    size_t p_x,
    size_t p_y,
    size_t p_z,
    float* B,
    size_t B_x,
    size_t B_y,
    size_t B_z,
    unsigned int path_x,
    unsigned int path_y,
    unsigned int path_z,
    const float scalar)
{
    // 使用无符号整数避免符号比较问题
    unsigned int global_idx = blockIdx.x * blockDim.x + threadIdx.x;
    const size_t p_total = p_x * p_y * p_z;
    if (global_idx >= p_total) return;

    __shared__ size_t size_p[2], size_B[2];

    // 每个线程块的第一个线程初始化共享内存
    if (threadIdx.x == 0)
    {
        size_p[0] = p_x;
        size_p[1] = p_y;
        size_B[0] = B_x;
        size_B[1] = B_y;
    }
    __syncthreads();

    // 使用共享内存计算索引,避免重复读取全局参数
    unsigned int k = global_idx / (size_p[0] * size_p[1]);
    unsigned int rem = global_idx % (size_p[0] * size_p[1]);
    unsigned int j = rem / size_p[0];
    unsigned int i = rem % size_p[0];

    // 显式类型转换,匹配arrayIndex的参数类型
    unsigned int b_idx = arrayIndex(static_cast<int>(i+path_x), 
                                   static_cast<int>(j+path_y), 
                                   static_cast<int>(k+path_z), 
                                   static_cast<int>(size_B[0]), 
                                   static_cast<int>(size_B[1]));
    unsigned int p_idx = arrayIndex(static_cast<int>(i), 
                                   static_cast<int>(j), 
                                   static_cast<int>(k), 
                                   static_cast<int>(size_p[0]), 
                                   static_cast<int>(size_p[1]));
    B[b_idx] += scalar * p[p_idx];
}

同时修改驱动代码的线程配置为CUDA推荐的合理值(比如256线程/块):

threadsPerBlock.x = 256;
blocksPerGrid.x = (px * py * pz + threadsPerBlock.x - 1) / threadsPerBlock.x;

内容的提问来源于stack exchange,提问作者adnan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 16:50:43