GPU编程自学4 —— CUDA核函数运行参数
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题。这里主要记录自己的GPU自学历程。
目录
- 《GPU编程自学1 —— 引言》
- 《GPU编程自学2 —— CUDA环境配置》
- 《GPU编程自学3 —— CUDA程序初探》
- 《GPU编程自学4 —— CUDA核函数运行参数》
- 《GPU编程自学5 —— 线程协作》
- 《GPU编程自学6 —— 函数与变量类型限定符》
- 《GPU编程自学7 —— 常量内存与事件》
四、 CUDA核函数运行参数
在前面的章节中,我们不止一次看到了在调用定义的核函数时采用了类似下面的形式:
kernel<<<1,1>>>(param1,param2,...)
“<<< >>>”中参数的作用是告诉我们该如何启动核函数(比如如何设置线程)。 下面我们先直接介绍参数概念,然后详细说明其意义。
4.1 核函数运行参数
当我们使用 gloabl 声明核函数后
__global__ void kernel(param list){ }
在主机端(Host)调用时采用如下的形式:
kernel<<<Dg,Db, Ns, S>>>(param list);
- Dg: int型或者dim3类型(x,y,z)。 用于定义一个grid中的block是如何组织的。 int型则直接表示为1维组织结构。
- Db: int型或者dim3类型(x,y,z)。 用于定义一个block中的thread是如何组织的。 int型则直接表示为1维组织结构。
- Ns: size_t类型,可缺省,默认为0。 用于设置每个block除了静态分配的共享内存外,最多能动态分配的共享内存大小,单位为byte。 0表示不需要动态分配。
- S: cudaStream_t类型,可缺省,默认为0。 表示该核函数位于哪个流。
4.2 线程结构
关于CUDA的线程结构,有着三个重要的概念: Grid, Block, Thread
- GPU工作时的最小单位是 thread。
- 多个 thread 可以组成一个 block,但每一个 block 所能包含的 thread 数目是有限的。因为一个block的所有线程最好应当位于同一个处理器核心上,同时共享同一块内存。 于是一个 block中的所有thread可以快速进行同步的动作而不用担心数据通信壁垒。
- 执行相同程序的多个 block,可以组成 grid。 不同 block 中的 thread 无法存取同一块共享的内存,无法直接互通或进行同步。因此,不同 block 中的 thread 能合作的程度是比较低的。不过,利用这个模式,可以让程序不用担心显示芯片实际上能同时执行的 thread 数目限制。例如,一个具有很少量执行单元的显示芯片,可能会把各个 block 中的 thread 顺序执行,而非同时执行。不同的 grid 则可以执行不同的程序(即 kernel)。
下图是一个结构关系图:
此外,Block, Thread的组织结构可以是可以是一维,二维或者三维。以上图为例,Block, Thread的结构分别为二维和三维。
CUDA中每一个线程都有一个唯一标识ThreadIdx,这个ID随着组织结构形式的变化而变化。 (注意:ID的计算,同计算行优先排列的矩阵元素ID思路一样。)
回顾之前我们的矢量加法:
// Block是一维的,Thread也是一维的
__global__ void addKernel(int *c, const int *a, const int *b)
{
int i = blockIdx.x *blockDim.x + threadIdx.x;
c[i] = a[i] + b[i];
}
// Block是一维的,Thread是二维的
__global__ void addKernel(int *c, int *a, int *b)
{
int i = blockIdx.x * blockDim.x * blockDim.y + threadIdx.y * blockDim.x + threadIdx.x;
c[i] = a[i] + b[i];
}
// Block是二维的,Thread是三维的
__global__ void addKernel(int *c, int *a, int *b)
{
int blockId = blockIdx.x + blockIdx.y * gridDim.x;
int i = blockId * (blockDim.x * blockDim.y * blockDim.z)
+ (threadIdx.z * (blockDim.x * blockDim.y))
+ (threadIdx.y * blockDim.x) + threadIdx.x;
c[i] = a[i] + b[i];
}
下表是不同计算能力的GPU的技术指标(更多可参见 CUDA Toolkit Documentation)
当然也可以通过下面的代码来直接查询自己GPU的具体指标:
#include "cuda_runtime.h"
#include <iostream>
int main()
{
cudaError_t cudaStatus;
// 初获取设备数量
int num = 0;
cudaStatus = cudaGetDeviceCount(&num);
std::cout << "Number of GPU: " << num << std::endl;
// 获取GPU设备属性
cudaDeviceProp prop;
if (num > 0)
{
cudaGetDeviceProperties(&prop, 0);
// 打印设备名称
std::cout << "Device: " <<prop.name << std::endl;
}
system("pause");
return 0;
}
其中 cudaDeviceProp是一个定义在driver_types.h中的结构体,大家可以自行查看其定义。
4.3 内存结构
如下图所示,每个 thread 都有自己的一份 register 和 local memory 的空间。同一个 block 中的每个 thread 则有共享的一份 share memory。此外,所有的 thread(包括不同 block 的 thread)都共享一份 global memory、constant memory、和 texture memory。不同的 grid 则有各自的 global memory、constant memory 和 texture memory。
这种特殊的内存结构直接影响着我们的线程分配策略,因为需要通盘考虑资源限制及利用率。 这些后续再进行讨论。
4.4 异构编程
如下图所示,是常见的GPU程序的处理流程,其实是一种异构程序,即CPU和GPU的协同。
主机上执行串行代码,设备上则执行并行代码。
参考资料:
- 《CUDA by Example: An Introduction to General-Purpose GPU Programming》 中文名《GPU高性能编程CUDA实战》
- 详解CUDA核函数及运行时参数 http://blog.csdn.net/a925907195/article/details/39500915
- CUDA之——深入理解threadidx http://blog.csdn.net/canhui_wang/article/details/51730264
- CUDA Toolkit Documentation http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#axzz4oh8uLanv
GPU编程自学4 —— CUDA核函数运行参数的更多相关文章
- GPU编程自学3 —— CUDA程序初探
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- GPU编程自学2 —— CUDA环境配置
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- GPU编程自学7 —— 常量内存与事件
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- GPU编程自学6 —— 函数与变量类型限定符
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- GPU编程自学5 —— 线程协作
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- GPU编程自学1 —— 引言
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- 第一篇:GPU 编程技术的发展历程及现状
前言 本文通过介绍 GPU 编程技术的发展历程,让大家初步地了解 GPU 编程,走进 GPU 编程的世界. 冯诺依曼计算机架构的瓶颈 曾经,几乎所有的处理器都是以冯诺依曼计算机架构为基础的.该系统架构 ...
- 《CUDA并行程序设计:GPU编程指南》
<CUDA并行程序设计:GPU编程指南> 基本信息 原书名:CUDA Programming:A Developer’s Guide to Parallel Computing with ...
- GPU编程和流式多处理器(六)
GPU编程和流式多处理器(六) 5. 纹理和表面 读取和写入纹理和表面的指令,所引用的隐式状态,比其他指令要多得多.header中包含诸如基地址,尺寸,格式和纹理内容的解释之类的参数,该header是 ...
随机推荐
- JAVA面试题整理(3)-Spring
1.BeanFactory 和 FactoryBean? 2.Spring IOC 的理解,其初始化过程? 3.BeanFactory 和 ApplicationContext? 4.Spring B ...
- 一键安装lnmp(2)
all(){path=`pwd`cd $pathechoecho "exclude=*.i386 *.i686" >> /etc/yum.confrpm -ivh ht ...
- 20145312 实验五 《Java网络编程》
20145312 实验五<Java网络编程> 一. 实验内容及要求 实验内容: 运行下载的TCP代码,结对进行,一人服务器,一人客户端: 利用加解密代码包,编译运行代码,一人加密,一人解密 ...
- 20145324 《Java程序设计》第6周学习总结
20145324 <Java程序设计>第6周学习总结 教材学习内容总结 第十章 1.使用输入串流将数据从来源取出 InputStream 使用输出串流将数据写入目的地 OutStream ...
- 20145328 《Java程序设计》实验二实验报告
20145328 <Java程序设计>实验二实验报告 实验名称 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 ...
- 20145329 《Java程序设计》第七周学习总结
教材学习内容总结 +JDK出现之前就已经存在的java.util.Date与java.util.Calendar等API +如果想取得系统时间,方法之一是使用System.currentTimeMil ...
- 记一次redis key丢失的问题排查
最近测试环境的redis经常性发生某些key丢失的问题,最终的找到的问题让人大吃一惊. 复盘一下步骤: 1.发现问题 不知道从某天开始,后台经常报错,原因是某些key丢失,一开始不在意,以为是小bug ...
- JVM反调调用优化,导致发生大量异常时log4j2线程阻塞
背景 在使用log4j2打日志时,当发生大量异常时,造成大量线程block问题的问题. 一个关于log4j2的高并发问题:https://blog.fliaping.com/a-high-concur ...
- linux下安装sphinx
1.下载sphinx源码包 上面截图的这个网址 复制链接地址 在putty终端使用:wget http://sphinxsearch.com/files/sphinx-2.3.1-beta.t ...
- 同时打印多个worksheets
https://support.office.com/en-us/article/print-a-sheet-or-workbook-0f104967-ebce-406f-9c37-d3ab0dc02 ...