文章目录
- 前言
- 一、GPGPU是什么?
- 1.1 GPU和GPGPU之间的差异
- 1.2 GPU和CPU之间的集成方式
- 1.3 GPU包含什么(列举和VMIPS向量体系结构的差异)
- 二、Vortex GPGPU是什么?
- 2.1 Vortex GPGPU的技术边界和验证环境
- 2.2 Vortex GPGPU的指令集设计(对比GPU的指令集)
- 2.3 Vortex GPGPU Core的6级流水微架构设计
- 2.4 Vortex GPGPU的微架构设计
- 2.5 Vortex GPGPU的Cache串行流水线设计和Cache多端口设计方法
- 三、Vortex GPGPU代码包含什么?
- 3.1 Vortex GPGPU的代码结构
- 3.2 Vortex GPGPU的握手协议
- 3.3 Vortex GPGPU代码中slave/master规范
- 3.4 Vortex GPGPU代码支持的debug
- 总结
前言
这次开始针对Vortex GPGPU进行架构分析、硬件代码分析、仿真代码分析和运行时代码分析。
Vortex GPGPU的官方文档可以见:Vortex GPGPU
Vortex GPGPU的github可见:github,其中vortex包含源码和必要的.md文件,其中vortex_tutorials包含作者在MICRO顶会上汇报的slide
本系列文章首先参考了知乎帖子,在略微深入了解Vortex GPGPU之后就觉得这可能是学习GPGPU系统工作的好机会。同时也为下一个研究工作做准备工作。
一、GPGPU是什么?
1.1 GPU和GPGPU之间的差异
顾名思义,Vortex GPGPU是一种简化版本的GPGPU。在此之前,可以简单回顾GPU的基本知识。(个人建议如果要深入研究GPGPU架构,还是先去把《计算机体系结构:量化研究方法》这一本书内关于数据级并行的知识去回顾一遍)由于GPU除了包含用于加速深度学习中矩阵乘的tensor core和支持其他计算的cuda core之外,还包含图形渲染等技术。GPU在处理视觉密集型任务,如视频游戏、三维动画、图形设计和视频编辑时表现出色。此外,GPU的并行计算能力在科学模拟、数据分析、深度学习和机器学习等领域表现出色。
而GPGPU是GPU的一个概念,指的是将GPU用于除了图形渲染之外的通用计算任务。GPGPU利用GPU的并行处理能力来加速科学模拟、数据分析和机器学习等计算密集型任务。这种技术允许开发者通过使用专门的编程框架,如CUDA或OpenCL,来编写能够在GPU上执行的代码,从而利用GPU的并行架构来加速计算。换句话说,GPGPU专注于使用GPU进行非图形的通用计算任务。
1.2 GPU和CPU之间的集成方式
注意GPU是图灵完备的,图灵完备是指理论上只要提供足够多的时间和内存,任何计算都可以完成。但是这并不代表GPU可以脱离CPU而存在,这是因为GPU并不是一个独立的计算设备,往往需要和CPU集成在一个芯片内。CPU负责GPU上的计算启动,并将数据传输到GPU上。关于两者的架构图根据场景分为2类:

图源《General-Purpose Graphics Processor Architecture》
图1.1(a)显示一个包含CPU和GPU的典型系统图,此处GPU是“独立GPU”,其中也包括用于连接CPU和GPU的总线如PCIE。CPU和GPU分别带有独立的DRAM内存空间,CPU的内存空间称为“系统内存System Memory”,GPU的内存空间称为“设备内存Device Memory”。并且,“系统内存”和“设备内存”通常会使用不同的DRAM技术,比如CPU使用DDR(这是因为CPU优先优化对DDR的访问延迟),GPU使用GDDR(这是因为GPU优先优化对GDDR的访问吞吐量)。
图1.1(b)是一个典型的集成CPU和GPU的逻辑图,比如AMD的Bristol Ridge APU或者移动设备的GPU(“移动GPU”),此处的CPU和GPU使用单一的DRAM内存空间,因此必须使用相同的内存技术,由于集成CPU和GPU的芯片出现在低功耗移动设备上,所以对这种内存的优化往往针对功耗展开(LPDDR)。
1.3 GPU包含什么(列举和VMIPS向量体系结构的差异)
现在来看看GPU包含了什么?


包含指令缓存、warp调度程序、SIMD车道或者说线程处理器、各个层次的存储器、互连网络等。
一个高度抽象的全架构图如下:

类似于向量体系结构,GPU有类似概念。
网格:在GPU上执行的可向量化循环,由一个或者多个可以并行执行的线程块组成。
线程块block:可以在多线程SIMD处理器上执行的向量化循环,由1个或者多个SIMD指令线程组成。它们可以通过局部存储器通信。
CUDA线程:对应于1个SIMD车道上执行的1个元素。
Warp:一种传统线程,仅包含多线程SIMD处理器上执行的SIMD指令。
PTX:在多个SIMD车道上执行的1条SIMD指令。
SM流式多处理器:多线程SIMD处理器执行SIMD指令的线程,和其他SIMD处理器无关。
Warp调度程序:当SIMD指令线程做好准备后,用于调度和发射这些线程的硬件,包括一个计分板,用于跟踪SIMD线程执行。
关于thread、block和warp之间的差异见:

