GPU编程自学6 —— 函数与变量类型限定符
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题。这里主要记录自己的GPU自学历程。
目录
- 《GPU编程自学1 —— 引言》
- 《GPU编程自学2 —— CUDA环境配置》
- 《GPU编程自学3 —— CUDA程序初探》
- 《GPU编程自学4 —— CUDA核函数运行参数》
- 《GPU编程自学5 —— 线程协作》
- 《GPU编程自学6 —— 函数与变量类型限定符》
- 《GPU编程自学7 —— 常量内存与事件》
六、 函数与变量类型限定符
在之前的小节中,我们已经遇到了 __global__ 和 __shared__这两种类型限定符。 前者属于函数类型限定符,后者则属于变量类型限定符。 接下来,我们来来了解一下这两类限定符。
6.1 函数类型限定符
函数类型限定符用来标识函数运行在主机还是设备上,函数由主机还是设备调用。
__global__
- __global__修饰的函数为 核函数。
- 运行在设备上;
- 可以由主机调用;
- 可以由计算能力大于3.2的设备调用;
- 必须有void返回类型;
- 调用时必须制定运行参数(<<< >>>)
- 该函数的调用时异步的,即可以不必等候该函数全部完成,便可以在CPU上继续工作;
__device__
- 运行在设备上;
- 只能由设备调用;
- 编译器会内联所有认为合适的__device__修饰的函数;
__host__
- 运行在主机上;
- 只能由主机调用;
- 效果等同于函数不加任何限定符;
- 不能与__global__共同使用, 但可以和__device__联合使用;
__noinline__
- 声明不允许内联
__forceinline__
- 强制编译器内联该函数
6.2 变量类型限定符
变量类型限定符用来标识变量在设备上的内存位置。
__device__ (单独使用时)
- 位于 global memory space
- 生命周期为整个应用期间(即与application同生死)
- 可以被grid内的所有threads读取
- 可以在主机中由以下函数读取
- cudaGetSymbolAddress()
- cudaGetSymbolSize()
- cudaMemcpyToSymbol()
- cudaMemcpyFromSymbol()
__constant__
- 可以和 __device__ 联合使用
- 位于 constant memory space
- 生命周期为整个应用期间
- 可以被grid内的所有threads读取
- 可以在主机中由以下函数读取
- cudaGetSymbolAddress()
- cudaGetSymbolSize()
- cudaMemcpyToSymbol()
- cudaMemcpyFromSymbol()
__shared__
- 可以和 __device__ 联合使用
- 位于一个Block的shared memory space
- 生命周期为整个Block
- 只能被同一block内的threads读写
__managed__
- 可以和 __device__ 联合使用
- 可以被主机和设备引用,主机或者设备函数可以获取其地址或者读写其值
- 生命周期为整个应用期间
__restrict__
该关键字用来对指针进行限制性说明,目的是为了减少指针别名带来的问题。
C99标准中引入了restricted指针,用以缓解C语言中指针二义性的问题。缓解指针二义性问题可用于编译器的代码优化。下面是一个指针二义性的例子:
void foo(const float* a,
const float* b,
float* c)
{
c[0] = a[0] * b[0];
c[1] = a[0] * b[0];
c[2] = a[0] * b[0] * a[1];
c[3] = a[0] * a[1];
c[4] = a[0] * b[0];
c[5] = b[0];
...
}
在C语言中,指针a, b, 和c可能有二义性(别名),因而对数组c的写入可能会更改数组a和b的元素的值。这就意味着,为了保证程序的正确性,编译器不能把a[0]和b[0]装载入寄存器,对它们做乘法,然后把结果写入c[0]和c[1],这是因为有这种可能a[0]和c[0]是同一个地址。故而编译器无法对相同的表达式进行优化。
通过把a, b, c声明为restricted指针,程序员可以断言这些指针实际上没有二义性(这里,所有的指针参数都要被设为restrict)
void foo(const float* __restrict__a,
const float* __restrict__ b,
float* __restrict__ c)
在增加了restrict关键字以后,编译器可以根据需要对代码进行优化:
void foo(const float* __restrict__ a,
const float* __restrict__ b,
float* __restrict__ c)
{
float t0 = a[0];
float t1 = b[0];
float t2 = t0 * t2;
float t3 = a[1];
c[0] = t2;
c[1] = t2;
c[4] = t2;
c[2] = t2 * t3;
c[3] = t0 * t3;
c[5] = t1;
...
}
这样便可以减少访存次数和计算量,而代价是增加寄存器的使用量。考虑到额外的寄存器使用可能会降低occupancy,因此这种优化也可能会带来负面效果。
参考资料
- “CUDA Toolkit Documentation B.C ”http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#c-language-extensions
GPU编程自学6 —— 函数与变量类型限定符的更多相关文章
- CUDA1.1-函数类型限定符与变量类型限定符
这部分来自于<CUDA_C_Programming_Guide.pdf>,看完<GPU高性能变成CUDA实战>的第四章,觉得这本书还是很好的,是一种循序渐进式的书,值得看,而不 ...
- GPU编程自学7 —— 常量内存与事件
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- GPU编程自学5 —— 线程协作
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- GPU编程自学4 —— CUDA核函数运行参数
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- GPU编程自学3 —— CUDA程序初探
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- GPU编程自学2 —— CUDA环境配置
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- GPU编程自学1 —— 引言
深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...
- C语言中类型限定符
通常用类型和存储类别来描述一个变量. C90还增加了两个属性:恒常性(constancy).易变性(volatility): 分别用关键字const和volatile来声明. 这两个关键字创建的类型是 ...
- ISO/IEC 9899:2011 条款6.7.3——类型限定符
6.7.3 类型限定符 语法 1.type-qualifier: const restrict volatile _Atomic 约束 2.除了指针类型(其被引用的类型是一个对象类型)之外的类型,不应 ...
随机推荐
- 20145314郑凯杰 《Java程序设计》第1周学习总结
20145314郑凯杰 <Java程序设计>第1周学习总结 教材学习内容总结 跟着教材的顺序开始总结我学过的内容: 1.三大平台 JAVA SE ,JAVA EE,JAVA ME 从毕向东 ...
- 置顶,置低实现与window.scroll
//置顶,置低实现 $('#updown .up').click(function(){$('html,body').animate({scrollTop: '0px'}, 300);}); $('# ...
- Labview 查看一次while循环运行的时间
在while循环中增加一个移位寄存器,移位寄存器的初始值使用时间计数器,在while循环里面增加一个减法Vi,再增加一个时间计数器,两者做差,最后显示差值. 在这里只能显示大概运行时间.如下图.
- idea 2017 常用图标
- jvm垃圾回收策略
一.jvm堆内存的分代划分 在基于分代的内存回收策略中,堆空间通常都被划分为3个代,年轻代,年老代(或者tenured代),永久代.在年轻代中又被划分了三个小的区域,分别为:Eden(伊甸)区,S0区 ...
- spring MVC 及 AOP 原理
SpringMVC工作原理https://www.cnblogs.com/xiaoxi/p/6164383.htmlspring MVC 原理https://blog.csdn.net/y199108 ...
- php入门(一)
一,在HTML中嵌入php代码 先看html的代码: <form action="processorder.php" method="post"> ...
- 安装mysql数据库中的技巧、错误排查
针对解压版本5.7.16(博主使用的这个版本.在某些低版本中部分命令失效) 一.安装.初始化data目录(解压版解压后没有data目录) 安装:配置path环境变量,然后管理员运行命令提示符cmd ...
- Impala 技术点梳理
1.优点 1.1 快! 主节点生成执行计划树并分发执行计划至各节点并行执行的拉式获取数据(MR:推式获取数据) 计算的中间结果不写入磁盘 1.2 便利 提供SQL语义,可以方便的进行复杂的数据分析任 ...
- 安装webpack命令环境
1.通过cnpm安装webpack命令环境,如图 2.安装完后查看webpack的版本,如图