Skip to content

DCliuzhe/GEM5_RISCV

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GEM5服务器部署

本文档将展示如何在服务器上部署GEM5,在部署前需先在服务器下使用conda创建属于自己的python环境,python>=3.9
conda使用:共享Conda使用说明 (yuque.com)

Step 1:安装与环境配置:

git clone https://github.com/gem5/gem5
cd gem5/
pip install -r requirement.txt

Step 2:编译GEM5

由于编译GEM5时,在默认文件夹下检索不到 libpython3.9.so.1.0 文件,因此需要找到并将其额外加入至环境变量,通常处于/data/anaconda3/envs/env_name/lib文件夹下

export LD_LIBRARY_PATH=/data/anaconda3/envs/liuzhe/lib:$LD_LIBRARY_PATH$

编译过程中服务器上可能会出现gcc版本不匹配的情况,因此需要额外指定gcc版本。如我的服务器上gcc是9.4.0,但所需版本是10.0,因此在编译指令前加上CC=gcc-10 CXX=g++-10

CC=gcc-10 CXX=g++-10 scons build/{ISA}/gem5.opt -j {thread num} --python=/data/anaconda3/envs/liuzhe/lib

Step 3:运行示例程序

编译完成后,会在gem5的build/RISCV/目录下生成一个gem5.opt可执行文件,需要指定一个处理器架构文件和一个编译过后的但运行文件,这里gem5项目提供了运行示例:

 ./build/RISCV/gem5.opt configs/deprecated/example/se.py -c tests/test-progs/hello/bin/riscv/linux/hello --output=sim.out --errout=sim.err

运行后的结果如下:
image.png
这里指定了输出到sim.out文件,运行报错到sim.err文件,可以在gem5/m5out目录下看到。并且在目录下有stats.txt文件记录了程序运行的详细信息。
如果需要运行自己编译的程序,则需额外安装riscv toolchain,使用其中的交叉编译器编译程序成二进制文件。
如果是自己搭建的架构,不指定是看不到输出结果的,在命令行中增加-stats-file参数指定输出文件路径,即可获得仿真过程中运行的信息。
参考:gem5: Building gem5

GEM5基础架构搭建

GEM5中所有的对象构建都继承自同一个基类——SimObject 位于项目/src/python/m5文件夹下,m5也是必须要导入的一个库。 SimObject 的大部分实现是用 C++ 编写的,但 gem5 提供了一种机制,可以将这些 C++ 对象导出到 Python 中。这意味着用户可以使用 Python 配置脚本来创建和操作 SimObject,而不需要直接编写 C++ 代码。

import m5
from m5.object inmport *

创建系统以及系统时钟域

利用System类创建system对象,所有的系统组件的父类均为System,可以用它创建系统的时钟域,下面给出一个创建简单时钟域并指定时钟域的时钟频率和电压域的例子:

system = System()
#设置系统时钟域
system.clk_domain = SrcClockdomain()
system.clk_domain.clock = '1GHz'
system.clk_domain.voltage_domain = VoltageDomain()

时钟域还有其他选择,例如DerivedClockDomian(),即派生时钟域,可以从另一个系统时钟域派生过来,二者时钟频率可以不同。另外每一个时钟域内要指定一个电压域,这里使用VoltageDomain初始化,默认值为1V。
具体类的代码实现可以在/src/sim文件夹下找到。

设置系统内存

系统内存设置至少需要指定两个参数,系统内存模式和系统的内存地址范围:mem_mode与mem_ranges。
系统内存模式分为四类:"timing", "invalid", "atomic"以及“atomic_nocaching"
timing: 精确模拟每个内存操作的时序行为,包括延迟、总线争用等,适用于详细的性能分析。
invalid: 这是一个占位符模式,表示当前内存模式无效或未设置。
atomic: 每个内存操作在一次调用中完成,不模拟实际的时序延迟,适用于快速功能模拟。
atomic_nocaching : 类似于 atomic模式,但不进行缓存,直接与主存通信。
image.png
mem_ranges则是直接指定大小即可(需要带单位)。下面给出设置timing内存模式,地址空间为512MB例子:

system.mem_mode = 'timing'
system.mem_ranges = [AddrRange('512MB')]

设置系统CPU

系统cpu设置需要指定system.cpu参数,可选的CPU类型如下:
AtomicSimpleCPU: 一种原子模式 CPU 模型,不模拟实际的时序延迟,适用于快速功能模拟。
NonCachingSimpleCPU: 一种简单的 CPU 模型,它不使用缓存,而是直接与内存进行交互。
O3CPU: 一种复杂的乱序执行 CPU 模型,模拟现代处理器的行为,适用于详细的性能分析和架构研究。
MinorCPU: 一种简化的乱序执行 CPU 模型,适用于中等复杂度的性能分析。
TimingSimpleCPU: 一种简单的时序 CPU 模型,它并不模拟复杂的流水线结构。
image.png
下面给出设置RISCV,TimingSimpleCPU的示例:

system.cpu = RiscvTimingSimpleCPU()

设置CPU时,默认是64位

设置系统内存总线

