前言

本文的目的很明确:介绍如何将二维数组传递进显存,以及如何将二维数组从显存传递回主机端。

实现步骤

1. 在显存中为二维数组开辟空间

2. 获取该二维数组在显存中的 pitch 值 (cudaMallocPitch 实现)

3. 将二维数组传递进显存 (cudaMemcpy2D 实现)

4. 在显存中对该二维数组进行处理 (目前必须按照 1 维数组的规则进行处理)

5. 将结果传递回内存 (cudaMemcpy2D实现)

重要概念 - pitch

对于内存的存取来说,对准偏移量为2的幂(现在一般要求2^4=16)的地址能获取更快的速度,而如果不对齐,可能你需要的数据需要更多的存取次数才能得到。

为了满足这个条件,对于一个二维数组来说(行优先row major),就希望每一行的开头都满足“对齐”。如果一行的长度不规整,导致下一行开头不在指定的位置,就需要在每一行末尾进行填充(padding),从而使得每一行都对齐,这和BMP格式的像素存储是一个道理。

pitch就是指每一行的字节数 + padding的字节数 。

使用 cudaMemcpy2D 的目的仅是为了利用 pitch 机制提升二维数组中元素的访问速度。事实上二维数组传递进显存后,还是得按照一维数组的规范去处理该二维矩阵。global 函数中目前不支持多下标访问,好坑。。

代码示例

 #include "cuda.h"
#include "cuda_runtime.h" #include <iostream> using namespace std; // 定义测试二维数组的行列数
const int R = ;
const int C = ; int main()
{
// 定义一个用于测试的二维数组,其每个元素都赋值为0,并将其打印出来。
int array2D[R][C];
cout << "传输前的测试矩阵:" << endl;
for (int i=; i<R; i++) {
for (int j=; j<C; j++) {
array2D[i][j] = ;
cout << array2D[i][j] << " ";
}
cout << endl;
} // 再定义另一个同样大小的二维数组用于获取从显存传回的结果
int result[R][C];
cout << "传输前的结果矩阵:" << endl;
for (int i=; i<R; i++) {
for (int j=; j<C; j++) {
result[i][j] = ;
cout << result[i][j] << " ";
}
cout << endl;
} // 为此二维数组在显存中分配内存
int *d_array2D;
cudaMalloc ((void**)&d_array2D, sizeof(int)*R*C); // 获取显存中的二维数组的 pitch 值
size_t d_pitch;
cudaMallocPitch ((void**) &d_array2D, &d_pitch, sizeof(int)*C, R); // 将二维数组转移进显存
cudaMemcpy2D (
d_array2D, // 目的地址
d_pitch, // 目的 pitch
array2D, // 源地址
sizeof(int)*C, // 源 pitch
sizeof(int)*C, // 数据拷贝宽度
R, // 数据拷贝高度
cudaMemcpyHostToDevice // 数据传递方向
); // 将二维数组从显存传输回主机端的结果矩阵中
cudaMemcpy2D (
result, // 目的地址
sizeof(int)*C, // 目的 pitch
d_array2D, // 源地址
d_pitch, // 源 pitch
sizeof(int)*C, // 数据拷贝宽度
R, // 数据拷贝高度
cudaMemcpyDeviceToHost // 数据传递方向
); // 打印传回到结果矩阵的数据
cout << "从显存获取到测试矩阵后的结果矩阵:" << endl;
for (int i=; i<R; i++) {
for (int j=; j<C; j++) {
cout << result[i][j] << " ";
}
cout << endl;
} cudaFree (d_array2D); cin.get(); return EXIT_SUCCESS;
}

运行测试

小结

本文介绍的仅仅是二维数组在两端之间的传输!当二维数组传递进了显存,在对其操作的过程中,是需要对其进行一个一维到二维的下标操作转换的,global 中不支持多下标访问。之所以加入 pitch 并使用 cudaMemcpy2D 只是为了提高元素的访问速度。

如果需要具体处理传递进入的二维数组,还要将 pitch 也作为参数传递进 kernel 函数,如下所示:

 // 下面的 kernel 函数将二维数组的所有位置为 2
__global__
void kernelFun (int *d_array2D, int pitch)
{
for (int i=; i<R; i++) {
int *row = (int *)((char *)d_array2D+i*pitch);
for (int j=; j<C; j++) {
row[j] = ;
}
} return;
}

最新文章

  1. angular 源码分析 1 - angularInit()
  2. bzoj4196
  3. 基于 Jenkins 快速搭建持续集成环境
  4. .NET异常问题总结
  5. iis+php+mysql
  6. java中static{}语句块详解
  7. ionic 写一个五星评价(非指令)
  8. 方法参数out
  9. 【转载】ABAP-如何读取内表的字段名称
  10. 超级详细 一听就会:利用JavaScript jQuery实现图片无限循环轮播(不借助于轮播插件)
  11. 解决打开png图片黑屏问题(批量还原Xcode优化后的png)
  12. Visual Studio Code初识与自动化构建工具安装
  13. Hibernte
  14. Qt 文件的操作
  15. postgresql,封装数据库语句时,查询报错。
  16. 常规DP专题练习
  17. 通过jedis远程访问redis服务器
  18. 重温IO
  19. Python编程练习:使用 turtle 库完成叠边形的绘制
  20. xcode svn commit is not under version control 和 git常用指令

热门文章

  1. Linux-软件包管理-yum在线管理-yum命令
  2. Linux命令-帮助命令:man
  3. idea 更换编辑器背景图片
  4. [bug]未能从程序集“System.ServiceModel, Version=3.0.0.0问题解决
  5. python ichat使用学习记录
  6. EMQ学习 ---集群
  7. 用string存取二进制数据
  8. pip install mysql-connector 安装出错
  9. 自己的一个验证电话和ecshop验证电话
  10. CentOS 6.4 yum安装chrome