【Gem5】入门准备和新手教程

Gem5入门

鉴于官网的一些东西已经过时,我觉得有必要专门写一个新的Gem5教程,这也是本文章的初衷!

1 编译Gem5

1.1 编译前准备

强烈建议在Ubuntu 16.04下安装编译(之前的ubuntu还需要你自己更新gcc版本),编译前通过apt管理器安装git build-essential scons python-dev swig libprotobuf-dev python-protobuf protobuf-compiler libgoogle-perftools-dev zlib1g-dev m4 mercurial这些包,关于每个包的介绍参考官网:http://www.m5sim.org/Dependencies

1.2 获取代码

下载gem5源代码文件,使用以下命令克隆:

hg clone http://repo.gem5.org/gem5

1.3 编译一个Gem5

对于每一个要模拟的ISA需要单独编译gem5。而且如果使用ruby,要为每个 cache coherence 协议单独编译。

使用scons命令来编译,在build_opts/X86中可以查看那些编译的选项,你可以自己修改,当然为了方便我们使用官方给的默认参数:

scons build/X86/gem5.opt -j4    #这里j4代表我的计算机有4个可用核心,调度更多核心能更快地编译

根据你的电脑性能,整个过程需要15~45分钟。

参考:gem5二进制类型区别

5 different binaries you can build for gem5: debug, opt, fast, prof, and perf.

这5种类型区别如下

  • debug

    Built with no optimizations and debug symbols. This binary is useful when using a debugger to debug if the variables you need to view are optimized out in the opt version of gem5. Running with debug is slow compared to the other binaries.

  • opt

    This binary is build with most optimizations on (e.g., -O3), but with debug symbols included. This binary is much faster than debug, but still contains enough debug information to be able to debug most problems.

  • fast

    Built with all optimizations on (including link-time optimizations on supported platforms) and with no debug symbols. Additionally, any asserts are removed, but panics and fatals are still included. fast is the highest performing binary, and is much smaller than opt. However, fast is only appropriate when you feel that it is unlikely your code has major bugs.

  • prof and perf

    These two binaries are build for profiling gem5. prof includes profiling information for the GNU profiler (gprof), and perf includes profiling information for the Google performance tools (gperftools).

2 创建一个简单的配置脚本

本节将模拟一个非常简单的系统,我们只有一个简单的CPU内核。该CPU内核将连接到系统内的内存总线。我们将有一个DDR3内存通道,也连接到内存总线。

2.1 Gem5配置脚本介绍

Gem5在运行前需要一个python脚本作为参数,在这个脚本文件里制定你自己的参数以按需仿真系统。

并且gem5中已经提供了许多示例配置脚本configs/examples。

本节从最简单的脚本文件开始,学习怎么构建一个配置脚本。

2.2 创建配置脚本

命令行里敲入如下命令,创建一个python文件,当然你也可以使用GUI的工具。

mkdir configs/tutorial
touch configs/tutorial/simple.py

使用编辑器打开该文件,首先需要导入m5库和编译的SimObjects:

import m5
from m5.objects import *

接下来创建第一个SimObject:我们要模拟的系统。该System对象将是我们模拟系统中所有其他对象的父对象。

system = System()

然后在这个system上设置时钟。首先设置一个时钟域,然后在这个是时钟域上设置频率,最后设置电压,不过我们不关心电压大小,用默认选项即可。

system.clk_domain = SrcClockDomain()
system.clk_domain.clock = '1GHz'
system.clk_domain.voltage_domain = VoltageDomain()

现在开始模拟内存,这里使用timing mode来模拟内存,大多数情况都要用timing,除非在fast-forwarding和 restoring from a checkpoint这两种情况。然后设置一下内存的大小。

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

接下来创建一个最简单的基于时序的CPU,然后创建一个系统范围的内存总线,现在有内存总线后把CPU的Cache端口连接到它。

system.cpu = TimingSimpleCPU()
system.membus = SystemXBar()
system.cpu.icache_port = system.membus.slave
system.cpu.dcache_port = system.membus.slave

下一步连接一些必要的端口,在CPU上创建一个I/O控制器并将它连接到内存总线。(只有X86需要3条中断端口线路,arm等其它isa不需要)

