博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CUDA线程
阅读量:4648 次
发布时间:2019-06-09

本文共 6100 字,大约阅读时间需要 20 分钟。

建议先看看前言中关于存储器的介绍:

 

线程

首先介绍进程,进程是程序的一次执行,线程是进程内的一个相对独立的可执行的单元。若把进程称为任务的话,那么线程则是应用中的一个子任务的执行。举个简单的例子:一个人要做饭,食谱就是程序代码,做的过程就是执行程序,做好的饭就是程序运行的结果,而在这期间,需要炒菜,放盐,放油等等就是线程。

 

 

线程同步

调用__syncthreads 创建一个 barrier 栅栏

 

每个线程在调用点等待块内所有线程执行到这个地方,然后所有线程继续执行后续命令

Mds[i] = Md[j];__syncthreads();func(Mds[i],Mds[i+1]);

 

要求线程的执行时间尽量接近,因为执行时间差别过大,等待时间过长,效率低下。

只在块内同步,全局同步开销大

 

线程同步会导致死锁,例如:

 

if(someFunc()){    __syncthreads();}else{    __syncthreads();}

 

线程调度

 

Warp——块内的一组线程,一般是32个线程为一组

线程调度的基本单位

运行于同一个 SM(流多处理器)

内部threadIdx值连续

warp内部线程不能沿不同分支执行

 

线程层次

Grid——一维或多维线程块(block)

一维或二维

Block——一组线程

一维,二维或三维

一个 Grid 里的每个 Block 的线程数是一样的

block内部的内个线程可以同步(synchronize)和访问共享存储器(shared memory)

 

 

线程组织模型

 

block下由线程束(warp) 组成,block 内部的线程共享“shared memory”

可以同步 “__syncthreads()”

 一个Kernel具有大量线程,Kernel启动一个 “grid”,包含若干线程块,用户设定

下图是一个 grid 模型:

从图中可以看出这个  grid 中用户指定了 2 个线程块,每个线程块中有 2 个线程

可以看到CUDA内存传输是这样:

Device端

针对每个线程,可以读写 local memory 和 register

针对每个线程块,可以读写 shared memory

针对每个 grid,可以读写 global memory,只读 constant memory 和 texture memory

Host端

可以读写 global memory,constant memory 和 texture memory

 

回顾线程层次

首先看一个计算 N × N 矩阵的例子:

 

假设N = 32

先指定 Grid 里面有 2 × 2 个线程块 Block,表示为

blockIdx ([0,1],[0,1])

 

每个块有 16 × 16 个线程 (跟 无关),表示为

threadIdx ([0,15],[0,15])

块大小这样表示

blockDim = 16

则某个线程的真实索引为

i = [0,1] * 16 + [0,15]

线程索引: threadIdx

一维Block Thread ID == Thread Index

二维 Block (Dx,Dy)

 Thread ID of index(x,y) == x + yDy

三维 Block (Dx,Dy,Dz)

Thread ID of index(x,y,z) == x + yDx + zDxDy

 

计算 N × N 矩阵,指定线程块为 1 块,大小为矩阵大小

__global__ void MatAdd(float A[N][N],float B[N][N],float C[N][N]){     int i = threadIdx.x;     int j = threadIdx.y;     C[i][j] = A[i][j] + B[i][j];} int main(){     int numBlocks = 1;                      //指定线程块为 1     dim3 threadsPerBlock(N,N);               //指定大小为 N × N     MatAdd<<
>>(A,B,C);}

 

Thread Block 线程块

线程的集合

位于相同的处理器核(SM)

共享所在核的存储器

 

块索引:blockIdx

维度:blockDim

一维,二维,三维

 

计算 N × N 矩阵,指定线程块大小为 16 × 16,若干个线程块