另外注意GPU有2级硬件调度程序:
线程块调度程序:将线程块分配给多线程SIMD处理器,确保线程块被分配给其局部存储器拥有相应数据的处理器;SIMD处理器内部的SIMD线程调度程序(就是Warp调度程序),用以调度何时运行SIMD指令线程。
当然GPU和向量体系结构这两者也是有差异的:
| GPU 向量体系结构 | |
|---|---|
共同点 | 1、可以解决数据级并行问题;2、都拥有Gather-Scatter数据传送;3、都支持mask寄存器; |
差异点 | 1、GPU的寄存器数量要比VMIPS多;2、由于没有一种接近的标量处理器,GPU有时会在运行时以硬件实现一些功能,VMIPS通常在编译时用软件来实现这些功能;3、与大多数VMIPS不同的是,GPU还依赖单个“多线程SIMD处理器“中的”多线程“来隐藏存储器延迟; |
展开SIMD车道

其余关于GPU怎么处理分支,为什么引入mask寄存器等之后有需补充。
二、Vortex GPGPU是什么?
2.1 Vortex GPGPU的技术边界和验证环境

以上是Vortex GPGPU团队提出的GPGPU架构,整个系统包括Host端和GPGPU Processor端,Host端通过设计两种不同平台的驱动来支持AMD的OpenCL和NVIDIA的CUDA,事实上作者开发了不止一种驱动,根据底层环境分为四种,后面再展开!在CUDA和OpenCL的运行时之上就是两类程序。而在Processor端,作者做了层级设计,包括计算和存储。存储包含设备内存、共享memory和Register File,计算层面则通过设计多个Core实现高度数据级并行,图示中的AFU是用于Host端给GPGPU的multi-banking DRAM填充数据的单元。Core的架构细节包括Warp调度程序单元、取指、译码、寄存器堆、ALU、FPU、LSU、SFU和共享存储。彼此之间的连接关系见后面。

以上是Vortex GPGPU设计的验证环境。
1、最右侧是作者团队设计的一个
周期精确的Vortex GPGPU模拟器,基于SIMX Driver驱动支持Vortex应用程序的运行。
2、从最右侧过来,左边第一个是纯Vortex GPGPU的验证环境,作者借助Verilator这个开源波形验证工具向上搭建RTLSIM驱动来支持Vortex应用程序的运行。
3、再往左边过来就是,使用AFU实现基本的数据可供给的系统,作者依旧借助Verilator这个开源工具向上搭建VLSIM驱动来支持Vortex应用程序的运行。
4、最左侧就是在FPGA平台上基于OPAE驱动来支持Vortex应用程序的运行。
这样的验证环境对我本人来说,是全新的。因此,对我而言,有愈发学习框架和代码的必要性。(此前,我只知道最左侧的验证环境和软件开发流程)
2.2 Vortex GPGPU的指令集设计(对比GPU的指令集)

上述只列举了部分RISC-V指令集扩展,主要是控制流指令。
对比《计算机体系结构:量化研究方法》上的指令集:




2.3 Vortex GPGPU Core的6级流水微架构设计

首先这个和超标量处理器类似,属于多发射的处理器。作者自己定调是6级顺序发射-乱序接收的GPGPU。每一级流水功能见下面图片:

这是调度阶段,包括前述提到的Warp调度程序和Warp Table。关于IPDOM(Immediate Postdominator) Table和Inflight Tracker,根据官网论文的细节看:
IPDOM Table是为了解决SIMT(单指令多线程)处理器中的控制流分歧问题。具体来说是因为:
控制流分歧导致性能降低:控制流分歧发生在同一个硬件warp中的线程想要执行不同的指令路径时。由于线程可能因为条件判断、循环等操作而产生不同的执行流程,这会导致SIMT处理器中的某些线程空闲,从而降低流水线的利用率。如果不加以处理,控制流分歧会导致处理器性能的显著下降。
IPDOM Table怎么解决这个问题:为了解决这个问题,引入了IPDOM栈。IPDOM栈的作用是跟踪warp中线程的执行状态,以便在发生控制流分歧时能够恢复到正确的执行路径。具体来说,每个warp都有一个私有的线程掩码寄存器,该寄存器存储当前正在运行的线程的掩码。当执行到分割指令时,当前线程掩码的状态、新线程掩码的逆,以及下一条指令的地址(PC+4)会被推入到IPDOM栈中。当执行合并指令时,会从IPDOM栈中弹出这些信息,以恢复到正确的执行状态。
IPDOM Table引入的好处:引入IPDOM栈的目的是为了简化硬件设计,同时有效处理控制流分歧。通过维护一个栈来跟踪和恢复执行状态,可以在不显著增加硬件复杂度的情况下,解决控制流分歧带来的性能问题。这种设计允许SIMT处理器更高效地处理线程执行中的条件分支和循环,提高了处理器的整体性能和利用率。
而Inflight Tracker主要是为了跟踪in flight指令,也就是跟踪执行中的指令。
Warp Scheduler:
1、Schedule the next PC into the pipeline
2、Track stalled, active warpsIPDOM Stack
1、Save split/join states for divergent threadsInflight Tracker
1、Track in-flight instructions

