面向CPU/GPU编程(如OpenGL),硬编码和软编码

《The Cg tutorial》(C图形教程)- http://developer.download.nvidia.com/CgTutorial/cg_tutorial_chapter01.html
开源的库实在完整,想做卷积运算有cudnn,想做卷积神经网络caffe、torch,想做rnn有mxnet、tensorflow等。
  GPU代表的是图形处理单元,但是,这些小小芯片除了处理图形功能,还有其它用处。比如,Google使用GPU来为人脑建模,Salesforce则依赖GPU分析Twitter微博数据流。
  计算机博士Eric Holk说:“GPU编程仍然需要程序员管理许多低层细节,这些细节是与GPU执行的主要任务分离的。我们想开发一个系统,帮助程序员管理这些细节,让GPU在提高生产力的同时仍然有很好的性能。”
  一般来说,电脑计算任务大多由CPU完成。一个CPU处理一个计算序列,也就是所谓的一次处理一个线程,它必须尽可能快地执行。GPU的设计初衷是一次处理多个线程,这些线程处理速度慢很多,但程序可以利用并行优势执行得更快一些,就像超级电脑一样。

  GPU编程语言,包括CUDA和OpenCL。

2007年推出的CUDA(Compute Unified Device Architecture)用代码来控制gpu进行并行计算。

> 硬编码和软编码
计算机科学中,只有硬编码(hardcode),以及非硬编码,有人也成为“软编码”。 
硬编码和软编码的区别是:软编码可以在运行时确定,修改;而硬编码是不能够改变的。

 软编码:使用CPU进行编码
 硬编码:使用非CPU进行编码,如显卡GPU、专用的DSP、FPGA、ASIC芯片等
 软编码:实现直接、简单,参数调整方便,升级易,但CPU负载重,性能较硬编码低,低码率下质量通常比硬编码要好一点。
 硬编码:性能高,低码率下通常质量低于硬编码器,但部分产品在GPU硬件平台移植了优秀的软编码算法(如X264)的,质量基本等同于软编码.

- 主流的GPU平台开发框架:
 CUDA:NVIDIA的封闭编程框架,通过框架可以调用GPU计算资源;
 AMD APP:AMD为自己的GPU提出的一套通用并行编程框架,标准开放,通过在CPU、GPU同时支持OpenCL框架,进行计算力融合。
 OpenCL:开放计算语言,为异构平台编写程序的该框架,异构平台可包含CPU、GPU以及其他计算处理器,目标是使相同的运算能支持不同平台硬件加速。
 Inel QuickSync:集成于Intel显卡中的专用视频编解码模块。
 > CPU 的并行编程技术,也是高性能计算中的热点;GPU 并行编程
区别一:缓存管理方式的不同
 GPU:缓存对程序员不透明,程序员可根据实际情况操纵大部分缓存 (也有一部分缓存是由硬件自行管理)。
 CPU:缓存对程序员透明。应用程序员无法通过编程手段操纵缓存。
区别二:指令模型的不同
 GPU:采用 SIMT - 单指令多线程模型,一条指令配备一组硬件,对应32个线程 (一个线程束)。
 CPU:采用 MIMD多指令多数据类型。多条指令构成指令流水线,且每个线程都有独立的硬件来操纵整个指令流。
 用通俗易懂的话来说,GPU 采用频繁的线程切换来隐藏存储延迟,而 CPU 采用复杂的分支预测技术来达到此目的。
区别三:硬件结构的不同
 GPU 内部有很多流多处理器。每个流多处理器都相当于一个“核",而且一个流多处理器每次处理 32 个线程。
 故 GPU 的数据吞吐量非常大,倾向于进行数据并发型优化;而 CPU 则倾向于任务并发型优化。

-- 计算机(Computer)和计算(Compute)的概念:
  在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语言是最贴近计算机的语言。而计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。
  对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言;越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Lisp语言。

