CUDA __shared__ thread、block、grid之间的一维关系 (例子chapter5 dot点积(GPU高性能编程))

chapter5里重要的例子是dot,来解释一个block内多个thread的共享内存和同步。

__shared__共享内存:“对于在GPU上启动的每个线程块,cuda c编译器都将创建该变量的一个副本。线程块中的每个线程都共享这块内存,并和其他线程块无关,这使一个线程块中多个线程能够在计算上进行通信和协作”

__syncthreads():确保线程块中的每个线程都执行完__syncthreads()前面的语句后,在往下执行。

例子是Grid->一维Block->一维Thread:

通过实例代码来分析:

#include <iostream>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "book.h"
#include "cpu_bitmap.h"

//1.minFun  对于每个Grid而言,选取block数比较少的,这样可以减少每个grid中最后一个block内thread的冗余。

int imin(int a,int b)
{
	if(a>b)
	{
		return b;
	}else{
		return a;
	}
}

const int N = 33*1;//整体线程的数量,即向量(a)*(b)中每个向量数组的大小
const int ThreadNumsPerBlock =256;//每个block中thread的数量
const int BlockNumsPerGrid = imin(32,(N+ThreadNumsPerBlock-1)/ThreadNumsPerBlock);//每个grid中block的数量,

__global__ void dot(float* a,float* b,float* c)//输入两个向量:a,b ;结果c大小为一个grid内block的大小,grid内每个block的位置对应数组c每个下标对应的数据,每个数据为多个grid相同的block下标下的thread的和,如图-1。
{
   int	everyThreadIndex  =  threadIdx.x+blockIdx.x*blockDim.x;//获取一个grid中thread的index
   int  cacheIndex = threadIdx.x;//获取一个block中thread的index
   __shared__ float cache[ThreadNumsPerBlock];

   float temp = 0;
   while(everyThreadIndex<N)//多个grid的跳跃index,
   {
	   temp += a[everyThreadIndex]*b[everyThreadIndex];
	   everyThreadIndex += blockDim.x*gridDim.x;//
   }
   cache[cacheIndex] = temp;//得到多个grid中 一个block里相应的一个thread的乘积的和
   __syncthreads();

   int i= blockDim.x/2;
   while(i!=0)   //一直纳闷这个怎么在多个线程中执行啊?应该是:一个thread执行到这里后,__syncthreads()之前一个语句等啊等,等到所有一个block里的threads全都执行一遍后,才往下进行
   {
	   if(cacheIndex<i)
	   {
		   cache[cacheIndex]= cache[cacheIndex]+cache[cacheIndex+i];//while里的这句是在block里不同的thread里执行的
	   }
	   __syncthreads();
	   i=i/2;//当每个thread都执行后,才能进行长度折半
   }
   if(0==cacheIndex)
   {
     c[blockIdx.x] = cache[0];
   }
}

int main(void)//
{
	float  *host_a,*host_b,*host_c;
	float  *device_a,*device_b,*device_c;

	host_a = (float*)malloc(N*sizeof(float));
	host_b = (float*)malloc(N*sizeof(float));
	host_c = (float*)malloc(BlockNumsPerGrid*sizeof(float));

	  for (int i=0; i<N; i++) {
        host_a[i] = i;
        host_b[i] = i*2;
    }

	//gpu上分配内存
	cudaMalloc((void**)&device_a,N*sizeof(float));
	cudaMalloc((void**)&device_b,N*sizeof(float));
	cudaMalloc((void**)&device_c,BlockNumsPerGrid*sizeof(float));

	cudaMemcpy(device_a,host_a,N*sizeof(float),cudaMemcpyHostToDevice);
	cudaMemcpy(device_b,host_b,N*sizeof(float),cudaMemcpyHostToDevice);

	dot<<<BlockNumsPerGrid,ThreadNumsPerBlock>>>(device_a,device_b,device_c);

	cudaMemcpy(host_c,device_c,BlockNumsPerGrid*sizeof(float),cudaMemcpyDeviceToHost);

	float c=0;
	for(int i=0;i<BlockNumsPerGrid;i++)
	{
		c = c + host_c[i];
	}
	  #define sum_squares(x)  (x*(x+1)*(2*x+1)/6)
	std::cout<<"结果1:"<<c<<"结果2:"<<2 * sum_squares( (float)(N - 1) )<<std::endl;

	cudaFree(device_a);
	cudaFree(device_b);
	cudaFree(device_c);

	free(host_a);
	free(host_b);
	free(host_c);

	return 0;
}

书中最后讲解了错误的修改方式:

while(i!=0)
   {
	   if(cacheIndex<i)
	   {
		   cache[cacheIndex]= cache[cacheIndex]+cache[cacheIndex+i];//while里的这句是在block里不同的thread里执行的
                   __syncthreads();            }
         i=i/2;//当每个thread都执行后,才能进行长度折半 
   }

原则是“线程执行相同的指令,不同的数据运算”

__syncthreads()中,cuda架构要确保一个block中每个thread都执行__syncthreads(),否则没有任何thread执行__syncthreads之后的操作。

当一些thread执行一条指令,而其他线程不需要时,这种情况称作线程发散(Thread Divergence).这种情况下要注意__syncthreads的位置。

小结:

1. dim3 a(x,y); dim3 b(x,y);         <<<a,b>>>  a:Grid中启动block的数量 b:Block中启动thread数量

2.注意线程块的向后取整(取上限);  还有通过  if(threadIndex<N)来确保thread的范围

