The Gaudi Framework
master (53dee381)
Toggle main menu visibility
Loading...
Searching...
No Matches
precedence.py
Go to the documentation of this file.
1
11
import
json
12
import
os
13
import
random
14
import
sys
15
16
# FIXME: workaround for the old version of networkx in LCG 100
17
import
warnings
18
19
warnings.filterwarnings(
"ignore"
, message=
'"is" with a literal'
, category=SyntaxWarning)
20
21
import
networkx
as
nx
22
from
Configurables
import
CPUCruncher, Gaudi__Sequencer
23
24
from
Gaudi.Configuration
import
INFO
25
26
27
def
_buildFilePath
(filePath):
28
if
not
os.path.exists(filePath):
29
__fullFilePath__ = os.path.realpath(
30
os.path.join(
31
os.environ.get(
"ENV_PROJECT_SOURCE_DIR"
,
""
),
32
"GaudiHive"
,
33
"data"
,
34
filePath,
35
)
36
)
37
if
not
os.path.exists(__fullFilePath__):
38
__fullFilePath__ = os.path.realpath(
39
os.path.join(
40
os.environ.get(
"ENV_PROJECT_SOURCE_DIR"
,
""
),
41
"Gaudi"
,
42
"GaudiHive"
,
43
"data"
,
44
filePath,
45
)
46
)
47
if
not
os.path.exists(__fullFilePath__):
48
print(
49
f
"\nERROR: invalid file path '{filePath}'. "
50
"It must be either absolute, or relative to "
51
"'$ENV_PROJECT_SOURCE_DIR/GaudiHive/data/' or to "
52
"'$ENV_PROJECT_SOURCE_DIR/Gaudi/GaudiHive/data/'."
53
)
54
sys.exit(1)
55
else
:
56
__fullFilePath__ = filePath
57
58
return
__fullFilePath__
59
60
61
class
UniformTimeValue
:
62
"""A class to manage uniform algorithm timing"""
63
64
def
__init__
(self, avgRuntime, varRuntime=0):
65
self.
avgRuntime
= avgRuntime
66
self.
varRuntime
= varRuntime
67
68
def
get
(self, algoName=""):
69
"""Get time and its variance (in a tuple) for a given algorithm name"""
70
71
return
self.
avgRuntime
, self.
varRuntime
72
73
74
class
RealTimeValue
:
75
"""A class to manage real algorithm timing"""
76
77
def
__init__
(self, path, defaultTime, factor=1):
78
"""
79
defaultTime -- run time, assigned to an algorithm if no time is found in provided timing library
80
(and it will also be scaled by the 'factor' argument)
81
"""
82
83
self.
path
= os.path.realpath(
_buildFilePath
(path))
84
self.
factor
= factor
85
self.
defaultTime
= defaultTime
# typically 0.05s
86
self.
varRuntime
= 0
87
88
self.
file
= open(self.
path
)
89
self.
timings
= json.load(self.
file
)
90
91
def
get
(self, algoName=""):
92
"""Get time for a given algorithm name"""
93
94
if
algoName
in
self.
timings
:
95
time = float(self.
timings
[algoName])
96
else
:
97
capAlgoName = algoName[0].upper() + algoName[1 : len(algoName)]
98
99
if
capAlgoName
in
self.
timings
:
100
time = float(self.
timings
[capAlgoName])
101
else
:
102
time = self.
defaultTime
103
print(
104
f
"WARNING: Timing for {algoName} (or {capAlgoName}) not found in the provided library, using default one: {time}"
105
)
106
107
time = time * self.
factor
108
109
return
time, self.
varRuntime
110
111
112
class
UniformBooleanValue
:
113
def
__init__
(self, value):
114
self.
value
= value
115
116
def
get
(self):
117
return
self.
value
118
119
120
class
RndBiasedBooleanValue
:
121
"""Provides randomly ordered set of boolean values with requested proportion of True and False."""
122
123
def
__init__
(self, pattern, seed=None):
124
"""
125
Keyword arguments:
126
pattern -- either a dictionary describing proportion of True and False (e.g., {True:5,False:15}), or
127
a list/tuple containing a pattern to be used as-is (e.g., [False,True,True,False])
128
seed -- an int, long or other hashable object to initialize random number generator (passed to random.shuffle as-is)
129
"""
130
131
if
isinstance(pattern, dict):
132
proportion = pattern
133
134
length = proportion[
True
] + proportion[
False
]
135
if
length <= 0:
136
raise
ValueError(f
"Wrong set length requested: {length}"
)
137
138
self.
pattern
= [
False
for
i
in
range(proportion[
False
])] + [
139
True
for
i
in
range(proportion[
True
])
140
]
141
142
if
seed
is
not
None
:
143
random.seed(seed)
144
145
random.shuffle(self.
pattern
)
146
147
elif
isinstance(pattern, (list, tuple)):
148
self.
pattern
= pattern
149
else
:
150
raise
"ERROR: unknown pattern type"
151
152
self.
generator
= self.
_create_generator
(self.
pattern
)
153
154
def
_create_generator
(self, pattern):
155
yield
from
pattern
156
157
def
get
(self):
158
return
next(self.
generator
)
159
160
def
get_pattern
(self):
161
return
self.
pattern
162
163
164
class
CruncherSequence
:
165
"""Constructs the sequence tree of CPUCrunchers with provided control flow and data flow precedence rules."""
166
167
unique_sequencers = []
168
dupl_seqs = {}
169
OR_sequencers = []
170
unique_algos = []
171
dupl_algos = {}
172
173
unique_data_objects = []
174
175
def
__init__
(
176
self,
177
timeValue,
178
BlockingBoolValue,
179
sleepFraction,
180
cfgPath,
181
dfgPath,
182
topSequencer,
183
showStat=False,
184
timeline=False,
185
outputLevel=INFO,
186
cardinality=1,
187
):
188
"""
189
Keyword arguments:
190
timeValue -- timeValue object to set algorithm execution time
191
BlockingBoolValue -- *BooleanValue object to set whether an algorithm has to experience CPU-blocking execution
192
cfgPath -- relative to $ENV_PROJECT_SOURCE_DIR/GaudiHive/data path to GRAPHML file with control flow dependencies
193
dfgPath -- relative to $ENV_PROJECT_SOURCE_DIR/GaudiHive/data path to GRAPHML file with data flow dependencies
194
showStat -- print out statistics on precedence graph
195
"""
196
197
self.
cardinality
= cardinality
198
self.
timeValue
= timeValue
199
self.
BlockingBoolValue
= BlockingBoolValue
200
self.
sleepFraction
= sleepFraction
201
202
self.
cfg
= nx.read_graphml(
_buildFilePath
(cfgPath))
203
self.
dfg
= nx.read_graphml(
_buildFilePath
(dfgPath))
204
205
self.
enableTimeline
= timeline
206
207
self.
outputLevel
= outputLevel
208
209
# Generate control flow part
210
self.
sequencer
= self.
_generate_sequence
(topSequencer)
211
212
if
showStat:
213
print(
"\n===== Statistics on Algorithms ====="
)
214
print(
215
"Total number of algorithm nodes: "
,
216
len(self.
unique_algos
)
217
+ sum([self.
dupl_algos
[i] - 1
for
i
in
self.
dupl_algos
]),
218
)
219
print(
"Number of unique algorithms: "
, len(self.
unique_algos
))
220
print(
221
" -->"
,
222
len(self.
dupl_algos
),
223
"of them being re-used with the following distribution: "
,
224
[self.
dupl_algos
[i]
for
i
in
self.
dupl_algos
],
225
)
226
# pprint.pprint(dupl_algos)
227
228
print(
"\n===== Statistics on Sequencers ====="
)
229
print(
230
"Total number of sequencers: "
,
231
len(self.
unique_sequencers
)
232
+ sum([self.
dupl_seqs
[i] - 1
for
i
in
self.
dupl_seqs
]),
233
)
234
print(
"Number of unique sequencers: "
, len(self.
unique_sequencers
))
235
print(
236
" -->"
,
237
len(self.
dupl_seqs
),
238
"of them being re-used with the following distribution: "
,
239
[self.
dupl_seqs
[i]
for
i
in
self.
dupl_seqs
],
240
)
241
# pprint.pprint(dupl_seqs)
242
print(
"Number of OR-sequencers: "
, len(self.
OR_sequencers
))
243
244
print(
"\n===== Statistics on DataObjects ====="
)
245
print(
"Number of unique DataObjects: "
, len(self.
unique_data_objects
))
246
# pprint.pprint(self.unique_data_objects)
247
print()
248
249
def
get
(self):
250
return
self.
sequencer
251
252
def
_declare_data_deps
(self, algo_name, algo):
253
"""Declare data inputs and outputs for a given algorithm."""
254
255
# Declare data inputs
256
for
inNode, outNode
in
self.
dfg
.in_edges(algo_name):
257
dataName = inNode
258
if
dataName
not
in
self.
unique_data_objects
:
259
self.
unique_data_objects
.append(dataName)
260
261
if
dataName
not
in
algo.inpKeys:
262
algo.inpKeys.append(dataName)
263
264
# Declare data outputs
265
for
inNode, outNode
in
self.
dfg
.out_edges(algo_name):
266
dataName = outNode
267
if
dataName
not
in
self.
unique_data_objects
:
268
self.
unique_data_objects
.append(dataName)
269
270
if
dataName
not
in
algo.outKeys:
271
algo.outKeys.append(dataName)
272
273
def
_generate_sequence
(self, name, seq=None):
274
"""Assemble the tree of sequencers."""
275
276
if
not
seq:
277
seq = Gaudi__Sequencer(name, ShortCircuit=
False
)
278
279
for
n
in
self.
cfg
[name]:
280
# extract entity name and type
281
algo_name = n.split(
"/"
)[1]
if
"/"
in
n
else
n
282
283
if
"type"
in
self.
cfg
.nodes[n]:
284
# first rely on explicit type, if given
285
algo_type = self.
cfg
.nodes[n].
get
(
"type"
)
286
else
:
287
# if the type is not given explicitly, try to extract it from entity name,
288
# and, if unsuccessful, assume it is an algorithm
289
algo_type = n.split(
"/"
)[0]
if
"/"
in
n
else
"Algorithm"
290
291
if
algo_type
in
[
"GaudiSequencer"
,
"AthSequencer"
,
"ProcessPhase"
]:
292
if
algo_name
in
[
"RecoITSeq"
,
"RecoOTSeq"
,
"RecoTTSeq"
]:
293
continue
294
295
if
n
not
in
self.
unique_sequencers
:
296
self.
unique_sequencers
.append(n)
297
else
:
298
if
n
not
in
self.
dupl_seqs
:
299
self.
dupl_seqs
[n] = 2
300
else
:
301
self.
dupl_seqs
[n] += 1
302
303
seq_daughter = Gaudi__Sequencer(algo_name, OutputLevel=INFO)
304
if
self.
cfg
.nodes[n].
get
(
"ModeOR"
) ==
"True"
:
305
self.
OR_sequencers
.append(n)
306
seq_daughter.ModeOR =
True
307
# if self.cfg.nodes[n].get('Lazy') == 'False':
308
# print "Non-Lazy - ", n
309
seq_daughter.ShortCircuit =
False
310
if
seq_daughter
not
in
seq.Members:
311
seq.Members += [seq_daughter]
312
# iterate deeper
313
self.
_generate_sequence
(n, seq_daughter)
314
else
:
315
# rndname = ''.join(random.choice(string.lowercase) for i in range(5))
316
# if algo_name in unique_algos: algo_name = algo_name + "-" + rndname
317
if
n
not
in
self.
unique_algos
:
318
self.
unique_algos
.append(n)
319
else
:
320
if
n
not
in
self.
dupl_algos
:
321
self.
dupl_algos
[n] = 2
322
else
:
323
self.
dupl_algos
[n] += 1
324
325
avgRuntime, varRuntime = self.
timeValue
.
get
(algo_name)
326
327
algo_daughter =
CPUCruncher
(
328
algo_name,
329
Cardinality=self.
cardinality
,
330
OutputLevel=self.
outputLevel
,
331
varRuntime=varRuntime,
332
avgRuntime=avgRuntime,
333
SleepFraction=self.
sleepFraction
334
if
self.
BlockingBoolValue
.
get
()
335
else
0.0,
336
Timeline=self.
enableTimeline
,
337
)
338
339
self.
_declare_data_deps
(algo_name, algo_daughter)
340
341
if
algo_daughter
not
in
seq.Members:
342
seq.Members += [algo_daughter]
343
344
return
seq
CPUCruncher
A class that implements a search for prime numbers.
Definition
CPUCruncher.h:30
precedence.CruncherSequence
Definition
precedence.py:164
precedence.CruncherSequence.unique_data_objects
list unique_data_objects
Definition
precedence.py:173
precedence.CruncherSequence.BlockingBoolValue
BlockingBoolValue
Definition
precedence.py:199
precedence.CruncherSequence.timeValue
timeValue
Definition
precedence.py:198
precedence.CruncherSequence.__init__
__init__(self, timeValue, BlockingBoolValue, sleepFraction, cfgPath, dfgPath, topSequencer, showStat=False, timeline=False, outputLevel=INFO, cardinality=1)
Definition
precedence.py:187
precedence.CruncherSequence._declare_data_deps
_declare_data_deps(self, algo_name, algo)
Definition
precedence.py:252
precedence.CruncherSequence.unique_sequencers
list unique_sequencers
Definition
precedence.py:167
precedence.CruncherSequence._generate_sequence
_generate_sequence(self, name, seq=None)
Definition
precedence.py:273
precedence.CruncherSequence.sequencer
sequencer
Definition
precedence.py:210
precedence.CruncherSequence.dfg
dfg
Definition
precedence.py:203
precedence.CruncherSequence.unique_algos
list unique_algos
Definition
precedence.py:170
precedence.CruncherSequence.enableTimeline
enableTimeline
Definition
precedence.py:205
precedence.CruncherSequence.get
get(self)
Definition
precedence.py:249
precedence.CruncherSequence.dupl_algos
dict dupl_algos
Definition
precedence.py:171
precedence.CruncherSequence.sleepFraction
sleepFraction
Definition
precedence.py:200
precedence.CruncherSequence.OR_sequencers
list OR_sequencers
Definition
precedence.py:169
precedence.CruncherSequence.cfg
cfg
Definition
precedence.py:202
precedence.CruncherSequence.cardinality
cardinality
Definition
precedence.py:197
precedence.CruncherSequence.outputLevel
outputLevel
Definition
precedence.py:207
precedence.CruncherSequence.dupl_seqs
dict dupl_seqs
Definition
precedence.py:168
precedence.RealTimeValue
Definition
precedence.py:74
precedence.RealTimeValue.__init__
__init__(self, path, defaultTime, factor=1)
Definition
precedence.py:77
precedence.RealTimeValue.defaultTime
defaultTime
Definition
precedence.py:85
precedence.RealTimeValue.get
get(self, algoName="")
Definition
precedence.py:91
precedence.RealTimeValue.timings
timings
Definition
precedence.py:89
precedence.RealTimeValue.path
path
Definition
precedence.py:83
precedence.RealTimeValue.file
file
Definition
precedence.py:88
precedence.RealTimeValue.varRuntime
int varRuntime
Definition
precedence.py:86
precedence.RealTimeValue.factor
factor
Definition
precedence.py:84
precedence.RndBiasedBooleanValue
Definition
precedence.py:120
precedence.RndBiasedBooleanValue.get
get(self)
Definition
precedence.py:157
precedence.RndBiasedBooleanValue.generator
generator
Definition
precedence.py:152
precedence.RndBiasedBooleanValue.__init__
__init__(self, pattern, seed=None)
Definition
precedence.py:123
precedence.RndBiasedBooleanValue._create_generator
_create_generator(self, pattern)
Definition
precedence.py:154
precedence.RndBiasedBooleanValue.pattern
list pattern
Definition
precedence.py:138
precedence.RndBiasedBooleanValue.get_pattern
get_pattern(self)
Definition
precedence.py:160
precedence.UniformBooleanValue
Definition
precedence.py:112
precedence.UniformBooleanValue.value
value
Definition
precedence.py:114
precedence.UniformBooleanValue.__init__
__init__(self, value)
Definition
precedence.py:113
precedence.UniformBooleanValue.get
get(self)
Definition
precedence.py:116
precedence.UniformTimeValue
Definition
precedence.py:61
precedence.UniformTimeValue.avgRuntime
avgRuntime
Definition
precedence.py:65
precedence.UniformTimeValue.get
get(self, algoName="")
Definition
precedence.py:68
precedence.UniformTimeValue.__init__
__init__(self, avgRuntime, varRuntime=0)
Definition
precedence.py:64
precedence.UniformTimeValue.varRuntime
varRuntime
Definition
precedence.py:66
Gaudi.Configuration
Definition
Configuration.py:1
precedence._buildFilePath
_buildFilePath(filePath)
Definition
precedence.py:27
GaudiHive
python
GaudiHive
precedence.py
Generated on
for The Gaudi Framework by
1.17.0