c++ - 如何将 4D 数组的一部分从主机内存复制到设备内存?
问题描述
我在主机阵列中展平了 4-D 阵列。
我想复制 4-D 数组的一部分(红色区域),如下图所示。
我不知道如何复制未序列化的数组。
我复制一部分数组的原因是因为原始数组大小超过 10GB,我只需要它的 10%。
所以一开始,我用for循环尝试了它。但这花费了太多时间。
有没有更好的主意..?
int main(){
int nx = 100; ny = 200; nz = 300; nch = 400;
int idx_x_beg = 50; int_x_end = 100;
int idx_y_beg = 100; int_y_end = 200;
int idx_z_beg = 150; int_z_end = 300;
int idx_ch_beg = 200; int_ch_end = 400;
double *h_4dArray = (double *)malloc(sizeof(double)*nx*ny*nz*ch);
double *d_4dArray;
cudaMalloc((void**)&d_4dArray, (sizeof(cuDoubleReal)*nx*ny*nz*ch));
for (int temp_ch = 0; temp_ch < (idx_ch_end - idx_ch_beg + 1); temp_ch++) {
for (int temp_z = 0; temp_z < (idx_z_end - idx_z_beg + 1); temp_z++) {
for (int temp_y = 0; temp_y < (idx_y_end - idx_y_beg + 1); temp_y++) {
cudaMemcpy(d_4dArray + temp_ch*idx_z_size*idx_y_size*idx_x_size + temp_z*idx_y_size*idx_x_size + temp_y*idx_x_size
, h_4dArray + temp_ch*nz*ny*nx + temp_z*ny*nx + temp_y * nx + idx_x_beg
, sizeof(double)*(int_x_end - int_x_beg), cudaMemcpyHostToDevice)
}
}
}
return 0;
}
解决方案
对于复制数组的子集,cuda 提供cudaMemcpy2D
(可以复制多维数组的单个 2D 部分)和cudaMemcpy3D
(可以复制多维数组的单个 3D 部分)。您可以在标签上找到很多问题,cuda
以了解如何使用这些问题。
这些方法有两个问题:
- 它们不一定扩展到 4D 案例。即你可能还需要一个循环
- 这些操作的性能(主机<->设备传输速度)通常明显低于复制
cudaMemcpy
相同字节总数的操作
所以这里没有免费的午餐。我相信最好的建议是在主机上创建一个额外的“连续”缓冲区,将所有切片复制到该缓冲区,然后在一次cudaMemcpy
调用中将该缓冲区从主机复制到设备。之后,如果您仍然需要设备上的 4D 表示,那么您将需要编写一个设备内核来为您“分散”数据。从概念上讲,与您显示的代码相反。
抱歉,我不会为您编写所有代码。但是,我将使用您显示的代码粗略地完成它的第一部分(将所有内容复制到设备上的单个连续缓冲区):
int main(){
int nx = 100; ny = 200; nz = 300; nch = 400;
int idx_x_beg = 50; int_x_end = 100;
int idx_y_beg = 100; int_y_end = 200;
int idx_z_beg = 150; int_z_end = 300;
int idx_ch_beg = 200; int_ch_end = 400;
double *h_4dArray = (double *)malloc(sizeof(double)*nx*ny*nz*ch);
double *d_4dArray, *h_temp, *d_temp;
size_t temp_sz = (int_x_end - int_x_begin)*(idx_ch_end - idx_ch_beg + 1)*(idx_z_end - idx_z_beg + 1)*(idx_y_end - idx_y_beg + 1);
h_temp = (double *)malloc(temp_sz*sizeof(double));
cudaMalloc(&d_temp, temp_sz*sizeof(double));
cudaMalloc((void**)&d_4dArray, (sizeof(cuDoubleReal)*nx*ny*nz*ch));
size_t size_tr = 0;
for (int temp_ch = 0; temp_ch < (idx_ch_end - idx_ch_beg + 1); temp_ch++) {
for (int temp_z = 0; temp_z < (idx_z_end - idx_z_beg + 1); temp_z++) {
for (int temp_y = 0; temp_y < (idx_y_end - idx_y_beg + 1); temp_y++) {
memcpy(h_temp+size_tr
, h_4dArray + temp_ch*nz*ny*nx + temp_z*ny*nx + temp_y * nx + idx_x_beg
, sizeof(double)*(int_x_end - int_x_beg));
size_tr += (int_x_end - int_x_beg);
}
}
}
cudaMemcpy(d_temp, h_temp, temp_sz*sizeof(double), cudaMemcpyHostToDevice);
// if necessary, put cuda kernel here to scatter data from d_temp to d_4dArray
return 0;
}
之后,如前所述,如果您需要设备上的 4D 表示,您将需要一个 CUDA 内核来为您分散数据。
推荐阅读
- spring - 带有 Spring Security 的 SpringBoot 2 执行器
- python - 从列表中添加和检索项目
- visual-studio - Reporting Services tablix 不允许我冻结列标题和行
- spring - 由于 Spring 5 中的 Access / CORS 问题,无法访问我的后端的 URL
- python - 通过根据 MultiIndex 级别更改的值过滤列
- c# - C#/Unity:Visual Studio 参数未通过
- c++ - Avro C++:如何压缩内容?
- firebase - 在 onResume() 方法中。当我输入“mFirebaseAuth.addAuthStateListener(mAuthStateListener);”时,不幸的是在安装时停止了
- google-sheets - Google表格-如何将第1列中的每个项目与第2列中的每个项目连接起来
- c# - 保持外部编辑的数据完整性