blob: 014581e0ff97c4aaf1414f614469481cbfa972cb [file] [log] [blame]
# Copyright 2015-2017 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""A Topology can be defined as an arrangement of
fundamental nodes, in various levels. Each topology
has a default level "all" which has each node represented
as a group. For example:
+--------+---------------------------------------+
| level | groups |
+========+=======================================+
| all | :code:`[[0, 1, 2, 3, 4]]` |
+--------+---------------------------------------+
| cluster| :code:`[[0, 1], [2, 3, 4]]` |
+--------+---------------------------------------+
| cpu | :code:`[[0], [1], [2], [3], [4], [5]]`|
+--------+---------------------------------------+
"""
class Topology(object):
"""Topology object allows grouping of
pivot values (called nodes) at multiple levels.
The implementation is targeted towards CPU topologies
but can be used generically as well
:param clusters: clusters can be defined as a
list of groups which are again lists of nodes.
.. note::
This is not a mandatory
argument but can be used to quickly create typical
CPU topologies.
For Example:
::
from trappy.stats.Topology import Topology
CLUSTER_A = [0, 1]
CLUTSER_B = [2, 3]
clusters = [CLUSTER_A, CLUSTER_B]
topology = Topology(clusters=clusters)
:type clusters: list
"""
def __init__(self, clusters=[]):
self._levels = {}
self._nodes = set()
if len(clusters):
self.add_to_level("cluster", clusters)
cpu_level = []
for node in self.flatten():
cpu_level.append([node])
self.add_to_level("cpu", cpu_level)
def __repr__(self):
repr_str = ""
for level_name in self._levels:
repr_str += level_name + " " + \
self.get_level(level_name).__repr__() + \
"\n"
return repr_str
def add_to_level(self, level_name, level_vals):
"""Add a group to a level
This function allows to append a
group of nodes to a level. If the level
does not exist a new level is created
:param level_name: The name of the level
:type level_name: str
:level_vals: groups containing nodes
:type level_vals: list of lists:
"""
if level_name not in self._levels:
self._levels[level_name] = []
self._levels[level_name] += level_vals
for group in level_vals:
self._nodes = self._nodes.union(set(group))
def get_level(self, level_name):
"""Returns the groups of nodes associated
with a level
:param level_name: The name of the level
:type level_name: str
"""
if level_name == "all":
return [self.flatten()]
else:
return self._levels[level_name]
def get_index(self, level, node):
"""Return the index of the node in the
level's list of nodes
:param level: The name of the level
:type level_name: str
:param node: The group for which the inde
is required
.. todo::
Change name of the arg to group
:type node: list
"""
nodes = self.get_level(level)
return nodes.index(node)
def get_node(self, level, index):
"""Get the group at the index in
the level
:param level: The name of the level
:type level_name: str
:param index: Index of the group in
the list
:type index: int
"""
nodes = self.get_level(level)
return nodes[index]
def __iter__(self):
return self._levels.__iter__()
def flatten(self):
"""Return a flattened list of nodes in the
topology
"""
return list(self._nodes)
def level_span(self, level):
"""Return the number of groups in a level
:param level: The name of the level
:type level_name: str
"""
if level == "all":
return len(self._nodes)
else:
return len(self._levels[level])
def has_level(self, level):
"""Returns true if level is present
:param level: The name of the level
:type level_name: str
"""
return (level in self._levels)