-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoverlay.py
351 lines (260 loc) · 10.6 KB
/
overlay.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
#!/usr/bin/env python
#
# Copyright (c) 2013-2016, ETH Zurich.
# All rights reserved.
#
# This file is distributed under the terms in the attached LICENSE file.
# If you do not find this file, copies can be found by writing to:
# ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
import scheduling
import helpers
import naive
import logging
import hybrid_model
from pygraph.classes.graph import graph
from pygraph.classes.digraph import digraph
class Overlay(object):
"""
Base class for finding the right overlay topology for a model
"""
"""Broadcast tree - expressed as a hybrid model. List of hybrid_model.MPTree
"""
tree = None
def __init__(self, mod):
"""
Initialize
"""
import model
assert isinstance(mod, model.Model)
self.mod = mod
self.tree = None
self.options = {}
def set_arguments(self, args):
"""Used to pass arguments to the overlay. Arguments are given like
this: adaptivetree-optimized
@param args list of strings
"""
for a in args:
print ('Overlay: activating argument: [%s]' % a)
self.options[a] = True
# Some options have to be passed to the Machine
if a == 'mm':
self.mod.enable_mm = True
def _get_broadcast_tree(self):
"""
Return the broadcast tree as a graph
:returns graph: Broadcast tree as graph
"""
tmp = self._build_tree(self.mod.get_graph())
assert isinstance(tmp, digraph)
return tmp
def _get_multicast_tree(self, g):
"""
Return the multicast tree for the given subtree of the original model
:param graph g: Input graph as subset of model to build the MC for
:returns graph: Multicast tree as graph
"""
return self._build_tree(g)
def _build_tree(self, g):
"""
Actual implementation of getting a {multi,broad}cast-tree.
This includes the edge weight, which is the propagation time.
:TODO: Make sure _build_tree returns a bigraph, also, make sure it has weights!
:param graph g: A graph with group members as nodes and weighted edges expressing the cost of sending a message
"""
raise Exception("Subclasses need to provide algorithm to build a tree")
def get_root_node(self):
"""
Return root node. If model does not have any constraints, just
start at 0.
"""
if self.mod.get_root_node():
return self.mod.get_root_node()
else:
# Choose root as first node in topology
return self.mod.get_cores(True)[0]
def get_name(self):
return None
def get_tree(self):
"""
Return previously generated tree. Functions generating a tree are:
:py:func:`get_broadcast_tree`, :py:func:`get_random_multicast_tree`
or :py:func:`get_multicast_tree`.
:returns: Previously generated tree
:rtype: List of :py:class:`hybrid_model.HybridModule`
"""
return self.tree
def get_broadcast_tree(self):
"""
Return broadcast tree
Will call _get_broadcast_tree on first execution and store
tree in broadcast_tree.
"""
if self.tree is None:
print ("Generating model")
# Get tree
tmp = self._get_broadcast_tree()
# Debug output of tree
fname = '%s_%s' % (self.mod.get_name(), self.get_name())
helpers.output_clustered_graph(tmp, fname, self.mod.get_numa_information())
if isinstance(tmp, graph) or isinstance(tmp, digraph):
self.tree = [ hybrid_model.MPTree(tmp, self) ]
elif isinstance(tmp, list):
self.tree = tmp
else:
import pdb; pdb.set_trace()
raise Exception('Result of _get_broadcast_tree is of unsupported data type')
assert not self.tree is None
return self.tree
def get_multicast_tree(self, nodes):
"""
Build a multicast tree for the given set of nodes
"""
mctree = digraph()
# Copy nodes
for n in nodes:
assert n in self.mod.get_graph().nodes()
mctree.add_node(n)
# Copy edges
for (s,d) in self.mod.get_graph().edges():
if s in nodes and d in nodes:
mctree.add_edge((s,d), self.mod.get_graph().edge_weight((s,d)))
self.tree = [ hybrid_model.MPTree(self._get_multicast_tree(mctree), self) ]
return self.tree
def get_coordinators(self):
"""
Selects one coordinator per node for given model.
"""
coordinators=[]
for core in range(len(self.mod.get_graph())):
# Add coordinator only if in active nodes, i.e. participating in multicast
new_coordinator = len(self.mod.filter_active_cores([core], True))>0
for c in coordinators:
if self.mod.on_same_numa_node(core, c):
new_coordinator = False
if new_coordinator:
coordinators.append(core)
coordinators = self.mod.filter_active_cores(coordinators, True)
print ("Coordinator nodes are: %s" % str(coordinators))
return coordinators
def get_scheduler(self, final_graph):
"""Return a scheduler for the given topology and graph.
"""
print ("Initializing scheduler in overlay: %s" % str(final_graph))
return naive.Naive(final_graph)
@staticmethod
def get_overlay_class(overlay_name):
"""
Return subclass of overlay that matches the given name
"""
import mst
import cluster
import binarytree
import sequential
import badtree
import adaptive
import fibonacci
d = {
'mst': mst.Mst,
'cluster': cluster.Cluster,
'bintree': binarytree.BinaryTree,
'sequential': sequential.Sequential,
'badtree': badtree.BadTree,
'adaptivetree': adaptive.AdapativeTree,
'fibonacci': fibonacci.Fibonacci
}
if overlay_name in d:
r = d[overlay_name]
else:
supported = ', '.join([ x for (x, _) in d.items()])
raise Exception('Unknown topology %s - Supported are: %s' % \
(overlay_name, supported))
return r
@staticmethod
def get_overlay(overlay_name, topo):
"""
@param topo That seems to be the machine!
"""
import hybrid
overlay = overlay_name.split('-')
overlay_name = overlay[0]
overlay_args = overlay[1:]
if overlay_name == 'shm':
r = hybrid.Hybrid(topo, None)
elif overlay_name.startswith('hybrid_'):
e = overlay_name.split('_')
print ('Detected hybrid model with base class', e[1])
r_mp_class = Overlay.get_overlay_class(e[1])
assert len(overlay_args) == 0 # Don't know how to pass the
# arguments for Hybrids
r = hybrid.Hybrid(topo, r_mp_class)
else:
o = Overlay.get_overlay_class(overlay_name)
r = o(topo)
r.set_arguments(overlay_args)
return r
def get_leaf_nodes(self, sched):
"""Return leaf nodes in this topology
@param sched scheduling.Scheduling The scheduler, which knows
the final schedule. This is necessary as - for some reason -
the tree stored with the overlay has edges in both directions
for each connection in the broadcast tree.
I think this is a bug, and once it is fixed, the Scheduler
should really not be needed here.
"""
assert isinstance(sched, scheduling.Scheduling)
leaf_nodes = []
for x in self.tree:
if isinstance(x, hybrid_model.MPTree):
logging.info(("Found message passing model", str(x.graph)))
tree = x.graph
for n in tree.nodes():
# OMG, edges are even dublicated in the Scheduler
# for some topologies! How would I ever figure
# out which are the last nodes ..
# Currently working correctly are:
# - adaptive tree
# - binary tree
# - clustered
# - sequential
# - fibonacci
# - mst
# - badtree
l = [ y for (x,y) in tree.edges() if x == n ]
# For some Overlays, it seems that there are edges
# in the broadcast tree that are not atually used
# in the final Schedule. I saw this happening
# especially because for each edge (s, r), there
# is also (r, s) in the broadcast tree.
l_ = [ r for r in l if r in \
[ rr for (_, rr) in sched.get_final_schedule(n)] ]
if len(l) != len(l_):
helpers.warn('Overlay contains edged that are not in final schedule. This is a bug')
if len(l_)==0:
logging.info((n, 'is a leaf node'))
leaf_nodes.append(n)
return leaf_nodes
def get_parents(self, sched):
"""Return a dict with each cores parent node
"""
assert isinstance(sched, scheduling.Scheduling)
parents = {}
for x in self.tree:
if isinstance(x, hybrid_model.MPTree):
logging.info(("Found message passing model", str(x.graph)))
tree = x.graph
for n in tree.nodes():
l = [ y for (x,y) in tree.edges() if x == n ]
# For some Overlays, it seems that there are edges
# in the broadcast tree that are not atually used
# in the final Schedule. I saw this happening
# especially because for each edge (s, r), there
# is also (r, s) in the broadcast tree.
l_ = [ r for r in l if r in \
[ rr for (_, rr) in sched.get_final_schedule(n)] ]
if len(l) != len(l_):
helpers.warn('Overlay contains edged that are not in final schedule. This is a bug')
logging.info(('Found children for', n, ' to ', str(l)))
for child in l:
parents[child] = n
return parents