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

前言

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

实现步骤

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

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

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

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

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

重要概念 - pitch

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

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

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

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

代码示例

 1 #include "cuda.h"
 2 #include "cuda_runtime.h"
 3
 4 #include <iostream>
 5
 6 using namespace std;
 7
 8 // 定义测试二维数组的行列数
 9 const int R = 5;
10 const int C = 10;
11
12 int main()
13 {
14     // 定义一个用于测试的二维数组,其每个元素都赋值为0,并将其打印出来。
15     int array2D[R][C];
16     cout << "传输前的测试矩阵:" << endl;
17     for (int i=0; i<R; i++) {
18         for (int j=0; j<C; j++) {
19             array2D[i][j] = 0;
20             cout << array2D[i][j] << " ";
21         }
22         cout << endl;
23     }
24
25     // 再定义另一个同样大小的二维数组用于获取从显存传回的结果
26     int result[R][C];
27     cout << "传输前的结果矩阵:" << endl;
28     for (int i=0; i<R; i++) {
29         for (int j=0; j<C; j++) {
30             result[i][j] = 1;
31             cout << result[i][j] << " ";
32         }
33         cout << endl;
34     }
35
36     // 为此二维数组在显存中分配内存
37     int *d_array2D;
38     cudaMalloc ((void**)&d_array2D, sizeof(int)*R*C);
39
40     // 获取显存中的二维数组的 pitch 值
41     size_t d_pitch;
42     cudaMallocPitch ((void**) &d_array2D, &d_pitch, sizeof(int)*C, R);
43
44     // 将二维数组转移进显存
45      cudaMemcpy2D (
46          d_array2D,    // 目的地址
47          d_pitch,    // 目的 pitch
48          array2D,    // 源地址
49          sizeof(int)*C,    // 源 pitch
50          sizeof(int)*C,    // 数据拷贝宽度
51          R,    // 数据拷贝高度
52          cudaMemcpyHostToDevice    // 数据传递方向
53         );
54
55      // 将二维数组从显存传输回主机端的结果矩阵中
56      cudaMemcpy2D (
57          result,    // 目的地址
58          sizeof(int)*C,    // 目的 pitch
59          d_array2D,    // 源地址
60          d_pitch,    // 源 pitch
61          sizeof(int)*C,    // 数据拷贝宽度
62          R,    // 数据拷贝高度
63          cudaMemcpyDeviceToHost    // 数据传递方向
64         );
65
66     // 打印传回到结果矩阵的数据
67     cout << "从显存获取到测试矩阵后的结果矩阵:" << endl;
68     for (int i=0; i<R; i++) {
69         for (int j=0; j<C; j++) {
70             cout << result[i][j] << " ";
71         }
72         cout << endl;
73     }
74
75     cudaFree (d_array2D);
76
77     cin.get();
78
79     return EXIT_SUCCESS;
80 }

运行测试

  

小结

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

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

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

    return;
}

二维数组的传输 (host <-> device),布布扣,bubuko.com

时间: 2024-10-03 13:10:31

二维数组的传输 (host <-> device)的相关文章

向函数中传输二维数组

void xxx (int **a, int r . int c){ // r代表行 , c代表列 //在转变后的函数中,array[i][j]这样的式子是不对的,因为编译器不能正确的为它寻址,所以我们需要模仿编译器的行为把array[i][j]这样的式子手工转变为 *( (int*) a + c* (i)  +  (j) ); } int a[3][3] =     {      {1, 1, 1},      {2, 2, 2},      {3, 3, 3}    }; xxx( (int

二维数组 cudaMallocPitch() 和三维数组 cudaMalloc3D() 的使用

? 使用  cudaMallocPitch()  和配套的  cudaMemcpy2D()  来使用二维数组.C 中二维数组内存分配是转化为一维数组,连贯紧凑,每次访问数组中的元素都必须从数组首元素开始遍历:而 cuda 中这样分配的二维数组内存保证了数组每一行首元素的地址值都按照 256 或 512 的倍数对齐,提高访问效率,但使得每行末尾元素与下一行首元素地址可能不连贯,使用指针寻址时要注意考虑尾部. 1 // cuda_rumtime_api.h 2 extern __host__ cud

二级指针与二维数组

最近看<Linux C程序设计大全>这本书,虽然书中有一些错误,但整体来说,书写得还算可以. 当看到网络编程[第23.2.4小节 获得主机信息]时,遇到了一段代码,原文如下: “一台主机有许多和网络相关的信息,例如,主机名称.IP地址.主机提供的服务等.这些信息一般都保存在系统中的某个文件里(例如/etc/hosts等),用户程序可以通过系统提供的函数读取这些文件上的内容.Linux环境下使用gethostent函数读取和主机有关的信息,该函数的原型如下: 1 #include <net

二维数组中按子数组首个元素值去重

后台更新了算法,用来挖掘数据,前台(我)配合后台搭建了新页面,历时两周,从 0 到 现在的联调完毕,呼呼,有累,但更多的是完成工作后的喜悦. 废话不多说,联调过程中遇到一个接口需要传输二维数组,是关于选择句子,然后将文档号和句子号拼接成数组,再压入大数组来向后台发送要保存的数据的. 而前台在存储时,选择的句子会直接存储其所属文档号,这样底层存储的数组就会变成对象数组: arr = [ {name:***,docNum:0,lineNum:3}, {name:***,docNum:2,lineNu

14-高效求最长公共子序列(二维数组存不下)

/*                                   See LCS again时间限制:1000 ms  |  内存限制:65535 KB难度:3 描述 There are A, B two sequences, the number of elements in the sequence is n.m; Each element in the sequence are different and less than 100000. Calculate the length

java基础:java中的二维数组

二维数组的概念: 一个元素为一维数组的数组. 格式1: 数据类型[][] 数组名 = new 数据类型[m][n]; m:表示这个二维数组有多少个一维数组. n:表示每一个一维数组的元素有多少个. 注意: A:以下格式也可以表示二维数组 a:数据类型 数组名[][] = new 数据类型[m][n]; b:数据类型[] 数组名[] = new 数据类型[m][n]; B:注意下面定义的区别 int x; int y; int x,y; int[] x; int[] y[]; int[] x,y[

二维数组

int[][]arr; arr=new int[5][6];//定义二维数组 int [][]grade=new int [5][6]//直接定义 for each循环:不使用下表就能访问: int=[]mum={12345} for(int a :m){ System.out.print(a)}  //num数组  a 12345;

二维数组与指针

二维数组: int / char / flaot a[n][m]; 可以看做是将一维数组做为基本类型产生的一维数组的数组类型,共n*m个最基本类型.这样看有许多优点(实际上计算机也是这样分配的). 二维数组数组名的注意事项: 1 #include <stdio.h> 2 int main() 3 { 4 int *p,a[3][4]; 5 p = a;//a是二维数组的首地址本质为行指针,原型为 a[][]:无法赋值给普通指针类型 *p: 6 return 0; 7 } 编译就会出现如下错误

二维数组中的查找-牛客网-剑指offer

1.问题描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 2.问题分析 水平方向.垂直方向二重循环查找 3.源代码 package www.nowcoder.com.conquerOffer.array; /** * 二维数组中的查找 * 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整