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

如何在cuBLAS中正确使用cudaMallocManaged统一内存?

在cuBLAS中正确使用统一内存的解决方案

我帮你定位到了统一内存版本失效的两个核心问题,调整后就能正常运行了:

问题根源分析

  • 数组索引错误:你的代码初始化vec和mat时用了从1开始的索引(i从1到dims),但C++数组是0索引的,这导致数组的第0个元素始终是未初始化的垃圾值(大概率为0)。而cuBLAS计算时会从数组起始位置(索引0)读取数据,相当于你实际在计算一个大部分元素为0的矩阵与向量相乘,结果自然全是0。
  • 缺少GPU-CPU同步:cuBLAS的API是异步执行的,GPU会在后台完成计算任务。统一内存虽然能自动在CPU和GPU间迁移数据,但如果CPU不等GPU计算完成就直接读取results,拿到的还是初始的0值。

修正后的完整代码

#include <cuda.h>
#include <cuda_runtime.h>
#include <iostream>
#include <ctime>
#include "cublas_v2.h"
#define cudaErrChk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true) {
    if (code != cudaSuccess) {
        fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
        if (abort) exit(code);
    }
}
static const char *cublasErrChk(cublasStatus_t error) {
    switch (error) {
        case CUBLAS_STATUS_SUCCESS: return "CUBLAS_STATUS_SUCCESS";
        case CUBLAS_STATUS_NOT_INITIALIZED: return "CUBLAS_STATUS_NOT_INITIALIZED";
        case CUBLAS_STATUS_ALLOC_FAILED: return "CUBLAS_STATUS_ALLOC_FAILED";
        case CUBLAS_STATUS_INVALID_VALUE: return "CUBLAS_STATUS_INVALID_VALUE";
        case CUBLAS_STATUS_ARCH_MISMATCH: return "CUBLAS_STATUS_ARCH_MISMATCH";
        case CUBLAS_STATUS_MAPPING_ERROR: return "CUBLAS_STATUS_MAPPING_ERROR";
        case CUBLAS_STATUS_EXECUTION_FAILED: return "CUBLAS_STATUS_EXECUTION_FAILED";
        case CUBLAS_STATUS_INTERNAL_ERROR: return "CUBLAS_STATUS_INTERNAL_ERROR";
    }
    return "<unknown>";
}
int main() {
    size_t dims = 4;
    double *vec, *mat, *results;
    cudaErrChk( cudaMallocManaged(&vec, dims * sizeof(double)) );
    cudaErrChk( cudaMallocManaged(&mat, dims * dims * sizeof(double)) );
    cudaErrChk( cudaMallocManaged(&results, dims * sizeof(double)) );

    // 初始化结果数组为0,确保初始状态可控
    for (int i = 0; i < dims; i++) {
        results[i] = 0.0;
    }

    printf("Vector:\n");
    // 改为0索引,同时保持原数值逻辑:第i个元素为0.5*(i+1)
    for (int i = 0; i < dims; i++) {
        vec[i] = 0.5 * (i + 1);
        printf("%.2lf ", vec[i]);
    }
    printf("\n\nMatrix:\n");
    // 同样改为0索引,保持原数值逻辑:第i个元素为i+1
    for (int i = 0; i < dims * dims; i++) {
        mat[i] = 1.0 * (i + 1);
        printf("%.2lf ", mat[i]);
        if ((i + 1) % dims == 0) printf("\n");
    }
    printf("\n");

    cublasHandle_t handle;
    cublasErrChk( cublasCreate(&handle) );
    double alpha = 1.0, beta = 1.0;
    // 执行矩阵-向量乘法
    cublasErrChk( cublasDgemv( handle, CUBLAS_OP_N, dims, dims, &alpha, mat, dims, vec, 1, &beta, results, 1 ) );

    // 等待GPU计算完成,确保结果已更新到统一内存
    cudaErrChk( cudaDeviceSynchronize() );

    printf("Results:\n");
    for (int i = 0; i < dims; i++) printf("%.2lf ", results[i]);
    printf("\n");

    // 释放资源
    cudaErrChk( cudaFree(vec) );
    cudaErrChk( cudaFree(mat) );
    cudaErrChk( cudaFree(results) );
    cublasErrChk( cublasDestroy(handle) ); // 销毁cuBLAS句柄,避免资源泄漏

    return 0;
}

关键调整说明

  1. 修正索引逻辑:将数组初始化的循环从1索引改为0索引,确保所有参与计算的元素都被正确赋值,匹配cuBLAS的内存访问逻辑;
  2. 添加同步操作:调用cudaDeviceSynchronize()等待GPU完成计算,保证CPU读取results时已经是计算后的结果;
  3. 完善资源释放:增加cublasDestroy(handle)销毁cuBLAS句柄,养成良好的资源管理习惯。

编译运行命令保持不变:

nvcc -o main main.cu -lcublas

现在运行修正后的程序,就能得到正确的矩阵-向量乘法结果了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:04:04