The Gaudi Framework  master (bdbe7744)
Loading...
Searching...
No Matches
hivetimeline Namespace Reference

Classes

class  Data

Functions

 read (f, regex=".*", skipevents=0)
 findEvents (data)
 setPalette (nevts, nevtcolors)
 plot (data, showThreads=True, batch=False, nevtcolors=10, width=1200, height=500)
 writeChromeTrace (data, outfile)
 main ()

Variables

str __author__ = "Frank Winklmeier"
 (c) Copyright 1998-2026 CERN for the benefit of the LHCb and ATLAS collaborations # # This software is distributed under the terms of the Apache version 2 licence, # copied verbatim in the file "LICENSE".
list algcolors = []
list evtcolors = []

Function Documentation

◆ findEvents()

findEvents ( data)
Find event start/stop times

Definition at line 48 of file hivetimeline.py.

48def findEvents(data):
49 """Find event start/stop times"""
50
51 t = defaultdict(lambda: [sys.maxsize, 0, -1]) # start,stop,slot
52 nbslots = 0
53 for d in data:
54 if d.start < t[d.event][0]:
55 t[d.event][0] = d.start
56 t[d.event][2] = d.slot
57 if d.end > t[d.event][1]:
58 t[d.event][1] = d.end
59 if d.slot > nbslots:
60 nbslots = d.slot
61
62 return t, nbslots
63
64

◆ main()

main ( )

Definition at line 285 of file hivetimeline.py.

285def main():
286 parser = argparse.ArgumentParser(
287 description=__doc__,
288 epilog=(
289 "By default, the timeline is plotted using ROOT. Use --chrome-trace "
290 "to export the timeline in Chrome Trace Event JSON format."
291 ),
292 )
293
294 parser.add_argument("timeline", nargs=1, help="timeline file")
295
296 parser.add_argument(
297 "-s", "--select", default=".*", help="Regular expression to filter algorithms"
298 )
299
300 parser.add_argument(
301 "-b",
302 "--batch",
303 action="store_true",
304 default=False,
305 help="Do not wait for user input",
306 )
307
308 parser.add_argument(
309 "--slots",
310 action="store_true",
311 default=False,
312 help="Show slots instead of threads (leads to overlaps!)",
313 )
314
315 parser.add_argument(
316 "-p",
317 "--print",
318 dest="outfile",
319 nargs="?",
320 const="timeline.png",
321 help="Save plot to FILE [%(const)s]",
322 )
323
324 parser.add_argument(
325 "-n",
326 "--nevtcolors",
327 default=10,
328 type=int,
329 help="Number of colors used for events (10 is default)",
330 )
331
332 parser.add_argument(
333 "-e",
334 "--skipevents",
335 default=0,
336 type=int,
337 help="Number of events to skip at the start",
338 )
339
340 parser.add_argument(
341 "-x", "--width", default=1200, type=int, help="width of the output picture"
342 )
343
344 parser.add_argument(
345 "-y", "--height", default=500, type=int, help="height of the output picture"
346 )
347
348 parser.add_argument(
349 "--chrome-trace",
350 metavar="FILE",
351 help="Save timeline as Chrome Trace JSON to FILE",
352 )
353
354 args = parser.parse_args()
355
356 data = read(args.timeline[0], args.select, args.skipevents)
357 if args.chrome_trace:
358 writeChromeTrace(data, args.chrome_trace)
359 if not args.outfile:
360 return 0
361 c = plot(data, not args.slots, args.batch, args.nevtcolors, args.width, args.height)
362 if args.outfile:
363 c.SaveAs(args.outfile)
364
365 return 0
366
367
int main()

◆ plot()

plot ( data,
showThreads = True,
batch = False,
nevtcolors = 10,
width = 1200,
height = 500 )

Definition at line 76 of file hivetimeline.py.

