CUDA线性内存分配

原文链接

概述:线性存储器可以通过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学习笔记

时间: 2024-08-09 18:04:31

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

线性表的动态内存分配顺序存储结构

1.线性表是最简单的一种数据结构,很容易实现其中单个元素的存取操作,但是对于插入和删除操作需要大量的移动.比较适用于相对稳定的线性表. 2.数据元素 struct SqList { ElemType * elem ; //存储空间基址 int length ; //当前长度 int listsize ; //当前分配的存储容量 }; 3.创建一个空的线性表 void InitList(SqList &L) { //构造一个空的顺序线性表L L.elem = (ElemType*)malloc(L

CUDA 纹理内存

原文链接 1.概述 纹理存储器中的数据以一维.二维或者三维数组的形式存储在显存中,可以通过缓存加速访问,并且可以声明大小比常数存储器要大的多. 在kernel中访问纹理存储器的操作称为纹理拾取(texture fetching).将显存中的数据与纹理参照系关联的操作,称为将数据与纹理绑定(texture binding). 显存中可以绑定到纹理的数据有两种,分别是普通的线性存储器和cuda数组. 注:线性存储器只能与一维或二维纹理绑定,采用整型纹理拾取坐标,坐标值与数据在存储器中的位置相同:  

【C/C++学院】0828-数组与指针/内存分配/数据结构数组接口与封装

[送给在路上的程序员] 对于一个开发者而言,能够胜任系统中任意一个模块的开发是其核心价值的体现. 对于一个架构师而言,掌握各种语言的优势并可以运用到系统中,由此简化系统的开发,是其架构生涯的第一步. 对于一个开发团队而言,能在短期内开发出用户满意的软件系统是起核心竞争力的体现. 每一个程序员都不能固步自封,要多接触新的行业,新的技术领域,突破自我. 数组与指针 #include<stdio.h> #include<stdlib.h> void main1() { int a[10]

iOS内存分配五大区:

iOS内存分配五大区: 栈区,堆区,静态区(全局区),常量区,代码区 动态数据区一般就是”堆栈”,栈是线性结构,堆是链式结构. 本地变量在堆栈中.通过堆栈的基地址和偏移量来访问本地变量 动态内存分配有系统根据程序需要即时分配,且分配的大小就是程序要求的大小. 全局变量(一般用static修饰的变量)和静态变量分配在静态区(需要预先分配存储空间) 静态内存分配:分配固定大小的内存分配方法,大多情况下会浪费大量的内存空间,少数情况下,当定义的数组不够大时,会引起越界. 局部变量采用栈的方式存放

linux内核内存分配(三、虚拟内存管理)

在分析虚拟内存管理前要先看下linux内核内存的详细分配我开始就是困在这个地方,对内核内存的分类不是很清晰.我摘录其中的一段: 内核内存地址 =========================================================================================================== 在linux的内存管理中,用户使用0-3GB的地址空间,而内核只是用了3GB-4GB区间的地址空间,共1GB:非连 续空间的物理映射就位于3G

数据结构中的堆和栈 与 内存分配中的堆区和栈区 分析

比較全面的总结了诸多版本号,知识无国界.感谢各位的辛勤劳作. 在计算机领域,堆栈是一个不容忽视的概念,我们编写的C/C++语言程序基本上都要用到.但对于非常多的初学着来说,堆栈是一个非常模糊的概念. (1) 数据结构的栈和堆 首先在数据结构上要知道堆栈,虽然我们这么称呼它,但实际上堆栈是两种数据结构:堆和栈. 堆和栈都是一种数据项按序排列的数据结构. 栈就像装数据的桶或箱子 我们先从大家比較熟悉的栈说起吧.它是一种具有后进先出性质的数据结构,也就是说后存放的先取.先存放的后取.这就如同我们要取出

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

本文主要讲述C++ new运算符和operator new, placement new之间的种种关联,new的底层实现,以及operator new的重载和一些在内存池,STL中的应用. 一 new运算符和operator new(): new:指我们在C++里通常用到的运算符,比如A* a = new A;  对于new来说,有new和::new之分,前者位于std operator new():指对new的重载形式,它是一个函数,并不是运算符.对于operator new来说,分为全局重载

MySQL内存分配

原文链接: MySQL Memory Allocation -- by Rick James 原文日期: Created 2010; Refreshed Oct, 2012, Jan, 2014 翻译人员: 铁锚 翻译日期: 2014年5月28日 MySQL 内存分配-- 快速设置方案 如果仅使用MyISAM存储引擎,设置 key_buffer_size 为可用内存的20%,(再加上设置 innodb_buffer_pool_size = 0 ) 如果仅使用InnoDB存储引擎,设置 innod

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

http://blog.csdn.net/pi9nc/article/details/23334659 注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料如<linux内核完全剖析>.<linux c 编程一站式学习>等,只是为了更好地理清系统编程和网络编程中的一些概念性问题,并没有深入地阅读分析源码,我也是草草翻过这本书,请有兴趣的朋友自己参考相关资料.此书出版较早,分析的版本为2.4.16,故出现的一些概念可能跟最新版本内核不同.