ATI 流计算介绍

引言:
      随着GPU的并行处理能力的不断提升,GPU的特性被不断的应用于图形无关的应用中,并获得了非常大的速度提升。大量的应用开始工作在GPU上,而不是利用多核CPU进行加速。类似于光线跟踪,光子映射等开销很大的计算都可以在GPU上达到静实时的性能。

      本文介绍了ATI流计算的一些基础知识,对于CAL,Brook+或者OpenCL有兴趣的朋友,可以看看。

正文:

ATI流计算模型:

      ATI流计算模型包含了一套软件系统以及ATI流处理器。下图展示了ATI流处理模块之间的关系:

            1 

      ATI流计算软件为客户端用户提供了一个灵活完整的接口,从而使开发人员充分利用ATI的硬件特性进行流计算。
      软件主要分为下面几个模块:

           编译器: 类似于Brook+的编译器,把Brook+内核的代码编译成为独立的C++文件以及IL代码。

           流处理器的设备驱动: ATI流计算抽象模型(CAL)。

           性能分析工具: Stream KernelAnalyzer,可以及时编译Brook+,IL代码,并且分析程序性能。

           性能库: AMD核心数学库(ACML),这部分是专用于特定领域的。

     在最新一代的ATI流处理器中,编程模型应用一种通用的Shader语言。可编程的流处理器可以执行用户指定的各种程序,这些程序被称为内核函数(Kernel)。这些流处理器可以以一种单指令多数据(SIMD)的形式执行一些与图形完全无关的任务。这种编程模型被称为流计算,内存中存储的大量相同类型的数据可以被分配到不同的SIMD引擎中进行处理,从而生成输出数据。

     每一个在SIMD引擎中被处理的实例被称作为线程(Thread)。在每个Pass里,可以有大量的线程被映射到一个矩形区域中,这个矩形区域被称为执行区域(Domain of Execution)。

     流计算处理器为每组线程都分配到一组线程处理器(Thread Processor)中,直到所有的线程都被处理。只有之前的线程完成计算之后,后面的线程才可以得到处理。下图为一个简化的ATI流计算模型:

          2

Brook+简介:

      Brook+为开发者提供了一个简便快捷的流计算开发接口。用户可以通过Brook+在ATI的硬件进行流计算开发。Brook+的内核程序是由一种类C语言编写的,所有非常适合传统的C以及C++程序员。Brook+语言中两个最关键的概念:

      1. 流。流就是一些类型相同的数据,他们可以被分配到不同的流处理器中进行处理。

      2. 内核。内核程序其实就是GPU硬件的行为程序,它指定了硬件的行为特性。

      Brook+的内核函数是被Brcc(Brook Code Compiler)编译的,编译后生成三个文件,其中两个是.h和.cpp文件,就是定义了一些和函数相关的类,还有一个最关键的就是IL代码。有了这些文件,这三个文件再和用户的其他源文件一起编译,链接,从而生成可执行性文件。Brook+的程序在运行时,是需要Brook runtime的。Brook+的内核程序也可以被CPU执行,还可以进行调试。

      目前,Brook+的版本是1.4版本。已经被提交到了SourceForge上,应该是没有太多的维护了。由于Brook+还有一些限制,所以在灵活性方面并不如CUDA好。而且由于过多的封装,效率也并不很高。唯一的好处就在于用Brook+开发比较简便,程序员需要管理的事情不是特别多,因为Brook+已经把很多复杂的内容都封装起来了。对于想做一些GPGPU测试程序的朋友,这个接口还不错。但是如果开发复杂的项目,Brook+会有一定的限制。

CAL简介:

     ATI CAL(Compute Abstraction Layer)是一个硬件驱动接口,程序员通过CAL可以访问硬件所提供的几乎所有特性,可以控制硬件非常底层的东西。相对于Brook+来说,要底层一些,没有什么限制,灵活的多。事实上Brook+就是基于CAL实现的。CAL具有以下特性:

       可以生成设备相关代码(ISA)。

       设备管理。

       资源管理。

       内核的读取与执行。

       多核GPU的支持。

       与3D图形接口的交互(Interoperability)。(关于这种交互,我专门有介绍过:http://blog.youkuaiyun.com/codeboycjy/archive/2009/11/28/4896835.aspx

       CAL可以支持用IL编写的内核函数,也同样可以接受用硬件高度相关的代码(ISA)来编写Kernel。

     CAL的优点在于,它是很底层的接口,用户可以非常灵活的控制GPU的很多模块。但是CAL也有一些缺点,CAL的内核编写是非常繁琐的,因为IL是一种类似于汇编的语言,所以在开发过程中,是很难调试的。而且也不适合快速开发,对于C程序员来说,可能上手也不是特别快。但是其实如果适应了IL的开发,这些困难也可能并不很大。

OpenCL简介:

     目前来说,如果想用A卡进行流计算,无非就是用Brook+,CAL或者OpenCL了。Brook+实际上没有后续支持了,所以并不是最理想的接口。而CAL虽然AMD一直都在更新,但是由于开发难度相对来说大一些,可能也不适合初学者。如果开发者不想用pixel shader进行流计算的话,就只能用OpenCL了。好在这个接口是有Khronos提出的,是一种开放的接口,可以跨平台工作,具有很大潜力。AMD还是比较重视这个接口的,早在9月份初,就已经实现了CPU的solution了。在10月中旬左右,AMD再次发布了基于GPU的OpenCL。

     用户可以通过下载ATI Stream 2.0 Bate 4.0来体验一下AMD的流计算功能。当然,必须要有一块显卡支持才可以。如果有HD Radeon 5000系列最好,但是如果没有的话,4000系列也是同样支持的。

     OpenCL的接口的优点在于,代码不仅可以运行在A卡上,还可以运行在N卡上,Nvidia也发布了OpenCL的solution了。而且还可以在x86架构上运行。由于接口的开放性,以后可能会有更多的处理器支持OpenCL接口。那么用户的OpenCL代码理论上来说,同样是可以跑在新的平台下的。OpenCL的内核编写也是用类C语言进行开发的,所以也非常简单易用。

Stream Kernel Analyzer:

     对于用IL或者Brook+开发的内核程序,用户可以用这个软件进行性能测试。可以在这里下载到:http://developer.amd.com/gpu/ska/Pages/default.aspx

     对于用IL开发程序的朋友来说,可能这个软件就更实用一些了。因为他可以检查一些语法错误,而且报告出的性能更接近与实际的。下图就是这个软件了:

          3

流处理器的硬件功能:

        4

      上图为ATI流处理器的简易模型。不同型号的GPU会有不同的性能参数(例如SIMD引擎的数量),但是基本都是一样的模型。

      一个流处理器里面包含很多SIMD引擎。每个SIMD引擎又包含了很多Thread处理器,每个线程处理器可以对于独立的数据进行内核所规定的操作。线程处理器还不算是最小的处理单元,一个线程处理器里面还包含了一定数量的流计算核心,这些核心才是最基本的进行处理的单元,他们可以进行整数,单精度浮点数,双精度浮点数等操作。在同一时间内,一个SIMD引擎中的所有的线程处理器都执行相同的指令集,不同的SIMD引擎是可以执行不同的指令的。

       5

      一个线程处理器中可以同时最多处理五条指令。我们看到上图中,一个线程处理器中有五个Stream core。其中一个是可以计算超越函数的,剩下四个可以同时计算当精度浮点数。双精度浮点数的处理是通过把四个stream core合起来才可以处理的,所以相对来说要慢一些。除了stream core,每个线程处理器实际还包含一个流控制器,他可以处理一些条件分支的情况。

     不同型号的GPU的细节参数都是不同的。例如,在ATI Radeon 3870 GPU(RV670)这款GPU里面一共包含了4个SIMD引擎,每个SIMD引擎里面有16个线程处理器,并且每个处理器里面有5个stream core。一共是320个物理处理核心单元。

线程处理:

     但同一个cycle中,每个SIMD引擎中的所有线程处理器都必须执行同一指令。为了隐藏内存访问所带来的延迟,线程在发送了内存访问命令之后会被立刻切换。GPU的流处理器里面的Cache并没有CPU多,对于内存访问的优化是通过线程之间的切换来进行的。

     在一个线程处理器中,每4个cycle中,实际可以对于线程处理器指定四条指令。例如,还是刚才那个3870的例子中,16个线程处理器执行同样的指令,每个线程处理器中可以一次执行四条指令(因为每个线程处理器中有4个stream core)。实际上,从外部看,3870的SIMD引擎可以同时处理64条指令的。被同时执行的所有线程的集合被称为wavefront。这里面我们可以理解为3870的wavefront的大小是64的,注意,不是16。

     wavefront的大小是根据GPU的型号不同而可变的。例如,HD 2600 和 HD 2400 的 wavefront的大小分别是32和16,而AMD FireStream 9170的wave front的大小就是64了。

流控制:

     流控制实际上是通过把所有的可能涉及的指令都执行结合起来实现的。举个例子,看下面伪代码:

      if( condition )
      {
          // cost T1
          perform operation 1
      }else
      {
          // cost T2
          perform operation 2
      }

     在一个wavefront里面,如果所有的线程都执行行为1,那么行为2的指令将不会被执行。反之亦然。但是如果有一部分执行了行为1,有一部分执行了行为2,即使是1个线程,那么硬件的做法实际上是让所有线程执行行为1,然后在让所有线程执行行为2。那么总的时间就是T1+T2。

     再举个例子,在一个内核函数的循环里面,每次循环cost T,一个wavefront的线程都只循环一两次,除了一个例外线程循环了100次。那么实际的执行时间就是100*T。这个道理和竹筒装水是一样的。

     所以我们在进行内核程序开发的时候,一定要对于这种分支很明显的情况保持高度敏感。

内存模型:

     在ATI流计算模型中,有三种内存模型:

        host端的内存:这部分内存就是host程序的数据内存等。他可以被host端访问,但是不能被GPU kernel访问。

        PCIe内存:这部分的内存可以被host端或者GPU端访问,但是要做好同步工作。在CAL里面要用calCtxIsEventDone函数,Brook+和OpenCL都已经把这些内容透明了,用户可以无视。

        Local内存:这里的局部是相对于GPU来说的,那么很显然,这种内存是可以被GPU访问的,但是不能被host端访问。

     有三种方式可以拷贝内存到流处理器内存(局部内存)中:

       通过 calResMap

       通过 calCtxMemCopy

       通过一些自定义内核函数从PCIe内存中拷贝。

流处理器的分配:

      高效的流处理器分配机制可以很好的隐藏内存访问所带来的延迟。上面提到GPU是通过线程间切换隐藏内存访问的,这里我们具体举个例子来看一下。

      7

     这里我们假设有四个线程。在最开始的时候,T0在运行,然后在第20个cycle的时候,该线程申请内存读取。其实,线程没有自己去读取内存,而是发送一条指令给DMA。然后T0就被suspend起了,这个thread processor就去执行T1。然后T1也会被suspend,切换T2。以此类推。在第70个cycle的时候,线程T0请求的内存被返回,所以这是T0就可以继续进行操作了。那么在T3结束后,T0会继续。从thread processor角度讲,在任何一个时间内,都在工作,没有idle状态,所以利用率很高。而从线程角度讲,由于线程的相互切换,内存访问的延迟就被隐藏起来了。

     访问全局的内存的cycle的数量级在200左右,而访问shared memory或者register就会在几个cycle内搞定。这个差距是非常大的。所以为了能够有效的隐藏全局访问的延迟,我们需要让计算更密集。就是说在尽可能少访问内存的情况下,多进行计算操作。另外还要有足够的线程数量,上面的例子是个最简单的例子,访问全局的延迟远远要大于四个指令读取的命令。一定要尽可能的保证线程数量的足够,这样才能最好的利用GPU的硬件特性。

     当然,这里绝对不是说为了更好的利用硬件,要增加一些无关的计算,以及一些无用的线程。线程当然是越少越快,但是如果少到一定的程度,甚至比stream core的数量还要少,GPU的利用率是非常低的。

     OK。就介绍这么多吧。希望能够对于想学习Stream computing的朋友有一点点的帮助。

基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
MPU6050是一款广泛应用在无人机、机器人和运动设备中的六轴姿态传感器,它集成了三轴陀螺仪和三轴加速度计。这款传感器能够实时监测并提供设备的角速度和线性加速度数据,对于理解物体的动态运动状态至关重要。在Arduino平台上,通过特定的库文件可以方便地与MPU6050进行通信,获取并解析传感器数据。 `MPU6050.cpp`和`MPU6050.h`是Arduino库的关键组成部分。`MPU6050.h`是头文件,包含了定义传感器接口和函数声明。它定义了类`MPU6050`,该类包含了初始化传感器、读取数据等方法。例如,`begin()`函数用于设置传感器的工作模式和I2C地址,`getAcceleration()`和`getGyroscope()`则分别用于获取加速度和角速度数据。 在Arduino项目中,首先需要包含`MPU6050.h`头文件,然后创建`MPU6050`对象,并调用`begin()`函数初始化传感器。之后,可以通过循环调用`getAcceleration()`和`getGyroscope()`来不断更新传感器读数。为了处理这些原始数据,通常还需要进行校准和滤波,以消除噪声和漂移。 I2C通信协议是MPU6050与Arduino交互的基础,它是一种低引脚数的串行通信协议,允许多个设备共享一对数据线。Arduino板上的Wire库提供了I2C通信的底层支持,使得用户无需深入了解通信细节,就能方便地与MPU6050交互。 MPU6050传感器的数据包括加速度(X、Y、Z轴)和角速度(同样为X、Y、Z轴)。加速度数据可以用来计算物体的静态位置和动态运动,而角速度数据则能反映物体转动的速度。结合这两个数据,可以进一步计算出物体的姿态(如角度和角速度变化)。 在嵌入式开发领域,特别是使用STM32微控制器时,也可以找到类似的库来驱动MPU6050。STM32通常具有更强大的处理能力和更多的GPIO口,可以实现更复杂的控制算法。然而,基本的传感器操作流程和数据处理原理与Arduino平台相似。 在实际应用中,除了基本的传感器读取,还可能涉及到温度补偿、低功耗模式设置、DMP(数字运动处理器)功能的利用等高级特性。DMP可以帮助处理传感器数据,实现更高级的运动估计,减轻主控制器的计算负担。 MPU6050是一个强大的六轴传感器,广泛应用于各种需要实时运动追踪的项目中。通过 Arduino 或 STM32 的库文件,开发者可以轻松地与传感器交互,获取并处理数据,实现各种创新应用。博客和其他开源资源是学习和解决问题的重要途径,通过这些资源,开发者可以获得关于MPU6050的详细信息和实践指南
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值