The Gaudi Framework  master (37c0b60a)
hivetimeline.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
12 """Plot timeline from TimelineSvc"""
13 
14 __author__ = "Frank Winklmeier"
15 
16 import argparse
17 import operator
18 import re
19 import sys
20 from collections import defaultdict
21 
22 algcolors = []
23 evtcolors = []
24 
25 # Attributes will be added in read()
26 
27 
28 class Data:
29  pass
30 
31 
32 def read(f, regex=".*", skipevents=0):
33  data = []
34  regex = re.compile(regex)
35  for l in open(f, "r"):
36  if l.startswith("#"): # e.g. #start end algorithm thread slot event
37  names = l.lstrip("#").split()
38  continue
39  d = Data()
40  for i, f in enumerate(l.split()):
41  setattr(d, names[i], int(f) if f.isdigit() else f)
42  if d.event >= skipevents:
43  data.append(d)
44  return data
45 
46 
47 def findEvents(data):
48  """Find event start/stop times"""
49 
50  t = defaultdict(lambda: [sys.maxsize, 0, -1]) # start,stop,slot
51  nbslots = 0
52  for d in data:
53  if d.start < t[d.event][0]:
54  t[d.event][0] = d.start
55  t[d.event][2] = d.slot
56  if d.end > t[d.event][1]:
57  t[d.event][1] = d.end
58  if d.slot > nbslots:
59  nbslots = d.slot
60 
61  return t, nbslots
62 
63 
64 def setPalette(nevts, nevtcolors):
65  global algcolors, evtcolors
66 
67  from ROOT import TColor
68 
69  algcolors = list(range(2, 10)) + [20, 28, 29, 30, 33, 38, 40] + list(range(41, 50))
70  evtcolors = [
71  TColor.GetColor(0, 255 - g, g) for g in range(20, 255, (255 - 20) // nevtcolors)
72  ]
73 
74 
75 def plot(data, showThreads=True, batch=False, nevtcolors=10, width=1200, height=500):
76  import ROOT
77 
78  tmin = min(f.start for f in data)
79  tmax = max(f.end for f in data)
80  slots = 1 + max(f.slot for f in data)
81  threads = sorted(list(set(f.thread for f in data)))
82  threadid = dict((k, v) for v, k in enumerate(threads)) # map thread : id
83  ymax = len(threads) if showThreads else slots
84 
85  c = ROOT.TCanvas("timeline", "Timeline", width, height)
86  c.SetLeftMargin(0.05)
87  c.SetRightMargin(0.2)
88  c.SetTopMargin(0.1)
89  c.SetBottomMargin(0.1)
90  c.coord = ROOT.TH2I("coord", ";Time (ns)", 100, 0, tmax - tmin, ymax, 0, ymax)
91  c.coord.GetYaxis().SetTitle(("Thread" if showThreads else "Slot"))
92  c.coord.GetYaxis().SetTitleOffset(0.5)
93  c.coord.GetYaxis().CenterTitle()
94  c.coord.SetStats(False)
95  c.coord.GetYaxis().SetNdivisions(ymax)
96  c.coord.GetXaxis().CenterTitle()
97 
98  c.Draw()
99  c.coord.Draw()
100 
101  c.lines = []
102  colors = {}
103  setPalette(ymax, nevtcolors)
104  mycolors = algcolors
105  for d in data:
106  y = threadid[d.thread] if showThreads else d.slot
107  alg = d.algorithm
108  if alg not in colors and len(mycolors) > 0:
109  colors[alg] = mycolors.pop(0)
110  if len(mycolors) == 0:
111  print("Too many algorithm to show")
112 
113  if alg in colors:
114  t0 = d.start - tmin
115  t1 = d.end - tmin
116 
117  # Alg
118  l = ROOT.TBox(t0, y + 0.1, t1, y + 0.8)
119  l.SetFillColor(colors[alg])
120 
121  # Event
122  l2 = ROOT.TBox(t0, y + 0.8, t1, y + 0.9)
123  l2.SetFillColor(evtcolors[d.event % nevtcolors])
124  c.lines += [l, l2]
125 
126  l2.Draw()
127  l.Draw()
128 
129  # Global event timeline
130  tevt, nbslots = findEvents(data)
131  bheight = 0.1
132  for k, v in tevt.items():
133  y = ymax + bheight * v[2]
134  l = ROOT.TBox(v[0] - tmin, y + 0.2 * bheight, v[1] - tmin, y + bheight)
135  l.SetFillColor(evtcolors[k % nevtcolors])
136  c.lines += [l]
137  l.Draw()
138 
139  # Alg legend
140  c.leg = ROOT.TLegend(0.8, 0.4, 0.98, 0.9)
141  for alg, cl in sorted(colors.items(), key=operator.itemgetter(1)):
142  e = c.leg.AddEntry("", alg, "F")
143  e.SetLineColor(cl)
144  e.SetFillColor(cl)
145  e.SetFillStyle(1001)
146 
147  # Event legend
148  bwidth = 0.18 / nevtcolors
149  for cl in range(nevtcolors):
150  l = ROOT.TLine()
151  c.lines.append(l)
152  l.SetLineWidth(10)
153  l.SetLineColor(evtcolors[cl])
154  l.DrawLineNDC(0.807 + bwidth * cl, 0.37, 0.807 + bwidth * (cl + 1), 0.37)
155 
156  c.t1 = ROOT.TText(0.807, 0.314, "Events")
157  c.t1.SetNDC()
158  c.t1.SetTextFont(42)
159  c.t1.SetTextSize(0.04)
160  c.t1.Draw()
161 
162  c.t2 = ROOT.TText(0.02, 0.92, "Event")
163  c.t2.SetNDC()
164  c.t2.SetTextFont(42)
165  c.t2.SetTextSize(0.03)
166  c.t2.SetTextAngle(90)
167  c.t2.Draw()
168  c.t3 = ROOT.TText(0.03, 0.922, "Slots")
169  c.t3.SetNDC()
170  c.t3.SetTextFont(42)
171  c.t3.SetTextSize(0.03)
172  c.t3.SetTextAngle(90)
173  c.t3.Draw()
174 
175  c.leg.Draw()
176  c.Update()
177  if not batch:
178  eval(input())
179  return c
180 
181 
182 def main():
183  parser = argparse.ArgumentParser(description=__doc__)
184 
185  parser.add_argument("timeline", nargs=1, help="timeline file")
186 
187  parser.add_argument(
188  "-s", "--select", default=".*", help="Regular expression to filter algorithms"
189  )
190 
191  parser.add_argument(
192  "-b",
193  "--batch",
194  action="store_true",
195  default=False,
196  help="Do not wait for user input",
197  )
198 
199  parser.add_argument(
200  "--slots",
201  action="store_true",
202  default=False,
203  help="Show slots instead of threads (leads to overlaps!)",
204  )
205 
206  parser.add_argument(
207  "-p",
208  "--print",
209  dest="outfile",
210  nargs="?",
211  const="timeline.png",
212  help="Save to FILE [%(const)s]",
213  )
214 
215  parser.add_argument(
216  "-n",
217  "--nevtcolors",
218  default=10,
219  type=int,
220  help="Number of colors used for events (10 is default)",
221  )
222 
223  parser.add_argument(
224  "-e",
225  "--skipevents",
226  default=0,
227  type=int,
228  help="Number of events to skip at the start",
229  )
230 
231  parser.add_argument(
232  "-x", "--width", default=1200, type=int, help="width of the output picture"
233  )
234 
235  parser.add_argument(
236  "-y", "--height", default=500, type=int, help="height of the output picture"
237  )
238 
239  args = parser.parse_args()
240 
241  data = read(args.timeline[0], args.select, args.skipevents)
242  c = plot(data, not args.slots, args.batch, args.nevtcolors, args.width, args.height)
243  if args.outfile:
244  c.SaveAs(args.outfile)
245 
246  return 0
247 
248 
249 if __name__ == "__main__":
250  sys.exit(main())
hivetimeline.Data
Definition: hivetimeline.py:28
ConditionsStallTest.Data
Data
Definition: ConditionsStallTest.py:77
hivetimeline.setPalette
def setPalette(nevts, nevtcolors)
Definition: hivetimeline.py:64
hivetimeline.main
def main()
Definition: hivetimeline.py:182
hivetimeline.plot
def plot(data, showThreads=True, batch=False, nevtcolors=10, width=1200, height=500)
Definition: hivetimeline.py:75
hivetimeline.read
def read(f, regex=".*", skipevents=0)
Definition: hivetimeline.py:32
hivetimeline.findEvents
def findEvents(data)
Definition: hivetimeline.py:47
Gaudi::Functional::details::zip::range
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.
Definition: details.h:97