原文链接

概述:线性存储器可以通过cudaMalloc()、cudaMallocPitch()和cudaMalloc3D()分配

1、1D线性内存分配

1 cudaMalloc(void**,int)    //在设备端分配内存
2 cudaMemcpy(void* dest,void* source,int size,enum direction) //数据拷贝
3 cudaMemcpyToSymbol //将数据复制到__constant__变量中,或者__device__变量中
4 cudaMemcpyFromSynbol //同上相反
5 cudaFree() //内存释放
6 cudaMemset() //内存初始化

注意:主机和设备间的数据交换会自动同步,而设备与设备却不会,需要使用cudaThreadSynchronize()

2、2D线性内存分配

2.1 分配

1 cudaMallocPitch( void** devPtr,size_t* pitch,size_t widthInBytes,size_t height ) //在线性内存中分配二维数组,width的单位是字节,而height单位是数据类型

c语言申请2维内存时,一般是连续存放的。a[y][x]存放在第y*widthofx*sizeof(元素)+x*sizeof(元素)个字节。

在cuda的global memory访问中,从256字节对齐的地址(addr=0, 256, 512, ...)开始的连续访问是最有效率的。这样,为了提高内存访问的效率,有了cudaMallocPitch函数。cudaMallocPitch函数分配的内存中,数组的每一行的第一个元素的开始地址都保证是对齐的。因为每行有多少个数据是不确定的,widthofx*sizeof(元素)不一定是256的倍数。故此,为保证数组的每一行的第一个元素的开始地址对齐,cudaMallocPitch在分配内存时,每行会多分配一些字节,以保证widthofx*sizeof(元素)+多分配的字节是256的倍数(对齐)。这样,上面的y*widthofx*sizeof(元素)+x*sizeof(元素)来计算a[y][x]的地址就不正确了。而应该是y*[widthofx*sizeof(元素)+多分配的字节]+x*sizeof(元素)。而函数中返回的pitch的值就是widthofx*sizeof(元素)+多分配的字节。说明:widthInBytes作为输入参数,应该是widthofx*sizeof(元素);这样的话,复制内容时也要作相应的修改。

2.2 访问

1 T* pElement = (T*)((char*)BaseAddress + Row * pitch) + Column;           //元素访问方式

cudaMallocPitch()以*pitch的形式返回间距,即所分配存储器的宽度,以字节为单位。间距用作存储器分配的一个独立参数,用于在2D数组内计算地址。

2.3 拷贝

1 cudaMemcpy2D( void* dst,size_t dpitch,const void* src,size_t spitch,size_t width,size_t height,enum cudaMemcpyKind kind )

这里需要特别注意width与pitch的区别,width是实际需要拷贝的数据宽度而pitch是2D线性存储空间分配时对齐的行宽,而当数据传递发生在设备与主机之间时,主机端pitch==width.

综上我们可以看到,CUDA下对二维线性空间的访问是不提供多下标支持的,访问时依然是通过计算偏移量得到,不同的地方在于使用pitch对齐后非常利于实现coalesce访问

例:下面的代码分配了一个尺寸为width*height的二维浮点数组,同时演示了怎样在设备代码中遍历数组元素

 1 // Host code
2 int width = 64, height = 64;
3 float* devPtr;
4 int pitch;
5 cudaMallocPitch((void**)&devPtr, &pitch, width * sizeof(float), height);
6 MyKernel<<<100, 512>>>(devPtr, pitch, width, height);
7 // Device code
8 __global__ void MyKernel(float* devPtr, int pitch, int width, int height){
9 for (int r = 0; r < height; ++r) {
10 float* row = (float*)((char*)devPtr + r * pitch);
11 for (int c = 0; c < width; ++c) {
12 float element = row[c];
13 }
14 }
15 }

3、3D线性内存

1 cudaError_t cudaMalloc3D(
2 struct cudaPitchedPtr * pitchedDevPtr,
3 struct cudaExtent extent
4 )

例:下面的代码分配了一个尺寸为width*height*depth的三维浮点数组,同时演示了怎样在设备代码中遍历数组元素

 1 // Host code