3.__shared__和__syncthreads()的正确用法,并注意线程发散情况

4.使用线程与使用线程块相比有什么优势? :一:解决线程块数量的限制  二:进行部分的数据共享和通讯

5.一维:threadIdx.x: block中的thread索引   blockIdx.x :Grid中block索引   blockDim.x:一个Block中thread数量; gridDim.x:一个Grid中Block数量

CUDA __shared__ thread、block、grid之间的一维关系 (例子chapter5 dot点积(GPU高性能编程)),布布扣,bubuko.com

时间: 2024-10-24 11:56:38

CUDA __shared__ thread、block、grid之间的一维关系 (例子chapter5 dot点积(GPU高性能编程))的相关文章

《GPU高性能编程CUDA实战》中代码整理

CUDA架构专门为GPU计算设计了一种全新的模块,目的是减轻早期GPU计算中存在的一些限制,而正是这些限制使得之前的GPU在通用计算中没有得到广泛的应用. 使用CUDA C来编写代码的前提条件包括:(1).支持CUDA的图形处理器,即由NVIDIA推出的GPU显卡,要求显存超过256MB:(2).NVIDIA设备驱动程序,用于实现应用程序与支持CUDA的硬件之间的通信,确保安装最新的驱动程序,注意选择与开发环境相符的图形卡和操作系统:(3).CUDA开发工具箱即CUDA Toolkit,此工具箱

《GPU高性能编程CUDA实战中文》中第四章的julia实验

在整个过程中出现了各种问题,我先将我调试好的真个项目打包,提供下载. 1 /* 2 * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. 3 * 4 * NVIDIA Corporation and its licensors retain all intellectual property and 5 * proprietary rights in and to this software and related docu

cuda中thread id

1 //////////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright 1993-2015 NVIDIA Corporation. All rights reserved. 4 // 5 // Please refer to the NVIDIA end user license agreement (EULA) associated 6 // with this sou

GPGPU OpenCL/CUDA 高性能编程的10大注意事项

转载自:http://hc.csdn.net/contents/content_details?type=1&id=341 1.展开循环 如果提前知道了循环的次数,可以进行循环展开,这样省去了循环条件的比较次数.但是同时也不能使得kernel代码太大. 1 #include 2 using namespace std; 3 4 int main(){ 5 int sum=0; 6 for(int i=1;i<=100;i++){ 7 sum+=i; 8 } 9 10 sum=0; 11 fo

Oracle Study之-AIX6.1构建主机之间的信任关系(ssh)

Oracle Study之-AIX6.1构建主机之间的信任关系(ssh)    在AIX环境下构建主机信任关系首选rsh,但在构建Oracle 11g RAC时需要ssh支持,以下文档介绍如何在AIX6.1下构建ssh的信任关系.    默认aix没有安装ssh软件包,首先要安装ssh软件包: 1.下载.解压软件包 [[email protected] ssh]#lsOpenSSH_5.8.0.6102.tar.Z  openssl-0.9.8.1802.tar.Z  ssh.txt 解压后通过

Prism 文档 第三章 管理组件之间的依赖关系

                                                                      第3章:管理组件之间的依赖关系 基于Prism库的复合应用程序可能包含许多松耦合的类型和服务.他们需要提供内容和接收基于用户行为的通知.因为他们是松散耦合的,他们需要一种方式进行互动和相互沟通来提供所需的业务功能. 为了集中这些不同的块,基于Prism库的应用程序依赖于依赖注入容器.依赖注入容器通过提供设施去实例化类的实例和管理他们基于容器配置的寿命来减少对

kbit和bit之间的换算关系

网络速率:用Kbps   Mbps   Gbps   或   Kb.   Mb.   Gb等来表示   1Gbps=1000Mbps   1Mbps=1000Kbps   1Kbps=1000bit 数据传输速率:用KBps   MBps   或KB.MB   .GB等来表示   1GB=1024MB   1MB=1024KB   1KB=1024Byte 1Byte=8bit 1kbps=1000bps 全称 :Bits   Per   Second 通信线路等数据传送速度的单位.比特每秒.1

UNIX和Linux之间有什么关系?

1.UNIX和Linux之间有什么关系? 答:1969年UNIX诞生于Bell实验室,是一种多用户多任务操作系统.最早是用汇编语言写的,之后用C语言重写.UNIX对硬件依赖性强,是一种非开源的商业操作系统. Linux是1991年一个芬兰研究生Linus写的一个类UNIX操作系统,Linux一出现就表现出强大的生命力,它可以运行在多种硬件平台上.后来Linus把源码公布出来,得到了很多人的支持,逐渐成为了基于GPL协议的GNU自由软件,免费且开源发展迅速. 2.BSD是什么? 我们通常说的Fre

[R语言]关联规则1---不考虑items之间的时序关系

本文介绍的是关联规则,分为两部分:第一部分是---不考虑用户购买的items之间严格的时序关系,每个用户有一个“购物篮”,查找其中的关联规则.第二部分--- 考虑items之间的严格的时序关系来分析用户道具购买路径以及关联规则挖掘.此文为第一部分的讲解.(本文所需的代码和数据集可以在这里下载.) 关联规则最常听说的例子是“啤酒与尿布”:购买啤酒的用户通常也会购买尿布.在日常浏览电商网站时也会出现“购买该商品的用户还会购买….”等提示,这其中应用的就是关联规则的算法. 本文重点讲解的是关联规则的R