CUDA Learning.

#@author:       gr
#@date: 2014-04-06
#@email: forgerui@gmail.com

1. Introduction

CPU和GPU的区别。GPU拥有更多的核心数,可以对简单逻辑、大量数据进行并行计算,大大提高了计算能力。

有更多的SM会有更好的性能。

2. General

1.1. kernel

核函数通过__global__声明。通过<<<...>>>指定执行的线程数。

__global__ void VecAdd(float* A, float* B, float* C)
{
int i = threadIdx.x;
C[i] = A[i] + B[i];
}
int main()
{
...
// Kernel invocation with N threads
VecAdd<<<1, N>>>(A, B, C);
...
}

1.2. Thread, Block, Grid

一次任务就可以算是一个Grid。在Grid里,可以分成几块Block。而Block里就是每个要处理的Thread。

核函数的形式是kernel<<<G, B, Ns, S>>>(...)

G代表grid的尺寸,可以是三维的,也可以是int

B是线程块block的大小。

Ns是每个block除了静态分配的shared memory之外,最多能动态分配的shared memory大小。

S是一个cudaStream_t类型的可选参数,默认值为0, 表示核函数处于哪个流中。

目前的GPU,block中线程的大小最大为1024, 一般取256,而\(G = N / B\),\(N\) 是线程总数,但我们需要对\(G\)的计算结果取上整,我们这里不是使用ceil函数,而是使用下面的式子\(G = (N + B - 1) / B\)来达到取上整的目的。

取上整会导致启动的线程总数大于需要的整数,我们可以利用条件进行检查。

if (tid < N)
c[tid] = a[tid] + b[tid]

上面实现的一个问题是,G同样也是有限制大小的,如果(N+B-1)/B大于65535时,核函数调用kernel<<<G, B>>>就会出错。为了确保不会启动过多的线程块,可以将线程块固定为某个确定的值。如下,取<<<256, 256>>>,让每个线程多做几个任务:

__global__ void add (int *a, int *b, int *c){
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < N){
c[tid] = a[tid] + b[tid];
// blockDim.x * gridDim.x表示的是启动的总共线程数量
tid += blockDim.x * gridDim.x;
}
} add<<<256, 256>>>(d_a, d_b, d_c);

核函数中的一些内置变量:

gridDim: 线程格的尺寸。上图中,gridDim = (3, 2, 1)

blockIdx: 线程块的索引值。上图中,Block(1, 1)的索引值blockIdx = (1, 1, 1)

blockDim: 线程块的尺寸。上图中,blockDim = (4, 3, 1)

threadIdx: 线程索引值。上图中,Thread(1, 1)的索引值threadIdx = (1, 1, 1)

代码如下:

void main(){
int a;
} __global__ void MatAdd(float** A, float** B, float** C, int N)
{
int i = blockIdx.x * blockDim.x + threadIdx.x;
int j = blockIdx.y * blockDim.y + threadIdx.y;
if (i < N && j < N)
C[i][j] = A[i][j] + B[i][j];
}
int main()
{
...
// Kernel invocation
dim3 threadsPerBlock(16, 16);
dim3 numBlocks(N / threadsPerBlock.x, N / threadsPerBlock.y);
MatAdd<<<numBlocks, threadsPerBlock>>>(A, B, C, N);
...
}

流的并行处理:

    cudaStream_t stream[5];
for(int i = 0; i<5; i++)
{
cudaStreamCreate(&stream[i]); //创建流
}
// Launch a kernel on the GPU with one thread for each element.
for(int i = 0; i<5; i++)
{
addKernel<<<1, 1, 0, stream[i]>>>(dev_c+i, dev_a+i, dev_b+i); //执行流
}
cudaDeviceSynchronize();
for(int i = 0;i<5;i++)
{
cudaStreamDestroy(stream[i]); //销毁流
}

进行规约(Reduction)的代码:

int i = blockDim.x / 2;
cacheIndex = threadIdx.x;
while (i != 0){
if (cacheIndex < i)
cache[cacheIndex] += cache[cacheIndex + i];
__syncthreads();
i /= 2;
}

3. Memory

**register: ** 线程私有,有缓存,比较快。

**local memory: ** 线程私有,无缓存。

**shared memory: ** block内线程共享,速度较快。

**global memory: ** 线程共享,较慢。

**constant memory: ** 只读,常量存储,线程共享,有缓存。

**texture memory: ** 只读,具有纹理缓存。

4. cuda-gdb

编译时需要加上调试选项:

nvcc -g -G test.cu -o test

cuda-gdb的使用和gdb很多是一样的,列出一些cuda特有的命令:

thread: 列出当前的主机线程

cuda thread: 显示当前活跃的GPU线程

Note

  1. 如果核函数访问内存出现问题,因为GPU有着完善的内存管理机制,会强行结束所有违反内存访问规则的进程,后面的代码也就不会执行。

