1# Copyright 2015-2017 ARM Limited 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# 15 16"""A Topology can be defined as an arrangement of 17fundamental nodes, in various levels. Each topology 18has a default level "all" which has each node represented 19as a group. For example: 20 21 +--------+---------------------------------------+ 22 | level | groups | 23 +========+=======================================+ 24 | all | :code:`[[0, 1, 2, 3, 4]]` | 25 +--------+---------------------------------------+ 26 | cluster| :code:`[[0, 1], [2, 3, 4]]` | 27 +--------+---------------------------------------+ 28 | cpu | :code:`[[0], [1], [2], [3], [4], [5]]`| 29 +--------+---------------------------------------+ 30 31""" 32 33class Topology(object): 34 """Topology object allows grouping of 35 pivot values (called nodes) at multiple levels. 36 The implementation is targeted towards CPU topologies 37 but can be used generically as well 38 39 :param clusters: clusters can be defined as a 40 list of groups which are again lists of nodes. 41 42 .. note:: 43 44 This is not a mandatory 45 argument but can be used to quickly create typical 46 CPU topologies. 47 48 For Example: 49 :: 50 51 from trappy.stats.Topology import Topology 52 53 CLUSTER_A = [0, 1] 54 CLUTSER_B = [2, 3] 55 56 clusters = [CLUSTER_A, CLUSTER_B] 57 topology = Topology(clusters=clusters) 58 59 :type clusters: list 60 """ 61 62 def __init__(self, clusters=[]): 63 self._levels = {} 64 self._nodes = set() 65 66 if len(clusters): 67 self.add_to_level("cluster", clusters) 68 cpu_level = [] 69 for node in self.flatten(): 70 cpu_level.append([node]) 71 self.add_to_level("cpu", cpu_level) 72 73 def __repr__(self): 74 repr_str = "" 75 for level_name in self._levels: 76 repr_str += level_name + " " + \ 77 self.get_level(level_name).__repr__() + \ 78 "\n" 79 return repr_str 80 81 def add_to_level(self, level_name, level_vals): 82 """Add a group to a level 83 84 This function allows to append a 85 group of nodes to a level. If the level 86 does not exist a new level is created 87 88 :param level_name: The name of the level 89 :type level_name: str 90 91 :level_vals: groups containing nodes 92 :type level_vals: list of lists: 93 """ 94 95 if level_name not in self._levels: 96 self._levels[level_name] = [] 97 98 self._levels[level_name] += level_vals 99 100 for group in level_vals: 101 self._nodes = self._nodes.union(set(group)) 102 103 def get_level(self, level_name): 104 """Returns the groups of nodes associated 105 with a level 106 107 :param level_name: The name of the level 108 :type level_name: str 109 """ 110 111 if level_name == "all": 112 return [self.flatten()] 113 else: 114 return self._levels[level_name] 115 116 def get_index(self, level, node): 117 """Return the index of the node in the 118 level's list of nodes 119 120 :param level: The name of the level 121 :type level_name: str 122 123 :param node: The group for which the inde 124 is required 125 126 .. todo:: 127 128 Change name of the arg to group 129 130 :type node: list 131 """ 132 133 nodes = self.get_level(level) 134 return nodes.index(node) 135 136 def get_node(self, level, index): 137 """Get the group at the index in 138 the level 139 140 :param level: The name of the level 141 :type level_name: str 142 143 :param index: Index of the group in 144 the list 145 :type index: int 146 """ 147 148 nodes = self.get_level(level) 149 return nodes[index] 150 151 def __iter__(self): 152 return self._levels.__iter__() 153 154 def flatten(self): 155 """Return a flattened list of nodes in the 156 topology 157 """ 158 return list(self._nodes) 159 160 def level_span(self, level): 161 """Return the number of groups in a level 162 163 :param level: The name of the level 164 :type level_name: str 165 """ 166 if level == "all": 167 return len(self._nodes) 168 else: 169 return len(self._levels[level]) 170 171 def has_level(self, level): 172 """Returns true if level is present 173 174 :param level: The name of the level 175 :type level_name: str 176 """ 177 178 return (level in self._levels) 179 180