diff --git a/PowerDiagram.py b/PowerDiagram.py index 9b19253..72b5a31 100644 --- a/PowerDiagram.py +++ b/PowerDiagram.py @@ -41,6 +41,7 @@ class Machine(object): self.current_capacity_constraint = None # the maximum amperes in this connection self.power_config = power_config self.power_consumption = 0.0 + self.rack_id = None def get_plug(self, plug_name): plugs = {'i': self.input_plugs, 'o': self.output_plugs}[plug_name[0]] @@ -199,6 +200,14 @@ class PowerConfig(object): machine_name = machine.name + # find its rack location + try: + rack_id, rack_slot_index = inventory.get_machine_rack_location(machine_name) + machine.rack_id = rack_id + machine.rack_slot_index = rack_slot_index + except SimpaDbUtil.TableAttrNotFound: + pass + if re.match('[a-z]+.._..', machine_name): # machine_name is a group of machines such as physix80_83 # in this case, we use a hack : the type and power consumption is based on the first machine of this group (in this example physix80) @@ -220,6 +229,7 @@ class PowerConfig(object): if power_consumption is not None: machine.power_consumption = power_consumption + def get_connection_to(self, to_plug): for connection in self.connections: if connection.to_plug == to_plug: @@ -261,6 +271,7 @@ def power_config_to_svg(power_config, svg_file_path): graph = pygraphviz.AGraph() graph.graph_attr['overlap'] = 'false' graph.graph_attr['splines'] = 'true' + graph.graph_attr['rankdir'] = 'LR' # to get hrizontal tree rather than vertical graph.edge_attr['colorscheme'] = 'rdylgn9' # 'brbg11' graph.node_attr['shape'] = 'box' @@ -280,6 +291,31 @@ def power_config_to_svg(power_config, svg_file_path): # graph.add_node('b') # graph.add_edge(u'a',u'b',color='blue') # graph.add_edge(u'b',u'a',color='blue') + racks = {} + + for con in power_config.connections: + for machine in [con.from_plug.machine, con.to_plug.machine]: + rack_id = machine.rack_id + if rack_id is not None: + if rack_id not in racks.keys(): + rack = {} + rack['name'] = rack_id + rack['machines'] = [] + racks[rack_id] = rack + rack = racks[rack_id] + if machine.name not in rack['machines']: + rack['machines'].append(machine) + + if False: + x = 0.0 + for rack in racks.itervalues(): + y = 0.0 + for machine in rack['machines']: + graph.add_node(machine.name, pos='%f,%f!' % (x, y)) # https://observablehq.com/@magjac/placing-graphviz-nodes-in-fixed-positions + print(machine.name, x, y) + y += 1.0 + x += 1.0 + for con in power_config.connections: # print(con.from_plug.machine.name, con.to_plug.machine.name) if not con.is_redundancy_cable(): # don't display redundancy cables, as they might overlap and hide the main one @@ -306,5 +342,19 @@ def power_config_to_svg(power_config, svg_file_path): # color='//%d' % int(9.0-amperes/capacity*8) graph.add_edge(con.from_plug.machine.name, con.to_plug.machine.name, color=color, label=label, penwidth=penwidth) - graph.layout(prog='twopi') + + if True: + for rack_id, rack in racks.iteritems(): + # sub = graph.add_subgraph(rack, name='cluster_%s' % rack_id, rank='same') + machine_names = list(machine.name for machine in rack['machines']) + sub = graph.add_subgraph(machine_names, name='cluster_%s' % rack_id) + sub.graph_attr['label'] = rack_id + # sub.graph_attr['rank']='same' + # assert False + #graph.layout(prog='twopi') + with open('./toto.dot', 'w') as f: + f.write(graph.string()) + + + graph.layout(prog='dot') graph.draw(svg_file_path) diff --git a/inventory.py b/inventory.py index 0c96e5a..4d3a4e7 100644 --- a/inventory.py +++ b/inventory.py @@ -130,6 +130,11 @@ class Inventory(object): ordering_date = datetime.datetime.strptime(ordering_date_as_str, '%d/%m/%Y') return ordering_date + def get_machine_rack_location(self, machine_id): + rack_id = self._sql_reader.get_table_attr('rackable_machine_to_location', 'machine_id', machine_id, 'rack_id') + slot_index = self._sql_reader.get_table_attr('rackable_machine_to_location', 'machine_id', machine_id, 'slot_index') + return rack_id, slot_index + def get_cpu_dflops(self, cpu_model): ''' returns the number of double precision operation per second this cpu can achieve