system.cpu.createInterruptController()
system.cpu.interrupts[0].pio = system.membus.master
system.cpu.interrupts[0].int_master = system.membus.slave
system.cpu.interrupts[0].int_slave = system.membus.master

system.system_port = system.membus.slave

创建一个内存控制器连接到这个membus,对于这个系统使用简单的DDR3即可。

system.mem_ctrl = DDR3_1600_8x8()
system.mem_ctrl.range = system.mem_ranges[0]
system.mem_ctrl.port = system.membus.master

至此,我们完成了一个没有cache的简单系统,整体结构如下:

【Gem5】入门准备和新手教程_第1张图片

完成系统后还需要给CPU加一些进程测试一下。我们准备使用SE Mode,这个模式下将CPU指向编译的可执行文件,这里以Hello World为例:创建一个process,设置相关的命令和参数,让CPU用这个process作为它的负载(workload),最后在CPU上创建一个功能执行的环境( functional execution contexts)

process = Process()
process.cmd = ['tests/test-progs/hello/bin/x86/linux/hello']
system.cpu.workload = process
system.cpu.createThreads()

最后一步就是实例化对象,创建root类,实例化每个SimObject,这个过程将创建对应的C++程序。

root = Root(full_system = False, system = system)
m5.instantiate()

启动这个实例并且在完成后检查系统状态

print ('Beginning simulation!')
exit_event = m5.simulate()

