python: Add utility function to override config parameters
Add a utility method, SimObject.apply_config that can be used to
implement SimObject param overrides from the command line. This
function provides safe and convenient semantics for CLI assignment:
* The override expression is evaluated in a restricted environment. The
only global variables are the child objects and params from the root
object.
* Only params can be overridden. For example, calling methods or setting
attributes on SimObjects isn't possible.
* Vectors use non-standard list semantics which enable something similar
to glob expansion on the shell. For example, setting:
root.system.cpu[0:2].numThreads = 2
will override numThreads for cpu 0 and 1 and:
root.system.cpus[0,2].numThreads = 2
sets it for cpus 0 and 2.
The intention is that the helper method is called to override default
values before calling m5.instantiate.
Change-Id: I73f99da21d6d8ce1ff2ec8db2bb34338456f6799
Reviewed-on: https://gem5-review.googlesource.com/c/12984
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Jason Lowe-Power <jason@lowepower.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017 ARM Limited
|
||||
# Copyright (c) 2017-2018 ARM Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
@@ -934,6 +934,63 @@ class ParamInfo(object):
|
||||
if not "created" in self.__dict__:
|
||||
self.__dict__[name] = value
|
||||
|
||||
class SimObjectCliWrapperException(Exception):
|
||||
def __init__(self, message):
|
||||
super(Exception, self).__init__(message)
|
||||
|
||||
class SimObjectCliWrapper(object):
|
||||
"""
|
||||
Wrapper class to restrict operations that may be done
|
||||
from the command line on SimObjects.
|
||||
|
||||
Only parameters may be set, and only children may be accessed.
|
||||
|
||||
Slicing allows for multiple simultaneous assignment of items in
|
||||
one statement.
|
||||
"""
|
||||
|
||||
def __init__(self, sim_objects):
|
||||
self.__dict__['_sim_objects'] = list(sim_objects)
|
||||
|
||||
def __getattr__(self, key):
|
||||
return SimObjectCliWrapper(sim_object._children[key]
|
||||
for sim_object in self._sim_objects)
|
||||
|
||||
def __setattr__(self, key, val):
|
||||
for sim_object in self._sim_objects:
|
||||
if key in sim_object._params:
|
||||
if sim_object._params[key].isCmdLineSettable():
|
||||
setattr(sim_object, key, val)
|
||||
else:
|
||||
raise SimObjectCliWrapperException(
|
||||
'tried to set or unsettable' \
|
||||
'object parameter: ' + key)
|
||||
else:
|
||||
raise SimObjectCliWrapperException(
|
||||
'tried to set or access non-existent' \
|
||||
'object parameter: ' + key)
|
||||
|
||||
def __getitem__(self, idx):
|
||||
"""
|
||||
Extends the list() semantics to also allow tuples,
|
||||
for example object[1, 3] selects items 1 and 3.
|
||||
"""
|
||||
out = []
|
||||
if isinstance(idx, tuple):
|
||||
for t in idx:
|
||||
out.extend(self[t]._sim_objects)
|
||||
else:
|
||||
if isinstance(idx, int):
|
||||
_range = range(idx, idx + 1)
|
||||
elif not isinstance(idx, slice):
|
||||
raise SimObjectCliWrapperException( \
|
||||
'invalid index type: ' + repr(idx))
|
||||
for sim_object in self._sim_objects:
|
||||
if isinstance(idx, slice):
|
||||
_range = range(*idx.indices(len(sim_object)))
|
||||
out.extend(sim_object[i] for i in _range)
|
||||
return SimObjectCliWrapper(out)
|
||||
|
||||
# The SimObject class is the root of the special hierarchy. Most of
|
||||
# the code in this class deals with the configuration hierarchy itself
|
||||
# (parent/child node relationships).
|
||||
@@ -1525,6 +1582,30 @@ class SimObject(object):
|
||||
for dt in item.generateDeviceTree(state):
|
||||
yield dt
|
||||
|
||||
# On a separate method otherwise certain buggy Python versions
|
||||
# would fail with: SyntaxError: unqualified exec is not allowed
|
||||
# in function 'apply_config'
|
||||
def _apply_config_get_dict(self):
|
||||
return {
|
||||
child_name: SimObjectCliWrapper(
|
||||
iter(self._children[child_name]))
|
||||
for child_name in self._children
|
||||
}
|
||||
|
||||
def apply_config(self, params):
|
||||
"""
|
||||
exec a list of Python code strings contained in params.
|
||||
|
||||
The only exposed globals to those strings are the child
|
||||
SimObjects of this node.
|
||||
|
||||
This function is intended to allow users to modify SimObject
|
||||
parameters from the command line with Python statements.
|
||||
"""
|
||||
d = self._apply_config_get_dict()
|
||||
for param in params:
|
||||
exec(param, d)
|
||||
|
||||
# Function to provide to C++ so it can look up instances based on paths
|
||||
def resolveSimObject(name):
|
||||
obj = instanceDict[name]
|
||||
|
||||
Reference in New Issue
Block a user