stdlib, configs: stdlib SimPoints support and example scripts
simpoints-se-checkpoint.py & simpoints-se-restore.py: These are two example scripts to show how to use SimPoints functions with the stdlib. se_binary_workload.py: Allow se_binary_workload to take in SimPoint Class item and schedule SimPoint exit events. exit_event.py: Added SIMPOINT_BEGIN and MAX_INSTS exit events. simulator.py: Added SIMPOINT_BEGIN and MAX_INSTS exit event scheduling functions. They can schedule exit events before or during the simulation. Jira Issue: https://gem5.atlassian.net/browse/GEM5-1259 Change-Id: Iaa07a83de9dddc293b9f1a230aba8e35d4f5af6c Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/63154 Reviewed-by: Bobby Bruce <bbruce@ucdavis.edu> Tested-by: kokoro <noreply+kokoro@google.com> Maintainer: Bobby Bruce <bbruce@ucdavis.edu>
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
# Copyright (c) 2022 The Regents of the University of California
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met: redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer;
|
||||
# redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution;
|
||||
# neither the name of the copyright holders nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
This configuation script shows an example of how to take checkpoints for
|
||||
SimPoints using the gem5 stdlib. SimPoints, SimPoints interval length,
|
||||
SimPoints weights, and the warmup instruction length are passed into the gem5
|
||||
SimPoint module. The gem5 SimPoint module will calculate where to take
|
||||
checkpoints based of the SimPoints, SimPoints interval length, and the warmup
|
||||
instruction length. In SE mode, when you pass in a SimPoint object to the
|
||||
set_se_binary_workload, it will schedule exit events for SimPoints in the init
|
||||
stage of the core. With the Simulator module and the exit event generator,
|
||||
checkpoints will be taken for the SimPoints.
|
||||
|
||||
This scipt builds a simple board with the gem5 stdlib with no cache and a
|
||||
simple memory structure to take checkpoints. Some of the components, such as
|
||||
cache hierarchy, can be changed when restoring checkpoints.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
```
|
||||
scons build/X86/gem5.opt
|
||||
./build/X86/gem5.opt \
|
||||
configs/example/gem5_library/checkpoints/simpoints-se-checkpoint.py
|
||||
|
||||
./build/X86/gem5.opt \
|
||||
configs/example/gem5_library/checkpoints/simpoints-se-restore.py
|
||||
```
|
||||
"""
|
||||
|
||||
from gem5.simulate.exit_event import ExitEvent
|
||||
from gem5.simulate.simulator import Simulator
|
||||
from gem5.utils.requires import requires
|
||||
from gem5.components.boards.simple_board import SimpleBoard
|
||||
from gem5.components.memory.single_channel import SingleChannelDDR3_1600
|
||||
from gem5.components.processors.simple_processor import SimpleProcessor
|
||||
from gem5.components.processors.cpu_types import CPUTypes
|
||||
from gem5.isas import ISA
|
||||
from gem5.resources.resource import Resource
|
||||
from pathlib import Path
|
||||
from gem5.components.cachehierarchies.classic.no_cache import NoCache
|
||||
from gem5.utils.simpoint import SimPoint
|
||||
from gem5.simulate.exit_event_generators import (
|
||||
save_checkpoint_generator,
|
||||
)
|
||||
|
||||
requires(isa_required=ISA.X86)
|
||||
|
||||
# When taking a checkpoint, the cache state is not saved, so the cache
|
||||
# hierarchy can be changed completely when restoring from a checkpoint.
|
||||
# By using NoCache() to take checkpoints, it can slightly improve the
|
||||
# performance when running in atomic mode, and it will not put any restrictions
|
||||
# on what people can do with the checkpoints.
|
||||
cache_hierarchy = NoCache()
|
||||
|
||||
# Using simple memory to take checkpoints might slightly imporve the
|
||||
# performance in atomic mode. The memory structure can be changed when
|
||||
# restoring from a checkpoint, but the size of the memory must be maintained.
|
||||
memory = SingleChannelDDR3_1600(size="2GB")
|
||||
|
||||
processor = SimpleProcessor(
|
||||
cpu_type=CPUTypes.ATOMIC,
|
||||
isa=ISA.X86,
|
||||
# SimPoints only works with one core
|
||||
num_cores=1,
|
||||
)
|
||||
|
||||
board = SimpleBoard(
|
||||
clk_freq="3GHz",
|
||||
processor=processor,
|
||||
memory=memory,
|
||||
cache_hierarchy=cache_hierarchy,
|
||||
)
|
||||
|
||||
simpoint = SimPoint(
|
||||
simpoint_list=[2, 3, 5, 15],
|
||||
weight_list=[0.1, 0.2, 0.4, 0.3],
|
||||
simpoint_interval=1000000,
|
||||
warmup_interval=1000000,
|
||||
)
|
||||
|
||||
board.set_se_binary_workload(
|
||||
binary=Resource("x86-print-this"),
|
||||
arguments=["print this", 15000],
|
||||
simpoint=simpoint,
|
||||
)
|
||||
|
||||
dir = Path("se_checkpoint_folder/")
|
||||
dir.mkdir(exist_ok=True)
|
||||
|
||||
simulator = Simulator(
|
||||
board=board,
|
||||
on_exit_event={
|
||||
# using the SimPoints event generator in the standard library to take
|
||||
# checkpoints
|
||||
ExitEvent.SIMPOINT_BEGIN: save_checkpoint_generator(dir)
|
||||
},
|
||||
)
|
||||
|
||||
simulator.run()
|
||||
147
configs/example/gem5_library/checkpoints/simpoints-se-restore.py
Normal file
147
configs/example/gem5_library/checkpoints/simpoints-se-restore.py
Normal file
@@ -0,0 +1,147 @@
|
||||
# Copyright (c) 2022 The Regents of the University of California
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met: redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer;
|
||||
# redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution;
|
||||
# neither the name of the copyright holders nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
This configuation script shows an example of how to restore a checkpoint that
|
||||
was taken for SimPoints in the
|
||||
configs/example/gem5_library/checkpoints/simpoints-se-checkpoint.py.
|
||||
The SimPoints, SimPoints interval length, and the warmup instruction length
|
||||
are passed into the SimPoint module, so the SimPoint object will store and
|
||||
calculate the warmup instruction length for each SimPoints based on the
|
||||
avaliable instructions before reaching the start of the SimPoint. With the
|
||||
Simulator module, exit event will be generated to stop when the warmup session
|
||||
ends and the SimPoints interval ends.
|
||||
|
||||
This scipt builds a more complex board than the board used for taking
|
||||
checkpoint.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
```
|
||||
scons build/X86/gem5.opt
|
||||
./build/X86/gem5.opt \
|
||||
configs/example/gem5_library/checkpoints/simpoints-se-checkpoint.py
|
||||
|
||||
./build/X86/gem5.opt \
|
||||
configs/example/gem5_library/checkpoints/simpoints-se-restore.py
|
||||
```
|
||||
"""
|
||||
|
||||
import imp
|
||||
from gem5.simulate.exit_event import ExitEvent
|
||||
from gem5.simulate.simulator import Simulator
|
||||
from gem5.utils.requires import requires
|
||||
from gem5.components.cachehierarchies.classic.private_l1_private_l2_cache_hierarchy import (
|
||||
PrivateL1PrivateL2CacheHierarchy,
|
||||
)
|
||||
from gem5.components.boards.simple_board import SimpleBoard
|
||||
from gem5.components.memory import DualChannelDDR4_2400
|
||||
from gem5.components.processors.simple_processor import SimpleProcessor
|
||||
from gem5.components.processors.cpu_types import CPUTypes
|
||||
from gem5.isas import ISA
|
||||
from gem5.resources.resource import Resource
|
||||
|
||||
from gem5.utils.simpoint import SimPoint
|
||||
from pathlib import Path
|
||||
from m5.stats import reset, dump
|
||||
|
||||
requires(isa_required=ISA.X86)
|
||||
|
||||
# The cache hierarchy can be different from the cache hierarchy used in taking
|
||||
# the checkpoints
|
||||
cache_hierarchy = PrivateL1PrivateL2CacheHierarchy(
|
||||
l1d_size="32kB",
|
||||
l1i_size="32kB",
|
||||
l2_size="256kB",
|
||||
)
|
||||
|
||||
# The memory structure can be different from the memory structure used in
|
||||
# taking the checkpoints, but the size of the memory must be maintained
|
||||
memory = DualChannelDDR4_2400(size="2GB")
|
||||
|
||||
processor = SimpleProcessor(
|
||||
cpu_type=CPUTypes.TIMING,
|
||||
isa=ISA.X86,
|
||||
num_cores=1,
|
||||
)
|
||||
|
||||
board = SimpleBoard(
|
||||
clk_freq="3GHz",
|
||||
processor=processor,
|
||||
memory=memory,
|
||||
cache_hierarchy=cache_hierarchy,
|
||||
)
|
||||
|
||||
simpoint = SimPoint(
|
||||
simpoint_list=[2, 3, 5, 15],
|
||||
weight_list=[0.1, 0.2, 0.4, 0.3],
|
||||
simpoint_interval=1000000,
|
||||
warmup_interval=1000000,
|
||||
)
|
||||
|
||||
board.set_se_binary_workload(
|
||||
binary=Resource("x86-print-this"), arguments=["print this", 15000]
|
||||
)
|
||||
|
||||
# configs/example/gem5_library/checkpoints/simpoints-se-checkpoint.py has to
|
||||
# run before running this script.
|
||||
# In here, it will get the path of the first SimPoint checkpoint taken by the
|
||||
# simpoints-se-checkpoint.py
|
||||
dir = Path("se_checkpoint_folder")
|
||||
subfolder = [int(str(name).split(".")[1]) for name in dir.iterdir()]
|
||||
dir = Path(dir / f"cpt.{min(subfolder)}").as_posix()
|
||||
|
||||
|
||||
def max_inst():
|
||||
warmed_up = False
|
||||
while True:
|
||||
if warmed_up:
|
||||
print("end of SimPoint interval")
|
||||
yield True
|
||||
else:
|
||||
print("end of warmup, starting to simulate SimPoint")
|
||||
warmed_up = True
|
||||
# Schedule a MAX_INSTS exit event during the simulation
|
||||
simulator.schedule_max_insts(simpoint.get_simpoint_interval())
|
||||
dump()
|
||||
reset()
|
||||
yield False
|
||||
|
||||
|
||||
simulator = Simulator(
|
||||
board=board,
|
||||
checkpoint_path=dir,
|
||||
on_exit_event={ExitEvent.MAX_INSTS: max_inst()},
|
||||
)
|
||||
|
||||
# Schedule a MAX_INSTS exit event before the simulation begins the
|
||||
# schedule_max_insts function only schedule event when the instruction length
|
||||
# is greater than 0.
|
||||
# In here, it schedules an exit event for the first SimPoint's warmup
|
||||
# instructions
|
||||
simulator.schedule_max_insts(simpoint.get_warmup_list()[0], True)
|
||||
simulator.run()
|
||||
@@ -26,10 +26,12 @@
|
||||
|
||||
from .abstract_board import AbstractBoard
|
||||
from ...resources.resource import AbstractResource
|
||||
from gem5.utils.simpoint import SimPoint
|
||||
|
||||
from m5.objects import SEWorkload, Process
|
||||
|
||||
from typing import Optional, List
|
||||
from m5.util import warn
|
||||
|
||||
|
||||
class SEBinaryWorkload:
|
||||
@@ -52,6 +54,7 @@ class SEBinaryWorkload:
|
||||
exit_on_work_items: bool = True,
|
||||
stdin_file: Optional[AbstractResource] = None,
|
||||
arguments: List[str] = [],
|
||||
simpoint: SimPoint = None,
|
||||
) -> None:
|
||||
"""Set up the system to run a specific binary.
|
||||
|
||||
@@ -60,11 +63,16 @@ class SEBinaryWorkload:
|
||||
* Dynamically linked executables are partially supported when the host
|
||||
ISA and the simulated ISA are the same.
|
||||
|
||||
**Warning:** SimPoints only works with one core
|
||||
|
||||
:param binary: The resource encapsulating the binary to be run.
|
||||
:param exit_on_work_items: Whether the simulation should exit on work
|
||||
items. True by default.
|
||||
:param stdin_file: The input file for the binary
|
||||
:param arguments: The input arguments for the binary
|
||||
:param simpoint: The SimPoint object that contains the list of
|
||||
SimPoints starting instructions, the list of weights, and the SimPoints
|
||||
interval
|
||||
"""
|
||||
|
||||
# We assume this this is in a multiple-inheritance setup with an
|
||||
@@ -87,5 +95,12 @@ class SEBinaryWorkload:
|
||||
for core in self.get_processor().get_cores():
|
||||
core.set_workload(process)
|
||||
|
||||
if simpoint is not None:
|
||||
if self.get_processor().get_num_cores() > 1:
|
||||
warn("SimPoints only works with one core")
|
||||
self.get_processor().get_cores()[0].set_simpoint(
|
||||
inst_starts=simpoint.get_simpoint_start_insts(), init=True
|
||||
)
|
||||
|
||||
# Set whether to exit on work items for the se_workload
|
||||
self.exit_on_work_items = exit_on_work_items
|
||||
|
||||
@@ -46,6 +46,8 @@ class ExitEvent(Enum):
|
||||
USER_INTERRUPT = ( # An exit due to a user interrupt (e.g., cntr + c)
|
||||
"user interupt"
|
||||
)
|
||||
SIMPOINT_BEGIN = "simpoint begins"
|
||||
MAX_INSTS = "number of instructions reached"
|
||||
|
||||
@classmethod
|
||||
def translate_exit_status(cls, exit_string: str) -> "ExitEvent":
|
||||
@@ -81,6 +83,10 @@ class ExitEvent(Enum):
|
||||
return ExitEvent.CHECKPOINT
|
||||
elif exit_string == "user interrupt received":
|
||||
return ExitEvent.USER_INTERRUPT
|
||||
elif exit_string == "simpoint starting point found":
|
||||
return ExitEvent.SIMPOINT_BEGIN
|
||||
elif exit_string == "a thread reached the max instruction count":
|
||||
return ExitEvent.MAX_INSTS
|
||||
raise NotImplementedError(
|
||||
"Exit event '{}' not implemented".format(exit_string)
|
||||
)
|
||||
|
||||
@@ -41,6 +41,7 @@ from .exit_event_generators import (
|
||||
default_switch_generator,
|
||||
default_workbegin_generator,
|
||||
default_workend_generator,
|
||||
default_simpoint_generator,
|
||||
)
|
||||
from .exit_event import ExitEvent
|
||||
from ..components.boards.abstract_board import AbstractBoard
|
||||
@@ -179,6 +180,8 @@ class Simulator:
|
||||
ExitEvent.WORKEND: default_workend_generator(),
|
||||
ExitEvent.USER_INTERRUPT: default_exit_generator(),
|
||||
ExitEvent.MAX_TICK: default_exit_generator(),
|
||||
ExitEvent.SIMPOINT_BEGIN: default_simpoint_generator(),
|
||||
ExitEvent.MAX_INSTS: default_simpoint_generator(),
|
||||
}
|
||||
|
||||
if on_exit_event:
|
||||
@@ -197,6 +200,40 @@ class Simulator:
|
||||
|
||||
self._checkpoint_path = checkpoint_path
|
||||
|
||||
def schedule_simpoint(
|
||||
self, simpoint_start_insts: List[int], schedule_at_init: bool = False
|
||||
) -> None:
|
||||
"""
|
||||
Schedule SIMPOINT_BEGIN exit events
|
||||
|
||||
**Warning:** SimPoints only work with one core
|
||||
|
||||
:param simpoint_start_insts: a list of number of instructions
|
||||
indicating the starting point of the simpoints
|
||||
:param schedule_at_init: if it is True, schedule the events in the init
|
||||
stage of the core, else, schedule the events during the simulation
|
||||
"""
|
||||
if self._board.get_processor().get_num_cores() > 1:
|
||||
warn("SimPoints only work with one core")
|
||||
self._board.get_processor().get_cores()[0].set_simpoint(
|
||||
simpoint_start_insts, schedule_at_init
|
||||
)
|
||||
|
||||
def schedule_max_insts(
|
||||
self, inst: int, schedule_at_init: bool = False
|
||||
) -> None:
|
||||
"""
|
||||
Schedule a MAX_INSTS exit event when any thread in the current core
|
||||
reaches the given number of instructions
|
||||
|
||||
:param insts: a number of instructions
|
||||
:param schedule_at_init: if it is True, schedule the event in the init
|
||||
stage of the core, else, schedule the event during the simulation
|
||||
"""
|
||||
self._board.get_processor().get_cores()[0].set_inst_stop_any_thread(
|
||||
inst, schedule_at_init
|
||||
)
|
||||
|
||||
def get_stats(self) -> Dict:
|
||||
"""
|
||||
Obtain the current simulation statistics as a Dictionary, conforming
|
||||
|
||||
Reference in New Issue
Block a user