本文介绍的系统基本配置为:
- X86
- PROTOCOL=MESI_Three_Level
- --ruby
- --network=garnet
- --topology=Mesh_XY
(一些碎碎念)
一开始受到官网对checkpoint介绍的误导(gem5: Checkpoints),如下:
加上确实本人尝试了建立MESI_Three_Level的gem5.opt,然后配置--ruby和--network=garnet在全系统模式下使用m5 checkpoint命令时,系统会异常退出,我就以为确实在以上的配置下不支持checkpoint,导致我在做实验的初期,对每一种配置的系统都需要重新创建操作系统,花费大量的时间(几个小时不等),而且直接对复杂的系统创建操作系统也会增加运行时间,实验效率极低。后面终于弄懂了checkpoint的正确使用方法,可以用于以上配置系统。
1. 编译gem5.opt
scons build/X86/gem5.opt -j$(nproc) PROTOCOL=MESI_Three_Level
在编译时需要指定系统配置的缓存一致性协议。
2. 全系统模式的环境准备(内核文件、镜像文件、测试程序)
gem5运行全系统模式需要指定模拟的操作系统的内核文件(--kernel)和镜像文件(--disk),均可在gem5 resources(gem5: gem5-resources)中获取。下载gem5-resources(建议下载stable版本的)后,解压缩得到:
文件README.md重点详细介绍了每种资源的使用方法,文件resources.json中有完整的资源下载路径,均可以根据需要找到对应资源的下载路径,利用提供的链接下载即可。
例如,本人的实验对象是X86指令集系统,在resources.json文件中找到相关的资源,如下(截图仅为部分):
- 内核
- 镜像
根据需要选择下载即可,本人选择的内核是x86-linux-kernel-5.4.49,镜像是x86-npb,下载后分别保存在路径gem5/fs_image_and_kernel/binaries和gem5/fs_image_and_kernel/disks中,并设置环境变量M5_PATH
export M5_PATH=gem5绝对路径/fs_image_and_kernel
p.s.一个大坑是镜像文件x86-ubuntu-18.04-img被设计为开机自动执行脚本文件,运行完后自动执行“m5 exit”退出(若没有指定运行脚步文件,则直接退出)。因此,若使用该镜像文件,需要首先编写脚本文件内容,并在运行gem5.opt时设定执行的脚本文件(--script=脚本文件所在路径)。例如,在gem5文件夹内新建一个readfile文件,内容如下:
然后在运行gem5.opt,指定--script=./readfile
./build/X86/gem5.opt \
configs/example/fs.py \
--ruby \
--network=garnet \
--kernel=x86-linux-kernel-5.4.49 \
--disk=x86-ubuntu.img \
--script=./readfile
运行结果会显示
- 测试程序
由于gem5全系统模式是启动操作系统,在操作系统中执行命令来仿真测试,因此如果要运行特定的测试程序,需要提前将测试程序放入操作系统的镜像文件中。
另外,(这也是本人做了无数次无效实验发现的坑)我们知道在仿真结束后gem5会生成stats.txt文件保存统计结果,其中包括了模拟时间这一统计指标(simSeconds),在全系统模式下,在操作系统中执行了一系列命令后,利用m5 exit退出后,将得到一个stats.txt,这个结果文件统计的是仿真整个过程的模拟时间和整个仿真过程的数据。那如果我们只想知道该系统运行一次测试程序的统计数据的话,就需要对测试程序利用m5进行特殊的编程和编译。参考gem5: M5ops,过程如下(以简单的打印“hello world!”测试程序为例):
(1)要在应用程序中使用m5提供的指令,首先需要生成m5以及对应的libm5.a库,在util/m5目录下,运行如下命令:
scons build/X86/out/m5
p.s. X86是本人的实验对象,可以根据需要换成其他指令集
(2)利用c++编写测试程序
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("Hello world!\n");
return 0;
}
(3)添加m5代码
#include <stdio.h>
#include "gem5/m5ops.h" //引入m5ops.h库
int main(int argc, char* argv[])
{
m5_reset_stats(0,0); //重置模拟统计数据
printf("Hello world!\n");
m5_dump_stats(0,0); //将模拟统计数据保存
return 0;
}
主要就是用到m5_reset_stats()和m5_dump_stats()两个函数,可以统计这两个函数之间的模拟数据。m5还提供了一些其他的函数,可以参考官网教程gem5: M5ops
(4)m5编译,添加gem5/include和gem5/util/m5/build/X86/out链接路径
g++ -o ../bin/x86/linux/hello_m5 hello_m5.cpp -std=c++11 \
—Igem5绝对路径/include \
-Lgem5绝对路径/util/m5/build/X86/out -lm5
得到可执行文件hello_m5,作为测试程序
将测试程序放入操作系统镜像文件的操作步骤如下:
(1)在gem5/fs_image_and_kernel/disks文件夹下新建mnt目录并挂载到npb.img
sudo mount -o loop,offset=1048576 ./npb.img ./mnt
此时利用dir /mnt可以查看npb.img文件系统
(2)放入测试可执行程序hello_m5
sudo cp hello_m5路径 ./mnt
利用dir ./mnt可查看移动后的npb.img文件系统,可以看到在根目录下包含hello_m5
(3)断开挂载
sudo umount ./mnt
这样之后利用gem5启动该镜像文件后可运行hello_m5(在根目录下)
p.s.需要注意的是,上述操作后只有重新启动操作系统才能生效,使用checkpoint启动无法发现新文件,因此建议在一开始最好将所有需要用到的测试程序放入镜像文件中。
3. 运行全系统模式,创建checkpoint
完成上述准备工作后,可以开始运行仿真了。如果直接使用全系统模拟完整的系统配置,由于涉及的系统组件非常多,每个系统组件都需要创建并加载系统文件,从而导致模拟速度非常慢。启动一个大型模拟系统通常需要很长的时间。因此,为了降低启动系统的时间开销,gem5中可以使用checkpoint功能。该功能可以简单理解为给系统生成了一个快照,下次重新启动的时候就可以直接进入上次系统退出的状态,从而避免了重新启动系统。
另外,为了尽可能减少系统启动所花时间,我们最好只指定所模拟系统的大小,即指定模拟系统的CPU核数量和内存大小,其他配置不用设置,按照所提供的默认值即可,在后续使用的时候再重新配置相关系统参数即可。
./build/X86/gem5.opt \
-d checkpoint/16core \
configs/example/fs.py \
--num-cpus=16 \
--kernel=x86-linux-kernel-5.4.49 \
--disk=npb.img \
--mem-size=4GB
p.s. -d用于指定结果保存的路径,会保存统计结果和checkpoint的cpt文件。需要注意的是,该参数配置只能紧跟在gem5.opt的后面,不然无法定向到指定的路径。
上述命令启动后,终端上显示
这时在路径gem5/util/term下启动一个新的终端(如果之前没有打开过,则先make,再进行下面的操作),与上述终端中显示的端口号相连
m5term localhost 3457
可以发现两个终端相连,开始启动操作系统
这里需要较长时间的等待。当成功启动操作系统后,可以在gem5/util/term终端开始对系统进行操作,此时输入命令m5 checkpoint,系统将在-d指定的输出路径下保存checkpoint的恢复信息。然后输入m5 exit将退出系统。
4. 使用checkpoint,对完整配置系统进行仿真
./build/X86/gem5.opt \
-d checkpoint/16core \
configs/example/fs.py \
--num-cpus=16 \
--kernel=x86-linux-kernel-5.4.49 \
--disk=npb.img \
-r 1 \
--checkpoint-dir=checkpoint/16core \
--restore-with-cpu=X86O3CPU \
--cpu-type=X86O3CPU \
--ruby \
--network=garnet \
--topology=Mesh_XY \
--mesh-rows=4 \
--l0d_size=32kB --l0i_size=32kB --l0d_assoc=8 --l0i_assoc=8 \
--l1d_size=512kB --l1d_assoc=8 \
--num-l2caches=16 --l2_size=16MB \
--num-dirs=16 \
--mem-size=4GB \
--mem-type=DDR4_2400_4x16
参数说明:
-r用于指定使用的checkpoint的序号,一般一个路径下仅有1个checkpoint,所以一般指定为1
--checkpoint-dir用于指定使用的checkpoint的cpt文件夹所在路径
--restore-with-cpu用于指定恢复时CPU的类型
--cpu-type用于指定CPU类型(一般在创建checkpoint时使用默认的AtomicSimpleCPU,在重新启动checkpoint时为了模拟时间更加准确,使用O3CPU)
--topology用于指定系统的拓扑(需要特别注意的是,使用拓扑Mesh_XY一定要指定和cpu数量相等或成倍的l1、l2、l3和dir数量,不然无法成功启动系统。例如:16核的系统,可以指定l3 cache和dir数量均为16)
--mesh-rows用于指定Mesh拓扑的行数(当使用Mesh拓扑时,一定要指定该参数)
同样,输入上述命令后,终端将等待m5的接入,需要在gem5/util/term路径下新建终端与端口建立连接。此时,系统将快速启动。
此时,可以对测试系统进行仿真测试。
执行完一次测试程序后,将在stats.txt中添加一次仿真统计信息,内容在“---------- Begin Simulation Statistics ----------”和“---------- End Simulation Statistics ----------”之间。
执行多次测试程序将在stats.txt文件中得到多个统计信息,直接可搜索Begin Simulation Statistics可定位到不同统计信息。
完成所有测试后,输入命令m5 exit系统退出,同时会在stats.txt文件最后再添加一个完整仿真过程的统计信息。
参考链接: