cuda学习2-block与thread数量的选取
由上一节可知,在main函数中,cuda程序的并行能力是在add<<<N,1>>>( dev_a, dev_b, dev_c )函数中体现的,这里面设置的是由N个block的构成的计算网络即grid,每一个block里面有1个thread存在。那么这种选取有什么用意呢,如何针对自己的计算问题设置计算网络呢?
首先要说明这两个数的选取没有固定的方法,完全是根据自身需求。其实它的完整形式是Kernel<<<Dg,Db, Ns, S>>>(param list);<<<>>>运算符内是核函数的执行参数,告诉编译器运行时如何启动核函数,用于说明内核函数中的线程数量,以及线程是如何组织的。
参数Dg用于定义整个grid的维度和尺寸,即一个grid有多少个block。为dim3类型。Dim3 Dg(Dg.x, Dg.y, 1)表示grid中每行有Dg.x个block,每列有Dg.y个block,第三维恒为1。整个grid中共有Dg.x*Dg.y个block,其中Dg.x和Dg.y最大值为65535。
参数Db用于定义一个block的维度和尺寸,即一个block有多少个thread。为dim3类型。Dim3 Db(Db.x, Db.y, Db.z)表示整个block中每行有Db.x个thread,每列有Db.y个thread,高度为Db.z。Db.x和Db.y最大值为512,Db.z最大值为62。 一个block中共有Db.x*Db.y*Db.z个thread。计算能力为1.0,1.1的硬件该乘积的最大值为768,计算能力为1.2,1.3的硬件支持的最大值为1024。
参数Ns是一个可选参数,用于设置每个block除了静态分配的shared Memory(以后会学习到)以外,最多能动态分配的shared memory大小,单位为byte。不需要动态分配时该值为0或省略不写。
参数S是一个cudaStream_t类型的可选参数,初始值为零,表示该核函数处在哪个流(以后会学习到)之中。
在这个例子中,由于计算很简单,就选了一个<<<N,1>>>这种搭配。现在我们看一个复杂一点的例子。
这个例子是说要计算两个任意长的向量的加法,可能会比比65535长,超过了block数的最大范围,甚至于比65535×512(thread上限)还长,应该怎么办呢?下面就用
<<<128,128>>>的计算网络来搞定。
核函数改为如下:
__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];
tid += blockDim.x * gridDim.x;
}
}
这段代码的精髓就在于它是一个循环,当编号为tid = threadIdx.x + blockIdx.x * blockDim.x的线程进行加法运算之后,tid += blockDim.x * gridDim.x;如果tid<N,则这个线程再做一次加法,依次循环下去。因为计算网络只有blockDim.x * gridDim.x这么大(次例为128×128),那么那些大于blockDim.x * gridDim.x并且小于N的数组分量的相加任务就需要继续分配给各个线程,如上就是用循环来分配的。
任意长度向量相加完整代码:
/*
* Copyright 1993-2010 NVIDIA Corporation. All rights reserved.
*
* NVIDIA Corporation and its licensors retain all intellectual property and
* proprietary rights in and to this software and related documentation.
* Any use, reproduction, disclosure, or distribution of this software
* and related documentation without an express license agreement from
* NVIDIA Corporation is strictly prohibited.
*
* Please refer to the applicable NVIDIA end user license agreement (EULA)
* associated with this source code for terms and conditions that govern
* your use of this NVIDIA software.
*
*/ #include "../common/book.h" #define N (33 * 1024) __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];
tid += blockDim.x * gridDim.x;
}
} int main( void ) {
int *a, *b, *c;
int *dev_a, *dev_b, *dev_c; // allocate the memory on the CPU
a = (int*)malloc( N * sizeof(int) );
b = (int*)malloc( N * sizeof(int) );
c = (int*)malloc( N * sizeof(int) ); // allocate the memory on the GPU
HANDLE_ERROR( cudaMalloc( (void**)&dev_a, N * sizeof(int) ) );
HANDLE_ERROR( cudaMalloc( (void**)&dev_b, N * sizeof(int) ) );
HANDLE_ERROR( cudaMalloc( (void**)&dev_c, N * sizeof(int) ) ); // fill the arrays 'a' and 'b' on the CPU
for (int i=; i<N; i++) {
a[i] = i;
b[i] = * i;
} // copy the arrays 'a' and 'b' to the GPU
HANDLE_ERROR( cudaMemcpy( dev_a, a, N * sizeof(int),
cudaMemcpyHostToDevice ) );
HANDLE_ERROR( cudaMemcpy( dev_b, b, N * sizeof(int),
cudaMemcpyHostToDevice ) ); add<<<,>>>( dev_a, dev_b, dev_c ); // copy the array 'c' back from the GPU to the CPU
HANDLE_ERROR( cudaMemcpy( c, dev_c, N * sizeof(int),
cudaMemcpyDeviceToHost ) ); // verify that the GPU did the work we requested
bool success = true;
for (int i=; i<N; i++) {
if ((a[i] + b[i]) != c[i]) {
printf( "Error: %d + %d != %d\n", a[i], b[i], c[i] );
success = false;
}
}
if (success) printf( "We did it!\n" ); // free the memory we allocated on the GPU
HANDLE_ERROR( cudaFree( dev_a ) );
HANDLE_ERROR( cudaFree( dev_b ) );
HANDLE_ERROR( cudaFree( dev_c ) ); // free the memory we allocated on the CPU
free( a );
free( b );
free( c ); return ;
}
总结:我们通常选取一定数量的线程来解决问题,通常都选2的倍数。是由grid,block,thread,这种三级结构实现的。一般的程序的计算量都会超过线程数量,因此要合理的把计算量尽量平均分配给各个线程来计算。感觉上来说,编写核函数的精髓就是如何利用线程的序号(索引值)来分配计算任务。
cuda学习2-block与thread数量的选取的更多相关文章
- CUDA学习笔记-1: CUDA编程概览
1.GPU编程模型及基本步骤 cuda程序的基本步骤如下: 在cpu中初始化数据 将输入transfer到GPU中 利用分配好的grid和block启动kernel函数 将计算结果transfer到C ...
- CUDA学习,第一个kernel函数及代码讲解
前一篇CUDA学习,我们已经完成了编程环境的配置,现在我们继续深入去了解CUDA编程.本博文分为三个部分,第一部分给出一个代码示例,第二部分对代码进行讲解,第三部分根据这个例子介绍如何部署和发起一个k ...
- CUDA学习之二:shared_memory使用,矩阵相乘
CUDA中使用shared_memory可以加速运算,在矩阵乘法中是一个体现. 矩阵C = A * B,正常运算时我们运用 C[i,j] = A[i,:] * B[:,j] 可以计算出结果.但是在CP ...
- 【CUDA学习】GPU硬件结构
GPU的硬件结构,也不是具体的硬件结构,就是与CUDA相关的几个概念:thread,block,grid,warp,sp,sm. sp: 最基本的处理单元,streaming processor 最 ...
- CUDA学习笔记(四)——CUDA性能
转自:http://blog.sina.com.cn/s/blog_48b9e1f90100fm5h.html 四.CUDA性能 CUDA中的block被划分成一个个的warp,在GeForce880 ...
- CUDA学习笔记(一)【转】
CUDA编程中,习惯称CPU为Host,GPU为Device.编程中最开始接触的东西恐怕是并行架构,诸如Grid.Block的区别会让人一头雾水,我所看的书上所讲述的内容比较抽象,对这些概念的内容没有 ...
- cuda学习1-初始庐山真面目
cuda作为gpu计算中的代表,拥有着超级高的计算效率,其原因是gpu实际相当与一台超级并行机组,使用过MPI做并行计算的人们可能知道,所谓的并行计算,简单讲就是用多个U(计算单元)来完成一个U的计算 ...
- 原 iOS深入学习(Block全面分析)http://my.oschina.net/leejan97/blog/268536
原 iOS深入学习(Block全面分析) 发表于1年前(2014-05-24 16:45) 阅读(26949) | 评论(14) 39人收藏此文章, 我要收藏 赞21 12月12日北京OSC源创会 ...
- CUDA学习之一:二维矩阵加法
今天忙活了3个小时,竟然被一个苦恼的CUDA小例程给困住了,本来是参照Rachal zhang大神的CUDA学习笔记来一个模仿,结果却自己给自己糊里糊涂,最后还是弄明白了一些. RZ大神对CUDA关于 ...
随机推荐
- WebGL 创建和初始化着色器过程
1.编译GLSL ES代码,创建和初始化着色器供WebGL使用.这些过程一般分为7个步骤: 创建着色器对象(gl.createBuffer()); 向着色器对象中填充着色器程序的源代码(gl.shad ...
- 自然梯度(Natural Gradient)
自然梯度(Natural Gradient)
- 跟着刚哥梳理java知识点——集合(十二)
Java集合分为Collection和Map两种体系 一.Collection接口: Collections接口为我们提供了以下方法: size():返回集合中元素的个数 add(Object obj ...
- Vue.js动画在项目使用的两个示例
欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 李萌,16年毕业,Web前端开发从业者,目前就职于腾讯,喜欢node.js.vue.js等技术,热爱新技术,热 ...
- 揭秘Kafka高性能架构之道 - Kafka设计解析(六)
原创文章,同步首发自作者个人博客.转载请务必在文章开头处以超链接形式注明出处http://www.jasongj.com/kafka/high_throughput/ 摘要 上一篇文章<Kafk ...
- 【2017-04-25】winform公共控件、菜单和工具栏、Tab和无边框窗体制作
一.公共控件 1. Button 按钮 + 布局 - AutoSize 按钮尺寸自动适应里面内容的长度 - Location 位置 - Margin 控件与控件外边距 - S ...
- 蓝桥杯-括号问题-java
/* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...
- 你跟上技术趋势了么? 来看看这10场2017热门it技术会议!
2016年各类大会让人应接不暇,技术圈儿最不缺的就是各种大会小会,有的纯干货,有的纯广告.作为一名技术开发者,参加了几场大会,你是不是也开始思忖:究竟哪些会议才值得参加?下面活动家为你推荐几场2017 ...
- ST-2
1.第一个程序没有覆盖到下表为0的数.第二个程序找到的是x中第一个等于0的数的下标. 2.对于第一个程序:x = [2,3,5], y = 3 对于第二个程序:X = [2,0,6] 3.对于两个程序 ...
- ST-1之乱码bug
我印象最深刻的一个错误就是乱码.上学期末做web期末作业时候,我就遇到了好多乱码问题.乱码问题并不是程序本身的逻辑错误,但是却让程序的可用性非常的差.只有输入英文时才能判断结果的正确与否.而且编译器又 ...