一、背景
本文基于两个教程进行全系统仿真实验,同时学习了其他帖子进行总结。
- 官方教程Building an x86 full-system simulation with the gem5 standard library;
- Sakura懋同学的教程《gem5学习——建立X86全系统仿真》;
- 最后输出结果分析学习按照好啊啊啊啊同学的《Gem5模拟器,详解官网教程的statistics and output(三)》教程。
二、环境
我是带有GPU的服务器中的docker中运行。
- ubuntu 18.04
- gem5 22.0.0.2
三、脚本分析
没有按照官方教程分析x86-ubuntu-run.py,按照《gem5学习——建立X86全系统仿真》分析gem5/configs/example/gem5_library/x86-ubuntu-run-with-kvm.py(x86-ubuntu-run.py后期还有用)。
1.在实验之前,必须构建一个ISA为x86的二进制可执行文件。
scons build/X86/gem5.opt -5
2.导入gem5标准库中的一些模块和组件类
这些导入语句是为了在gem5模拟过程中使用gem5标准库的各种组件和功能。根据具体的模拟需求,可以使用这些组件和功能来构建和配置gem5模拟系统。
from gem5.utils.requires import requires
from gem5.components.boards.x86_board import X86Board
from gem5.components.memory.single_channel import SingleChannelDDR3_1600
from gem5.components.processors.simple_switchable_processor import (
SimpleSwitchableProcessor,
)
from gem5.components.processors.cpu_types import CPUTypes
from gem5.isas import ISA
from gem5.coherence_protocol import CoherenceProtocol
from gem5.simulate.simulator import Simulator
from gem5.simulate.exit_event import ExitEvent
from gem5.resources.workload import Workload
3.调用requires
函数
requires
函数用于在gem5配置中声明和检查依赖项。通过调用requires函数并传递这些参数,gem5可以根据配置要求来检查所需的依赖项是否满足。如果依赖项不满足,gem5将产生错误或警告,以确保所需的配置和环境可用。
requires(
isa_required=ISA.X86,
coherence_protocol_required=CoherenceProtocol.MESI_TWO_LEVEL,
kvm_required=True,
其中我的kvm_required=True表示在过程中使用KVM加速(硬件虚拟化)gem5模拟器加速模拟过程。但是这个是可选的,如果不支持的话可以将这个选项设置为False。(后面与我遇到的一个问题有关)
4.指定系统组件配置
(1)缓存层次结构
from gem5.components.cachehierarchies.ruby.mesi_two_level_cache_hierarchy import (
MESITwoLevelCacheHierarchy,
)
# Here we setup a MESI Two Level Cache Hierarchy.
cache_hierarchy = MESITwoLevelCacheHierarchy(
l1d_size="16kB",
l1d_assoc=8,
l1i_size="16kB",
l1i_assoc=8,
l2_size="256kB",
l2_assoc=16,
num_l2_banks=1,
)
设置了 MESI 二级 (ruby) 缓存层次结构。通过构造函数,将 L1 数据缓存和 L1 指令缓存设置为 32 kB,将 L2 缓存设置为 256 kB。
(2)内存系统
# Setup the system memory.
memory = SingleChannelDDR3_1600(size="3GB")
大小为 3GiB 的单通道 DDR3 1600 设置。
注意:默认情况下,SingleChannelDDR3_1600 组件的大小为 8GiB。然而,由于 X86Board 的已知限制,无法使用大于 3GiB 的内存系统,因此必须设置尺寸。
(3)处理器
processor = SimpleSwitchableProcessor(
starting_core_type=CPUTypes.KVM,
switch_core_type=CPUTypes.TIMING,
isa=ISA.X86,
num_cores=2,
)
这里使用 gem5 标准库的特殊 SimpleSwitchableProcessor。该处理器可用于用户想要在仿真期间将一种类型的核心切换为另一种类型的仿真。
starting_core_type 参数指定启动模拟的 CPU 类型。在本例中为 KVM 核心。 (注意:如果主机系统不支持 KVM,则该模拟将无法运行。您必须将其更改为其他 CPU 类型,例如 CPUTypes.ATOMIC) switch_core_type 参数指定在模拟中切换到哪种 CPU 类型。在这种情况下,我们将从 KVM 核心切换到 TIMING 核心。
最后一个参数 num_cores 指定处理器内的核心数量。
使用此处理器,用户可以调用processor.switch() 在启动核心和切换核心之间进行切换。
(4)board
# Here we setup the board. The X86Board allows for Full-System X86 simulations.
board = X86Board(
clk_freq="3GHz",
processor=processor,
memory=memory,
cache_hierarchy=cache_hierarchy,
)
这里使用 X86Board。该板用于在全系统模式下模拟典型的 X86 系统。
注意:在board配置中,至少需要指定 clk_freq、处理器、内存和 cache_hierarchy 四个参数。
5.系统工作负载配置
command = (
"m5 exit;"
+ "echo 'This is running on Timing CPU cores.';"
+ "sleep 1;"
+ "m5 exit;"
)
workload = Workload("x86-ubuntu-18.04-boot")
workload.set_parameter("readfile_contents", command)
board.set_workload(workload)
对上述代码进行分析:
(1)定义command字符串,包含了一系列命令:
- m5 exit;:执行m5 exit命令,暂时退出模拟。
- echo 'This is running on Timing CPU cores.';:输出"This is running on Timing CPU cores."。
- sleep 1;:等待1秒。
- m5 exit;:再次执行m5 exit命令,完全退出模拟。
(2)创建了一个名为workload
的Workload
对象,参数为"x86-ubuntu-18.04-boot"。这表示使用"x86-ubuntu-18.04-boot"作为工作负载。
(3)使用set_parameter方法,将command作为参数设置到workload中的readfile_contents参数中。这意味着在系统启动时,command中的命令将被执行。
(4)使用board对象的set_workload方法,将workload设置为board的工作负载。
6.仿真器配置
simulator = Simulator(
board=board,
on_exit_event={
# Here we want override the default behavior for the first m5 exit
# exit event. Instead of exiting the simulator, we just want to
# switch the processor. The 2nd m5 exit after will revert to using
# default behavior where the simulator run will exit.
ExitEvent.EXIT: (func() for func in [processor.switch])
},
)
simulator.run()
该代码段配置了一个模拟器,并定义了一个自定义的退出事件处理函数。在模拟器运行期间,当遇到m5 exit
命令时,第一个m5 exit
将触发处理器切换,而不是退出模拟器,而第二个m5 exit
将导致模拟器运行结束。
四、运行过程
1.在gem/的根目录下执行配置脚本
./build/X86/gem5.opt configs/example/gem5_library/x86-ubuntu-run-with-kvm.py
提示报错:Exception: [configs/example/gem5_library/x86-ubuntu-run.py] KVM is required but is unavailable on this system。
该问题在其他帖子中有详解,这里就不再详细说明了。
运行一段时间后提示停留在这个界面:
表示:(1)模拟器的board
对象正在监听端口3456,等待远程连接;(2)模拟器还在另一个端口7000上监听远程GDB连接。
一旦成功建立远程连接,您可以使用相应的工具(如Telnet、SSH或GDB)连接到模拟器,以便进行交互、调试或其他操作。
2.打开新的终端,使用m5term远程连接
在/gem5/util/term的目录下执行以下命令:
m5term localhost 3456
该指令意味着通过m5term工具连接到正在本地主机上运行的gem5模拟器,并使用端口3456进行通信。
(在我运行的过程中,出现了报错。在另一个帖子中会详细介绍)
上述报错意味着系统无法找到名为 m5term
的命令。
解决了上述问题继续执行,此时表示已经启动了m5终端,并接入之前运行的gem5配置系统。
程序会持续执行,大概时间为1h+(因为晚上等了半个多小时没结束,就提前回去了)
执行结果表示m5term成功连接到gem5仿真器,并执行了一个名为 /tmp/script 的脚本文件。
从上述执行信息来看,gem5 模拟器成功启动并读取了脚本文件,并在脚本执行完成后退出。这表明 m5term 与 gem5 模拟器之间的连接正常,并且脚本的执行也成功完成。
但在Sakura懋同学的教程中说“如果是首次所用m5term,需要先在目录gem5/util/term下执行make”,我直接使用的github中gem5源码,没有报错。留个坑,后期熟悉了后再说。
五、结果
运行完成后,就会将输出结果保存在gem5/m5out文件夹中。此时就需要用到好啊啊啊啊同学的《Gem5模拟器,详解官网教程的statistics and output(三)》教程。
1.查看结果
此时查看m5out文件夹:
- board_pc_com_1.device:该文件保存了通过board.pc.com_1.device监听的端口的通信记录。这通常用于与模拟器进行远程通信的情况下,记录与外部实体的交互信息
- stats.txt:该文件保存了gem5模拟器的统计信息。这些统计信息包括模拟器运行期间的各种指标、事件和资源使用情况。例如,模拟器的指令执行次数、缓存命中率、内存访问次数等。
- config.ini:该文件保存了gem5模拟器运行时使用的配置信息。它记录了在运行模拟器时设置的各种参数和选项,包括模拟器配置、系统配置、CPU配置等。
- config.json:该文件也保存了gem5模拟器的配置信息,但以JSON格式进行存储。它提供了与config.ini相同的配置信息,但以不同的格式呈现。
2.通过stats.txt查看统计信息
在m5out文件夹中执行以下命令:
vim stats.txt
提示如下(实际过长,不再一一展示):
(1)查看某个统计信息
我们可以直接在命令模式下直接键入需要查询的字符(如需要查询findtext,则键入/findtext),N键查找下一个:
(2)使用脚本直接收集多个统计信息
这部分在pengGG0229同学的《Gem5 Garnet互连网络环境安装与程序测试》的第三部分末有详细说明。
其运行过程主要如下:
① 在gem5的根目录下执行以下命令
echo > network_stats.txt
grep "packets_injected::total" m5out/stats.txt | sed 's/system.ruby.network.packets_injected::total\s*/packets_injected = /' >> network_stats.txt
- echo是将一个空的字符串通过重定向操作符>写入到名为network_stats.txt的文件中。如果该文件不存在,则会在当前目录中创建一个新的空文件。这个指令实际上是清空或创建一个空的network_stats.txt文件。
- 指令是将m5out/stats.txt文件中包含字符串"packets_injected::total"的行进行筛选,并将结果通过管道传递给sed命令进行进一步处理。sed命令会将匹配行中的字符串"system.ruby.network.packets_injected::total"替换为"packets_injected = ",然后将结果追加到network_stats.txt文件中。
- grep命令可以多行,同时筛选多个统计信息。
② 简便方法,直接保存为脚本
将上述代码段保存到gem5根目录下为extract_network_stats.sh,每次运行完成后都需要重新执行该脚本,更新network_stats.txt中的统计信息。
六、总结
- 本文主要是对仿真流程记录,待后续需要时再回头反补。
- 由于是刚接触gem5仿真器,在写第一篇帖子时难免有些过于流水线记录,有部分介绍过于粗糙,没有解释清楚。待后续研究深入后再继续填坑吧!
- 也感谢几位同学的帖子,提供自己的仿真过程和心得。