|
版权声明 本文首发于知乎专栏:移动端算法优化
本专栏「移动端算法优化」所有文章著作权归作者所有。
允许个人直接分享本专栏文章到个人微博、朋友圈。但媒体(包括但不限于网站、微信公众号、微博营销号)转载需事先征得专栏同意。转载需在正文开头显著位置注明出处,给出原始链接,注明「发表于知乎专栏《移动端算法优化》」,并不得进行任何形式的修改演绎。 <hr/>一、概述
如今的时代是一个数据爆炸的时代,如何处理海量的数据是各行各业不得不面临的一个重要问题。随着摩尔定律的失效,支持大量并行计算的异构处理器开始大放异彩。其中,无论是在 PC 端还是移动端,GPU 无疑是其中最璀璨的明星。
接下来,我们首先会对 GPU 的发展历史和硬件架构(移动端)进行简单地介绍,随后对 OpenCL 编程框架进行详细的介绍。
二、从 GPU 到 GPGPU
2.1 GPU 简介
GPU 简介
GPU (Graphics Processing Unit) 图形处理器,又称为显示核心、视觉处理器、显示芯片, 是一种专门在个人电脑、工作站、游戏机和移动设备(平板电脑、手机)上做图像和图形相关相关运算工作的微处理器。
GPU 通常可以分为如下几类:
独立 GPU | 封装在独立的电路板,专用的显存(显示储存器) | 性能高,功耗大 | 集成 GPU | 内嵌到主板上,共享系统内存 | 性能中等,功耗中等 | 移动端 GPU | 嵌在 SoC(System On Chip)中,共享系统内存 | 性能低,功耗低 | 2.2 从 GPU 到 GPGPU
在 GPU 发展早期,由于其主要面向图形绘制等操作,功能相对来说比较单一。后来,NVIDIA公司发展了一种可编程的着色器,每个像素经过一段“简短”的程序计算,然后在将结果投到屏幕上。2007年,NVIDIA更进一步地提出了CUDA(Compute Unified Device Architecture,统一计算架构)用于通用计算领域。
此后,专注于通用并行计算能力的 GPU 也有了新的名称:GPGPU(General-Purpose computing on Graphics Processing Units)。
近年来,AI、区块链等技术的蓬勃发展对算力的需求愈发强烈,GPU 也受到了前所未有的关注。在 PC 端,NVIDIA 和 AMD 瓜分了几乎整个市场。而在移动端,则主要以高通的 Adreno GPU和 ARM 的 Mali GPU 占主导。
三、GPU 硬件介绍
3.1 GPU与CPU的比较
GPU 与 CPU 的硬件比较
CPU | GPU | 数据吞吐量 | 小 | 大 | 计算核心数量 | 少 | 非常多 | 控制单元 | 可以进行复杂的逻辑判断 | 简单的逻辑判断 | 算术逻辑单元 | 计算快,延迟低 | 计算较慢,延迟较高 | 缓存 | 大 | 小 |
从上面可以看出,与CPU相比,GPU更擅长处理逻辑判断较简单、数据量大的可并行计算任务。 3.2 Qualcomm Adreno GPU
3.2.1 Adreno GPU 简介
高通 Adreno GPU,其前身是 AMD 的移动 GPU Imageon 系列,在 2009 年被高通收购,并改名为 Adreno GPU。每一代的高通骁龙 SoC 也都无一例外地集成了 Adreno GPU。
下面是对部分 Adreno GPU 信息的整理:
Adreno GPU 信息列表
3.2.2 Adreno650的硬件架构介绍:
Adreno GPU架构示意图
在Adreno650 GPU中,主要包含了以下的部件:
- Command Processor:指令处理器,接受与执行外部指令;
- SP(Shader/Streaming Processor)x3: 着色/流处理器, GPU的基本运算单;
- L2 Cache:128KB, 进行读写的缓存;
- Memory Manage Unit:内存管理单元 MMU。
视运算能力的不同,一个 GPU 中往往包含了数量不同的 SP。但是由于移动端的面积和功耗的限制,移动端 GPU 的 SP 数量一般相对较少。这也是移动端 GPU 的性能落后 PC 端 GPU 的一个重要原因。
SP 架构图
下面是 SP 的基本组成:
Instruction Cache | 指令缓存 | Scheduler | 负责任务的调度 | Local Buffer | 本地内存,可编程,有时也可当作SP的缓存 | GPRs | 通用目的寄存器(General Purpose Registers),存储每个运算任务的变量状态 | ALU | 算术逻辑单元(Arithmetic logic unit),加减等简单运算时被调用 | SFU | 特殊运算单元(Special Function Unit),计算三角函数、开根号等复杂运算时被调用 | Load/Store | 数据载入/储存 | Texture Pipe | 用于纹理数据加载和缓存 | 一般来说,进行复杂运算(SFU)和数据的载入与储存(Load/Store)会消耗较多的时钟周期,而简单运算(ALU) 速度则较快。通过合理的调度,SP可以尽可能地让每个运算资源都有相应的任务在运行,避免过多任务等待同一个运算资源,从而达到掩盖等待时间的目的。
除了基本的 Cache 之外,GPU 一般还带有专用的纹理处理单元,用来完成对于 2 维/ 3 维图像数据的访问加速以及提供一些如插值等操作的硬件加速。
3.3 ARM Mali GPU
3.3.1 Mali GPU简介:
Mali GPU的架构发展
Mali 是一款由 ARM Holdings 研发设计的 移动GPU系列。Mali GPUs 是由 Falanx Microsystems A/S 发展而来,其最初是挪威科技大学孵化的一个研究项目。2006年,Falanx Microsystems A/S 被 ARM Holdings 收购后改名为ARM Norway,并继续负责 ARM Mali GPU 系列的研发设计。
Mali 的架构一共经历了四个架构的更迭,分别为 Utgard、Midgard、Bifrost、Valhall。2021年,Valhall 架构已经更新到了第三代,以 Mali-G710、Mali-G510、Mali-G310 为代表。
下面我们列举一些具体的 Mali GPU 的信息:
Mali GPU 信息列表
3.3.2 Mali-G710的硬件架构介绍:
Mali-G710 示意图
Mali GPU 的基本处理单元为 Shader Core(类似于 Adreno GPU 中的 SP)。每个 Shader Core 中有自己的指令缓存、调度器、寄存器资源、缓存和运算单元。
但值得注意的是,Mali GPU 并没有像其他 GPU 一样内嵌到片上的 Local Memory 和 Private Memory,而是通过 Global Memory + Cache 的方法来代替。这意味着每当你使用 OpenCL 申请 Local Memory 或者 Private Memory 的时候,你实际上申请的是 Global Memory。将数据从 Global Memory 拷贝到 Local Memory 也并不会对性能有任何提高。
截止到 2021 年 12 月,基于 Valhall 架构的第三代 GPU Mali-G710 是性能最高的 Arm GPU。相较前一代,G710 在性能上和能效上均提升了 20%,且对于机器学习的性能也有 35% 的提升。可选核心数量为 7~16,L2 Cache 在 512KB 到 2MB 之间。
四、OpenCL 介绍
4.1 什么是OpenCL?
OpenCL(Open Computing Language, 开放设计语言) 是一个为异构平台(CPU/GPU/DSP/FPGA等等)编程设计的框架。OpenCL 由一门编写 kernel 的语言(基于C99)和一组用于定义和控制平台的 API 来组成,主要用于并行运算方面。
OpenCL - 异构计算框架
4.2 OpenCL的诞生与发展
由于各个硬件厂家在 GPU 硬件设计上存在着较大差别,为了降低跨平台的开发难度,人们迫切需要一套能够兼容各类硬件设备的计算框架。
OpenCL 最初由苹果公司开发,拥有其商标权。2008 年,苹果公司向 Khronos Group 提交了一份关于跨平台计算框架 (OpenCL) 的草案,随后与 AMD、IBM、Intel、和 NVIDIA 公司合作逐步完善,其接口大量借鉴了 CUDA。后续,OpenCL 的管理权移交给了非盈利组织 Khronos Group,且于2008年12月发布了 OpenCL 1.0。最新的OpenCL 3.0 于 2020 年 9 月发布。
OpenCL各版本的发布时间
为了更好地适用于不同处理器,OpenCL 抽象出了如下四大模型:
- 平台模型:对不同硬件及软件实现抽象,方便应用于不同设备;
- 存储模型:对硬件的各种存储器进行了抽象;
- 执行模型:程序是如何在硬件上执行的(任务划分 & 计算流程管理);
- 编程模型:数据并行和任务并行。
我们接下来将对这四种模型进行详细讲解。
4.3 OpenCL的四大模型
4.3.1 平台模型
OpenCL 平台模型图示
在 OpenCL 中,我们首先需要一个主机处理器(Host),一般是 CPU。而其他的硬件处理器(多核CPU/GPU/DSP 等)被抽象成 OpenCL 设备(Device)。每个设备包含多个计算单元(Compute Unit),每个计算单元又包含多个处理单元(Processing Element)。
Device 对应我们上面提到的 Adreno GPU 和 Mali GPU,计算单元 CU 对应 Adreno GPU 中的 SP 和 Mali GPU 中的 Shader Core,而处理单元 PE 可以对应 SP 和 Shader Core 中的运算单元。
在执行中,主要的流程为 Host 端发送数据和任务给 Device 端,Device 端进行计算,最后在 Host 端进行同步。
4.3.2 存储器模型
OpenCL 异构平台由主机端和设备端构成,存储器区域包含主机与设备的存储。
在 OpenCL 中具体定义了下面几种不同的存储区域:
OpenCL 储存器模型示意图
- 主机存储(Host Memory):主机可用的存储,通常对应主机 (Host) 端的内存,可以通过直接传输/共享内存的方式与设备端进行数据传输;
- 全局存储 (Global Memory):通常指显存,允许上下文中任何设备上工作组 (Work Group) 中的所有工作项 (Work Item) 读写;
- 常量存储(Constant Memory):片上特殊内存,只读,在内核执行期间数据保持不变;
- 局部存储(Local Memory):对整个工作组内部所有的工作项可见,用于同一工作组内部工作项之间的数据共享;
- 私有存储 (Private Memory):工作项的私有区域,对其它工作项不可见,在硬件实现上通常映射为寄存器。
在 OpenCL 中,全局存储器中的数据内容通过存储对象来表示(Memory Object),在 OpenCL 中较为常用的两个存储对象为:Buffer Objects 和 Image Objects
Buffer Object 与 Image Object
4.3.3 执行模型
OpenCL 执行模型图示
在理解 OpenCL 的执行模型时,我们需要知道如下几个概念:
- Context(上下文):每个device对应一个Context,Host端通过Context与Device端进行交互和管理;
- Command Queue(命令队列):Host 端对计算设备进行控制的通道,推送一系列的命令让Device端去执行,包括数据传输、执行计算任务等。一个命令队列只能管理一个设备,可以顺序执行也可以乱序执行;
- Kernel Objects (内核对象):OpenCL 计算的核心部分,表现为一段C风格的代码。在需要设备执行计算任务时,数据会被推送到Device端,然后 Device 端的多个计算单元会并发地执行内核程序,完成预定的计算过程;
- Program Objects(程序对象):内核对象的集合,在 OpenCL 中使用 cl_program 表示程序对象,可以使用源代码文本或者使用二进制数据来创建。
那么,如何更好地控制多核之间的并行计算呢?OpenCL 会对任务进行划分,可以分割成一维、二维和三维的任务网格,一般为二维。这里,我们以二维来举例:
OpenCL的任务划分网格
- 首先,需要用户自定义总的工作项网格 [G0 x G1] 作为Global Size;
- 然后,用户定义一个更小的网格 [L0 x L1] 作为Local Size(一般来说G0/G1是L0/L1的倍数);
- 同一个Local Size中的运算任务会被打包给到一个Work Group中,其中的每个Work Item并发地执行。
- 这样,每个Work Item在Global Size中会有一个唯一的全局索引(Gx, Gy);同时,也有一个对应的局部索引(Lx, Ly)。通过可以利用这些索引,可以让我们更加灵活地设计内核函数。
4.3.4 编程模型
OpenCL 定义了两种不同的编程模型:任务并行和数据并行。
- 数据并行模式中,划分计算数据,分配给不同的计算单元进行同时计算,适用于数据相互独立的计算任务。
- 任务并行是指,计算步骤的每一个步骤有前后依赖,这使得我们无法将计算任务并行执行。于是,我们只能对每一个步骤的数据进行并行,之后将整个流程进行异步/同步串行执行,为了协调整个流程的先后关系,OpenCL 提供了Event 机制用来进行流程同步控制。
五、总结
本文首先对 GPU 进行了概述,然后着重地对移动端的 GPU 进行了分析,随后我们又详细地介绍了 OpenCL 的背景知识和 OpenCL 的四大编程模型。希望能帮助大家更好地进行移动端高性能代码的开发。
参考资料
- https://en.wikipedia.org/wiki/Adreno
- https://en.wikipedia.org/wiki/Mali_(GPU)
- https://developer.arm.com/ip-products/graphics-and-multimedia/mali-gpus
- https://www.qualcomm.com/products/features/adreno
- https://developer.arm.com/documentation/100614/0314/OpenCL-concepts
- https://www.khronos.org/opencl/
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|