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