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

CUDA矩阵乘法出现Segmentation fault (core dumped)错误的排查与解决

CUDA矩阵乘法程序段错误分析与修复

错误成因

1. 硬编码Block Size与传入参数不匹配

内核中通过#define BLOCK_SIZE 16固定了共享内存数组tile_a、tile_b的尺寸,但主机端使用命令行传入的block_size参数配置线程块(dimBlock)。当传入的block_size不等于16时,线程索引(threadIdx.x/threadIdx.y)会超出共享内存数组的边界,触发共享内存越界访问,直接导致段错误。

2. 内核循环条件逻辑错误

内核中循环条件for (int sub = 0; sub < gridDim.x; ++sub)存在问题:gridDim.x是主机端根据block_size计算的网格列数,当矩阵尺寸n无法被block_size整除时,gridDim.x不等于实际需要的子块数量,会导致循环次数不足或过多,进而引发全局内存访问越界。

排查步骤

  • 一致性检查:核对内核中共享内存尺寸与主机端配置的线程块尺寸是否完全匹配
  • 内存越界定位:使用cuda-memcheck工具运行程序,工具会精准报告共享内存/全局内存的越界访问位置
  • 循环逻辑验证:手动计算矩阵尺寸与block size的整除关系,验证循环次数是否覆盖所有子矩阵块

修复方案

1. 模板化内核传递Block Size

将内核改为模板函数,从主机端传入Block Size参数,确保共享内存尺寸与线程块尺寸严格一致:

template <int BLOCK_SIZE>
__global__ void gpu_square_matrix_mult(int *d_a, int *d_b, int *d_result, int n) {
    __shared__ int tile_a[BLOCK_SIZE][BLOCK_SIZE];
    __shared__ int tile_b[BLOCK_SIZE][BLOCK_SIZE];

    int row = blockIdx.y * BLOCK_SIZE + threadIdx.y;
    int col = blockIdx.x * BLOCK_SIZE + threadIdx.x;
    int tmp = 0;
    int idx;

    // 计算需要遍历的子块总数
    int num_sub = (n + BLOCK_SIZE - 1) / BLOCK_SIZE;
    for (int sub = 0; sub < num_sub; ++sub) {
        // 读取tile_a时,同时检查row是否越界
        idx = row * n + sub * BLOCK_SIZE + threadIdx.x;
        if (row >= n || idx >= n * n) {
            tile_a[threadIdx.y][threadIdx.x] = 0;
        } else {
            tile_a[threadIdx.y][threadIdx.x] = d_a[idx];
        }

        // 读取tile_b时,同时检查col是否越界
        idx = (sub * BLOCK_SIZE + threadIdx.y) * n + col;
        if (col >= n || idx >= n * n) {
            tile_b[threadIdx.y][threadIdx.x] = 0;
        } else {
            tile_b[threadIdx.y][threadIdx.x] = d_b[idx];
        }
        __syncthreads();

        for (int k = 0; k < BLOCK_SIZE; ++k) {
            tmp += tile_a[threadIdx.y][k] * tile_b[k][threadIdx.x];
        }
        __syncthreads();
    }

    if (row < n && col < n) {
        d_result[row * n + col] = tmp;
    }
}

2. 主机端动态匹配模板实例

在main函数中,根据命令行传入的block_size选择对应的内核模板实例:

// Launch kernel
switch(block_size) {
    case 8:
        gpu_square_matrix_mult<8><<<dimGrid, dimBlock>>>(d_a, d_b, d_c, n);
        break;
    case 16:
        gpu_square_matrix_mult<16><<<dimGrid, dimBlock>>>(d_a, d_b, d_c, n);
        break;
    case 32:
        gpu_square_matrix_mult<32><<<dimGrid, dimBlock>>>(d_a, d_b, d_c, n);
        break;
    default:
        fprintf(stderr, "不支持的Block Size,请使用8、16或32\n");
        return 1;
}

3. 移除硬编码的BLOCK_SIZE宏

删除原代码中的#define BLOCK_SIZE 16,避免硬编码带来的不一致问题。

额外优化

  • 在访问全局内存时,增加对row/col的越界检查,避免因索引计算溢出导致的内存访问错误
  • 保持主机端与内核端的矩阵尺寸参数一致,确保所有内存访问的边界判断正确

内容的提问来源于stack exchange,提问作者Ahmed Emad Tawfik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 15:02:08