1# Copyright (c) 2012 Advanced Micro Devices, Inc.
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met: redistributions of source code must retain the above copyright
7# notice, this list of conditions and the following disclaimer;
8# redistributions in binary form must reproduce the above copyright
9# notice, this list of conditions and the following disclaimer in the
10# documentation and/or other materials provided with the distribution;
11# neither the name of the copyright holders nor the names of its
12# contributors may be used to endorse or promote products derived from
13# this software without specific prior written permission.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26#
27# Authors: Jason Power
28
29from __future__ import print_function
30from __future__ import absolute_import
31
32from .BaseTopology import BaseTopology
33
34class Cluster(BaseTopology):
35    """ A cluster is a group of nodes which are all one hop from eachother
36        Clusters can also contain other clusters
37        When creating this kind of topology, return a single cluster (usually
38        the root cluster) from create_system in configs/ruby/<protocol>.py
39    """
40
41    _num_int_links = 0
42    _num_ext_links = 0
43    _num_routers = 0
44
45    # Below methods for auto counting
46    @classmethod
47    def num_int_links(cls):
48        cls._num_int_links += 1
49        return cls._num_int_links - 1
50    @classmethod
51    def num_ext_links(cls):
52        cls._num_ext_links += 1
53        return cls._num_ext_links - 1
54    @classmethod
55    def num_routers(cls):
56        cls._num_routers += 1
57        return cls._num_routers - 1
58
59    def __init__(self, intBW=0, extBW=0, intLatency=0, extLatency=0):
60        """ internalBandwidth is bandwidth of all links within the cluster
61            externalBandwidth is bandwidth from this cluster to any cluster
62                connecting to it.
63            internal/externalLatency are similar
64            **** When creating a cluster with sub-clusters, the sub-cluster
65                 external bandwidth overrides the internal bandwidth of the
66                 super cluster
67        """
68        self.nodes = []
69        self.router = None # created in makeTopology
70        self.intBW = intBW
71        self.extBW = extBW
72        self.intLatency = intLatency
73        self.extLatency = extLatency
74
75    def add(self, node):
76        self.nodes.append(node)
77
78    def makeTopology(self, options, network, IntLink, ExtLink, Router):
79        """ Recursively make all of the links and routers
80        """
81
82        # make a router to connect all of the nodes
83        self.router = Router(router_id=self.num_routers())
84        network.routers.append(self.router)
85
86        for node in self.nodes:
87            if type(node) == Cluster:
88                node.makeTopology(options, network, IntLink,
89                                  ExtLink, Router)
90
91                # connect this cluster to the router
92                link_out = IntLink(link_id=self.num_int_links(), src_node=self.router,
93                           dst_node=node.router)
94                link_in = IntLink(link_id=self.num_int_links(), src_node=node.router,
95                                  dst_node=self.router)
96
97                if node.extBW:
98                    link_out.bandwidth_factor = node.extBW
99                    link_in.bandwidth_factor = node.extBW
100
101                # if there is an internal b/w for this node
102                # and no ext b/w to override
103                elif self.intBW:
104                    link_out.bandwidth_factor = self.intBW
105                    link_in.bandwidth_factor = self.intBW
106
107                if node.extLatency:
108                    link_out.latency = node.extLatency
109                    link_in.latency = node.extLatency
110                elif self.intLatency:
111                    link_out.latency = self.intLatency
112                    link_in.latency = self.intLatency
113
114                network.int_links.append(link_out)
115                network.int_links.append(link_in)
116            else:
117                # node is just a controller,
118                # connect it to the router via a ext_link
119                link = ExtLink(link_id=self.num_ext_links(), ext_node=node,
120                        int_node=self.router)
121
122                if self.intBW:
123                    link.bandwidth_factor = self.intBW
124                if self.intLatency:
125                    link.latency = self.intLatency
126
127                network.ext_links.append(link)
128
129    def __len__(self):
130        return len([i for i in self.nodes if type(i) != Cluster]) + \
131               sum([len(i) for i in self.nodes if type(i) == Cluster])
132