The Gaudi Framework  v36r9p1 (5c15b2bb)
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 argparse
18 import operator
19 import re
20 import sys
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 
70  algcolors = range(2, 10) + [20, 28, 29, 30, 33, 38, 40] + range(41, 50)
71  evtcolors = [
72  TColor.GetColor(0, 255 - g, g) for g in range(20, 255, (255 - 20) / nevtcolors)
73  ]
74 
75 
76 def 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.iteritems():
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.iteritems(), 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  raw_input()
180  return c
181 
182 
183 def main():
184  parser = argparse.ArgumentParser(description=__doc__)
185 
186  parser.add_argument("timeline", nargs=1, help="timeline file")
187 
188  parser.add_argument(
189  "-s", "--select", default=".*", help="Regular expression to filter algorithms"
190  )
191 
192  parser.add_argument(
193  "-b",
194  "--batch",
195  action="store_true",
196  default=False,
197  help="Do not wait for user input",
198  )
199 
200  parser.add_argument(
201  "--slots",
202  action="store_true",
203  default=False,
204  help="Show slots instead of threads (leads to overlaps!)",
205  )
206 
207  parser.add_argument(
208  "-p",
209  "--print",
210  dest="outfile",
211  nargs="?",
212  const="timeline.png",
213  help="Save to FILE [%(const)s]",
214  )
215 
216  parser.add_argument(
217  "-n",
218  "--nevtcolors",
219  default=10,
220  type=int,
221  help="Number of colors used for events (10 is default)",
222  )
223 
224  parser.add_argument(
225  "-e",
226  "--skipevents",
227  default=0,
228  type=int,
229  help="Number of events to skip at the start",
230  )
231 
232  parser.add_argument(
233  "-x", "--width", default=1200, type=int, help="width of the output picture"
234  )
235 
236  parser.add_argument(
237  "-y", "--height", default=500, type=int, help="height of the output picture"
238  )
239 
240  args = parser.parse_args()
241 
242  data = read(args.timeline[0], args.select, args.skipevents)
243  c = plot(data, not args.slots, args.batch, args.nevtcolors, args.width, args.height)
244  if args.outfile:
245  c.SaveAs(args.outfile)
246 
247  return 0
248 
249 
250 if __name__ == "__main__":
251  sys.exit(main())
hivetimeline.Data
Definition: hivetimeline.py:29
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:183
ProduceConsume.Data
Data
Definition: ProduceConsume.py:170
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.read
def read(f, regex=".*", skipevents=0)
Definition: hivetimeline.py:33
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:102