### CUDA的更多相关文章

  1. CUDA[2] Hello,World

    Section 0:Hello,World 这次我们亲自尝试一下如何用粗(CU)大(DA)写程序 CUDA最新版本是7.5,然而即使是最新版本也不兼容VS2015 ...推荐使用VS2012 进入VS ...

  2. CUDA[1] Introductory

    Section 0 :Induction of CUDA CUDA是啥?CUDA®: A General-Purpose Parallel Computing Platform and Program ...

  3. Couldn't open CUDA library cublas64_80.dll etc. tensorflow-gpu on windows

    I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_load ...

  4. ubuntu 16.04 + N驱动安装 +CUDA+Qt5 + opencv

    Nvidia driver installation(after download XX.run installation file) 1. ctrl+Alt+F1   //go to virtual ...

  5. 手把手教你搭建深度学习平台——避坑安装theano+CUDA

    python有多混乱我就不多说了.这个混论不仅是指整个python市场混乱,更混乱的还有python的各种附加依赖包.为了一劳永逸解决python的各种依赖包对深度学习造成的影响,本文中采用pytho ...

  6. [CUDA] CUDA to DL

    又是一枚祖国的骚年,阅览做做笔记:http://www.cnblogs.com/neopenx/p/4643705.html 这里只是一些基础知识.帮助理解DL tool的实现. “这也是深度学习带来 ...

  7. 基于Ubuntu14.04系统的nvidia tesla K40驱动和cuda 7.5安装笔记

    基于Ubuntu14.04系统的nvidia tesla K40驱动和cuda 7.5安装笔记 飞翔的蜘蛛人 注1:本人新手,文章中不准确的地方,欢迎批评指正 注2:知识储备应达到Linux入门级水平 ...

  8. CUDA程序设计(一)

    为什么需要GPU 几年前我启动并主导了一个项目,当时还在谷歌,这个项目叫谷歌大脑.该项目利用谷歌的计算基础设施来构建神经网络. 规模大概比之前的神经网络扩大了一百倍,我们的方法是用约一千台电脑.这确实 ...

  9. 使用 CUDA范例精解通用GPU编程 配套程序的方法

    用vs新建一个cuda的项目,然后将系统自动生成的那个.cu里头的内容,除了头文件引用外,全部替代成先有代码的内容. 然后程序就能跑了. 因为新建的是cuda的项目,所以所有的头文件和库的引用系统都会 ...

  10. CUDA代码移植

    如果CUDA的代码移植,一个是要 include文件夹对不对,这个是.h文件能否找到的关键,另一个就是lib,这个是.lib文件能否找到的关键.具体检查地方,见下头. include: lib:

随机推荐

  1. jquery完成带单选按钮的表格行高亮显示

    jquery完成带单选按钮的表格行高亮显示 上篇博客写的是复选框的,这次写的是单选框的,有时查询的时候,只能选择一条记录,如果将选中的这条记录的行高亮显示,同时该行的单选按钮也被选中了,这样会提高用户 ...

  2. Android 添加、移除和判断 桌面快捷方式图标

    思路: Launcher为了应用程序能够定制自己的快捷图标,就注册了一个 BroadcastReceiver 专门接收其他应用程序发来的快捷图标定制信息.所以只需要根据该 BroadcastRecei ...

  3. React中的Statics对象

    statics 对象允许你定义静态的方法,这些静态的方法可以在组件类上调用.例如 var MyComponent = React.createClass({ statics: { customMeth ...

  4. URAL 1019 - Line Painting

    跟前面某个题一样,都是区间染色问题,还是用我的老方法,区间离散化+二分区间端点+区间处理做的,时间跑的还挺短 坑爹的情况就是最左端是0,最右端是1e9,区间求的是开区间 #include <st ...

  5. Unity3D-UnityVS的安装和使用

    我们先下载UnityVS,在下面这个网站的资源中搜索一下 http://www.u3dchina.com/portal.php 安装完毕后,执行以下操作 1:打开你的Unity项目 2:在Unity中 ...

  6. Mysql 存储过程、函数、触发器和视图的权限检查

    当存储过程.函数.触发器和视图创建后,不单单创建者要执行,其它用户也可能需要执行,换句话说,执行者有可能不是创建者本身,那么在执行存储过程时,MySQL是如何做权限检查的? 在默认情况下,MySQL将 ...

  7. mysql下命令行执行sql脚本

    1. 登录mysql mysql -uroot -p 2. 执行脚本 mysql>use dbname; mysql>source /home/db/xx.sql

  8. 滑雪_poj_1088(记忆化搜索).java

    滑雪 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 67987   Accepted: 25013 Description ...

  9. [Open Projects Series] ViewPagerTransforms

    https://github.com/jfeinstein10/JazzyViewPager https://github.com/ToxicBakery/ViewPagerTransforms

  10. Hadoop可视化与交互式工具:Zeppelin和Hue

    https://yq.aliyun.com/articles/42282?spm=5176.team18.teamshow1.19.9TkKmZ#rd