stdlib: Allow passing of func as Exit Event generator (#195)
In this case the function is turned into a generator with the "yield" of the generator the return the function's execution. Translation of this stale Gerrit Change: https://gem5-review.googlesource.com/c/public/gem5/+/62872
This commit is contained in:
@@ -85,7 +85,11 @@ class Simulator:
|
||||
on_exit_event: Optional[
|
||||
Dict[
|
||||
ExitEvent,
|
||||
Union[Generator[Optional[bool], None, None], List[Callable]],
|
||||
Union[
|
||||
Generator[Optional[bool], None, None],
|
||||
List[Callable],
|
||||
Callable,
|
||||
],
|
||||
]
|
||||
] = None,
|
||||
expected_execution_order: Optional[List[ExitEvent]] = None,
|
||||
@@ -97,16 +101,21 @@ class Simulator:
|
||||
This is optional and used to override default behavior. If not set,
|
||||
whether or not to run in FS mode will be determined via the board's
|
||||
`is_fullsystem()` function.
|
||||
:param on_exit_event: An optional map to specify the generator to
|
||||
execute on each exit event. The generator may yield a boolean which,
|
||||
if True, will have the Simulator exit the run loop. A List of functions
|
||||
may also be used. Each function must be callable with no arguments and
|
||||
return a boolean specifying if the Simulation should exit the run loop.
|
||||
:param expected_execution_order: May be specified to check the exit
|
||||
events come in a specified order. If the order specified is not
|
||||
encountered (e.g., 'Workbegin', 'Workend', then 'Exit'), an Exception
|
||||
is thrown. If this parameter is not specified, any ordering of exit
|
||||
events is valid.
|
||||
:param on_exit_event: An optional map to specify what to execute on
|
||||
each exit event. There are three possibilities here: a generator, a
|
||||
list of functions, or a single function.:
|
||||
1. Generator: The generator may yield a boolean each time the
|
||||
associated exit event is encountered. If True the simulator will exit
|
||||
the simulation loop.
|
||||
2. List of functions: Each function must be callable with no mandatory
|
||||
arguments and return a boolean specifying if the Simulation should exit
|
||||
the simulation loop. Upon each exit event the list will pop the start
|
||||
of the list and execute it. If the list is empty the default behavior
|
||||
for that exit event will be executed.
|
||||
3. Single function: The function must be callable with no mandatory
|
||||
arguments and return a boolean specifying if the Simulation should exit
|
||||
or not. This function is executed each time the associated exit event
|
||||
is encountered.
|
||||
:param checkpoint_path: An optional parameter specifying the directory
|
||||
of the checkpoint to instantiate from. When the path is None, no
|
||||
checkpoint will be loaded. By default, the path is None. **This
|
||||
@@ -195,6 +204,29 @@ class Simulator:
|
||||
again before finally, on the forth exit event will call
|
||||
`stop_simulation` which will stop the simulation as it returns False.
|
||||
|
||||
With a function
|
||||
===============
|
||||
A single function can be passed. In this case every exit event of that
|
||||
type will execute that function every time. The function should not
|
||||
accept any mandatory parameters and return a boolean specifying if the
|
||||
simulation loop should end after it is executed.
|
||||
An example:
|
||||
```
|
||||
def print_hello() -> bool:
|
||||
print("Hello")
|
||||
return False
|
||||
simulator = Simulator(
|
||||
board=board,
|
||||
on_exit_event = {
|
||||
ExitEvent.Exit : print_hello
|
||||
},
|
||||
)
|
||||
```
|
||||
The above will print "Hello" on every `Exit` type Exit Event. As the
|
||||
function returns False, the simulation loop will not end on these
|
||||
events.
|
||||
|
||||
|
||||
Exit Event defaults
|
||||
===================
|
||||
|
||||
@@ -266,6 +298,15 @@ class Simulator:
|
||||
# In instances where we have a list of functions, we
|
||||
# convert this to a generator.
|
||||
self._on_exit_event[key] = (func() for func in value)
|
||||
elif isinstance(value, Callable):
|
||||
# In instances where the user passes a lone function, the
|
||||
# function is called on every exit event of that type. Here
|
||||
# we convert the function into an infinite generator.
|
||||
def function_generator(func: Callable):
|
||||
while True:
|
||||
yield func()
|
||||
|
||||
self._on_exit_event[key] = function_generator(func=value)
|
||||
else:
|
||||
raise Exception(
|
||||
f"`on_exit_event` for '{key.value}' event is "
|
||||
|
||||
@@ -41,8 +41,9 @@ About to exit the simulation for the 3 st/nd/rd/th time
|
||||
Handling the final exit event. We'll exit now.
|
||||
```
|
||||
|
||||
By default a generator is passed to define the evit_event. A list of functions
|
||||
can also be passed. This is enabled by passing the `--list-format` flag.
|
||||
By default a generator is passed to define the exit_event behavior. A list of
|
||||
functions or a lone function can also be passed. This can be specified by the
|
||||
`--exit-event-type` parameter.
|
||||
"""
|
||||
|
||||
from gem5.resources.resource import obtain_resource
|
||||
@@ -63,11 +64,12 @@ parser = argparse.ArgumentParser(
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--list-format",
|
||||
action="store_true",
|
||||
help="Use a list of functions, instead of a generator, for the exit event "
|
||||
"handler",
|
||||
"-e",
|
||||
"--exit-event-type",
|
||||
type=str,
|
||||
choices=("generator", "function-list", "function"),
|
||||
default="generator",
|
||||
help="Used to specify what exit event format is to be passed.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
@@ -106,9 +108,9 @@ binary = obtain_resource(
|
||||
)
|
||||
motherboard.set_se_binary_workload(binary)
|
||||
|
||||
# Create the exit event handler. Here there are two kinds: either pass a
|
||||
# generator or a list of functions. In this script they both do the same things
|
||||
# for testing purposes.
|
||||
# Create the exit event handler. Here there are three kinds: either pass a
|
||||
# generator, a list of functions, or a lone function. In this script they all
|
||||
# do the same thing for testing purposes.
|
||||
|
||||
|
||||
def event_handle() -> bool:
|
||||
@@ -129,11 +131,24 @@ def generator():
|
||||
|
||||
func_list = [event_handle, event_handle, event_handle_final]
|
||||
|
||||
i = 0
|
||||
|
||||
|
||||
def lone_function() -> bool:
|
||||
global i
|
||||
i += 1
|
||||
if i < 3:
|
||||
return event_handle()
|
||||
return event_handle_final()
|
||||
|
||||
|
||||
exit_event_handler = None
|
||||
if args.list_format:
|
||||
if args.exit_event_type == "function-list":
|
||||
exit_event_handler = func_list
|
||||
else:
|
||||
elif args.exit_event_type == "generator":
|
||||
exit_event_handler = generator()
|
||||
elif args.exit_event_type == "function":
|
||||
exit_event_handler = lone_function
|
||||
|
||||
assert exit_event_handler is not None
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ gem5_verify_config(
|
||||
"configs",
|
||||
"simulator_exit_event_run.py",
|
||||
),
|
||||
config_args=["-l"],
|
||||
config_args=["-e", "function-list"],
|
||||
valid_isas=(constants.all_compiled_tag,),
|
||||
length=constants.quick_tag,
|
||||
)
|
||||
@@ -64,7 +64,24 @@ gem5_verify_config(
|
||||
"configs",
|
||||
"simulator_exit_event_run.py",
|
||||
),
|
||||
config_args=[],
|
||||
config_args=["-e", "generator"],
|
||||
valid_isas=(constants.all_compiled_tag,),
|
||||
length=constants.quick_tag,
|
||||
)
|
||||
|
||||
gem5_verify_config(
|
||||
name="simulator-exit-event-handler-with-lone-function",
|
||||
verifiers=verifiers,
|
||||
fixtures=(),
|
||||
config=joinpath(
|
||||
config.base_dir,
|
||||
"tests",
|
||||
"gem5",
|
||||
"stdlib",
|
||||
"configs",
|
||||
"simulator_exit_event_run.py",
|
||||
),
|
||||
config_args=["-e", "function"],
|
||||
valid_isas=(constants.all_compiled_tag,),
|
||||
length=constants.quick_tag,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user