CUDA并行存储模型

CUDA将CPU作为主机(Host),GPU作为设备(Device)。一个系统中可以有一个主机和多个设备。CPU负责逻辑性强的事务处理和串行计算,GPU专注于执行高度线程化的并行处理任务。它们拥有相互独立的存储器(主机端的内存和显卡端的显存)。

运行在GPU上的函数称为kernel(内核函数)。一个完整的CUDA程序是由一些列的kernel函数和主机端的串行处理步骤共同完成的。CPU串行代码的工作包括在kernel启动前进行的数据准备、设备初始化以及在kernel之间进行一些串行化计算。

kernel函数以函数类型限定符_global_定义,并且只能在主机端代码中调用。调用时需要制定kernel的Grid中的block数目以及每个block中thread的数目。每个线程有自己的blockID和threadID,可用来区分其它的线程,这两个内建变量是只读的,由专用寄存器提供,只能有kernel函数调用。

CUDA将计算任务映射为大量的可并行执行的线程,并由硬件动态调度和执行这些线程。kernel是以线程网格Grid的形式组织,每个Grid又若干个线程块block组成,每个block又由若干线程thread组成。本质上,kernel是以block为单位执行的,grid只是用来表示一些列并行block的集合。Block之间是不能彼此通信的。目前一个kernel只支持一个grid,在多指令多数据(MIMD)构架中会存在多个grid。

为方便编程,CUDA使用了dim3类型的内建变量threadIdx和threadIdx。

对于一维的block,线程的编号是threadIdx.x。

对于二维(Dx,Dy)的block,线程的编号是threadIdx.x+threadIdx.y * Dx。

对于三维(Dx,Dy,Dz)的block,线程的编号是threadIdx.x+threadIdx.y * Dx+hreadIdx.z* Dx * Dy。

GPU的计算核心是流多处理器(SM),每个SM包含8个标量流处理器(SP)以及其它的运算单元。Kernel是以block为单位执行的,同一个block的线程需要共享数据,因此它们共享同一个SM。一个block必须分配到一个SM,但是可以一个SM中同一个时刻有多个活动块(active block)执行等待,即同一个SM可以有多个block上下文。实际运行中,block会被分为更小的线程束(wrap),线程束的大小由硬件的计算能力决定,Tesla的构架中一个wrap由32个线程组成。

CUDA采用了单指令多线程执行模型。这个模型是对单指令多数据的改进。CUDA中执行宽度可以在1——512个线程之间变化,但是在单指令多数据中执行宽度必须是一个wrap(32)。

每一个线程拥有自己的私有存储器,每一个线程块拥有一块共享存储器(Shared memory);最后,grid中所有的线程都可以访问同一块全局存储器(global memory)。除此之外,还有两种可以被所有线程访问的只读存储器:常数存储器(constant memory)和纹理存储器(Texture memory),它们分别为不同的应用进行了优化。全局存储器、常数存储器和纹理存储器中的值在一个内核函数执行完成后将被继续保持,可以被同一程序中其也内核函数调用。


存储器


位置


拥有缓存


访问权限


变量生存周期


register


GPU片内


N/A


Device可读/写


与thread相同


Local memory


板载显存



Device可读/写


与thread相同


Shared memory


GPU片内


N/A


Device可读/写


与block相同


Constant memory


板载显存



Device可读,host要读写


可在程序中保持


Texture memory


板载显存



Device可读,host要读写


可在程序中保持


Global memory


板载显存



Device可读/写, host可读/写


可在程序中保持


Host memory


Host内存



host可读/写


可在程序中保持


Pinned memory


Host内存



host可读/写


可在程序中保持

CUDA存储器模型:

GPU片内:register,shared memory;

板载显存:local memory,constant memory,texture memory,global memory;

host 内存: host memory, pinned memory.

register: 访问延迟极低;

  基本单元:register file (32bit/each)

  计算能力1.0/1.1版本硬件:8192/SM;

  计算能力1.2/1.3版本硬件: 16384/SM;

  每个线程占有的register有限,编程时不要为其分配过多私有变量;

local memory:寄存器被使用完毕,数据将被存储在局部存储器中;

  大型结构体或者数组;

  无法确定大小的数组;

  线程的输入和中间变量;

  定义线程私有数组的同时进行初始化的数组被分配在寄存器中;

shared memory:访问速度与寄存器相似;

  实现线程间通信的延迟最小;

  保存公用的计数器或者block的公用结果;

硬件1.0~1.3中,16KByte/SM,被组织为16个bank;

声明关键字 _shared_  int sdata_static[16];

