目录
3.14更新
对gem5: Memory system进行学习后才知道,Atomic访问和Timing访问不能在一个存储系统中共存,因此在下面介绍的两种CPU切换配置中,两种CPU不能分别是Atomic类型和Timing类型。
(本文记录对官网教程gem5: X86 Full-System Tutorial的理解和实践)
关键点
- 利用gem5中的标准库(standard library)建立了一个双核X86处理器,可以进行全系统模拟(操作Ubuntu操作系统,并运行测试程序)
- 该系统可以利用gem5对切换核心的仿真能力(利用一个快速CPU进行操作系统的初始化,然后切换到一个更具体的CPU上进行仿真)
- 有助于快速理解gem5全系统建立和仿真过程(kernel、image、启动事件、仿真事件等)
- 有助于利用标准库编写系统配置文件
环境
- ubuntu 18.04
- gem5 22.0.0.2
脚本文件详解
(源码对应configs/example/gem5_library/x86-ubuntu-run-with-kvm.py,与官方教程略有偏差,但没有关键影响。以下介绍截取源码。)
0. 导入声明
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.resources.resource import Resource
from gem5.simulate.simulator import Simulator
from gem5.simulate.exit_event import ExitEvent
from gem5.components.cachehierarchies.ruby.\
mesi_two_level_cache_hierarchy import (
MESITwoLevelCacheHierarchy,
)
1. requires模块
requires(
isa_required=ISA.X86,
coherence_protocol_required=CoherenceProtocol.MESI_TWO_LEVEL,
# kvm_required=True,
kvm_required=False,
)
require函数的功能是用于检查gem5模拟器(.opt)是否与想要建立的处理器相匹配:
- ISA
- 缓存一致性协议
- KVM
KVM说明
官方教程中需要用到kvm,用于初始化的CPU是基于kvm的,要求主机支持KVM。但我在实际运行时发现我的主机不支持KVM,运行后错误如下:
尝试配置KVM发现不是很简单,然后了解gem5中的基于KVM的CPU功能为:
gem5支持基于KVM的CPU模型,当主机ISA与gem5中运行的应用程序相同,它能绕过模拟并使用底层主机的处理器来运行gem5中运行的二进制文件,此时gem5上程序的运行速度和在主机上几乎相同。这主要可用于采样模拟以及快速前进到感兴趣区域和检查点位置。
即该模型用于加快仿真速度,应该不是必备选项,因此用户可根据实际情况选择性配置。
因此我为了避免不必要的问题,选择不使用KVM,在该require函数中将kvm_required参数设置为False,然后在后续设置CPU类型时进行相应的修改。
2. 处理器配置
(1)cache
# 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,
)
(2)memory
# Setup the system memory.
memory = SingleChannelDDR3_1600(size="3GB")
SingleChannelDDR3_1600模块的默认内存大小为8GiB,但我们所使用的X86Board模块的内存大小最大为3GiB,因此需要在这里设定内存大小参数。
(3)processor
processor = SimpleSwitchableProcessor(
# starting_core_type=CPUTypes.KVM,
starting_core_type=CPUTypes.TIMING,
switch_core_type=CPUTypes.TIMING,
isa=ISA.X86,
num_cores=2,
)
在这里使用了gem5标准库中的SimpleSwitchableProcessor类,用于在仿真过程中进行两种类型CPU之间的切换(starting_core_type->switch_core_type) 。官方教程中初始化CPU是基于KVM的CPU,而由于我没有配置KVM,因此在这里将其改为TIMING类型。
注意:在官方教程中提出若不支持KVM,则可以将CPU类型修改为ATOMIC。但我尝试之后发现无法运行,出现以下错误:
怀疑是ATOMIC不能用于包含Cache的处理器中(真正原因是Atomic类型和Timing类型不能共存),因此将CPU类型修改为TIMING,可正常运行。
(4)board
board = X86Board(
clk_freq="3GHz",
processor=processor,
memory=memory,
cache_hierarchy=cache_hierarchy,
)
3. 工作负载配置
gem5的全系统模式会启动完整的Linux操作系统,需要配置内核(kernel)和磁盘镜像(disk_image),同时,可选择性配置运行指令列表(readfile_contents),文件内容是启动操作系统后在由于仿真的指令序列。
command = "m5 exit;" \
+ "echo 'This is running on Timing CPU cores.';" \
+ "sleep 1;" \
+ "m5 exit;"
board.set_kernel_disk_workload(
# The x86 linux kernel will be automatically downloaded to the if not
# already present.
kernel=Resource("x86-linux-kernel-5.4.49"),
# The x86 ubuntu image will be automatically downloaded to the if not
# already present.
disk_image=Resource("x86-ubuntu-18.04-img"),
readfile_contents=command,
)
(1)kernel & disk_image
官方教程中使用的kernel和disk_image直接来自于gem5资源库(resource repository),直接利用Resource类(应该是直接下载到本地)。用户也可以使用自定义的kernel和disk_image。
问题:这个kernel和disk_image除了指定操作系统以外,还有什么影响吗?会影响到仿真处理器的配置上限吗?如果与处理器配置无关的话,那为什么还需要自定义 呢?
注意:这里选用的磁盘镜像文件是x86-ubuntu18.04-img,它被设计为启动操作系统、自动登陆并执行m5 readfile。m5 readfile内容通过readfile_contents指定,因此若所用该镜像文件,需指定参数readfile_contents,不然在成功进入操作系统后将直接退出,不能通过终端执行指令。(这也就是为什么运行脚本文件x86-ubuntu-run.py时,使用终端接入该操作系统后会直接退出。下图展示该过程。)
(2)指令序列文件
文件内容为command的值,传给readfile_contents参数,最终将存储在文件gem5/m5out/readfile中。
4. simulator配置
simulator = Simulator(
board=board,
on_exit_event={
ExitEvent.EXIT : (func() for func in [processor.switch]),
},
)
参数on_exit_event用于指定指令m5 exit执行后触发的事件,默认为退出操作系统。这里表示第一个m5 exit指令执行将触发processor.switch函数,即进行CPU的切换,第二个m5 exit指令使操作系统正常退出。
运行过程
1. 执行配置脚本
打开终端,在gem5/目录下执行:
./build/X86/gem5.opt configs/example/gem5_library/x86-ubuntu-run-with-kvm.py
等待一段时间后终端界面保持不变(进入等待接入状态)
2. 使用m5term远程连接
新建一个终端,进入目录gem5/util/term下,执行指令:
m5term localhost 3456
将启动m5终端,并接入之前运行的gem5配置系统。
等待指令文件中全部指令执行完成后结束仿真。
注意:如果是首次所用m5term,需要先在目录gem5/util/term下执行make。
3. 结果
最终的结果保存在gem5/m5out文件夹中:
- board_pc_com_1.device:终端输出(官方教程有误)
- stats.txt:仿真结果数据
- config.ini, config.json:模拟处理器的配置
总结
想要完成一个自定义处理器的全系统仿真,可依照以上配置文件编写流程和执行流程照猫画虎。难点在于配置和实现不同的处理器架构:
- gem5标准库的利用和扩展。这个教程中使用了一个SimpleSwitchableProcessor类,实例化了一个双核处理器。可以对gem5标准库进行更深入的了解,看是否存在可直接利用的类,若没有,则需要学习如何编写实现满足自身需求的类。
- 还需要对各种组件的具体实现进行深入学习,例如:X86Board中的processor、memory、cache等是如何连接,如何在其中添加新的组件等。
参考链接: