CUDA ---- 线程配置
前言
线程的组织形式对程序的性能影响是至关重要的,本篇博文主要以下面一种情况来介绍线程组织形式:
- 2D grid 2D block
线程索引
矩阵在memory中是row-major线性存储的:

在kernel里,线程的唯一索引非常有用,为了确定一个线程的索引,我们以2D为例:
- 线程和block索引
- 矩阵中元素坐标
- 线性global memory 的偏移
首先可以将thread和block索引映射到矩阵坐标:
ix = threadIdx.x + blockIdx.x * blockDim.x
iy = threadIdx.y + blockIdx.y * blockDim.y
之后可以利用上述变量计算线性地址:
idx = iy * nx + ix

上图展示了block和thread索引,矩阵坐标以及线性地址之间的关系,谨记,相邻的thread拥有连续的threadIdx.x,也就是索引为(0,0)(1,0)(2,0)(3,0)...的thread连续,而不是(0,0)(0,1)(0,2)(0,3)...连续,跟我们线代里玩矩阵的时候不一样。
现在可以验证出下面的关系:
thread_id(2,1)block_id(1,0) coordinate(6,1) global index 14 ival 14
下图显示了三者之间的关系:

代码
int main(int argc, char **argv) {
printf("%s Starting...\n", argv[]);
// set up device
int dev = ;
cudaDeviceProp deviceProp;
CHECK(cudaGetDeviceProperties(&deviceProp, dev));
printf("Using Device %d: %s\n", dev, deviceProp.name);
CHECK(cudaSetDevice(dev));
// set up date size of matrix
int nx = <<;
int ny = <<;
int nxy = nx*ny;
int nBytes = nxy * sizeof(float);
printf("Matrix size: nx %d ny %d\n",nx, ny);
// malloc host memory
float *h_A, *h_B, *hostRef, *gpuRef;
h_A = (float *)malloc(nBytes);
h_B = (float *)malloc(nBytes);
hostRef = (float *)malloc(nBytes);
gpuRef = (float *)malloc(nBytes);
// initialize data at host side
double iStart = cpuSecond();
initialData (h_A, nxy);
initialData (h_B, nxy);
double iElaps = cpuSecond() - iStart;
memset(hostRef, , nBytes);
memset(gpuRef, , nBytes);
// add matrix at host side for result checks
iStart = cpuSecond();
sumMatrixOnHost (h_A, h_B, hostRef, nx,ny);
iElaps = cpuSecond() - iStart;
// malloc device global memory
float *d_MatA, *d_MatB, *d_MatC;
cudaMalloc((void **)&d_MatA, nBytes);
cudaMalloc((void **)&d_MatB, nBytes);
cudaMalloc((void **)&d_MatC, nBytes);
// transfer data from host to device
cudaMemcpy(d_MatA, h_A, nBytes, cudaMemcpyHostToDevice);
cudaMemcpy(d_MatB, h_B, nBytes, cudaMemcpyHostToDevice);
// invoke kernel at host side
int dimx = ;
int dimy = ;
dim3 block(dimx, dimy);
dim3 grid((nx+block.x-)/block.x, (ny+block.y-)/block.y);
iStart = cpuSecond();
sumMatrixOnGPU2D <<< grid, block >>>(d_MatA, d_MatB, d_MatC, nx, ny);
cudaDeviceSynchronize();
iElaps = cpuSecond() - iStart;
printf("sumMatrixOnGPU2D <<<(%d,%d), (%d,%d)>>> elapsed %f sec\n", grid.x,
grid.y, block.x, block.y, iElaps);
// copy kernel result back to host side
cudaMemcpy(gpuRef, d_MatC, nBytes, cudaMemcpyDeviceToHost);
// check device results
checkResult(hostRef, gpuRef, nxy);
// free device global memory
cudaFree(d_MatA);
cudaFree(d_MatB);
cudaFree(d_MatC);
// free host memory
free(h_A);
free(h_B);
free(hostRef);
free(gpuRef);
// reset device
cudaDeviceReset();
return ();
}
编译运行:
$ nvcc -arch=sm_20 sumMatrixOnGPU-2D-grid-2D-block.cu -o matrix2D
$ ./matrix2D
输出:
./a.out Starting...
Using Device : Tesla M2070
Matrix size: nx ny
sumMatrixOnGPU2D <<<(,), (,)>>> elapsed 0.060323 sec
Arrays match.
接下来,我们更改block配置为32x16,重新编译,输出为:
sumMatrixOnGPU2D <<<(512,1024), (32,16)>>> elapsed 0.038041 sec
可以看到,性能提升了一倍,直观的来看,我们会认为第二个配置比第一个多了一倍的block所以性能提升一倍,实际上也确实是因为block增加了。但是,如果你继续增加block的数量,则性能又会降低:
sumMatrixOnGPU2D <<< (1024,1024), (16,16) >>> elapsed 0.045535 sec
下图展示了不同配置的性能;