2 cudaPitchedPtr devPitchedPtr;
3 cudaExtent extent = make_cudaExtent(64, 64, 64);
4 cudaMalloc3D(&devPitchedPtr, extent);
5 MyKernel<<<100, 512>>>(devPitchedPtr, extent);
6 // Device code
7 __global__ void MyKernel(cudaPitchedPtr devPitchedPtr, cudaExtent extent) {
8 char* devPtr = devPitchedPtr.ptr;
9 size_t pitch = devPitchedPtr.pitch;
10 size_t slicePitch = pitch * extent.height;
11 for (int z = 0; z < extent.depth; ++z) {
12 char* slice = devPtr + z * slicePitch;
13 for (int y = 0; y < extent.height; ++y) {
14 float* row = (float*)(slice + y * pitch);
15 for (int x = 0; x < extent.width; ++x) { float element = row[x];
16 }
17 }
18 }
 

CUDA线性内存分配的更多相关文章

  1. 【CUDA 基础】5.1 CUDA共享内存概述

    title: [CUDA 基础]5.1 CUDA共享内存概述 categories: - CUDA - Freshman tags: - CUDA共享内存模型 - CUDA共享内存分配 - CUDA共 ...

  2. CUDA -- 内存分配

    CUDA可以认为是一个由软件和硬件构成的并行计算系统,其依赖于GPU的并行计算单元,CUDA有类C的API,方便程序编写.其依赖于CPU和GPU的异构体系,通过在CPU上串行执行环境初始化.内存分配. ...

  3. CUDA 纹理内存

    原文链接 1.概述 纹理存储器中的数据以一维.二维或者三维数组的形式存储在显存中,可以通过缓存加速访问,并且可以声明大小比常数存储器要大的多. 在kernel中访问纹理存储器的操作称为纹理拾取(tex ...

  4. Linux内核笔记--内存管理之用户态进程内存分配

    内核版本:linux-2.6.11 Linux在加载一个可执行程序的时候做了种种复杂的工作,内存分配是其中非常重要的一环,作为一个linux程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你 ...

  5. java\c程序的内存分配

    JAVA 文件编译执行与虚拟机(JVM)介绍 Java 虚拟机(JVM)是可运行Java代码的假想计算机.只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何Java代码能够在该 ...

  6. c++内存分配

    [导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不 ...

  7. 【转】C++ 内存分配(new,operator new)详解

    本文主要讲述C++ new运算符和operator new, placement new之间的种种关联,new的底层实现,以及operator new的重载和一些在内存池,STL中的应用. 一 new ...

  8. 内存管理概述、内存分配与释放、地址映射机制(mm_struct, vm_area_struct)、malloc/free 的实现

    http://blog.csdn.net/pi9nc/article/details/23334659 注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料 ...

  9. Linux内核中常见内存分配函数(二)

    常用内存分配函数 __get_free_pages unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order) __get_f ...

随机推荐

  1. 实用的vue插件大汇总

    Vue是一个构建数据驱动的 web 界面的渐进式框架.Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件特别整理了常用的vue插件,来了个大汇总,方便查找使用,便于工作 ...

  2. 分布式思想和rpc解决方案介绍

    1.RPC的诞生 RPC(Remote Procedure Call)远程过程调用,通过这个rpc协议,调用远程计算机上的服务,就像调用本地的服务一样. 不同的服务部署在不同的机器上面,并且在启动后在 ...

  3. UGUI 切割图片

    1.图片设置为以下格式,然后点击Sprite Editor. 2.点击Slice. 3.再点击Slice. 4.效果图.

  4. adb root错误信息adbd cannot run as root in production builds问题解决

    adb root错误信息adbd cannot run as root in production builds问题解决 一.问题描述 1.输入指令 >adb root adbd cannot ...

  5. php-fpm 进程在云服务器cpu分配不均匀

    8核的云服务器,开了200个php-fpm进程,用top命令查看  大部分进程都在cpu 0 上跑着,导致其他cpu 负载很低,cpu分配不均匀: 使用shell 解决问题: 列出所有php-fpm ...

  6. jquery validation yyyy-MM-dd格式日期在ie中无法验证通过

    自己开发的公众号,可以领取淘宝内部优惠券 问题 首先在ie6.7.8下面打开这个页面http://jqueryvalidation.org/date-method/,输入的日期格式为:yyyy-MM- ...

  7. Spring Boot + Redis 实现Shiro集群

    为实现Web应用的分布式集群部署,要解决登录session的统一.本文利用shiro做权限控制,redis做session存储,结合spring boot快速配置实现session共享. 1.引入相关 ...

  8. python面试题——网络编程和并发

    1.简述 OSI 七层协议. 物理层(电信号.比特流) 基于电器特性发送高低电压(电信号) RJ45.IEEE802.3 数据链路层(数据帧) 定义了电信号的分组方式,分组方式后来形成了统一的标准,即 ...

  9. Android5.0以后,materialDesign风格的加阴影和裁剪效果

    5.0以后,materialDesign风格,出现了立体这种概念,高光,阴影,也就是Z轴,凸显层次:同时,裁剪view也变得方便简单了很多. 1,先说说阴影的实现. 方案1:在xml中设置 xml中设 ...

  10. GDB多线程调试分析

    0x00: 在Linux系统上Gdb提供了一组多线程调试命令,如表所示: 多线程调试的主要任务是准确及时地捕捉被调试程序线程状态的变化的事件,并且GDB针对根据捕捉到的事件做出相应的操作,其实最终的结 ...