这是取指阶段,包括设计Cache,处理ICache请求和响应。作者额外设计了预防死锁的设计(具体细节看代码的时候展开)。
1、Retrieve instructions from memory
2、Handle I-cache requests/responses

这是译码阶段,主要负责分析指令的各个field,从而确定操作类型和操作数。
1、Decode fetched instructions
2、Notify warp scheduler on control instructions

这是发射阶段,包括指令buffer、计分板、寄存器堆和操作数分发。
IBuffer
1、Store decoded instructions in separate per-warp queuesScoreboard
1、Track in-use registers
2、Check register use for decoded instructionsOperands Collector
1、Fetch the operands for issued instructions from the register file

这是执行阶段,包括四大类Cluster。
ALU Unit
1、Handle arithmetic and branch operationsFPU Unit
1、Handle floating-point operationsLSU Unit
1、Handle load/store operationsSFU Unit
1、Handle warp control operations
2、Handle Control Status Registers (CSRs) operations
注意执行阶段还包括:Dispatch和Gather单元。


这是回收阶段,用于获取执行完的结果,并完成写回到cache的操作。
Commit
1、Write result back to the register file and update the Scoreboard.
2.4 Vortex GPGPU的微架构设计

计算部分的层次不过多解释!
2.5 Vortex GPGPU的Cache串行流水线设计和Cache多端口设计方法

这是个很典型的cache设计,包括Tag和Data部分。可以先简单回顾Cache的流水设计,以下图来自《超标量处理器设计》:

一个4路组相联的cache设计如上,访存地址分为Tag、Index、Block Offset。Index用于选中4路中的哪一行,也就是选中Tag Memory中某一行,随后使用Tag来确定是否命中了4路中的某一路,如果命中,则接下来在Data Memory对应的路中根据Block offset选中某个cacheline data block。
用于cache的并行化访问流水(这里的并行指的是对Tag Memory和Data Memory的并行访问,同理后面提到的串行也是这两者的串行访问)


一般来说,会倾向于选择串行访问,原因是减少了MUX的数量,因为在现代CPU中,L1 ICache一般采用4路组相联(我们以intel i4为例),L1 DCache一般采用8路组相联。L2 Cache同样会采用8路组相联。因此高相联度的cache必然会带来多路选择器,而串行访问明显降低了对2个memory的访问延迟。当然缺陷也是明显的,就是增加了load指令的延迟,因为多了一拍。
世界线收束一下!

单从这张图可以看出作者采用了Tag Memory和Data Memory的串行流水线设计。与此同时,作者提到为了适应多发射的需要,引入virtual multi-porting的设计。通常cache因为面积本来就很大,很少考虑True multi-porting设计。因为端口数量增加会导致面积增加。尽管如此,但是还是能接受,因为对于ICache而言,需要每个周期读取多条指令,多端口设计基本可以保证每拍都可以取出指令。当然发射的指令数量完全取决于一次取多少和cacheline block字节的对齐程度。
在超标量处理器中,会有一些部件考虑使用True multi-porting,比如Register File、ROB和Issue Queue,但这些部件容量本身就不大。
相比之下,DCache采用这个方案对访问延迟和面积都有极大的消极影响。一般的处理方案是multi-banking,以AMD Opteron为例:

以multi-banking的形式有利于分割开物理存储,减少访问竞争。一张更形象的图是:

使用多体交叉的方式来支持多端口访问。
至于这里提到的virtual multi-porting设计方法,不太理解为什么作者将DCache和ICache都进行了同样处理(这一点先存疑,但感觉大概率是进行了同样操作,后续等读完代码后再来澄清这个问题)。为什么这么设计,作者也提到了优势,可能具体有多好还得回到代码中去看看。
三、Vortex GPGPU代码包含什么?
3.1 Vortex GPGPU的代码结构


这里提到在FPGA上的部署,我简单看了作者代码,大概率是可以支持Vortex GPGPU和ZYNQ构建SoC,作者并未套用Xilinx提供的axi full封装代码,而是自己重构了。这可能是本源码的第不知道多少个值得学习的地方。




一个是基于Intel的开发板,一个是基于xilinx的开发板。作者提到了具体支持的板子类型:

世界线收束!




3.2 Vortex GPGPU的握手协议

只是截个图,保证后面看代码的时候没遗漏细节!
3.3 Vortex GPGPU代码中slave/master规范

3.4 Vortex GPGPU代码支持的debug








总结
本文简单回顾GPU和CPU之间的集成方式,GPU和GPGPU之间的差异,同时根据经典书籍展开GPU的基本知识,并与VMIPS进行对比。随后展开Vortex GPGPU的架构设计细节,并同时深入分析了作者设计的4种验证环境。最后简单展开Vortex GPGPU的源码结构。