76def plot(data, showThreads=True, batch=False, nevtcolors=10, width=1200, height=500):
77 import ROOT
78
79 tmin = min(f.start for f in data)
80 tmax = max(f.end for f in data)
81 slots = 1 + max(f.slot for f in data)
82 threads = sorted(list(set(f.thread for f in data)))
83 threadid = dict((k, v) for v, k in enumerate(threads)) # map thread : id
84 ymax = len(threads) if showThreads else slots
85
86 c = ROOT.TCanvas("timeline", "Timeline", width, height)
87 c.SetLeftMargin(0.05)
88 c.SetRightMargin(0.2)
89 c.SetTopMargin(0.1)
90 c.SetBottomMargin(0.1)
91 c.coord = ROOT.TH2I("coord", ";Time (ns)", 100, 0, tmax - tmin, ymax, 0, ymax)
92 c.coord.GetYaxis().SetTitle("Thread" if showThreads else "Slot")
93 c.coord.GetYaxis().SetTitleOffset(0.5)
94 c.coord.GetYaxis().CenterTitle()
95 c.coord.SetStats(False)
96 c.coord.GetYaxis().SetNdivisions(ymax)
97 c.coord.GetXaxis().CenterTitle()
98
99 c.Draw()
100 c.coord.Draw()
101
102 c.lines = []
103 colors = {}
104 setPalette(ymax, nevtcolors)
105 mycolors = algcolors
106 for d in data:
107 y = threadid[d.thread] if showThreads else d.slot
108 alg = d.algorithm
109 if alg not in colors and len(mycolors) > 0:
110 colors[alg] = mycolors.pop(0)
111 if len(mycolors) == 0:
112 print("Too many algorithm to show")
113
114 if alg in colors:
115 t0 = d.start - tmin
116 t1 = d.end - tmin
117
118 # Alg
119 l = ROOT.TBox(t0, y + 0.1, t1, y + 0.8)
120 l.SetFillColor(colors[alg])
121
122 # Event
123 l2 = ROOT.TBox(t0, y + 0.8, t1, y + 0.9)
124 l2.SetFillColor(evtcolors[d.event % nevtcolors])
125 c.lines += [l, l2]
126
127 l2.Draw()
128 l.Draw()
129
130 # Global event timeline
131 tevt, nbslots = findEvents(data)
132 bheight = 0.1
133 for k, v in tevt.items():
134 y = ymax + bheight * v[2]
135 l = ROOT.TBox(v[0] - tmin, y + 0.2 * bheight, v[1] - tmin, y + bheight)
136 l.SetFillColor(evtcolors[k % nevtcolors])
137 c.lines += [l]
138 l.Draw()
139
140 # Alg legend
141 c.leg = ROOT.TLegend(0.8, 0.4, 0.98, 0.9)
142 for alg, cl in sorted(colors.items(), key=operator.itemgetter(1)):
143 e = c.leg.AddEntry("", alg, "F")
144 e.SetLineColor(cl)
145 e.SetFillColor(cl)
146 e.SetFillStyle(1001)
147
148 # Event legend
149 bwidth = 0.18 / nevtcolors
150 for cl in range(nevtcolors):
151 l = ROOT.TLine()
152 c.lines.append(l)
153 l.SetLineWidth(10)
154 l.SetLineColor(evtcolors[cl])
155 l.DrawLineNDC(0.807 + bwidth * cl, 0.37, 0.807 + bwidth * (cl + 1), 0.37)
156
157 c.t1 = ROOT.TText(0.807, 0.314, "Events")
158 c.t1.SetNDC()
159 c.t1.SetTextFont(42)
160 c.t1.SetTextSize(0.04)
161 c.t1.Draw()
162
163 c.t2 = ROOT.TText(0.02, 0.92, "Event")
164 c.t2.SetNDC()
165 c.t2.SetTextFont(42)
166 c.t2.SetTextSize(0.03)
167 c.t2.SetTextAngle(90)
168 c.t2.Draw()
169 c.t3 = ROOT.TText(0.03, 0.922, "Slots")
170 c.t3.SetNDC()
171 c.t3.SetTextFont(42)
172 c.t3.SetTextSize(0.03)
173 c.t3.SetTextAngle(90)
174 c.t3.Draw()
175
176 c.leg.Draw()
177 c.Update()
178 if not batch:
179 eval(input())
180 return c
181
182

◆ read()

read ( f,
regex = ".*",
skipevents = 0 )

Definition at line 33 of file hivetimeline.py.

33def read(f, regex=".*", skipevents=0):
34 data = []
35 regex = re.compile(regex)
36 for l in open(f):
37 if l.startswith("#"): # e.g. #start end algorithm thread slot event
38 names = l.lstrip("#").split()
39 continue
40 d = Data()
41 for i, f in enumerate(l.split()):
42 setattr(d, names[i], int(f) if f.isdigit() else f)
43 if d.event >= skipevents:
44 data.append(d)
45 return data
46
47

◆ setPalette()