print ('Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause()))

2.3 运行Gem5

命令行进入Gem5的根目录,然后运行:

build/X86/gem5.opt configs/tutorial/simple.py

3 配置一个加上Cache的系统

本小节配置一个如图的具有two level cache的层次结构。

【Gem5】入门准备和新手教程_第2张图片

3.1 创建缓存对象

这里使用classic cache,之所以不用ruby,是因为我们在构建CPU系统这里不考虑cache coherence。

先在configs/tutorial创建一个caches.py

from m5.objects import Cache

# Some specific options for caches
# For all options see src/mem/cache/Cache.py

class L1Cache(Cache):
    """Simple L1 Cache with default values"""

    # Default parameters for both L1 I and D caches
    assoc = 2
    tag_latency = 2
    data_latency = 2
    response_latency = 2
    mshrs = 4
    tgts_per_mshr = 20

    def connectCPU(self, cpu):
        """Connect this cache's port to a CPU-side port
           This must be defined in a subclass"""
        raise NotImplementedError

    def connectBus(self, bus):
        """Connect this cache to a memory-side bus"""
        self.mem_side = bus.slave

class L1ICache(L1Cache):
    """Simple L1 instruction cache with default values"""

    # Set the default size
    size = '16kB'

    def connectCPU(self, cpu):
        """Connect this cache's port to a CPU icache port"""
        self.cpu_side = cpu.icache_port

class L1DCache(L1Cache):
    """Simple L1 data cache with default values"""

    # Set the default size
    size = '64kB'

    def connectCPU(self, cpu):
        """Connect this cache's port to a CPU dcache port"""
        self.cpu_side = cpu.dcache_port

class L2Cache(Cache):
    """Simple L2 Cache with default values"""

    # Default parameters
    size = '256kB'
    assoc = 8
    tag_latency = 20
    data_latency = 20
    response_latency = 20
    mshrs = 20
    tgts_per_mshr = 12

    def connectCPUSideBus(self, bus):
        """"Connect this cache to a cpu-side bus"""
        self.cpu_side = bus.master

    def connectMemSideBus(self, bus):
        """"Connect this cache to a memory-side bus"""
        self.mem_side = bus.slave

注意以上的代码表示配置cache simObject。其中assoc代表关联度,tag_latency代表标签查找延迟,data_latency代表数据访问延迟,response_latency代表miss后的返回延迟。

3.2添加缓存后的配置脚本

这里为了方便,用之前创建的simple.py:

cp simple.py two_level.py

修改这个新的脚本如下:

from caches import *

3.3 实现脚本的参数功能

进行gem5实验时,每次编辑配置脚本显得比较繁琐,你也可以在此脚本文件中添加接收参数的功能,这个不是必须的,详细教程见:http://learning.gem5.org/book/part1/cache_config.html#adding-parameters-to-your-script

4 了解Gem5的统计和输出信息

除了模拟出的信息,运行gem5后在 m5out 目录下会生成下列3个文件:

config.ini

​ 包含为模拟创建的每个SimObject列表以及其参数的值

config.json

​ 与config.ini相同,但是采用json格式

stats.txt

​ 所有为仿真注册的gem5统计信息的文本表示

5 学习默认的配置脚本

之前我们自己手动编写了配置脚本,但是很多系统(ARM、X86)的设置非常复杂,幸运的是gem5提供了许多默认的脚本文件。

5.1 浏览文件存放的目录

所有gem5的配置文件在configs/下可以找到,目录的结构如下所示:

configs/boot:
ammp.rcS            halt.sh                micro_tlblat2.rcS              netperf-stream-udp-local.rcS
...

configs/common:
Benchmarks.py     cpu2000.py     Options.py
Caches.py         FSConfig.py    O3_ARM_v7a.py     SysPaths.py
CacheConfig.py    CpuConfig.py   MemConfig.py      Simulation.py

configs/dram:
sweep.py

configs/example:
fs.py       read_config.py       ruby_mem_test.py      ruby_random_test.py
memtest.py  ruby_direct_test.py  ruby_network_test.py  se.py

configs/ruby:
MESI_Three_Level.py  MI_example.py           MOESI_CMP_token.py  Network_test.py
MESI_Two_Level.py    MOESI_CMP_directory.py  MOESI_hammer.py     Ruby.py

configs/splash2:
cluster.py  run.py

configs/topologies:
BaseTopology.py  Cluster.py  Crossbar.py  MeshDirCorners.py  Mesh.py  Pt2Pt.py  Torus.py

解释几个重要的:

boot/

这些是在Full System mode下使用的,由Linux启动后被模拟器加载并由shell执行。

common/

Caches.py和我们之前创建的caches.py文件等很相似,也是一些关于cache的设置

Options.py包含了一些关于在命令行设置的选项,比如CPU数量,系统时钟等等

CacheConfig.py包含了为classic memory system设置的相关cache参数

MemConfig.py提供了设置memory system的一些帮助函数

examples/此文件中的函数用来执行gem5仿真,此文件非常复杂,但是它在运行仿真的时候灵活性非常大

examples/

包含一些可用于运行gem5的开箱即用的示例的gem5配置脚本。se.py并且fs.py非常有用。此目录中还有一些其他实用程序配置脚本。

dram/

一些测试DRAM的脚本

ruby/

包含ruby和cache coherence 的相关配置脚本

topologies/

包含创建Ruby cache hierarchy时候可用的拓扑实现

5.2 使用se.py和fs.py

这节讨论用命令行传递选项给se.py和fs.py。比如只需要如下就能运行hello world程序:

build/X86/gem5.opt configs/example/se.py --cmd=tests/test-progs/hello/bin/x86/linux/hello

然鹅,默认情况下gem5采取的是原子CPU模式和原子内存访问,所以报告不是真实的时序,你不信的话看看config.ini里[system.cpu]部分,type那里写的清清楚楚。

现在我们想用时序模式,按如下运行gem5:

build/X86/gem5.opt configs/example/se.py --cmd=tests/test-progs/hello/bin/x86/linux/hello --cpu-type=TimingSimpleCPU --l1d_size=64kB --l1i_size=16kB

虽然时序问题解决了,但是你在config.ini里找不到cache部分,虽然我们明确了cache的size,但我们没告诉这个system我们要用cache,所以自然就没创建cache,正确的形式如下:

build/X86/gem5.opt configs/example/se.py --cmd=tests/test-progs/hello/bin/x86/linux/hello --cpu-type=TimingSimpleCPU --l1d_size=64kB --l1i_size=16kB --caches

对比两次运行的ticks,发现后者的总时间更少,所以cache应该是启用的了。

5.3 对于se.py 和 fs.py常见的一些选项

详情在这里:http://learning.gem5.org/book/part1/example_configs.html#some-common-options-se-py-and-fs-py

你可能感兴趣的:(【Gem5】入门准备和新手教程)