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关于 ...
随机推荐
- Android M以上运行时权限(Google官方出品)
转载请注明出处:http://www.cnblogs.com/cnwutianhao/p/6690152.html 网上运行时权限的例子.Demo无计其数,但是和Google官方出品的比起来,都显得很 ...
- 用MPLAB IDE编程时,软件总是弹出一个窗口提示: “the extended cpu mode configuration bit is enabled,but the program that was loaded was not built using extended cpu instructions. therefore,your code may not work properly
用MPLAB IDE编程时,软件总是弹出一个窗口提示:"the extended cpu mode configuration bit is enabled,but the program ...
- MySQL关于check约束无效的解决办法
首先看下面这段MySQL的操作,我新建了一个含有a和b的表,其中a用check约束必须大于0,然而我插入了一条(-2,1,1)的数据,其中a=-2,也是成功插入的. 所以MySQL只是check,但是 ...
- salt-stack部署
saltstack部署 环境准备 [root@server elasticsearch]# cat /etc/redhat-release CentOS release 6.6 (Final)[r ...
- 【shell编程基础0】bash shell编程的基本配置
前面一篇“shell编程之变量篇”主要讲述下shell编程的变量的基本知识:设置变量的方式,自定义变量和环境变量的差别,变量的替换.删除.测试等. 这一篇主要是讲述在bash shell下的一些基本配 ...
- 关于 __proto__和prototype的一些理解
var Person = function(name) {}; Person.prototype.say = function() { console.log("Person say&quo ...
- 基于 Haproxy 构建负载均衡集群
1.HAPROXY简介 HAProxy提供高可用性.负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费.快速并且可靠的一种负载均衡解决方案.HAProxy特别适用于那些负载特大的web ...
- 求解释一个蛋疼的bug
大婶儿们出来解决个问题,看看有碰见过的没 截图中的 if (order.EShopOrder_PayStatus == 0 && order.EShopOrder_Status == ...
- java异常处理机制(try-catch-finally)
/* * 异常处理机制 * 1.分类:Error和Exception * Error错误是JVM自动报错的,程序员无法解决例如开数组过大int a[]=new int [1024*1024*1024] ...
- Java中遍历Map的常用方法
以下方法适用于任何map实现(HashMap, TreeMap, LinkedHashMap, Hashtable, 等等): 方式一(推荐): // 推荐 // 在for-each循环中使用entr ...