global memory:存在于显存中,也称为线性内存(显存可以被定义为线性存储器或者CUDA数组);

  cudaMalloc()函数分配,cudaFree()函数释放,cudaMemcpy()进行主机端与设备端的数据传输;

  初始化共享存储器需要调用cudaMemset();

  二维三维数组:cudaMallocPitch()和cudaMalloc3D()分配线性存储空间,可以确保分配满足对齐要求;

  cudaMemcpy2D(),cudaMemcpy3D()与设备端存储器进行拷贝;

host内存:分为pageable memory 和 pinned memory

pageable memory: 通过操作系统API(malloc(),new())分配的存储器空间;

pinned memory:始终存在于物理内存中,不会被分配到低速的虚拟内存中,能够通过DMA加速与设备端进行通信;cudaHostAlloc(), cudaFreeHost()来分配和释放pinned memory;

使用pinned memory优点:主机端-设备端的数据传输带宽高;某些设备上可以通过zero-copy功能映射到设备地址空间,从GPU直接访问,省掉主存与显存间进行数据拷贝的工作;pinned memory 不可以分配过多:导致操作系统用于分页的物理内存变,导致系统整体性能下降;通常由哪个cpu线程分配,就只有这个线程才有访问权限;

cuda2.3版本中,pinned memory功能扩充:

portable memory:让控制不同GPU的主机端线程操作同一块portable memory,实现cpu线程间通信;

使用cudaHostAlloc()分配页锁定内存时,加上cudaHostAllocPortable标志;

write-combined Memory:提高从cpu向GPU单向传输数据的速度;不使用cpu的L1,L2 cache对一块pinned memory中的数据进行缓冲,将cache资源留给其他程序使用;在pci-e总线传输期间不会被来自cpu的监视打断;在调用cudaHostAlloc()时加上cudaHostAllocWriteCombined标志;cpu从这种存储器上读取的速度很低;

mapped memory:两个地址:主机端地址(内存地址),设备端地址(显存地址)。

可以在kernnel程序中直接访问mapped memory中的数据,不必在内存和显存之间进行数据拷贝,即zero-copy功能;在主机端可以由cudaHostAlloc()函数获得,在设备端指针可以通过cudaHostGetDevicePointer()获得;通过cudaGetDeviceProperties()函数返回的canMapHostMemory属性知道设备是否支持mapped memory;在调用cudaHostAlloc()时加上cudaHostMapped标志,将pinned memory映射到设备地址空间;必须使用同步来保证cpu和GPu对同一块存储器操作的顺序一致性;显存中的一部分可以既是portable memory又是mapped memory;在执行CUDA操作前,先调用cudaSetDeviceFlags()(加cudaDeviceMapHost标志)进行页锁定内存映射。

constant memory:只读地址空间;位于显存,有缓存加速;64Kb;用于存储需要频繁访问的只读参数 ;只读;使用_constant_ 关键字,定义在所有函数之外;两种常数存储器的使用方法:直接在定义时初始化常数存储器;定义一个constant数组,然后使用函数进行赋值;

texture memory:只读;不是一块专门的存储器,而是牵涉到显存、两级纹理缓存、纹理拾取单元的纹理流水线;数据常以一维、二维或者三维数组的形式存储在显存中;缓存加速;可以声明大小比常数存储器大得多;适合实现图像树立和查找表;对大量数据的随机访问或非对齐访问有良好的加速效果;在kernel中访问纹理存储器的操作成为纹理拾取(texture fetching);纹理拾取使用的坐标与数据在显存中的位置可以不同,通过纹理参照系约定二者的映射方式;将显存中的数据与纹理参照系关联的操作,称为将数据与纹理绑定(texture binding);显存中可以绑定到纹理的数据有:普通线性存储器和cuda数组;存在缓存机制;可以设定滤波模式,寻址模式等;

时间: 2024-10-12 11:57:16

CUDA并行存储模型的相关文章

剖析Elasticsearch集群系列第一篇 Elasticsearch的存储模型和读写操作

剖析Elasticsearch集群系列涵盖了当今最流行的分布式搜索引擎Elasticsearch的底层架构和原型实例. 本文是这个系列的第一篇,在本文中,我们将讨论的Elasticsearch的底层存储模型及CRUD(创建.读取.更新和删除)操作的工作原理. Elasticsearch是当今最流行的分布式搜索引擎,GitHub. SalesforceIQ.Netflix等公司将其用于全文检索和分析应用.在Insight,我们用到了Elasticsearch的诸多不同功能,比如: 全文检索 比如找

【CUDA并行编程之三】Cuda矢量求和运算

