python: Add DeprecatedParam type

There are times when we need to change the name of parameter, but this
breaks the external-facing python API used in configuration files. Using
this "type" for a parameter will warn users that they are using the old
name, but allow for backwards compatibility.

Declaring a SimObject parameter of type `DeprecatedParam` allows the
python configuration files to use the old name transparently. This
leverages some of the SimObject magic to remember the names of
deprecated parameters and the DeprecatedParam object stores the
"translation" from old name to new name.

This has been tested with Ports, "normal" parameters, and SimObject
parameters. It has not been tested with checkpointing as there are no
checkpointing tests in gem5 right now. The testing was manually adding
some deprecated params and checking that config scripts still run
correctly that use the old, deprecated, variables.

Change-Id: I0465a748c08a24278d6b1a9d9ee1bcd67baa5b13
Signed-off-by: Jason Lowe-Power <jason@lowepower.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/31954
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Jason Lowe-Power
2020-07-29 08:21:10 -07:00
committed by Jason Lowe-Power
parent df639a1c28
commit b1245973be
2 changed files with 105 additions and 1 deletions

View File

@@ -467,6 +467,12 @@ class MetaSimObject(type):
cls._params = multidict() # param descriptions
cls._ports = multidict() # port descriptions
# Parameter names that are deprecated. Dict[str, DeprecatedParam]
# The key is the "old_name" so that when the old_name is used in
# python config files, we will use the DeprecatedParam object to
# translate to the new type.
cls._deprecated_params = multidict()
# class or instance attributes
cls._values = multidict() # param values
cls._hr_values = multidict() # human readable param values
@@ -495,6 +501,7 @@ class MetaSimObject(type):
cls._base = base
cls._params.parent = base._params
cls._ports.parent = base._ports
cls._deprecated_params.parent = base._deprecated_params
cls._values.parent = base._values
cls._hr_values.parent = base._hr_values
cls._children.parent = base._children
@@ -532,6 +539,15 @@ class MetaSimObject(type):
elif isinstance(val, Port):
cls._new_port(key, val)
# Deprecated variable names
elif isinstance(val, DeprecatedParam):
new_name, new_val = cls._get_param_by_value(val.newParam)
# Note: We don't know the (string) name of this variable until
# here, so now we can finish setting up the dep_param.
val.oldName = key
val.newName = new_name
cls._deprecated_params[key] = val
# init-time-only keywords
elif key in cls.init_keywords:
cls._set_keyword(key, val, cls.init_keywords[key])
@@ -604,6 +620,18 @@ class MetaSimObject(type):
cls._port_refs[attr] = ref
return ref
def _get_param_by_value(cls, value):
"""Given an object, value, return the name and the value from the
internal list of parameter values. If this value can't be found, raise
a runtime error. This will search both the current object and its
parents.
"""
for k,v in cls._value_dict.items():
if v == value:
return k,v
raise RuntimeError("Cannot find parameter {} in parameter list"
.format(value))
# Set attribute (called on foo.attr = value when foo is an
# instance of class cls).
def __setattr__(cls, attr, value):
@@ -1255,6 +1283,11 @@ class SimObject(object):
return ref
def __getattr__(self, attr):
if attr in self._deprecated_params:
dep_param = self._deprecated_params[attr]
dep_param.printWarning(self._name, self.__class__.__name__)
return getattr(self, self._deprecated_params[attr].newName)
if attr in self._ports:
return self._get_port_ref(attr)
@@ -1287,6 +1320,11 @@ class SimObject(object):
object.__setattr__(self, attr, value)
return
if attr in self._deprecated_params:
dep_param = self._deprecated_params[attr]
dep_param.printWarning(self._name, self.__class__.__name__)
return setattr(self, self._deprecated_params[attr].newName, value)
if attr in self._ports:
# set up port connection
self._get_port_ref(attr).connect(value)