__global__ void MatAdd(float A[N][N],float B[N][N],float C[N][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(){     dim3 threadsPerBlock(16,16);     dim3 numBlocks(N / threadsPerBlock.x , N / threadsPerBlock.y);     MatAdd<<
>>(A,B,C);}

 

 
 

线程块之间彼此独立执行

任意顺序:并行或串行

被任意数量的处理器以任意顺序调度:处理器的数量具有可扩展性

 

一个块内部的线程

共享容量有限的低延迟存储器

同步执行:合并访存,__syncThreads()Barrier ——块内线程一起等待所有线程都执行某处语句,轻量级

 

 

实例演示

编写一个矩阵 M,N 相乘的程序,维度一致。

先介绍几个函数:

 

cudaMalloc()

在设备端分配 global memory 

cudaFree()

释放存储空间

 

cudaMemcpy()

内存传输

Host to host

Host to device

Device to host

Device to device

 

cudaMemcpy(Md,M,size,cudaMemcpyHostToDevice);

Md 目的地址

M   原地址

size 大小

 

CPU端代码:

void MatrixMulOnHost(float** M,float** N,float** P,int width){    for(int i = 0 ; i < width ; ++i)        for(int j = 0 ; j < width ; ++j)        {            float sum = 0;            for(int k = 0 ; k < width ; ++k)            {                float a = M[i][k];                float b = N[k][j];                sum += a * b;            }            P[i][j] = sum;        }}

 

 

CUDA 算法框架

int main()

{

     1.管理内存,为输入的原始数据,以及输出结果在GPU上分配内存

     2.并行处理

     3.结果拷贝回 CPU,释放内存

     return 0;

}

 

1.

int size = Width * Width * sizeof(float);     cudaMalloc(Md,size);     cudaMemcpy(Md,M,size,cudaMemcpyHostToDevice);     cudaMalloc(Nd,N,size,cudaMemcpyHostToDevice);          cudaMalloc(Pd,size);

 

 

2.

__global__ void MatrixMulKernel(float* Md,float* Nd,float* Pd,int width){   int tx = threadIdx.x;   int ty = threadIdx.y;   float Pvalue = 0;   for(int k = 0 ; k < width ; ++k) {       float Mdelement = Md[ty * Md.width + k];       float Ndelement = Nd[k * Nd.width + tx];       Pvalue += Mdelement * Ndelement;   }   Pd[ty * width + tx] = Pvalue; }

 

 

3.

cudaMemcpy(P,Pd,size,cudaMemcpyDeviceToHost);     cudaFree(Md);     cudaFree(Nd);     cudaFree(Pd);

在main()中调用 Kernel

dim3 dimBlock(WIDTH,WIDTH);dim3 dimGrid(1,1);MatrixMulKernel <<
>>(Md,Nd,Pd);

完整GPU程序如下:

 

/* ============================================================================ Name        : Martix.cu Author      : wzn Version     : Copyright   : Your copyright notice Description : CUDA compute reciprocals ============================================================================ */#include 
#include
#include
__global__ void MatrixMulKernel(float* Md,float* Nd,float* Pd,int Width){ int tx = threadIdx.x; int ty = threadIdx.y; float Pvalue = 0; for(int k = 0 ; k < Width ; ++k) { float Mdelement = Md[ty * Width + k]; float Ndelement = Nd[k * Width + tx]; Pvalue += Mdelement * Ndelement; } Pd[ty * Width + tx] = Pvalue; }int main(void){ int Width = 30; int size = Width * Width * sizeof(float); float M[Width][Width],N[Width][Width],P[Width][Width]; for(int i = 0;i<30;i++){ for(int j = 0;j<30;j++){ M[i][j] = j; N[i][j] = j; } } float *Md,*Nd,*Pd; cudaMalloc((void **)&Md,size); cudaMalloc((void **)&Nd,size); cudaMemcpy(Md,M,size,cudaMemcpyHostToDevice); cudaMemcpy(Nd,N,size,cudaMemcpyHostToDevice); cudaMalloc((void **)&Pd,size); dim3 dimBlock(Width,Width); dim3 dimGrid(1,1); MatrixMulKernel <<
>>(Md,Nd,Pd,Width); cudaMemcpy(P,Pd,size,cudaMemcpyDeviceToHost); cudaFree(Md); cudaFree(Nd); cudaFree(Pd); for(int i = 0;i<30;i++){ for(int j = 0;j<30;j++){ std::cout<
<<" "; } std::cout<<"\n"; } return 0;}CPU端程序:#include
using namespace std;void MatrixMulOnHost(float** M,float** N,float** P,int width){ for(int i = 0 ; i < width ; ++i) for(int j = 0 ; j < width ; ++j) { float sum = 0; for(int k = 0 ; k < width ; ++k) { float a = M[i][k]; float b = N[k][j]; sum += a * b; } P[i][j] = sum; }}int main(){ int Width = 30; float **M,**N,**P; M = new float* [Width]; for(int i = 0 ;i

 

运行结果比较

 

转载于:https://www.cnblogs.com/NikkiNikita/p/9450731.html

你可能感兴趣的文章
Intellij IDEA 配置Tomcat远程调试
查看>>
python3 进程和线程(一)
查看>>
python-综合练习题(if条件语句,while循环,奇数偶数
查看>>
C语言基础-第三章
查看>>
PowerDesigner教程系列(一)概念数据模型
查看>>
python常用类库总结
查看>>
题解 CF962C 【Make a Square】
查看>>
只读数据文件损坏恢复
查看>>
k8s集群上线web静态网站
查看>>
【转】Impala和Hive的关系
查看>>
IDEA操作git
查看>>
windows 下安装elasticsearch
查看>>
C语言学习12:带参数的main函数,无指定的函数形参,调用库函数处理无指定的函数形参,...
查看>>
禁止某程序联网
查看>>
[LOJ6191][CodeM]配对游戏(概率期望DP)
查看>>
mysql中utf8和utf8mb4区别
查看>>
谈谈源码管理那点事儿(一)——源码管理十诫(转)
查看>>
拒绝switch,程序加速之函数指针数组
查看>>
[你必须知道的.NET]第二十五回:认识元数据和IL(中)
查看>>
.NET中的三种Timer的区别和用法
查看>>