python: Move find from group to AbstractStat

This expands the 'find' feature to be recursive and find all the
stats/groups of stats of that regex all the way down the SimStats tree.

Change-Id: Id888911a6189e0440d2537f9720aa594353e00c7
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/63692
Maintainer: Bobby Bruce <bbruce@ucdavis.edu>
Reviewed-by: Bobby Bruce <bbruce@ucdavis.edu>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Bobby R. Bruce
2022-09-16 10:51:44 -07:00
committed by Bobby Bruce
parent b65fa9e0d8
commit 905b71c375
2 changed files with 61 additions and 86 deletions

View File

@@ -26,6 +26,15 @@
from .serializable_stat import SerializableStat
import re
from typing import (
Callable,
List,
Optional,
Pattern,
Union,
)
class AbstractStat(SerializableStat):
"""
@@ -34,4 +43,55 @@ class AbstractStat(SerializableStat):
All PyStats are JsonSerializable.
"""
pass
def children(
self,
predicate: Optional[Callable[[str], bool]] = None,
recursive: bool = False,
) -> List["AbstractStat"]:
"""Iterate through all of the children, optionally with a predicate
```
>>> system.children(lambda _name: 'cpu' in name)
[cpu0, cpu1, cpu2]
```
:param: predicate(str) -> bool: Optional. Each child's name is passed
to this function. If it returns true, then the child is
yielded. Otherwise, the child is skipped.
If not provided then all children are returned.
"""
to_return = []
for attr in self.__dict__:
obj = getattr(self, attr)
if isinstance(obj, AbstractStat):
if (predicate and predicate(attr)) or not predicate:
to_return.append(obj)
if recursive:
to_return = to_return + obj.children(
predicate=predicate, recursive=True
)
return to_return
def find(self, regex: Union[str, Pattern]) -> List["AbstractStat"]:
"""Find all stats that match the name, recursively through all the
SimStats.
```
>>> system.find('cpu[0-9]')
[cpu0, cpu1, cpu2]
```
Note: The above will not match `cpu_other`.
:param: regex: The regular expression used to search. Can be a
precompiled regex or a string in regex format
"""
if isinstance(regex, str):
pattern = re.compile(regex)
else:
pattern = regex
return self.children(
lambda _name: re.match(pattern, _name), recursive=True
)

View File

@@ -24,15 +24,11 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import re
from typing import (
Callable,
Dict,
Iterator,
List,
Mapping,
Optional,
Pattern,
Union,
)
@@ -68,87 +64,6 @@ class Group(AbstractStat):
for key, value in kwargs.items():
setattr(self, key, value)
def children(
self, predicate: Optional[Callable[[str], bool]] = None
) -> Iterator[Union["Group", Statistic]]:
"""Iterate through all of the children, optionally with a predicate
```
>>> system.children(lambda _name: 'cpu' in name)
[cpu0, cpu1, cpu2]
```
:param: predicate(str) -> bool: Optional. Each child's name is passed
to this function. If it returns true, then the child is
yielded. Otherwise, the child is skipped.
If not provided then all children are returned.
"""
for attr in self.__dict__:
# Check the provided predicate. If not a match, skip this child
if predicate and not predicate(attr):
continue
obj = getattr(self, attr)
if isinstance(obj, Group) or isinstance(obj, Statistic):
yield obj
def find(self, name: str) -> Iterator[Union["Group", Statistic]]:
"""Find all stats that match the name
This function searches all of the "children" in this group. It yields
the set of attributes (children) that have the `name` as a substring.
The order of the objects returned by the generator is arbitrary.
```
>>> system.find('cpu')
[cpu0, cpu1, cpu2, cpu3, other_cpu, ...]
```
This is useful for performing aggregates over substats. For instance:
```
>>> total_instructions = sum([cpu.exec_context.thread_0.numInsts.value
for cpu in simstat.system.find('cpu')])
100000
```
:param: name: The name to search for
"""
yield from self.children(lambda _name: _name in name)
def find_re(
self, regex: Union[str, Pattern]
) -> Iterator[Union["Group", Statistic]]:
"""Find all stats that match the name
This function searches all of the "children" in this group. It yields
the set of attributes (children) that have the `name` mathing the
regex provided. The order of the objects returned by the generator is
arbitrary.
```
>>> system.find_re('cpu[0-9]')
[cpu0, cpu1, cpu2]
```
Note: The above will not match `cpu_other`.
:param: regex: The regular expression used to search. Can be a
precompiled regex or a string in regex format
"""
if isinstance(regex, str):
pattern = re.compile(regex)
else:
pattern = regex
yield from self.children(lambda _name: bool(pattern.search(_name)))
def _repr_name(self) -> str:
return "Group"
def __repr__(self) -> str:
stats_list = []
for key in self.__dict__:
stats_list.append(key)
return f"{self._repr_name()}: {stats_list}"
class Vector(Group):
"""