33def read(f, regex=".*", skipevents=0):
35 regex = re.compile(regex)
38 names = l.lstrip(
"#").split()
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:
66 global algcolors, evtcolors
68 from ROOT
import TColor
70 algcolors = list(range(2, 10)) + [20, 28, 29, 30, 33, 38, 40] + list(range(41, 50))
72 TColor.GetColor(0, 255 - g, g)
for g
in range(20, 255, (255 - 20) // nevtcolors)
76def plot(data, showThreads=True, batch=False, nevtcolors=10, width=1200, height=500):
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))
84 ymax = len(threads)
if showThreads
else slots
86 c = ROOT.TCanvas(
"timeline",
"Timeline", width, height)
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()
107 y = threadid[d.thread]
if showThreads
else d.slot
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")
119 l = ROOT.TBox(t0, y + 0.1, t1, y + 0.8)
120 l.SetFillColor(colors[alg])
123 l2 = ROOT.TBox(t0, y + 0.8, t1, y + 0.9)
124 l2.SetFillColor(evtcolors[d.event % nevtcolors])
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])
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")
149 bwidth = 0.18 / nevtcolors
150 for cl
in range(nevtcolors):
154 l.SetLineColor(evtcolors[cl])
155 l.DrawLineNDC(0.807 + bwidth * cl, 0.37, 0.807 + bwidth * (cl + 1), 0.37)
157 c.t1 = ROOT.TText(0.807, 0.314,
"Events")
160 c.t1.SetTextSize(0.04)
163 c.t2 = ROOT.TText(0.02, 0.92,
"Event")
166 c.t2.SetTextSize(0.03)
167 c.t2.SetTextAngle(90)
169 c.t3 = ROOT.TText(0.03, 0.922,
"Slots")
172 c.t3.SetTextSize(0.03)
173 c.t3.SetTextAngle(90)
184 """Write timeline data in Chrome Trace Event JSON format."""
187 trace = {
"traceEvents": []}
188 with open(outfile,
"w")
as f:
192 tmin = min(d.start
for d
in data)
196 threads = sorted(set(d.thread
for d
in data))
197 thread_ids = {thread: idx
for idx, thread
in enumerate(threads, 1)}
202 flows = defaultdict(list)
205 flows[(d.algorithm, d.event)].append(d)
207 for executions
in flows.values():
208 executions.sort(key=
lambda d: d.start)
211 flow_ids = {key: idx
for idx, key
in enumerate(sorted(flows), 1)}
216 for key, executions
in flows.items():
217 flow_id = flow_ids[key]
219 for i, d
in enumerate(executions):
220 tid = thread_ids[d.thread]
222 ts = (d.start - tmin) // 1000
223 dur = (d.end - d.start) // 1000
229 "cat": f
"slot {d.slot}",
243 if len(executions) > 1:
253 flow_event[
"ph"] =
"s"
254 elif i == len(executions) - 1:
255 flow_event[
"ph"] =
"f"
256 flow_event[
"bp"] =
"e"
258 flow_event[
"ph"] =
"t"
260 trace_events.append(flow_event)
263 for thread, tid
in thread_ids.items():
266 "name":
"thread_name",
271 "name": f
"Thread {thread}",
277 "traceEvents": trace_events,
278 "displayTimeUnit":
"ns",
281 with open(outfile,
"w")
as f:
286 parser = argparse.ArgumentParser(
289 "By default, the timeline is plotted using ROOT. Use --chrome-trace "
290 "to export the timeline in Chrome Trace Event JSON format."
294 parser.add_argument(
"timeline", nargs=1, help=
"timeline file")
297 "-s",
"--select", default=
".*", help=
"Regular expression to filter algorithms"
305 help=
"Do not wait for user input",
312 help=
"Show slots instead of threads (leads to overlaps!)",
320 const=
"timeline.png",
321 help=
"Save plot to FILE [%(const)s]",
329 help=
"Number of colors used for events (10 is default)",
337 help=
"Number of events to skip at the start",
341 "-x",
"--width", default=1200, type=int, help=
"width of the output picture"
345 "-y",
"--height", default=500, type=int, help=
"height of the output picture"
351 help=
"Save timeline as Chrome Trace JSON to FILE",
354 args = parser.parse_args()
356 data =
read(args.timeline[0], args.select, args.skipevents)
357 if args.chrome_trace:
361 c =
plot(data,
not args.slots, args.batch, args.nevtcolors, args.width, args.height)
363 c.SaveAs(args.outfile)