如何在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索引改为0索引,确保所有参与计算的元素都被正确赋值,匹配cuBLAS的内存访问逻辑;
- 添加同步操作:调用
cudaDeviceSynchronize()等待GPU完成计算,保证CPU读取results时已经是计算后的结果; - 完善资源释放:增加
cublasDestroy(handle)销毁cuBLAS句柄,养成良好的资源管理习惯。
编译运行命令保持不变:
nvcc -o main main.cu -lcublas
现在运行修正后的程序,就能得到正确的矩阵-向量乘法结果了。
内容的提问来源于stack exchange,提问作者mrwhynot243
相关产品推荐
相关产品推荐

