CUDA下100×200×800 3D矩阵零填充至128×256×1024最优方案咨询
CUDA实现3D矩阵补零的最优方案
首先直接给结论:你不需要额外分配第二份设备内存,也不用多次调用cudaMemcpy,使用cudaMemcpy3D即可实现类似MATLAB的3D切片赋值效果,性能最优。
CUDA C/C++本身没有原生的MATLAB风格切片赋值语法糖,但cudaMemcpy3D原生支持跨不同维度的3D内存拷贝,刚好匹配你的需求。你不需要提前把主机数据拷到设备端,直接按以下步骤实现即可:
实现步骤
1. 内存初始化
和你现有的代码一致,先分配主机、设备内存,再把设备端目标矩阵全部置零:
// 现有主机内存分配 int* h_data = (int*)malloc(sizeof(int)*100*200*800); // 这里是你给h_data赋值的业务逻辑 // 现有设备内存分配 int *d_data; cudaMalloc((void**)&d_data, sizeof(int)*128*256*1024); // 设备内存全置零,相当于MATLAB的zeros操作,效率远高于自定义核函数 cudaMemset(d_data, 0, sizeof(int)*128*256*1024);
2. 配置3D拷贝参数
构造cudaMemcpy3DParms结构体,指定源、目标的内存布局和拷贝范围:
cudaMemcpy3DParms copyParams = {0}; // 源参数:主机端的100×200×800连续矩阵 copyParams.srcPtr = make_cudaPitchedPtr( (void*)h_data, 100 * sizeof(int), // 源矩阵每行的字节数(x维度总字节) 100, // 源矩阵x维度元素数 200 // 源矩阵y维度元素数 ); copyParams.srcPos = make_cudaPos(0, 0, 0); // 从源矩阵的(0,0,0)位置开始拷贝 // 目标参数:设备端的128×256×1024补零矩阵 copyParams.dstPtr = make_cudaPitchedPtr( (void*)d_data, 128 * sizeof(int), // 目标矩阵每行的字节数 128, // 目标矩阵x维度元素数 256 // 目标矩阵y维度元素数 ); copyParams.dstPos = make_cudaPos(0, 0, 0); // 拷贝到目标矩阵(0,0,0)起始的子区域 // 拷贝范围:x方向100个元素、y方向200个、z方向800个 copyParams.extent = make_cudaExtent(100 * sizeof(int), 200, 800); copyParams.kind = cudaMemcpyHostToDevice;
3. 执行拷贝
cudaMemcpy3D(©Params);
执行完成后,d_data就是你需要的128×256×1024补零矩阵,和MATLAB的切片赋值效果完全一致。
关于原地重排的问题
如果你已经把原始扁平数据拷贝到了d_data的起始地址,无法实现原地重排:重排过程中会覆盖还未读取的原始数据,会导致数据错误。这种场景最优的方案是临时分配一块大小为100×200×800的设备内存存储原始数据,拷贝完成后立即释放,仅需要额外占用~64MB内存(100200800*4字节),开销极小。
内容的提问来源于stack exchange,提问作者brnk
相关产品推荐
相关产品推荐

