全系统模拟
官方教程:Gem5官方教程 全系统模拟一共需要三部分
- gem5.opt
- 内核镜像
- 磁盘镜像
不过我们并不需要所有都自己编译,gem5提供了不同处理器架构的预编译文件,可以在gem5 resource中搜索需要的文件
一、编译Gem5.opt
本机环境: Ubuntu 22.04
需要安装如下依赖
sudo apt install build-essential git m4 scons zlib1g zlib1g-dev libprotobuf-dev protobuf-compiler libprotoc-dev libgoogle-perftools-dev python-dev python
安装完依赖之后,进入项目的Gem5目录,之下如下命令编译出gem5.opt
bash
scons build/X86/gem5.opt -j <your cores + 1>
二、 获取资源
-
已经编译gem5.opt,当前位于 gem5 根目录,编译得到X86架构的
build/X86/gem5.opt
-
获取内核镜像
bashwget http://dist.gem5.org/dist/v22-0/kernels/x86/static/vmlinux-4.4.186
这里使用的是预编译过的 4.4.186 linux内核,当然也可以选择其他版本比如4.19.83
如果需要其他内核版本则需要自行编译Linux内核,请参考Linux 内核编译编译得到根目录下的vmlinux
-
获取磁盘镜像
磁盘镜像解压之后稍微有点大,大概25GB左右
bashwget http://dist.gem5.org/dist/v22-0/images/x86/ubuntu-18-04/parsec.img.gz gzip -d parsec.img.gz
三、开始全系统模拟
模拟的命令要手敲! 不要用 Makefile, 坑死我了......
创建目录
bash
mkdir full-system-image
mkdir full-system-image/disks
mkdir full-system-image/kernel
cp vmlinux-4.4.186 full-system-image/kernel
cp parsec.img full-system-image/disks
# 保存模拟结果
mkdir fs-result
这里的 disks
和 kernel
目录名不要修改
配置全局M5_PATH
bash
vim ~/.bashrc
添加full-system-image的路径,假定gem5目录保存在~下
bash
export M5_PATH=~/gem5/full-system-image
这一步可以每次都在终端里手动输入, 如果你确定路径不变的话建议直接写到 .bashrc 中,比较方便
bash
source ~/.bashrc
修改路径信息
在gem5根目录下
bash
vim configs/common/SysPaths.py
找到 paths=['dist/m5/system', 'n/poolfs/z/dist/m5/system']
将第二个路径修改为full-system-image目录
python
paths=['dist/m5/system', '~/gem5/full-system-image']
开始模拟
配置项设置模拟的kernel镜像地址和磁盘的地址。 下面这段是原始的,但不能用,最近的gem5 已经移除了configs/example/fs.py,需使用下面那段命令。
bash
此段错误
build/X86/gem5.opt -d fs-result configs/example/fs.py \
--disk=full-system-image/disks/parsec.img \
--kernel=full-system-image/kernel/vmlinux-4.4.186
bash
此段正确
build/X86/gem5.opt -d fs-result configs/deprecated/example/fs.py \
--disk=full-system-image/disks/parsec.img \
--kernel=full-system-image/kernel/vmlinux-4.4.186
这里的-d后面是全系统模拟结果的目录,默认是m5out, --disk和--kernel则分别是磁盘和内核的路径
此时开始模拟,终端会输出一些信息,我们新开一个终端然后登录端口等待. gem5 提供了登陆的工具, 我们只需简单的编译使用即可
bash
cd utils/term
make
sudo install -o root -m 555 m5term /usr/local/bin
最后一行的命令是将名为 "m5term" 的文件安装到 "/usr/local/bin" 目录中,并将文件的所有者(Owner)设置为 root 用户,权限(Permission)设置为 555, 这样我们就可以在全局使用 m5term 了
bash
m5term localhost 3456
除了 m5term 我们也可以使用一般 linux 发行版自带的 telnet, 他们的功能完全相同. 但是使用
telnet localhost 3456
的时候会出现输入重复显示一行的问题, 所以还是使用 m5term 比较好这里可以在 .bashrc 中设置一下比如 alias m5c='m5term localhost 3456' 方便后续使用
初次启动全系统模拟需要等待很长一段时间(大概30分钟),之后就会进入bash了,这里的交互操作响应是很缓慢的
在启动模拟的过程中可以看到 gem5 端和登陆端都有很多 log 信息, 其中不乏 warnning 和 error, 我们暂时忽略即可并无大碍
保存checkpoint
每次都重新模拟太慢了,我们可以保存checkpoint以便后续快速进入,也可以保存所做的修改
bash
m5 checkpoint
退出全系统
bash
m5 exit
如果只是退出telnet的话使用 ctrl + d 后输入quit即可.
使用checkpoint进入
依然是上面那个文件问题
bash
build/X86/gem5.opt -d fs-result configs/example/fs.py \
--disk=full-system-image/disks/parsec.img \
--kernel=full-system-image/kernel/vmlinux-4.4.186 \
--checkpoint-dir=fs-result \
-r 1
bash
build/X86/gem5.opt -d fs-result configs/deprecated/example/fs.py \
--disk=full-system-image/disks/parsec.img \
--kernel=full-system-image/kernel/vmlinux-4.4.186 \
--checkpoint-dir=fs-result \
-r 1
这里的--checkpoint-dir
为checkpoint保存的路径, -r
参数用于指定哪个checkpoint,1即为第一个checkpoint,当指定的目录中有多个checkpoint时,多个checkpoint的排序是按照系统创建checkpoint的ticks进行排序的
也就是说, 如果依次使用
m5 checkpoint
保存了三次, 那么想要使用最后一次的进入模拟应该使用-r 3
进入系统后执行
如果您使用默认配置进入全系统模拟之后打算执行一些测试程序, 我们并不需要一直坐在电脑前等待直到进入进入命令行交互, gem5提供了 --script
参数用于指定进入后执行的 shell 脚本, 您可以编写一个shell脚本完成你的测试, 然后只需要在启动模拟的命令行中加入该参数并指定所用脚本即可, 如下所示
bash
build/X86/gem5.opt -d fs-result configs/example/fs.py \
--disk=full-system-image/disks/parsec.img \
--kernel=full-system-image/kernel/vmlinux-4.4.186 \
--script=configs/boot/hack_back_ckpt.rcS
修改磁盘镜像
在fs中操作是很慢的, 所以通常需要在磁盘中配置环境或者预先编译一些代码.这里可以使用挂载的方式修改磁盘文件
我们这里使用之前下载的 full-system-image/disks/parsec.img
磁盘镜像
bash
cd full-system-image/disks
# 在disks目录下创建一个挂载镜像文件的目录
mkdir local_mnt
sudo mount -o loop,offset=$((2048*512)) parsec.img local_mnt
sudo mount -o bind /proc local_mnt/proc
sudo mount -o bind /dev local_mnt/dev
sudo mount -o bind /dev/pts local_mnt/dev/pts
sudo mount -o bind /sys local_mnt/sys
# 进入磁盘映像
cd local_mnt
sudo chroot ./
这里简单解释一下挂载, 挂载是将一个文件系统连接到另一个文件系统上的过程,使得被连接的文件系统能够通过目录结构来访问。在Linux系统中,挂载是通过VFS(虚拟文件系统)层实现的。VFS是一个抽象层,它将不同的文件系统类型封装在一起,使得它们可以被以相同的方式来访问。
当我们执行挂载命令时,操作系统会为文件系统映像文件分配一个设备号,并将该文件系统与一个目录进行关联,使得该目录成为文件系统的根目录。此时,我们可以通过该目录来访问文件系统中的文件和目录。实际上,VFS会将目录和文件名翻译成文件系统特定的I/O操作,并将其发送到相应的文件系统驱动程序中。
-o loop
指使用循环设备(loop device)来挂载文件系统,这允许将文件作为块设备处理。offset=$((2048*512))
指设置文件系统映像文件的偏移量(offset),这样操作系统就能够在正确的位置找到文件系统。在这个命令中,偏移量被设置为2048*512,这意味着文件系统从文件的第2048个块开始,并且每个块的大小为512字节
挂载完成之后我们就可以进入 local_mnt 中对磁盘进行操作了,比如这里我们在 /home 下创建一个文件
bash
echo "hello world" > /home/test.txt
修改结束后取消挂载即可
bash
cd ..
sudo umount local_mnt/proc
sudo umount local_mnt/dev/pts
sudo umount local_mnt/dev
sudo umount local_mnt/sys
sudo umount local_mnt
如果卸载时出现 umount: /mnt: target is busy.
之类的报错, 说明卸载磁盘正在使用,导致无法直接卸载。需要将当前使用数据盘的进程杀掉,才能卸载. 通常来说是你的 bash进程 没有退出这个 local_mnt 文件夹
bash
# 查看正在使用磁盘的进程
fuser -mv local_mnt
# 杀死正在使用磁盘的进程
fuser -kv local_mnt
此时parsec.img
就已经被修改了,我们再次启动全系统模拟就可以看到磁盘上的修改了
其他注意事项
首先需要明确的是 gem5 fs模拟需要两部分核心内容: kernel 和 disk, checkpoint 仅作一次当前模拟器中计算机运行状态的保存, 如果您在保存 checkpoint 之后修改了 kernel 或者 disk 那么再次使用这个 checkpoint 进入会存在很大的问题, 需要重新启动模拟
这里进入全系统时我们使用的是默认的 CPU 类型(AtomicSimpleCPU), 后续如果您尝试使用不同类型的 CPU, DRAM 等等您可能发现直接使用诸如X86TimingSimpleCPU启动fs慢的离谱(这是真的,我大概用了6个小时 ), 这是因为 fs 启动会走一遍 linux 启动的流程, 检查各项配置, 您的 CPU 模型或者其他因素可能会大大影响启动进入模拟的时间. 但通常来说我们并不关心如何启动, 而是关心启动之后运行时的效果. 这时候有一个比较聪明的做法是先使用默认的模式启动, 例如
bash
build/X86/gem5.opt -d fs-result configs/example/fs.py \
--disk=full-system-image/disks/parsec.img \
--kernel=full-system-image/kernel/vmlinux-5.4.49-cxl \
--mem-size=1GB
进入系统后保存 checkpoint 后退出, 接着在使用 checkpoint 恢复的时候修改参数 , 例如这里使用了 --cpu-type=X86TimingSimpleCPU --restore-with-cpu=X86TimingSimpleCPU
以 X86TimingSimpleCPU 的模式启动 CPU, 并修改 DRAM 类型为 NVM_2400_1x64
bash
build/X86/gem5.opt -d fs-result configs/example/fs.py \
--disk=full-system-image/disks/parsec.img --kernel=full-system-image/kernel/vmlinux-5.4.49-cxl \
--checkpoint-dir=fs-result \
-r 1 \
--mem-type=NVM_2400_1x64 \
--cpu-type=X86TimingSimpleCPU --restore-with-cpu=X86TimingSimpleCPU \
--mem-size=1GB
您可以使用下面的选项查看所有 fs 提供的选项
bash
./build/X86/gem5.opt configs/example/fs.py --help
注意有一些因素(例如mem-size)影响了 checkpoint 的内容, 所以您不能在使用 checkpoint 恢复时修改 mem-size, 此选项需要和启动时相同
相关参数
- -n NUM_CPUS: CPU的数量,默认为1
- --sys-voltage SYS_VOLTAGE: 系统电压,默认为1V
- --sys-clock SYS_CLOCK: 系统时钟频率,默认为2GHz
- --list-mem-types: 列出可用的内存类型
- --mem-type: 内存类型,默认为DDR3_1600_8x8
- --mem-channels MEM_CHANNELS: 内存通道数,默认为2
- --mem-ranks MEM_RANKS: 内存等级数,默认为2
- --mem-size MEM_SIZE: 内存容量,默认为2GB
- --enable-dram-powerdown: 是否启用DRAM休眠
- --mem-channels-intlv MEM_CHANNELS_INTLV: 内存通道间隔,默认为256
- --memchecker: 是否启用内存检查器
- --external-memory-system EXTERNAL_MEMORY_SYSTEM: 使用外部内存系统
- --tlm-memory TLM_MEMORY: 使用TLM内存模型
- --caches: 是否启用缓存
- --l2cache: 是否启用L2缓存
- --num-dirs NUM_DIRS: 目录数,默认为1
- --num-l2caches NUM_L2CACHES: L2缓存数量,默认为1
- --num-l3caches NUM_L3CACHES: L3缓存数量,默认为0
- --l1d_size L1D_SIZE: L1数据缓存大小,默认为64kB
- --l1i_size L1I_SIZE: L1指令缓存大小,默认为64kB
- --l2_size L2_SIZE: L2缓存大小,默认为2MB
- --l3_size L3_SIZE: L3缓存大小,默认为16MB
- --l1d_assoc L1D_ASSOC: L1数据缓存关联度,默认为2
- --l1i_assoc L1I_ASSOC: L1指令缓存关联度,默认为2
- --l2_assoc L2_ASSOC: L2缓存关联度,默认为8
- --l3_assoc L3_ASSOC: L3缓存关联度,默认为16
- --cacheline_size CACHELINE_SIZE: 缓存行大小,默认为64字节
- --ruby: 是否使用Ruby内存子系统
- -m TICKS: 执行的总时钟数,默认为0
- --rel-max-tick TICKS: 相对最大时钟数,默认为0
- --maxtime MAXTIME: 执行的最长时间,默认为0
- -P PARAM: gem5参数文件
- --list-cpu-types: 列出可用的CPU类型
- --cpu-type: CPU类型,默认为TimingSimpleCPU
- --list-bp-types: 列出可用的分支预测类型
- --list-indirect-bp-types: 列出可用的间接分支预测类型
- --ruby:启用Ruby内存层次结构模拟器。
- -m/--num-cpus:模拟的CPU数量。
- --rel-max-tick/--maxtick:当达到相对或绝对最大时钟周期时停止仿真。
- --maxtime:以毫秒为单位的仿真最大时长。
- -P/--param:设置指定组件的参数。例如,"-P system.cpu_cluster.l1.strg_size = 32768"将L1数据缓存的大小设置为32KB。
- --list-cpu-types:列出可用的CPU类型。
- --cpu-type:选择要使用的CPU类型。
- --list-bp-types:列出可用的分支预测器类型。
- --list-indirect-bp-types:列出可用的间接分支预测器类型。
- --bp-type/--indirect-bp-type:选择要使用的分支预测器类型/间接分支预测器类型。
- --list-rp-types:列出可用的重定向策略类型。
- --list-hwp-types:列出可用的硬件预取类型。
- --l1i-hwp-type/--l1d-hwp-type/--l2-hwp-type:选择要使用的L1指令/数据缓存或L2缓存的硬件预取类型。
- --checker:启用组件之间的一致性检查器。
- --cpu-clock:CPU时钟频率,以GHz为单位。
- --smt:启用超线程。
- --elastic-trace-en:启用弹性跟踪。此标志用于记录与其他仿真节点通信的指令流。
- --inst-trace-file/--data-trace-file:指定指令/数据跟踪文件名。
- --dist/--dist-sync-on-pseudo-op/--is-switch/--dist-rank/--dist-size/--dist-server-name/--dist-server-port/- --dist-sync-repeat/--dist-sync-start:这些标志用于在分布式仿真环境中使用,其中多个仿真进程在不同的计算机上运行。