> GPU工作原理,可编程渲染管线,图形流水线和GPU架构- https://blog.csdn.net/leoysq/article/details/51457727
  由于计算机图形的性质,最图形管线已构造为计算状态与数据流动作为它们之间的数据流。每个阶段工作在一组元素,如顶点,三角形或像素。
  当前GPU 小号允许用户在形式的图形流水线的两个阶段几乎任何类型的功能进行编程顶点程序和片段的方案。这些允许用户分别写在顶点和片段数据的程序。
  -- 顶点处理器
  顶点处理器输入的顶点值和其相关的数据进行操作。它的目的是执行传统的图形操作,如:顶点变换,正常转化和规范化,纹理坐标生成和改造,照明和颜色计算[ Ros04。因为顶点处理器是能够改变输入的顶点数据的位置,从而影响最终图像的要绘制。由于图像是,在本质上,的存储器阵列,顶点处理器能够分散状操作。另外,最近的处理器能够从纹理存储器读出,从而产生一种特殊的延迟收集动作。我们称之为延迟,因为顶点不能直接从其他顶点元件读取的信息,但它可以读取的任何数据从先前的计算结果,如果它是在纹理存储器编码。在后面的章节中,我们将看到如何利用这一点来执行简单的计算。
  顶点处理器可以在SIMD(单指令多数据)或MIMD(多指令多数据)模式下运行; 因此,允许两个,一个处理器单元中的指令和任务并行。由于现代GPU 小号包含多个顶点处理器(最新的NVIDIA 和ATI卡有多达六个),我们可以开始欣赏并行这些体系结构上实现的水平。
  -- 碎片处理器
  该片段处理器上的片段和它们相关联的数据进行操作。一些传统上与片段着色器相关联的操作是:质地接入和应用,雾,颜色和与上内插值一般操作。如同顶点着色器,片段着色器可用于在GPU上执行几乎任何种类的计算。因为片段处理器可以访问纹理存储器的随机这是很容易的片段程序内执行聚集操作。实际上,这是很常见的使用纹理信息进行依赖于其他纹理查找窗口; 功能移植算法的流计算模型时来真的很方便。

  虽然在目前的GPU架构碎片处理器可以在SIMD模式下运行,是非常严格的那种,他们允许我们将看到,他们还是很容易执行一般的计算操作。加,由于片段的处理片段的处理器数量的计算频率比顶点处理器的数目越高。当前顶级的线卡有十六岁左右的片段处理器。

>了解CUDA(Compute Unified Device Architecture)的线程模型是 GPU 并行编程的基础。
GPU 和 CPU 在并行计算方面的不同:
1. 任务数量
 CPU 适合比较少量的任务,而 GPU 则适合做大量的任务。
2. 任务复杂度
 CPU 适合逻辑比较复杂的任务,而 GPU 则适合处理逻辑上相对简单的任务 (可用比较少的语句描述)。
3. 线程支持方式
 由于 CPU 中线程的寄存器组是公用的,因此CPU 在切换线程的时候,会将线程的寄存器内容保存在 RAM 中,当线程再次启动的时候则会从 RAM 中恢复数据到寄存器。
 而 GPU 中的各个线程则各自拥有其自身的寄存器组,因此其切换速度会快上不少。
 当然,对于单个的线程处理能力来说,CPU 更强。
4. 处理器分配原则
 CPU 一般是基于时间片轮转调度原则,每个线程固定地执行单个时间片;而 GPU 的策略则是在线程阻塞的时候迅速换入换出。
5. 数据吞吐量
 GPU 中的每个流处理器就相当于一个 CPU 核,一个 GPU 一般具有 16 个流处理器,而且每个流处理器一次能计算 32 个数。

CPU可以并行计算,传统的计算阵列也是用CPU组建的。
 现在的GPU计算是因为单个GPU的多核心,重复计算能力强,通过低投入的GPU计算阵列就可以达到以往大型CPU阵列并行系统的效率。
 CPU计算在通用计算上的价值更大。
 比如说大量数据的重复运算就可以用并行计算的方式来进行,可利用GPU加速,而线性处理的时候GPU效率较低,此时CPU效率更高。
 因此现在全球超级计算机前几名的机器都采用了混合架构,也就是CPU-GPU混合架构。

GPU编程的两个问题:GPU的存储有限问题,所以数据需要从外部导入;导入的过程带来IO的问题,使得IO的时间远大于GPU处理的时间
gpu的io问题一直是比较严重的瓶颈,我自己总结有三种解决方案。
  1.优化算法,选择更有效的存储方式,减少显存的使用。只拷贝必要数据,优化数据结构等等。
  2.使用cuda内存优化技巧。比如显存整块申请和拷贝,使用pinned memory,shared memory,constant memory,使用流来掩盖内存延迟等等。
  3.硬件解决方案,放弃pci-e,使用ibm的power架构和p100,直接用nv-link进行内存传输。这个方案是一劳永逸的,但是要准备好money,一整套下来很贵的。
  第三个方案一般整不起,前两个方案是算法和语言技巧方面,与算法本身有很大的关系。个人经验上来讲方案1提升的潜力比较大。使用cuda对算法加速是一个很复杂的过程,io是一个比较大的问题,还有条件分支,共享内存bank conflick问题,指令优化等等,这些在优化时都要考虑。

现在常用的GPU编程架构,如CUDA是否已经解决了这个问题?可以尝试一下下面几个方法:
1. 是否用满了GPU的运算能力? 答案可以通过你的数据和GPU计算能力比较得到。
2. 是否IO次数过多? 每次IO都会消耗一定的时间,IO次数越多,消耗时间越多。
3. 算法中是否包含了过多的if/else等逻辑跳转?  GPU适用于并行计算,而不适用于逻辑判断。

  CUDA涉及的主机端存储主要有分页内存(pageable memory)和锁页内存(pinned memory)。分页内存使用malloc()和free()分配释放(通常情况),内存页可能被换出磁盘,无法使用DMA传输。而锁页内存将一直存在于内存空间中,支持DMA访问和与GPU异步通信,通过cudaHostAlloc()和cudaFreeHost()分配释放。在主机端使用锁页内存比使用分页内存的PCI-E传输速度快一倍左右,效果明显。

  在考虑用GPU加速算法时,可以先做benchmark,估计整套算法的访存时间,再看是不是需要更多的时间来计算。计算时间=访存时间的话,可以相互掩盖,计算时间>访存时间的话,就是受限于计算能力的算法,更适合用GPU来做(根据算法数值计算过程不同,不一定都适合,一些算法还要深度优化才行)。

  对于CUDA来说,解决的方法就是shared memory,尽量减少对 global memory部分的访问,把每一个block需要的数据一次载入存储到block内,利用cache,其实IO性能瓶颈的解决无论CPU还是GPU思路是都是接近的就是不断增加缓存,因为离计算单元越远性能越差,还有合理的控制分配数据的读写,前者是硬件架构只要你的环境支持就可以利用,后者就需要你考虑如何你的数据读写了,这些都是可以计算出来能够提升多少性能的,也是可以利用不同点策略改进的,还是拿CUDA举例,你可以使用TILE来把要处理的图像或者其他数据来分割开来,每一个小块载入他们所需要的数据,这样他们就可以各干各的了,不需要大家都跑去global那里讨要数据,毕竟global的带宽提升幅度是有限的。 

  I/O问题一直就是nvidia这样的discrete GPU的短板,但是AMD的APU那种CPU和GPU共享DRAM的GPU的计算能力又太弱。首先如果你的数据大量存在磁盘(包括SSD)上,GPU没有处理磁盘I/O的能力,即使有,SSD的带宽也远远比不上GPU device memory的带宽。如果你的数据已经缓存在host的DRAM上,需要在host和GPU之间做data transfer,16 lane PCIe 3.0的带宽可以达到16GB/s,但是也还是远低于 device memory的带宽。
  可行的解决办法就是看你的应用input能不能被分成小块(chunking),如果可以的话,就可以用多个streams来overlap data transfers和compute。或者就是看你的input能不能被什么解压速度特别的快的压缩算法压缩,减少data transfer的量,然后在GPU上解压,用计算换I/O。
  机器学习的话,一般training的data set都不是很大吧,主要还是train model的计算量比较大。如果是test的话,我记得有个文章分析过,通过overlap data transfer和compute,即使是普通的硬盘的带宽(只要>65MB)应该就足够撑满K20了。
  cuda应该是类似(用的是 nvdia显卡和opencl编程)。

io绝对不是瓶颈。 我做手机显示芯片的1080p视频数据的io没有任何明显延迟。 一般处理瓶颈就两个, 1.视频, 图像的解码  2. 算法。

【GPU编程系列之一】从深度学习选择什么样的gpu来谈谈gpu的硬件架构- https://blog.csdn.net/ikerpeng/article/details/52389085

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值