30-GPU(上):为什么玩游戏需要使用GPU?
图形渲染的流程
图像进行实时渲染的过程分5个步骤:
- 顶点处理(Vertex Processing)
- 把顶点按三维空间里面的位置,转化到二维空间里
- 图元处理(Primitive Processing)
- 把顶点处理完成之后的各个顶点连起来,变成多边形。我们针对这些多边形,剔除和裁剪(Cull and Clip)
- 栅格化(Rasterization)
- 把做完图元处理的多边形转换成屏幕里面的一个个像素点
- 片段处理(Fragment Processing)
- 计算每一个像素的颜色、透明度等信 息,给像素点上色
- 像素操作(Pixel Operations)
- 把多边形的像素点“混合(Blending)”到一起。
顶点处理
顶点处理 :把顶点按三维空间里面的位置,转化到二维空间里
图元处理
图元处理 :把顶点处理完成之后的各个顶点连起来,变成多边形。我们针对这些多边形,剔除和裁剪(Cull and Clip)
栅格化
栅格化:把做完图元处理的多边形转换成屏幕里面的一个个像素点
片段处理
片段处理: 计算每一个像素的颜色、透明度等信 息,给像素点上色
像素操作
把多边形的像素点“混合(Blending)”到一起。
这样5个步骤的渲染流程呢,一般也被称之为图形流水线(Graphic Pipeline)。
解放图形渲染的GPU
- 问题:图形渲染的流程是简单,固定的,怎么优化硬件的实现?
- 解决:用定制的硬件来处理这部分过程。
早期:CPU执行顶点处理,其余由GPU执行
31-GPU(下):为什么深度学习需要使用GPU?
Shader的诞生和可编程图形处理器
- 问题:程序员希望我们的GPU也能有一定的可编程能力,在整个的渲染管线(Graphics Pipeline)的一些特别步骤,能够自 己去定义处理数据的算法或者操作
- 解决:一开始的可编程管线呢,仅限于顶点处理(Vertex Processing)和片段处理(Fragment Processing)部 分。
- 情况:早期GPU的线段处理和顶点处理是分开两部分的Shader中进行
- 优点:硬件结构简单
- 缺点:会浪费一半Shader
- 解决:统一着色器架构,
- 两部分逻辑虽然不同但是可以用相同的指令集。不再区分直接同一调度
这些可以编程的接口,我们称之为Shader,中文名称就是着色器。
统一着色器架构(Unified Shader Architecture)
现代GPU的三个核心创意
- 问题: GPU的整个处理过程是一个流式处理(Stream Processing)不用处理复杂的逻辑判断,分支预测。怎么提高性能?
- 解决:GPU只留下取指令、指令译码、ALU,寄存器。
多核并行和SIMT
我们可以塞很多个这样并行的 GPU电路来实现计算,GPU运算是天然并行的
- 问题:除了多核GPU还能怎么加速?(线程级并行)
- 解决:SIMT(指令级并行)
- SIMT:图形计算大多都用相同的指令流程进行计算。可以把多条数据,交给不同的线程去处理。
SIMT(Single Instruction,Multiple Threads)类似CPU的SIMD
GPU里的“超线程”
- 问题: GPU里的指令,可能会遇到和CPU类似的“流水线停顿”问题。
- 解决:遇到停顿的时候,调度一些别的计算任务给当前的ALU。 所 以一个Core里面的执行上下文的数量,需要比ALU多。
32-FPGA、ASIC和TPU(上):计算机体系结构的黄金时代
FPGA
- 问题:制造cpu太复杂,能不能不用单独制造一块专门的芯片来验证硬件设计呢?
- 解决: FPGA,现场可编程门阵列(Field-Programmable Gate Array)。
FPGA的特点
- P代表Programmable,一个可以通过编程来控制的硬件。
- G代表Gate:它就代表芯片里面的门电路。
- A代表的Array,叫作阵列,有很多电路门
- F。可以进行在“现场”多次地进行编程。 区别于只能烧录一次
FPGA的实现方法
-
第一,用存储换功能实现组合逻辑。 把真值表存入LUT中,每次判断都查询LUT。LUT是门级别
LUT(Look-Up Table,查找表)
-
第二,在FPGA里面直接放上D触发器作为寄存器实现的时序逻辑电路
- 逻辑簇 :LUT的电路和寄存器组合在一起
逻辑簇 (Logic Cluster)也叫CLB(Configurable Logic Block,可配置逻辑块)
-
第三,FPGA是通过可编程逻辑布线,来连接各个不同的CLB。
-
LUT和寄存器组合出CLB,通过连接不同的CLB,实现芯片功能。
-
问题:为什么更改软件就能改写硬件?
-
改变LUT能改变电路门的类型,改变CLB之间的连接顺序能改变电路门之间的连接顺序。
LUT
连接CLB
ASIC
-
问题:在专门用途的场景下使用通用CPU会造成浪费
-
解决: ASIC。针对专门用途的场景,单独设计一个芯片。
ASIC(Application-Specific Integrated Circuit),专用集成电路。
-
优点:在单片成本和功耗上优于需要做通用计算的CPU和GPU。
-
缺点:ASIC硬件研发成本大
NRE(Non-Recuring Engineering Cost,一次性工程费用)
-
-
解决:用FPGA来实现ASIC
-
优点:没有硬件研发成本
-
缺点:单片成本高,专项性能没ASIC优秀
LUT比实现门电路更复杂,需要的晶体管更多,能耗更大,单片制造成本更高
-
-
选择用FPGA还是ASIC关键取决于成本。包括每块成本和研发成本
33-解读TPU:设计和拆解一块ASIC芯片
TPU V1想要解决什么问题?
-
问题:在深度学习中计算量最大的是推断部分,如何优化推断部分?
-
解决:TPU
-
问题:那推断相对于训练有哪些特点?
-
特点:推断工作简单,对灵活性低。
- 方案:TPU中把计算步骤都做成了专门对应的电路。
-
特点:性能偏好。训练重视吞吐量,推断重视响应时间
- 方案:TPU用了大cache,数据读写速度快
-
特点:推断工作使用频繁希望高耗能比
-
特点:需求精度低
- 方案:对数据进行归一化和正则化后用8B而不是32B储存浮点数。精度够而且能放下更多的计算量使得TPU的推断 速度更快。
-
第一代TPU的设计目标:保证低响应时间下,尽可能高能耗比
推断部分:利用训练完成的模型去计算输入的数据
深入理解TPU V1
快速上线和向前兼容,一个FPU的设计
- 问题:第一代TPU要特殊考虑什么?
- 答案:兼容和快速上线
- TPU实现向前兼容。可用用于PCI-E接口,通过CPU取指令
- 这时的TPU是一个像FPU(浮点数处理器)的协处理器(Coprocessor),而不是像CPU和 GPU这样可以独立工作的Processor Unit。
专用电路和大量缓存,适应推断的工作流程
-
问题:如何设芯片模块?
-
解决:按推断的流程串联硬件模块
推断分多层计算。每层(Layer)的计算过程:矩阵乘法,累加,调用激活函数,归一化,池化。
ASIC的典型设计思路:把确定的程序指令流程,变成固定的硬件电路。
设计开发ASIC的核心原因:用特制的硬件,最大化特定任务的运行效率。
- 控制电路:只占了2%。这是因为,TPU的计算过程基 本上是一个固定的流程。
- 矩阵乘法单元:推断的过程中,矩阵乘法的计算量是最大的所以占用较多晶体管。
- 本地统一缓冲区:为了读写速度使用SRAM,所以占用面积大
Local Unified Buffer(本地统一缓冲区)和矩阵乘法单元(Matrix Mutliply Unit)占着TPU过半面积,控制电路(Control)
用数字说话,TPU的应用效果
- 性能上同水平TPU比CPU,GPU快15~30倍
- 能耗比:30~80倍
- Google已经用TPU替换了自家数据中 心里95%的推断任务
34-理解虚拟机:你在云上拿到的计算机是什么样的?
缘起分时系统
- 问题:早期计算机昂贵
- 解决:提高CPU忙碌率。多人共用
从“黑色星期五”到公有云
- 情景:数据中心有多余的计算能力
- 问题:如何出租?
- 解决:对服务器整机出租
- 缺点:机器性能对中小客户来说是过剩的。
- 缺点:不同租客间的切换麻烦
- 解决:用虚拟机技术来实现按需求租性能
虚拟机的技术变迁
虚拟机(Virtual Machine)技术,其实就是指在现有硬件的操作系统上,能够模拟一个计算机系统的技术。 而模拟一个计算机系统,最简单的办法,其实不能算是虚拟机技术,而是一个模拟器(Emulator)。
解释型虚拟机
思路:兼容宿主机计算机系统的指令集
模拟器实现过程:客户机指令-》应用程序转换-》宿主机指令
- 优势:模拟的系统可以跨硬件
- 缺点:用软件难以精确的模拟硬件
- 缺点:性能太差。每条指令都得经过软件翻译
- 原先的操作系统叫作宿主机(Host)
- 有能力去模拟指令执行的软件,叫作 模拟器(Emulator)
- 实际运行在模拟器上被“虚拟”出来的系统呢,我们叫客户机(Guest VM)。
Type-1和Type-2:虚拟机的性能提升
-
问题:不需要跨平台,怎么去除两个缺点?
-
解决:在宿主机上再跑一个完整的客户机操作系统
-
思路:加入一个中间层,把硬件信息映射到虚拟系统中
虚拟机监视器,英文叫VMM(Virtual Machine Manager)或者Hypervisor。
-
方案:Type-1
-
客户机的指令交给虚拟机监视器后,可以直接由虚拟机监视器去调用硬件。
-
实现:这里虚拟机监视器是一个 嵌入在操作系统内核里面的一部分
-
优点:执行效率高。
-
缺点:兼容性差
-
缺点:直接和硬件接触(没有分层)导致软件较大
-
-
方案:Type-2
- 在虚拟机监视器里执行翻译指令的工作
-
虚拟机监视器,英文叫VMM(Virtual Machine Manager)或者Hypervisor。
Docker:新时代的最佳选择?
- 问题:我们不需要运行多个独立的操作系统。我们只需要独立的计算资源
- 解决:不再需要在操作系统上再跑一个操作系统,通过容器编排工具,能够进行各个应用之间的环境和资源隔离
35-存储器层次结构全景:数据存储的大金字塔长什么样?
理解存储器的层次结构
CPU Cache用SRAM(Static Random-Access Memory,静态随机存取存储器)
SRAM
SRAM不用刷新,存储数据占用空间大。速度非常快。
内存用DRAM(Dynamic Random Access Memory,动态随机 存取存储器)跟SRAM相比密度大,便宜。 DRAM需要定期刷新,电路复杂访问延时长,破坏性读取形式
存储器的层级结构
存储器只和相邻的一层存储器打交道,并且随着一层层向下,存储器的容量大,速度慢,成本下降
使用存储器的时候,该如何权衡价格和性能?
36-局部性原理:数据库性能跟不上,加个缓存就好了?
- 问题:服务端系统遇到访问数据库性能瓶颈如何解决?
- 解决:加层缓存
这种添加缓存的策略一定是有效的吗?或者说,这种策略在什么情况下是有效 的呢?如果从理论角度去分析,添加缓存一定是我们的最佳策略么?进一步地,如果我们对于访问性能的要 求非常高,希望数据在1毫秒,乃至100微妙内完成处理,我们还能用这个添加缓存的策略么?
理解局部性原理
- 问题:怎么样才能综合各种储存设备的优点
- 解决:分层结构
- 由于局部 性原理,每层只需要少量储存空间即可提高大部分速度
局部 性原理(Principle of Locality)包括时间局部性(temporal locality)和空间局部性(spatial locality)
时间局部性:如果一个数据被访问了,那么它在短时间内还会被再次访问。
空间局部性:如果一个数据被访问了,那么和它相邻的数据也很快会被访问。
37-理解CPUCache(上):“4毫秒”究竟值多少钱?
我们为什么需要高速缓存?
- 问题:为什么要cache?
- 答案:内存不能满足CPU的处理速度,需要再加层缓存
Cache的数据结构和读取过程是什么样的?
-
问题:cache储存数据的规则
-
解决:直接映射
- cache和内存块地址多对一。利用mod实现
-
缓存块存储:组标记(Tag)。 来区分具体是哪块内存
-
实际数据数据(Data Block )
-
有效位(valid bit)。
cpu通过设置偏移量(Offset)来读取Data Block 中的一个word
内存地址对cache的映射关系:组标记,索引,偏移量
如果内存中的数据已经在CPU Cache里了,那一个内存地址的访问,就会经历这样4个步骤:
- 根据内存地址的低位,计算在Cache中的索引;
- 判断该cache的有效位
- 对比内存访问地址的高位,和Cache中的组标记,再读取数据块
- 根据内存地址的Offset位,从Data Block中,读取希望读取到的字。
如果有效位和组标记不符合,会读取内存并更新cache和对应信息
除了直接映射Cache之外,我们常见的缓存放置策略还有全相连Cache(Fully Associative Cache)、组相连Cache(Set Associative Cache)。
38-高速缓存(下):你确定你的数据更新了么?
- 问题:volatile关键字的作用是什么?
- 答案:避免数据不一致
- 确保我们对于这个变量的读取和写入,都一定会同步到主内存里,而不是从Cache里面读 取。
CPU高速缓存的写入
cache结构
对于数据,我们不光要读,还要去写入修改。这个时候,有两个问题来了。
- 问题:写cache和内存的同步如何处理?
- 解决:写直达
- 始终要把数据同步到内存面。
- 写回
- 写时只写cache,只有脏数据要被替换时才把数据写回内存
- 问题:写回在多CPU,多线程的情况下如何解决cache的一致性?
- 解决:MESI协议
写直达(Write-Through)
写回(Write-Back)
39-MESI协议:如何让多核CPU的高速缓存保持一致?
缓存一致性(Cache Coherence)的问题。
缓存一致性问题
- 问题:如何解决缓存一致性的问题?
- 解决:MESI
- 思路:同步多个核心内的缓存
- 实现同步的条件:
- 写传播(Write Propagation)。写传播是说,在一个CPU核心里,我们的Cache数据更新,必须能 够传播到其他的对应节点的Cache Line里
- 事务的串行化(Transaction Serialization):所有CPU看到的操作的先后顺序都是一样的
- 问题:如何实现事务的串行化?
- 解决:第一点是一个CPU核心对于数据的操作,需要同步通信 给到其他CPU核心。
- 第二点是,如果两个CPU核心里有同一个数据的Cache,那么对于这个Cache数据的更 新,需要有一个“锁”的概念。
总线嗅探机制和MESI协议
-
问题:多个CPU之间如何传递消息
-
解决:总线嗅探(Bus Snooping)
- 本质上就是把所有的读写请求都通过总线(Bus)广播给所有的CPU核心,然后让各个核心 去“嗅探”这些请求,再根据本地的情况进行响应。
MESI协议
MESI协议,是一种叫作写失效(Write Invalidate)的协议。在写失效协议里,只有一个CPU核心负责写入 数据,其他的核心,只是同步读取到这个写入。在这个CPU核心写入Cache之后,它会去广播一个“失 效”请求告诉所有其他的CPU核心。其他的CPU核心,只是去判断自己是否也有一个“失效”版本的Cache Block,然后把这个也标记成失效的就好了。
写广播(Write Broadcast)协议。一个写入请求广播 到所有的CPU核心,同时更新各个核心里的Cache。
写广播实现简单,但是需要广播数据内容,所以占用更多的总线带宽。
MESI协议标记cache四种不同状态: M:代表已修改(Modified) E:代表独占(Exclusive) S:代表共享(Shared) I:代表已失效(Invalidated)
-
已修改是自己写了,已失效是别人写了
-
“独占”和“共享”这两个状态都是干净的数据
-
问题:独占和共享的区别?
-
答案:独占可以自由写,独占接收到总线对该数据的读请求则会变成共享
-
共享写之前要先广播变成无效然后再更新cache数据。
这个广播操作,一般叫作RFO(Request For Ownership),也就是获取当前对应Cache Block数据的所有权。
类似读写锁,共享状态都可以读,写时要先上锁获得所有权
整个MESI的状态,可以用一个有限状态机来表示它的状态流转。 对于不同状态触发的事件 操作,可能来自于当前CPU核心,也可能来自总线里其他CPU核心广播出来的信号。