前言

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

实现步骤

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;
}

第六篇:二维数组的传输 (host <-> device)的更多相关文章

  1. 二维数组的传输 (host <-> device)

    前言 本文的目的很明确:介绍如何将二维数组传递进显存,以及如何将二维数组从显存传递回主机端. 实现步骤 1. 在显存中为二维数组开辟空间 2. 获取该二维数组在显存中的 pitch 值 (cudaMa ...

  2. Java菜鸟学习笔记--数组篇(三):二维数组

    定义 //1.二维数组的定义 //2.二维数组的内存空间 //3.不规则数组 package me.array; public class Array2Demo{ public static void ...

  3. java杨辉三角和空心菱形(二维数组篇)

    一.杨辉三角 import java.util.Scanner; //导入包 public class Test7 { public static void main(String[]args){ S ...

  4. C语言数组篇(五)多级指针和二维数组指针的区别

    多级指针   以二级指针为例 二级指针的由来是 指针数组 的指针形式. int *p[10] 读取的顺序是 p[] --> 10个空间的数组 * p[] --> 这10个空间的数组里面存放 ...

  5. C语言数组篇(四)二维数组

      二维数组声明: ][] ={{,,},{,,}; //两行 三列         二维数组在声明的时候可以不写行,但一定要写列 ] = {{,},{,,},{}}; //未声明的地方自动补零 二维 ...

  6. 第二篇 javascript一维数组和二维数组及方法

    一.数组 什么是数组 程序=数据+算法 数组就是一种很常见的保存批量数据的数据结构 一.定义数组 var arr1=[]; //定义了一个不包含元素的数组 ,,]; //定义了一个包含三个元素的数组 ...

  7. 剑指Offer的学习笔记(C#篇)-- 二维数组中的查找

    题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数 ...

  8. PHP代码篇(二)-- array_column函数将二维数组格式化成固定格式的一维数组,及优化查询方法

    小白因为经常用到多表查询,比如获取一个会员领取的卡卷list,里面当然包含了1“会员优惠券记录表t_coupon_members”主表,然后2“门店优惠券表t_coupon”,和3“门店信息表t_sh ...

  9. 唠唠C++二级指针、二维数组、指针数组、数组指针等的区分

    今天看c++primer第六章,有这部分的内容,脑子有点糊涂了,看了几篇博客,自己敲了下,记录一下备忘. 二级指针: int **p; 二维数组: int p[10][10]; char q[10][ ...

随机推荐

  1. 设置linux中tcp默认的20秒connect超时时间(转)

    无论你用任何语言或者是网络库,你都可以设置网络操作的超时时间,特别是connect.read.write的超时时间. 你可以在代码中把超时时间设置任意大小值,但是connect方法会有一点特殊. co ...

  2. spring3.1之前的HandlerMapping ,HandlerAdapter以及spring3.1写法

    <!--Spring3.1之前的注解 HandlerMapping --><!-- <bean class="org.springframework.web.serv ...

  3. Windows2008 R2下,应用程序池 'XXXXXXXX' 被自动禁用,原因是为此应用程序池提供服务的进程中出现一系列错误。

    转:http://www.cnblogs.com/freeton/archive/2012/08/28/2660585.html http://www.hack001.com/post/151

  4. Java Persistence with MyBatis 小结3

    1 映射器配置文件和映射器接口 在 com.mybatis3.mappers 包中的 StudentMapper.xml 配置文件内,是如何配置 id 为”findStudentById”的 SQL ...

  5. Python目录常用操作

    os.path.basename(path) #取文件名 os.path.getsize(path) #取文件大小 os.path.exists(path) #文件是否存在 os.path.dirna ...

  6. Atitit. 有限状态机 fsm 状态模式

    Atitit. 有限状态机 fsm 状态模式 1. 有限状态机 1 2. "状态表"和"状态轮换表" 1 3. 有限状态机概念(状态(State)事件(Even ...

  7. 01、Windows Phone 套接字(Socket)实战之交互设计

    这个 Demo 主要使用 WP 中提供的 Socket 对象,来与 PC 端进行文字.文件的互相传输.因为在 WP 中系统 对存储的操作限制的比较多,例如,你把 .doc..txt..zip 等常见的 ...

  8. 教程-Delphi中的GExperts搜索代码快捷键

    Shift+Ait+S  打开搜索 Ctrl+Ait+R 打开上次搜索结果

  9. cocos2dx场景切换的坑

    有一个类可以使用不同的数据源,每个数据源对应一个对象. 我在类里保存了对象的实例,由于要在其它地方使用所以做成了静态,并在每次初始化时 重新设置,析构时删除. 现在我打开了A,切换到B,结果这个静态的 ...

  10. osgi实战学习之路:6. Service-1

    什么是Service? 它是注冊到osgi的一个java对象 Service注冊: 通过BundleContext::registerService(java.lang.String[] clazze ...