本文将通过矢量求和运算来说明基本的Cuda并行编程的基本概念.所谓矢量求和运算,就是两个数组数据中对应的元素两两相加,并将结果保存在第三个数组中.如下图所示: 1.基于CPU的矢量求和: 代码非常简单: #include<iostream> using namespace std; const int N =10; void add( int *a ,int *b , int *c) { int tid = 0; while(tid < N) { c[tid] = a[tid] + b[

【CUDA并行程序设计系列(1)】GPU技术简介

http://www.cnblogs.com/5long/p/cuda-parallel-programming-1.html 本系列目录: [CUDA并行程序设计系列(1)]GPU技术简介 [CUDA并行程序设计系列(2)]CUDA简介及CUDA初步编程 [CUDA并行程序设计系列(3)]CUDA线程模型 [CUDA并行程序设计系列(4)]CUDA内存 [CUDA并行程序设计系列(5)]CUDA原子操作与同步 [CUDA并行程序设计系列(6)]CUDA流与多GPU 关于CUDA的一些学习资料

多核程序设计——存储模型

最近在看<现代体系结构上的UNIX系统--内核程序员的SMP和Caching技术>,这里抄点东西作为笔记吧! 顺序存储模型强制存储器操作(load和store)都按照程序次序来执行,即这些指令是按照在随程序执行的指令流中出现的顺序次序来执行的.它也指定了,由不同处理器完成的load和store操作也要以某种顺序.但又是非确定性的方式排序.这种存储模型应该是大家最容易理解的,甚至都认为实际MP也是这样工作的.但是,这种存储结构是非常落后的,现代处理器应该已经淘汰了这种结构. 书中讲到了一个例子,

【CUDA并行编程之七】数组元素之和

现在需要求得一个数组的所有元素之和,之前感觉似乎不太可能,因为每个线程只处理一个元素,无法将所有元素联系起来,但是最近学习了一段代码可以实现,同时也对shared memory有了进一步的理解. 一.C++串行实现 串行实现的方法非常之简单,只要将所有元素依次相加就能够得到相应的结果,实际上我们注重的不是结果,而是运行的效率.那么代码如下: array_sum.cc: #include<iostream> #include<stdio.h> #include "kmean

Bitcask存储模型

----<大规模分布式存储系统:原理解析与架构实战>读书笔记 近期一直在分析OceanBase的源代码,恰巧碰到了OceanBase的核心开发人员的新作<大规模分布式存储系统:原理解析与架构实战>.看完样章后决定入手,果然物有所值. 对于准备学习分布式的同学,这是一本不错的书籍,相对系统,全面的介绍了分布式的相关技术和项目,基本都是干货. 另一半是在介绍OceanBase的内容,对我来说,正是踏破铁鞋无觅处.接下来会有几篇专门研究存储引擎的读书笔记哟.废话不多说,转入正题. 1.存

Bitcask 存储模型的实现 - merge与hint文件

在<Bitcask存储模型的实现 - 基本框架>中,我们了解了Bitcask存储模型中数据的存储方式.内存索引的组织形式,以及如何使用缓存加速数据读取.另外,Bitcask存储模型中提出闲时进行merge减少数据冗余.运用hint文件加速创建内存索引,下面我们来看merge的具体实现.如何用hint文件加速索引创建. merge Bitcask是日志型存储模型,对于新增和更改的操作,都Append到磁盘,磁盘使用率将随着操作的增多而增长. 以上图例表示,key及对应val最开始存放在25.w,

C语言存储模型

描述方法(三个方面) 作用域 代码块.函数原型 文件作用域 链接类型 外部链接 内部链接 空链接 存储时期 静态存储时期 动态存储时期 变量类型 变量存储类型 作用域 链接类型 存储时期 C语言存储模型(类) 文件 外部 静态 具有外部链接的静态 内部(static) 具有内部链接的静态 代码块 无链接 静态(static) 空链接静态变量 动态 自动变量 寄存器(性质与自动变量类似,存储在寄存器中) 寄存器 注: 具有外部链接的在其他文件使用前必须以exturn声明 具有静态存储期的变量必须使

LSM树存储模型

----<大规模分布式存储系统:原理解析与架构实战>读书笔记 之前研究了Bitcask存储模型,今天来看看LSM存储模型,两者虽然同属于基于键值的日志型存储模型.但是Bitcask使用哈希表建立索引,而LSM使用跳跃表建立索引.这一差别导致了两个存储系统的构造出现明显的分化.为此,我还先去捣腾了一番跳跃表的实现.今天算是进入了正题. LSM的结构 LSM的基本思想是将修改的数据保存在内存,达到一定数量后在将修改的数据批量写入磁盘,在写入的过程中与之前已经存在的数据做合并.同B树存储模型一样,L