深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题。这里主要记录自己的GPU自学历程。

目录

六、 函数与变量类型限定符

在之前的小节中,我们已经遇到了 __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语言中指针二义性的问题。缓解指针二义性问题可用于编译器的代码优化。下面是一个指针二义性的例子:

  1. void foo(const float* a,
  2. const float* b,
  3. float* c)
  4. {
  5. c[0] = a[0] * b[0];
  6. c[1] = a[0] * b[0];
  7. c[2] = a[0] * b[0] * a[1];
  8. c[3] = a[0] * a[1];
  9. c[4] = a[0] * b[0];
  10. c[5] = b[0];
  11. ...
  12. }

在C语言中,指针a, b, 和c可能有二义性(别名),因而对数组c的写入可能会更改数组a和b的元素的值。这就意味着,为了保证程序的正确性,编译器不能把a[0]和b[0]装载入寄存器,对它们做乘法,然后把结果写入c[0]和c[1],这是因为有这种可能a[0]和c[0]是同一个地址。故而编译器无法对相同的表达式进行优化。

通过把a, b, c声明为restricted指针,程序员可以断言这些指针实际上没有二义性(这里,所有的指针参数都要被设为restrict

  1. void foo(const float* __restrict__a,
  2. const float* __restrict__ b,
  3. float* __restrict__ c)

在增加了restrict关键字以后,编译器可以根据需要对代码进行优化:

  1. void foo(const float* __restrict__ a,
  2. const float* __restrict__ b,
  3. float* __restrict__ c)
  4. {
  5. float t0 = a[0];
  6. float t1 = b[0];
  7. float t2 = t0 * t2;
  8. float t3 = a[1];
  9. c[0] = t2;
  10. c[1] = t2;
  11. c[4] = t2;
  12. c[2] = t2 * t3;
  13. c[3] = t0 * t3;
  14. c[5] = t1;
  15. ...
  16. }

这样便可以减少访存次数和计算量,而代价是增加寄存器的使用量。考虑到额外的寄存器使用可能会降低occupancy,因此这种优化也可能会带来负面效果。

参考资料

GPU编程自学6 —— 函数与变量类型限定符的更多相关文章

  1. CUDA1.1-函数类型限定符与变量类型限定符

    这部分来自于<CUDA_C_Programming_Guide.pdf>,看完<GPU高性能变成CUDA实战>的第四章,觉得这本书还是很好的,是一种循序渐进式的书,值得看,而不 ...

  2. GPU编程自学7 —— 常量内存与事件

    深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...

  3. GPU编程自学5 —— 线程协作

    深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...

  4. GPU编程自学4 —— CUDA核函数运行参数

    深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...

  5. GPU编程自学3 —— CUDA程序初探

    深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...

  6. GPU编程自学2 —— CUDA环境配置

    深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...

  7. GPU编程自学1 —— 引言

    深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...

  8. C语言中类型限定符

    通常用类型和存储类别来描述一个变量. C90还增加了两个属性:恒常性(constancy).易变性(volatility): 分别用关键字const和volatile来声明. 这两个关键字创建的类型是 ...

  9. ISO/IEC 9899:2011 条款6.7.3——类型限定符

    6.7.3 类型限定符 语法 1.type-qualifier: const restrict volatile _Atomic 约束 2.除了指针类型(其被引用的类型是一个对象类型)之外的类型,不应 ...

随机推荐

  1. Java线程状态流转---线程

    说明:线程共包括以下5种状态.1. 新建状态(New)         : 线程对象被创建后,就进入了新建状态.例如,Thread thread = new Thread().2. 就绪状态(Runn ...

  2. saltstack之nginx、php的配置

    saltstack为nginx提供状态配置 1.创建nginx配置需要的目录 mkdir /srv/salt/prod/nginx mkdir /srv/salt/prod/nginx/files 2 ...

  3. 20145327 《Java程序设计》第六周学习总结

    20145327 <Java程序设计>第六周学习总结 教材学习内容总结 父类中的方法: 流(Stream)是对「输入输出」的抽象,而「输入输出」是相对程序而言的. 标准输入输出: Syst ...

  4. Painter's Problem

    Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 5378   Accepted: 2601 Description There ...

  5. zsh + oh-my-zsh 主题预览

    The Themes robbyrussell the (default) that Robby uses The rest of the themes, in alphabetical order: ...

  6. Quick Launcher FAQ

    Q: Which category can be previewed and selected in Finder? A: All the categories can be selected in ...

  7. ubuntu 18.04在更新软件库时出现E: Release file for http://security.ubuntu.com/ubuntu/dists/bionic-security/InRelease is not valid yet...

    1.完整的错误信息如下: E: Release file for http://security.ubuntu.com/ubuntu/dists/bionic-security/InRelease i ...

  8. 【论文解析】MTCNN论文要点翻译

    目录 0.论文连接 1.前言 2.论文Abstract翻译 3.论文的主要贡献 4.4 训练 5 模型性能分析 5.1 关于在线挖掘困难样本的性能 5.2 将人脸检测与对齐联合的性能 5.3 人脸检测 ...

  9. JavaScript高级程序设计-读书笔记(5)

    第13章 事件 1.事件流 事件流描述的是从页面中接收事件的顺序.IE的事件流是事件冒泡流,而Netscape Communicator的事件流是事件捕获流. (1)事件冒泡,即事件开始时由最具体的元 ...

  10. 深入理解AUC

    https://tracholar.github.io/machine-learning/2018/01/26/auc.html 我觉得作者写的很不错