setPalette ( nevts,
nevtcolors )

Definition at line 65 of file hivetimeline.py.

65def setPalette(nevts, nevtcolors):
66 global algcolors, evtcolors
67
68 from ROOT import TColor
69
70 algcolors = list(range(2, 10)) + [20, 28, 29, 30, 33, 38, 40] + list(range(41, 50))
71 evtcolors = [
72 TColor.GetColor(0, 255 - g, g) for g in range(20, 255, (255 - 20) // nevtcolors)
73 ]
74
75

◆ writeChromeTrace()

writeChromeTrace ( data,
outfile )
Write timeline data in Chrome Trace Event JSON format.

Definition at line 183 of file hivetimeline.py.

183def writeChromeTrace(data, outfile):
184 """Write timeline data in Chrome Trace Event JSON format."""
185
186 if not data:
187 trace = {"traceEvents": []}
188 with open(outfile, "w") as f:
189 json.dump(trace, f)
190 return
191
192 tmin = min(d.start for d in data)
193
194 # Perfetto doesn't accept uint64 tids so convert to index starting from 1
195 # but use the original tid in the thread name later
196 threads = sorted(set(d.thread for d in data))
197 thread_ids = {thread: idx for idx, thread in enumerate(threads, 1)}
198
199 # Execution of asynchronous algorithm can be split into multiple ranges,
200 # so group by (algorithm, event) to find all ranges corresponding to the same execution
201 # and create a flow events connecting all individual ranges
202 flows = defaultdict(list)
203
204 for d in data:
205 flows[(d.algorithm, d.event)].append(d)
206
207 for executions in flows.values():
208 executions.sort(key=lambda d: d.start)
209
210 # Assign a unique flow ID to each (algorithm, event) pair.
211 flow_ids = {key: idx for idx, key in enumerate(sorted(flows), 1)}
212
213 trace_events = []
214
215 # Algorithm execution events + flow events
216 for key, executions in flows.items():
217 flow_id = flow_ids[key]
218
219 for i, d in enumerate(executions):
220 tid = thread_ids[d.thread]
221
222 ts = (d.start - tmin) // 1000 # Convert to microseconds
223 dur = (d.end - d.start) // 1000 # Convert to microseconds
224
225 # Create duration slices for individual executions of the algorithm
226 trace_events.append(
227 {
228 "name": d.algorithm,
229 "cat": f"slot {d.slot}",
230 "ph": "X",
231 "pid": 1,
232 "tid": tid,
233 "ts": ts,
234 "dur": dur,
235 "args": {
236 "event": d.event,
237 },
238 }
239 )
240
241 # Connect the individual execution slices by flow events.
242 # A flow event should be enclosed by corresponding duration slice
243 if len(executions) > 1:
244 flow_event = {
245 "name": d.algorithm,
246 "cat": "flow",
247 "pid": 1,
248 "tid": tid,
249 "ts": ts,
250 "id": flow_id,
251 }
252 if i == 0: # start
253 flow_event["ph"] = "s"
254 elif i == len(executions) - 1: # stop
255 flow_event["ph"] = "f"
256 flow_event["bp"] = "e"
257 else: # intermediate
258 flow_event["ph"] = "t"
259
260 trace_events.append(flow_event)
261
262 # Add thread names metadata
263 for thread, tid in thread_ids.items():
264 trace_events.append(
265 {
266 "name": "thread_name",
267 "ph": "M",
268 "pid": 1,
269 "tid": tid,
270 "args": {
271 "name": f"Thread {thread}",
272 },
273 }
274 )
275
276 trace = {
277 "traceEvents": trace_events,
278 "displayTimeUnit": "ns",
279 }
280
281 with open(outfile, "w") as f:
282 json.dump(trace, f)
283
284

Variable Documentation

◆ __author__

str hivetimeline.__author__ = "Frank Winklmeier"
private

(c) Copyright 1998-2026 CERN for the benefit of the LHCb and ATLAS collaborations # # This software is distributed under the terms of the Apache version 2 licence, # copied verbatim in the file "LICENSE".

# # In applying this licence, CERN does not waive the privileges and immunities # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. #

Definition at line 14 of file hivetimeline.py.

◆ algcolors

list hivetimeline.algcolors = []

Definition at line 23 of file hivetimeline.py.

◆ evtcolors

list hivetimeline.evtcolors = []

Definition at line 24 of file hivetimeline.py.