基本的GPU内存操作

GPU内存

虽然GPU具有强大的算力,但GPU不能单独工作,需要与CPU一起并作为CPU的协处理器才能工作。CPU与GPU分别具有独立的内存系统,见下图。CPU端也称为Host端,CPU内存称为Host(主机)内存;GPU端也成为Device(设备)端,其内存称为Device内存。一般情况下,如果我们要在GPU端进行计算,就需要把待处理的数据拷贝到到Device内存中,待数据处理完成之后,还需要把计算结果拷贝到Host端做进一步的处理,比如存储到硬盘中或者打印到显示器上。这一小节主要介绍如何在GPU端分配与释放内存以及如何在CPU与GPU之间进行数据的拷贝。



把前面小节中向量加的main函数代码拷贝到下面:

int main(void) {
    size_t size = N * sizeof(int);
    int *h_a, *h_b; 
    int *d_a, *d_b, *d_c;
    h_a = (int *)malloc(size);
    h_b = (int *)malloc(size);
    ...
    cudaMalloc((void **)&d_a, size);
    cudaMalloc((void **)&d_b, size);
    cudaMalloc((void **)&d_c, size);

    cudaMemcpy(d_a, h_a, size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_b, h_b, size, cudaMemcpyHostToDevice);
    vectoradd<<<Grid, block>>>(d_a, d_b, d_c, N);
    cudaMemcpy(h_c, d_c, size, cudaMemcpyDeviceToHost);

    cudaFree(d_a); cudaFree(d_b); cudaFree(d_c);
    free(h_a); free(h_b);
    return 0;
}

从这段代码中我们可以看到,总共声明了两类不同的指针,int *h_a, *h_b;以及int *d_a, *d_b, *d_c;。前者是Host指针,指向host端内存;后者是Device指针,指向Device端内存。Device端的指针可以在主机端调用,但是不能在主机端解引用。主机端指针同样不能在设备端解引用。这里的设备端指针并不是位于设备端,而是指向设备端的内存。指针仍然是在主机端上,所以主机端可以使用这个指针,但是不能够解引用指向设备端内存的指针。

内存分配与释放

我们知道在CPU端代码中,内存的分配、初始化以及释放可以调用下面的函数实现:

malloc(size_t)
memset(void *, int, size_t)
free(void*)

相应的CUDA也提供了丰富的API进行内存管理与操作,其内存的分配、初始化以及释放的API如下:

cudaMalloc(void**, size_t)
cudaMemset(void*, int, size_t) 
cudaFree(void*)

其使用方法与CPU中的相应函数类似,更加具体的参数以及使用参加官方的文档:CUDA Documentation。cudaMalloc()分配的是线性内存,对应的释放内存的API是cudaFree()。线性内存也可以采用cudaMallocPitch()以及CUDAMalloc3D()来分配。这两个函数更加推荐用于2D以及3D数组的分配,这样可以保证内存的对齐要求。设备端内存在对齐访问的时候有更高的效率,这点会在后面详细GPU内存管理中进行介绍。

内存拷贝

不同方式的内存分配对应不同方式的内存拷贝的API。比如采用cudaMalloc分配的内存可以采用下面的CUDA API来在CPU与GPU之间传输数据:

cudaMemcpy ( void* dst, const void* src, size_t count, cudaMemcpyKind kind ) 

其中dst代表目的内存地址,src代表源内存地址,count代表需要拷贝的内存大小(bytes),kind代表数据拷贝的方向,必须是cudaMemcpyHostToHost, cudaMemcpyHostToDevice, cudaMemcpyDeviceToHost, cudaMemcpyDeviceToDevice以及cudaMemcpyDefault之一。可以看出该函数既可以实现在CPU与GPU内存之间的拷贝,也可以实现GPU内部之间的数据拷贝。需要注意的是cudaMemcpyDefault只能在支持统一虚拟地址(UVA)的系统上实现。在调用cudaMemcpy的时候,如果dst以及src的指针与拷贝的方向不一致时将会导致错误。相应的,采用 cudaMallocPitch()以及cudaMalloc3D()分配的内存,可以采用 cudaMemcpy2D()以及cudaMemcpy3D()来传输数据。
cudaMalloc是在设备端动态的分配内存,类似于CPU代码,我们也可以直接在设备端声明一个数据,这里需要用到__device__以及__constant__等标识符。下面的一段代码展示了不同访问device内存的方式:

__constant__ float constData[256];
float data[256];
cudaMemcpyToSymbol(constData, data, sizeof(data));
cudaMemcpyFromSymbol(data, constData, sizeof(data));

__device__ float devData;
float value = 3.14f;
cudaMemcpyToSymbol(devData, &value, sizeof(float));

__device__ float* devPointer;
float* ptr;
cudaMalloc(&ptr, 256 * sizeof(float));
cudaMemcpyToSymbol(devPointer, &ptr, sizeof(ptr));

需要指出的是cudaMemcpy是阻塞式的API,也就是CPU端代码在调用该API时,只有当该API完成拷贝之后,CPU才能继续处理后面的任务。这有一个好处就是保证了计算结果已经完全从GPU端拷贝到了CPU。同时CUDA也提供了非阻塞拷贝的API:cudaMemcpyAsync(), 非阻塞拷贝也称为异步拷贝,指的是该API在拷贝完成之前就返回,使得CPU可以继续处理后续的代码。异步拷贝API使得CPU与GPU之间的数据拷贝与CPU计算的并发称为可能。如果该API与CUDA中流(Stream)相结合使用,也可以实现数据的拷贝与GPU计算进行并发执行,这一点会在流与并发这一部分进行介绍。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容

  • 开篇一张图,后面听我编 1. 知识准备 1.1 中央处理器(CPU) 中央处理器(CPU,Central Proc...
    He_Yu阅读 47,060评论 7 115
  • CUDA从入门到精通(零):写在前面 本文原版链接: 在老板的要求下,本博主从2012年上高性能计算课程开始接触C...
    Pitfalls阅读 3,608评论 1 3
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  • GPU虚拟化 一、GPU概述 GPU的英文名称为Graphic Processing Unit,GPU中文全称为计...
    oo水桶oo阅读 2,987评论 0 2
  • 要求 相信 接收 相信已经拥有,感恩看到听到感觉到并深深相信,我此刻正在享受着我所用的手机,苹果电脑,太棒了,此刻...
    A下一个奇迹阅读 291评论 0 1