系统内存总线有两大类,分别是CoherentXBar和NonconherentXBar,二者均继承自父类BaseXBar,最基本的两个端口是cpu_side_ports和mem_side_ports。
image.png
基于CoherentXBar派生出SystemXBar和L2XBar,基于NoncoherentXBar派生出IOXBar。
SystemXBar: 是一个通用的交叉开关总线,主要用于连接 CPU、内存控制器、缓存和其他系统级设备。
L2XBar: 是一个专用于二级缓存(L2 Cache)的交叉开关总线。它连接多个一级缓存(L1 Cache)和二级缓存,处理缓存层次结构中的数据传输。
IOXBar: 一个专用于输入输出设备的交叉开关总线。它处理系统中的外设和 I/O 设备之间的通信。
下面给出使用SystemBar的例子:

system.membus = SystemXBar()
#将总线与cpu端口接在一起
system.cpu.icache_port = system.membus.cpu_side_ports
system.cpu.dcache_port = system.membus.cpu_side_ports

设置系统中断控制器

创建并配置一个中断控制器(Interrupt Controller)来管理和处理 CPU 的中断请求。示例如下:

system.cpu.createInterruptController()

设置系统内存控制器

  1. 先为系统初始化一个MemCtrl
  2. 可以指定mem_ctrl连接的DRAM模型,GEM5提供了部分DRAM模型的接口,并定义了DRAM模型参数,接口文件路径为/mem/src/DRAMInterface.py。
  3. 之后再将定义后的内存地址空间赋给内存控制器
  4. 最后将内存控制器接在总线上
system.mem_ctrl = MemCtrl()
system.mem_ctrl.dram = DDR3_1600_8x8()
system.mem_ctrl.dram.range = system.mem_ranges[0]
system.mem_ctrl.port = system.membus.mem_side_ports

至此,我们已经搭建好了如下图所示的系统模型:
image.png

GEM5中Cache的使用

GEM5中Cache的分类

在GEM5中,Cache分为两大类,一类是Classic Cache,一类是Ruby Cache。因为GEM5是GEMS与m5两个的结合,在GEMS中使用的是Ruby Cache,在m5中则使用的是Ruby Cache。Ruby Cache相比于Classic Cache,其模型更加复杂,并且更细致地考虑了Cache一致性问题,且提供了许多一致性协议供用户选择。
因为Cache一致性问题并不是我们所考虑的重点,因此接下来将主要讲述Classic Cache的使用。

Cache的参数

所有的Cache类同样继承自SimObject这了父类,基于这个父类,GEM5在/mem/cahce/Cache.py文件中给出了BaseCache类的定义,BaseCache派生出NoncoherentCache和Cache。
一些基本的参数如下:
size:Cache的大小
assoc:Cache组相联的配置
tag_latency:Cache中数据的tag比对花费的周期
data_latency:数据访问延迟周期
response_latency:Cache未命中时,到下一级内存获取数据并返回所需的周期
write_buffers:写缓冲区的数量,默认是支持8个写请求
is_read_only:Cache是否只可读(适用于指令缓存)
replacement_policy: Cache的替换策略,默认是替换LRU策略使用进行替换。
writeback_clean:是否采用writeback策略,默认使用
更多参数可以参考具体文件中BaseCache的定义。

Cache的使用

有关Cache的使用,可以关注Basic_Test文件目录下的simple_withCache.pytest_Cache.py两个文件。test_Cache.py从Cache类派生出实验所需的L1 Cache和L2 Cache两种类,并进一步从L1 Cache派生出L1ICache和L1DCache用于本次实验。simple_withCache.py将test_Cache中的类引入,并搭建了一个具有L1,L2两级Cache的处理器,如下图所示:
image.png
simple_nocache.txt和simple_cache.txt给出了运行在有Cache和无Cache架构下测试一个16×16GEMM Kernel的stats数据。

GEM5的RVV支持

这部分需要分成两部分进行讨论,即RISC-V交叉编译器(gcc)和GEM5分别对RVV的支持。

RISC-V Toolchain的编译与使用

riscv-gnu-toolchain中gcc支持版本为13.2,此版本对RVV0.7支持,对RVV Intrinsic支持到1.0。
关于toolchain的编译参考:riscv-collab/riscv-gnu-toolchain: GNU toolchain for RISC-V, including GCC (github.com)(请记得将编译好的二进制文件目录加入到环境变量中)
使用toolchain的gcc对程序进行编译:

riscv64-unknown-elf-gcc -march=rv64gcv -mabi=lp64d your_program.c -o program_name

**-march=rv64gcv**:

  • **rv64**: 表示 RISC-V 64 位架构。
  • **g**: 表示基本指令集(G,是“general”的缩写),包括整数、乘法、原子操作、浮点数(单精度和双精度)等扩展。
  • **c**: 表示压缩指令集扩展(compressed),用于减少指令的大小,从而减小代码的存储空间和提升执行效率。
  • **v**: 表示向量指令集扩展(vector),用于高效执行矢量运算

**-mabi=lp64d**:

  • **l**: 表示 long 类型数据占 64 位(8 字节)。
  • **p**: 表示指针类型数据占 64 位(8 字节)。
  • **64**: 表示 64 位架构。
  • **d**: 表示双精度浮点数 ABI(Application Binary Interface,应用二进制接口),即使用双精度浮点数进行参数传递和返回值处理。

GEM5的RVV支持

GEM5则直接支持最新的RVV1.0,并且支持用户对vlen做自定义修改,修改方式如下:

import m5
from m5.objects import RiscvISA
...
system.cpu.isa = RiscvISA(vlen = xxx)
...

其中vlen的默认大小为256。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published