关于性能的分析将在之后的博文中总结,现在只是了解下,本文在于掌握线程组织的方法。
代码下载:CodeSamples.zip
CUDA ---- 线程配置的更多相关文章
- 最优的cuda线程配置
1 每个SM上面失少要有192个激活线程,寄存器写后读的数据依赖才能被掩盖 2 将 寄存器 的bank冲突降到最低,应尽量使每个block含有的线程数是64的倍数 3 block的数量应设置得 ...
- GPU编程自学2 —— CUDA环境配置
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- Tomcat 内存和线程配置优化
1. tomcat 的线程配置参数详情如下: 修改conf/server.xml中的<Connector .../> 节点如下: <Connector port="8080 ...
- 十五、springboot集成定时任务(Scheduling Tasks)(二)之(线程配置)
配置类: /** * 定时任务线程配置 * */ @Configuration public class SchedulerConfig implements SchedulingConfigurer ...
- 【深度学习】在linux和windows下anaconda+pycharm+tensorflow+cuda的配置
在linux和windows下anaconda+pycharm+tensorflow+cuda的配置 在linux和windows下anaconda+pycharm+tensorflow+cuda的配 ...
- OpenCV GPU CUDA OpenCL 配置
首先,正确安装OpenCV,并且通过测试. 我理解GPU的环境配置由3个主要步骤构成. 1. 生成关联文件,即makefile或工程文件 2. 编译生成与使用硬件相关的库文件,包括动态.静态库文件. ...
- CUDA学习笔记(二)——CUDA线程模型
转自:http://blog.sina.com.cn/s/blog_48b9e1f90100fm5b.html 一个grid中的所有线程执行相同的内核函数,通过坐标进行区分.这些线程有两级的坐标,bl ...
- GPU(CUDA)学习日记(十一)------ 深入理解CUDA线程层次以及关于设置线程数的思考
GPU线程以网格(grid)的方式组织,而每个网格中又包含若干个线程块,在G80/GT200系列中,每一个线程块最多可包含512个线程,Fermi架构中每个线程块支持高达1536个线程.同一线程块中的 ...
- 【CUDA】Win10 + VS2017新 CUDA 项目配置
一.新建项目 打开VS2017 → 新建项目 → Win32控制台应用程序 → “空项目”打钩 二.调整配置管理器平台类型 右键项目 → 属性 → 配置管理器 → 全改为“x64” 三.配置生成属性 ...
随机推荐
- JAVA框架 Spring 事务
一.我们之前在hibernate的时候,需要直接写事务,需要绑定当前线程保证获取同一个连接,虽然hibernate的帮我们封装绑定当前现成的操作,但是需要我们手动的去开启和关闭事务. 而spring帮 ...
- css样式匹配苹果个型号手机
/*适配苹果X*/ @media only screen and (device-width: 375px) and (device-height: 812px) and (-webkit-devic ...
- java中线程的几种状态和停止线程的方法
1.线程的状态图 需要注意的是:线程调用start方法是使得线程到达就绪状态而不是运行状态 2.停止线程的两种方法 1)自然停止:线程体自然执行完毕 2)外部干涉:通过线程体标识 1.线程类中定义线程 ...
- FAT32文件系统学习(2) —— FAT表
1.题外话 在继续本文学习FAT32文件系统之前,先来插入一点别的话题.我们都知道U盘有一个属性是容量,就拿笔者的U盘为例,笔者手上的U盘是金士顿的DataTraveler G3 4GB的一个U盘.电 ...
- POJ1807&&1276
DP专题下的背包专题 其实就是PJ的那些东西了 主流的背包有三种:01背包,完全背包和多重背包 其中01背包和完全背包的转移就比较经典了,而多重背包也是在前两者基础上演变一下即可 1837 题意:有一 ...
- Luogu P2055 [ZJOI2009]假期的宿舍
一道网络有关的问题,还是一句话 网络流重在建模! 这里主要讲两种算法. 1.二分图匹配: 分析题意,我们可以知道题目要求是让所有留在学校的人都能有床睡 而 所有留在学校的人=本校不回家的人+外校的人: ...
- [Oracle]如果误删了某个数据文件,又没有被备份,能否恢复?
如果你有从这个数据文件创建之前,直到现在的,所有的ArchiveLog 和 Online REDO,是有可能进行恢复的. 执行: RMAN> restore datafile <filei ...
- stl源码剖析 详细学习笔记 RB_tree (1)
// // RB_tree_STL.cpp // 笔记 // // Created by fam on 15/3/21. // // #include "RB_tree_STL.h&q ...
- TensorFlow训练MNIST数据集(3) —— 卷积神经网络
前面两篇随笔实现的单层神经网络 和多层神经网络, 在MNIST测试集上的正确率分别约为90%和96%.在换用多层神经网络后,正确率已有很大的提升.这次将采用卷积神经网络继续进行测试. 1.模型基本结构 ...
- 简单模拟flume
NetCat方式: 远程访问的方式进行消息传递 配置一个Agent,主要配置三个组件: source, channel, sink 上图中为什么channel会带s,变成channels? 可以绑定多 ...