schedgraph.py revision 173568
1139313Sjeff#!/usr/local/bin/python
2139313Sjeff
3139313Sjeff# Copyright (c) 2002-2003, Jeffrey Roberson <jeff@freebsd.org>
4139313Sjeff# All rights reserved.
5139313Sjeff#
6139313Sjeff# Redistribution and use in source and binary forms, with or without
7139313Sjeff# modification, are permitted provided that the following conditions
8139313Sjeff# are met:
9139313Sjeff# 1. Redistributions of source code must retain the above copyright
10139313Sjeff#    notice unmodified, this list of conditions, and the following
11139313Sjeff#    disclaimer.
12139313Sjeff# 2. Redistributions in binary form must reproduce the above copyright
13139313Sjeff#    notice, this list of conditions and the following disclaimer in the
14139313Sjeff#     documentation and/or other materials provided with the distribution.
15139313Sjeff#
16139313Sjeff# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17139313Sjeff# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18139313Sjeff# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19139313Sjeff# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20139313Sjeff# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21139313Sjeff# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22139313Sjeff# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23139313Sjeff# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24139313Sjeff# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25139313Sjeff# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26139313Sjeff#
27139313Sjeff# $FreeBSD: head/tools/sched/schedgraph.py 173568 2007-11-12 17:33:07Z jeff $
28139313Sjeff
29139313Sjeffimport sys
30139313Sjeffimport re
31139313Sjefffrom Tkinter import *
32139313Sjeff
33139366Sarr# To use:
34139366Sarr# - Install the ports/x11-toolkits/py-tkinter package.
35139366Sarr# - Add KTR_SCHED to KTR_COMPILE and KTR_MASK in your KERNCONF
36139366Sarr# - It is encouraged to increase KTR_ENTRIES size to 32768 to gather
37139366Sarr#    enough information for analysis.
38168940Skris# - Rebuild kernel with proper changes to KERNCONF and boot new kernel.
39168940Skris# - Run your workload to be profiled.
40168940Skris# - While the workload is continuing (i.e. before it finishes), disable
41168940Skris#   KTR tracing by setting 'sysctl debug.ktr.mask=0'.  This is necessary
42168940Skris#   to avoid a race condition while running ktrdump, i.e. the KTR ring buffer
43168940Skris#   will cycle a bit while ktrdump runs, and this confuses schedgraph because
44168940Skris#   the timestamps appear to go backwards at some point.  Stopping KTR logging
45168940Skris#   while the workload is still running is to avoid wasting log entries on
46168940Skris#   "idle" time at the end.
47139366Sarr# - Dump the trace to a file: 'ktrdump -ct > ktr.out'
48139366Sarr# - Run the python script: 'python schedgraph.py ktr.out'
49139366Sarr#
50139366Sarr# To do:
51139313Sjeff# 1)  Add a per-thread summary display
52139313Sjeff# 2)  Add bounding box style zoom.
53139313Sjeff# 3)  Click to center.
54139313Sjeff# 4)  Implement some sorting mechanism.
55168940Skris#
56168940Skris# BUGS: 1) Only 8 CPUs are supported, more CPUs require more choices of
57168940Skris#          colours to represent them ;-)
58168940Skris#       2) Extremely short traces may cause a crash because the code
59168940Skris#          assumes there is always at least one stathz entry logged, and
60168940Skris#          the number of such events is used as a denominator
61139313Sjeff
62139313Sjeffticksps = None
63139313Sjeffstatus = None
64139313Sjeffconfigtypes = []
65139313Sjeff
66139313Sjeffdef ticks2sec(ticks):
67166203Sjeff	us = ticksps / 1000000
68166203Sjeff	ticks /= us
69139313Sjeff	if (ticks < 1000):
70139313Sjeff		return (str(ticks) + "us")
71139313Sjeff	ticks /= 1000
72139313Sjeff	if (ticks < 1000):
73139313Sjeff		return (str(ticks) + "ms")
74139313Sjeff	ticks /= 1000
75139313Sjeff	return (str(ticks) + "s")
76139313Sjeff
77139313Sjeffclass Scaler(Frame):
78139313Sjeff	def __init__(self, master, target):
79139313Sjeff		Frame.__init__(self, master)
80139313Sjeff		self.scale = Scale(self, command=self.scaleset,
81166209Sjeff		    from_=1000, to_=10000000, orient=HORIZONTAL,
82166209Sjeff		    resolution=1000)
83139313Sjeff		self.label = Label(self, text="Ticks per pixel")
84139313Sjeff		self.label.pack(side=LEFT)
85139313Sjeff		self.scale.pack(fill="both", expand=1)
86139313Sjeff		self.target = target
87139313Sjeff		self.scale.set(target.scaleget())
88139313Sjeff		self.initialized = 1
89139313Sjeff
90139313Sjeff	def scaleset(self, value):
91139313Sjeff		self.target.scaleset(int(value))
92139313Sjeff
93139313Sjeff	def set(self, value):
94139313Sjeff		self.scale.set(value)
95139313Sjeff
96139313Sjeffclass Status(Frame):
97139313Sjeff	def __init__(self, master):
98139313Sjeff		Frame.__init__(self, master)
99139313Sjeff		self.label = Label(self, bd=1, relief=SUNKEN, anchor=W)
100139313Sjeff		self.label.pack(fill="both", expand=1)
101139313Sjeff		self.clear()
102139313Sjeff
103139313Sjeff	def set(self, str):
104139313Sjeff		self.label.config(text=str)
105139313Sjeff
106139313Sjeff	def clear(self):
107139313Sjeff		self.label.config(text="")
108139313Sjeff
109139313Sjeff	def startup(self, str):
110139313Sjeff		self.set(str)
111139313Sjeff		root.update()
112139313Sjeff
113139313Sjeffclass EventConf(Frame):
114139313Sjeff	def __init__(self, master, name, color, enabled):
115139313Sjeff		Frame.__init__(self, master)
116139313Sjeff		self.name = name
117139313Sjeff		self.color = StringVar()
118139313Sjeff		self.color_default = color
119139313Sjeff		self.color_current = color
120139313Sjeff		self.color.set(color)
121139313Sjeff		self.enabled = IntVar()
122139313Sjeff		self.enabled_default = enabled
123139313Sjeff		self.enabled_current = enabled
124139313Sjeff		self.enabled.set(enabled)
125139313Sjeff		self.draw()
126139313Sjeff
127139313Sjeff	def draw(self):
128139313Sjeff		self.label = Label(self, text=self.name, anchor=W)
129139313Sjeff		self.sample = Canvas(self, width=24, height=24,
130139313Sjeff		    bg='grey')
131139313Sjeff		self.rect = self.sample.create_rectangle(0, 0, 24, 24,
132139313Sjeff		    fill=self.color.get())
133139313Sjeff		self.list = OptionMenu(self, self.color,
134139313Sjeff		    "dark red", "red", "pink",
135139313Sjeff		    "dark orange", "orange",
136139313Sjeff		    "yellow", "light yellow",
137139313Sjeff		    "dark green", "green", "light green",
138139313Sjeff		    "dark blue", "blue", "light blue",
139139313Sjeff		    "dark violet", "violet", "purple",
140139313Sjeff		    "dark grey", "light grey",
141139313Sjeff		    "white", "black",
142139313Sjeff		    command=self.setcolor)
143139313Sjeff		self.checkbox = Checkbutton(self, text="enabled",
144139313Sjeff		    variable=self.enabled)
145139313Sjeff		self.label.grid(row=0, column=0, sticky=E+W)
146139313Sjeff		self.sample.grid(row=0, column=1)
147139313Sjeff		self.list.grid(row=0, column=2, sticky=E+W)
148139313Sjeff		self.checkbox.grid(row=0, column=3)
149139313Sjeff		self.columnconfigure(0, weight=1)
150139313Sjeff		self.columnconfigure(2, minsize=110)
151139313Sjeff
152139313Sjeff	def setcolor(self, color):
153139313Sjeff		self.color.set(color)
154139313Sjeff		self.sample.itemconfigure(self.rect, fill=color)
155139313Sjeff
156139313Sjeff	def apply(self):
157139313Sjeff		cchange = 0
158139313Sjeff		echange = 0
159139313Sjeff		if (self.color_current != self.color.get()):
160139313Sjeff			cchange = 1
161139313Sjeff		if (self.enabled_current != self.enabled.get()):
162139313Sjeff			echange = 1
163139313Sjeff		self.color_current = self.color.get()
164139313Sjeff		self.enabled_current = self.enabled.get()
165139313Sjeff		if (echange != 0):
166139313Sjeff			if (self.enabled_current):
167139313Sjeff				graph.setcolor(self.name, self.color_current)
168139313Sjeff			else:
169139313Sjeff				graph.hide(self.name)
170139313Sjeff			return
171139313Sjeff		if (cchange != 0):
172139313Sjeff			graph.setcolor(self.name, self.color_current)
173139313Sjeff
174139313Sjeff	def revert(self):
175139313Sjeff		self.setcolor(self.color_current)
176139313Sjeff		self.enabled.set(self.enabled_current)
177139313Sjeff
178139313Sjeff	def default(self):
179139313Sjeff		self.setcolor(self.color_default)
180139313Sjeff		self.enabled.set(self.enabled_default)
181139313Sjeff
182139313Sjeffclass EventConfigure(Toplevel):
183139313Sjeff	def __init__(self):
184139313Sjeff		Toplevel.__init__(self)
185139313Sjeff		self.resizable(0, 0)
186139313Sjeff		self.title("Event Configuration")
187139313Sjeff		self.items = LabelFrame(self, text="Event Type")
188139313Sjeff		self.buttons = Frame(self)
189139313Sjeff		self.drawbuttons()
190139313Sjeff		self.items.grid(row=0, column=0, sticky=E+W)
191139313Sjeff		self.columnconfigure(0, weight=1)
192139313Sjeff		self.buttons.grid(row=1, column=0, sticky=E+W)
193139313Sjeff		self.types = []
194139313Sjeff		self.irow = 0
195139313Sjeff		for type in configtypes:
196139313Sjeff			self.additem(type.name, type.color, type.enabled)
197139313Sjeff
198139313Sjeff	def additem(self, name, color, enabled=1):
199139313Sjeff		item = EventConf(self.items, name, color, enabled)
200139313Sjeff		self.types.append(item)
201139313Sjeff		item.grid(row=self.irow, column=0, sticky=E+W)
202139313Sjeff		self.irow += 1
203139313Sjeff
204139313Sjeff	def drawbuttons(self):
205139313Sjeff		self.apply = Button(self.buttons, text="Apply",
206139313Sjeff		    command=self.apress)
207139313Sjeff		self.revert = Button(self.buttons, text="Revert",
208139313Sjeff		    command=self.rpress)
209139313Sjeff		self.default = Button(self.buttons, text="Default",
210139313Sjeff		    command=self.dpress)
211139313Sjeff		self.apply.grid(row=0, column=0, sticky=E+W)
212139313Sjeff		self.revert.grid(row=0, column=1, sticky=E+W)
213139313Sjeff		self.default.grid(row=0, column=2, sticky=E+W)
214139313Sjeff		self.buttons.columnconfigure(0, weight=1)
215139313Sjeff		self.buttons.columnconfigure(1, weight=1)
216139313Sjeff		self.buttons.columnconfigure(2, weight=1)
217139313Sjeff
218139313Sjeff	def apress(self):
219139313Sjeff		for item in self.types:
220139313Sjeff			item.apply()
221139313Sjeff
222139313Sjeff	def rpress(self):
223139313Sjeff		for item in self.types:
224139313Sjeff			item.revert()
225139313Sjeff
226139313Sjeff	def dpress(self):
227139313Sjeff		for item in self.types:
228139313Sjeff			item.default()
229139313Sjeff
230139313Sjeffclass EventView(Toplevel):
231139313Sjeff	def __init__(self, event, canvas):
232139313Sjeff		Toplevel.__init__(self)
233139313Sjeff		self.resizable(0, 0)
234139313Sjeff		self.title("Event")
235139313Sjeff		self.event = event
236139313Sjeff		self.frame = Frame(self)
237139313Sjeff		self.frame.grid(row=0, column=0, sticky=N+S+E+W)
238139313Sjeff		self.buttons = Frame(self)
239139313Sjeff		self.buttons.grid(row=1, column=0, sticky=E+W)
240139313Sjeff		self.canvas = canvas
241139313Sjeff		self.drawlabels()
242139313Sjeff		self.drawbuttons()
243139313Sjeff		event.displayref(canvas)
244139313Sjeff		self.bind("<Destroy>", self.destroycb)
245139313Sjeff
246139313Sjeff	def destroycb(self, event):
247139313Sjeff		self.unbind("<Destroy>")
248139313Sjeff		if (self.event != None):
249139313Sjeff			self.event.displayunref(self.canvas)
250139313Sjeff			self.event = None
251139313Sjeff		self.destroy()
252139313Sjeff
253139313Sjeff	def clearlabels(self):
254139313Sjeff		for label in self.frame.grid_slaves():
255139313Sjeff			label.grid_remove()
256139313Sjeff
257139313Sjeff	def drawlabels(self):
258139313Sjeff		ypos = 0
259139313Sjeff		labels = self.event.labels()
260139313Sjeff		while (len(labels) < 7):
261139313Sjeff			labels.append(("", "", 0))
262139313Sjeff		for label in labels:
263139313Sjeff			name, value, linked = label
264139313Sjeff			l = Label(self.frame, text=name, bd=1, width=15,
265139313Sjeff			    relief=SUNKEN, anchor=W)
266139313Sjeff			if (linked):
267139313Sjeff				fgcolor = "blue"
268139313Sjeff			else:
269139313Sjeff				fgcolor = "black"
270139313Sjeff			r = Label(self.frame, text=value, bd=1,
271139313Sjeff			    relief=SUNKEN, anchor=W, fg=fgcolor)
272139313Sjeff			l.grid(row=ypos, column=0, sticky=E+W)
273139313Sjeff			r.grid(row=ypos, column=1, sticky=E+W)
274139313Sjeff			if (linked):
275139313Sjeff				r.bind("<Button-1>", self.linkpress)
276139313Sjeff			ypos += 1
277139313Sjeff		self.frame.columnconfigure(1, minsize=80)
278139313Sjeff
279139313Sjeff	def drawbuttons(self):
280139313Sjeff		self.back = Button(self.buttons, text="<", command=self.bpress)
281139313Sjeff		self.forw = Button(self.buttons, text=">", command=self.fpress)
282139313Sjeff		self.new = Button(self.buttons, text="new", command=self.npress)
283139313Sjeff		self.back.grid(row=0, column=0, sticky=E+W)
284139313Sjeff		self.forw.grid(row=0, column=1, sticky=E+W)
285139313Sjeff		self.new.grid(row=0, column=2, sticky=E+W)
286139313Sjeff		self.buttons.columnconfigure(2, weight=1)
287139313Sjeff
288139313Sjeff	def newevent(self, event):
289139313Sjeff		self.event.displayunref(self.canvas)
290139313Sjeff		self.clearlabels()
291139313Sjeff		self.event = event
292139313Sjeff		self.event.displayref(self.canvas)
293139313Sjeff		self.drawlabels()
294139313Sjeff
295139313Sjeff	def npress(self):
296139313Sjeff		EventView(self.event, self.canvas)
297139313Sjeff
298139313Sjeff	def bpress(self):
299139313Sjeff		prev = self.event.prev()
300139313Sjeff		if (prev == None):
301139313Sjeff			return
302139313Sjeff		while (prev.real == 0):
303139313Sjeff			prev = prev.prev()
304139313Sjeff			if (prev == None):
305139313Sjeff				return
306139313Sjeff		self.newevent(prev)
307139313Sjeff
308139313Sjeff	def fpress(self):
309139313Sjeff		next = self.event.next()
310139313Sjeff		if (next == None):
311139313Sjeff			return
312139313Sjeff		while (next.real == 0):
313139313Sjeff			next = next.next()
314139313Sjeff			if (next == None):
315139313Sjeff				return
316139313Sjeff		self.newevent(next)
317139313Sjeff
318139313Sjeff	def linkpress(self, wevent):
319139313Sjeff		event = self.event.getlinked()
320139313Sjeff		if (event != None):
321139313Sjeff			self.newevent(event)
322139313Sjeff
323139313Sjeffclass Event:
324139313Sjeff	name = "none"
325139313Sjeff	color = "grey"
326139313Sjeff	def __init__(self, source, cpu, timestamp, last=0):
327139313Sjeff		self.source = source
328139313Sjeff		self.cpu = cpu
329139313Sjeff		self.timestamp = int(timestamp)
330139313Sjeff		self.entries = []
331139313Sjeff		self.real = 1
332139313Sjeff		self.idx = None
333139313Sjeff		self.state = 0
334139313Sjeff		self.item = None
335139313Sjeff		self.dispcnt = 0
336139313Sjeff		self.linked = None
337139313Sjeff		if (last):
338139313Sjeff			source.lastevent(self)
339139313Sjeff		else:
340139313Sjeff			source.event(self)
341139313Sjeff
342139313Sjeff	def status(self):
343139313Sjeff		statstr = self.name + " " + self.source.name
344139313Sjeff		statstr += " on: cpu" + str(self.cpu)
345139313Sjeff		statstr += " at: " + str(self.timestamp)
346139313Sjeff		statstr += self.stattxt()
347139313Sjeff		status.set(statstr)
348139313Sjeff
349139313Sjeff	def stattxt(self):
350139313Sjeff		return ""
351139313Sjeff
352139313Sjeff	def textadd(self, tuple):
353139313Sjeff		pass
354139313Sjeff		self.entries.append(tuple)
355139313Sjeff
356139313Sjeff	def labels(self):
357139313Sjeff		return [("Source:", self.source.name, 0),
358139313Sjeff				("Event:", self.name, 0),
359139313Sjeff				("CPU:", self.cpu, 0),
360139313Sjeff				("Timestamp:", self.timestamp, 0)] + self.entries
361139313Sjeff	def mouseenter(self, canvas, item):
362139313Sjeff		self.displayref(canvas)
363139313Sjeff		self.status()
364139313Sjeff
365139313Sjeff	def mouseexit(self, canvas, item):
366139313Sjeff		self.displayunref(canvas)
367139313Sjeff		status.clear()
368139313Sjeff
369139313Sjeff	def mousepress(self, canvas, item):
370139313Sjeff		EventView(self, canvas)
371139313Sjeff
372139313Sjeff	def next(self):
373139313Sjeff		return self.source.eventat(self.idx + 1)
374139313Sjeff
375139313Sjeff	def prev(self):
376139313Sjeff		return self.source.eventat(self.idx - 1)
377139313Sjeff
378139313Sjeff	def displayref(self, canvas):
379139313Sjeff		if (self.dispcnt == 0):
380139313Sjeff			canvas.itemconfigure(self.item, width=2)
381139313Sjeff		self.dispcnt += 1
382139313Sjeff
383139313Sjeff	def displayunref(self, canvas):
384139313Sjeff		self.dispcnt -= 1
385139313Sjeff		if (self.dispcnt == 0):
386139313Sjeff			canvas.itemconfigure(self.item, width=0)
387139313Sjeff			canvas.tag_raise("point", "state")
388139313Sjeff
389139313Sjeff	def getlinked(self):
390139313Sjeff		return self.linked.findevent(self.timestamp)
391139313Sjeff
392139313Sjeffclass PointEvent(Event):
393139313Sjeff	def __init__(self, thread, cpu, timestamp, last=0):
394139313Sjeff		Event.__init__(self, thread, cpu, timestamp, last)
395139313Sjeff
396139313Sjeff	def draw(self, canvas, xpos, ypos):
397139313Sjeff		l = canvas.create_oval(xpos - 6, ypos + 1, xpos + 6, ypos - 11,
398139313Sjeff		    fill=self.color, tags=("all", "point", "event")
399139313Sjeff		    + (self.name,), width=0)
400139313Sjeff		canvas.events[l] = self
401139313Sjeff		self.item = l
402139313Sjeff		if (self.enabled == 0):
403139313Sjeff			canvas.itemconfigure(l, state="hidden")
404139313Sjeff
405139313Sjeff		return (xpos)
406139313Sjeff
407139313Sjeffclass StateEvent(Event):
408139313Sjeff	def __init__(self, thread, cpu, timestamp, last=0):
409139313Sjeff		Event.__init__(self, thread, cpu, timestamp, last)
410139313Sjeff		self.duration = 0
411139313Sjeff		self.skipnext = 0
412139313Sjeff		self.skipself = 0
413139313Sjeff		self.state = 1
414139313Sjeff
415139313Sjeff	def draw(self, canvas, xpos, ypos):
416139313Sjeff		next = self.nextstate()
417139313Sjeff		if (self.skipself == 1 or next == None):
418139313Sjeff			return (xpos)
419139321Sjeff		while (self.skipnext):
420139313Sjeff			skipped = next
421139313Sjeff			next.skipself = 1
422139313Sjeff			next.real = 0
423139313Sjeff			next = next.nextstate()
424139313Sjeff			if (next == None):
425139313Sjeff				next = skipped
426139321Sjeff			self.skipnext -= 1
427139313Sjeff		self.duration = next.timestamp - self.timestamp
428166209Sjeff		if (self.duration < 0):
429166209Sjeff			self.duration = 0
430166209Sjeff			print "Unsynchronized timestamp"
431166209Sjeff			print self.cpu, self.timestamp
432166209Sjeff			print next.cpu, next.timestamp
433139313Sjeff		delta = self.duration / canvas.ratio
434139313Sjeff		l = canvas.create_rectangle(xpos, ypos,
435139313Sjeff		    xpos + delta, ypos - 10, fill=self.color, width=0,
436139313Sjeff		    tags=("all", "state", "event") + (self.name,))
437139313Sjeff		canvas.events[l] = self
438139313Sjeff		self.item = l
439139313Sjeff		if (self.enabled == 0):
440139313Sjeff			canvas.itemconfigure(l, state="hidden")
441139313Sjeff
442139313Sjeff		return (xpos + delta)
443139313Sjeff
444139313Sjeff	def stattxt(self):
445139313Sjeff		return " duration: " + ticks2sec(self.duration)
446139313Sjeff
447139313Sjeff	def nextstate(self):
448139313Sjeff		next = self.next()
449139313Sjeff		while (next != None and next.state == 0):
450139313Sjeff			next = next.next()
451139313Sjeff		return (next)
452139313Sjeff
453139313Sjeff	def labels(self):
454139313Sjeff		return [("Source:", self.source.name, 0),
455139313Sjeff				("Event:", self.name, 0),
456139313Sjeff				("Timestamp:", self.timestamp, 0),
457139313Sjeff				("CPU:", self.cpu, 0),
458139313Sjeff				("Duration:", ticks2sec(self.duration), 0)] \
459139313Sjeff				 + self.entries
460139313Sjeff
461139313Sjeffclass Count(Event):
462139313Sjeff	name = "Count"
463139313Sjeff	color = "red"
464139313Sjeff	enabled = 1
465139313Sjeff	def __init__(self, source, cpu, timestamp, count):
466139313Sjeff		self.count = int(count)
467139313Sjeff		Event.__init__(self, source, cpu, timestamp)
468139313Sjeff		self.duration = 0
469139313Sjeff		self.textadd(("count:", self.count, 0))
470139313Sjeff
471139313Sjeff	def draw(self, canvas, xpos, ypos):
472139313Sjeff		next = self.next()
473139313Sjeff		self.duration = next.timestamp - self.timestamp
474139313Sjeff		delta = self.duration / canvas.ratio
475139313Sjeff		yhight = self.source.yscale() * self.count
476139313Sjeff		l = canvas.create_rectangle(xpos, ypos - yhight,
477139313Sjeff		    xpos + delta, ypos, fill=self.color, width=0,
478139313Sjeff		    tags=("all", "count", "event") + (self.name,))
479139313Sjeff		canvas.events[l] = self
480139313Sjeff		self.item = l
481139313Sjeff		if (self.enabled == 0):
482139313Sjeff			canvas.itemconfigure(l, state="hidden")
483139313Sjeff		return (xpos + delta)
484139313Sjeff
485139313Sjeff	def stattxt(self):
486139313Sjeff		return " count: " + str(self.count)
487139313Sjeff
488139313Sjeffconfigtypes.append(Count)
489139313Sjeff
490139313Sjeffclass Running(StateEvent):
491139313Sjeff	name = "running"
492139313Sjeff	color = "green"
493139313Sjeff	enabled = 1
494139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
495139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
496139313Sjeff		self.prio = prio
497139313Sjeff		self.textadd(("prio:", self.prio, 0))
498139313Sjeff
499139313Sjeffconfigtypes.append(Running)
500139313Sjeff
501139313Sjeffclass Idle(StateEvent):
502139313Sjeff	name = "idle"
503139313Sjeff	color = "grey"
504139313Sjeff	enabled = 0
505139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
506139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
507139313Sjeff		self.prio = prio
508139313Sjeff		self.textadd(("prio:", self.prio, 0))
509139313Sjeff
510139313Sjeffconfigtypes.append(Idle)
511139313Sjeff
512139313Sjeffclass Yielding(StateEvent):
513139313Sjeff	name = "yielding"
514139313Sjeff	color = "yellow"
515139313Sjeff	enabled = 1
516139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
517139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
518173568Sjeff		self.skipnext = 0
519139313Sjeff		self.prio = prio
520139313Sjeff		self.textadd(("prio:", self.prio, 0))
521139313Sjeff
522139313Sjeffconfigtypes.append(Yielding)
523139313Sjeff
524139313Sjeffclass Swapped(StateEvent):
525139313Sjeff	name = "swapped"
526139313Sjeff	color = "violet"
527139313Sjeff	enabled = 1
528139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
529139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
530139313Sjeff		self.prio = prio
531139313Sjeff		self.textadd(("prio:", self.prio, 0))
532139313Sjeff
533139313Sjeffconfigtypes.append(Swapped)
534139313Sjeff
535139313Sjeffclass Suspended(StateEvent):
536139313Sjeff	name = "suspended"
537139313Sjeff	color = "purple"
538139313Sjeff	enabled = 1
539139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
540139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
541139313Sjeff		self.prio = prio
542139313Sjeff		self.textadd(("prio:", self.prio, 0))
543139313Sjeff
544139313Sjeffconfigtypes.append(Suspended)
545139313Sjeff
546139313Sjeffclass Iwait(StateEvent):
547139313Sjeff	name = "iwait"
548139313Sjeff	color = "grey"
549139313Sjeff	enabled = 0
550139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
551139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
552139313Sjeff		self.prio = prio
553139313Sjeff		self.textadd(("prio:", self.prio, 0))
554139313Sjeff
555139313Sjeffconfigtypes.append(Iwait)
556139313Sjeff
557139313Sjeffclass Preempted(StateEvent):
558139313Sjeff	name = "preempted"
559139313Sjeff	color = "red"
560139313Sjeff	enabled = 1
561139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, bythread):
562139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
563166203Sjeff		self.skipnext = 1
564139313Sjeff		self.prio = prio
565139313Sjeff		self.linked = bythread
566139313Sjeff		self.textadd(("prio:", self.prio, 0))
567139313Sjeff		self.textadd(("by thread:", self.linked.name, 1))
568139313Sjeff
569139313Sjeffconfigtypes.append(Preempted)
570139313Sjeff
571139313Sjeffclass Sleep(StateEvent):
572139313Sjeff	name = "sleep"
573139313Sjeff	color = "blue"
574139313Sjeff	enabled = 1
575139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, wmesg):
576139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
577139313Sjeff		self.prio = prio
578139313Sjeff		self.wmesg = wmesg
579139313Sjeff		self.textadd(("prio:", self.prio, 0))
580139313Sjeff		self.textadd(("wmesg:", self.wmesg, 0))
581139313Sjeff
582139313Sjeff	def stattxt(self):
583139313Sjeff		statstr = StateEvent.stattxt(self)
584139313Sjeff		statstr += " sleeping on: " + self.wmesg
585139313Sjeff		return (statstr)
586139313Sjeff
587139313Sjeffconfigtypes.append(Sleep)
588139313Sjeff
589139313Sjeffclass Blocked(StateEvent):
590139313Sjeff	name = "blocked"
591139313Sjeff	color = "dark red"
592139313Sjeff	enabled = 1
593139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, lock):
594139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
595139313Sjeff		self.prio = prio
596139313Sjeff		self.lock = lock
597139313Sjeff		self.textadd(("prio:", self.prio, 0))
598139313Sjeff		self.textadd(("lock:", self.lock, 0))
599139313Sjeff
600139313Sjeff	def stattxt(self):
601139313Sjeff		statstr = StateEvent.stattxt(self)
602139313Sjeff		statstr += " blocked on: " + self.lock
603139313Sjeff		return (statstr)
604139313Sjeff
605139313Sjeffconfigtypes.append(Blocked)
606139313Sjeff
607139313Sjeffclass KsegrpRunq(StateEvent):
608139313Sjeff	name = "KsegrpRunq"
609139313Sjeff	color = "orange"
610139313Sjeff	enabled = 1
611139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, bythread):
612139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
613139313Sjeff		self.prio = prio
614139313Sjeff		self.linked = bythread
615139313Sjeff		self.textadd(("prio:", self.prio, 0))
616139313Sjeff		self.textadd(("by thread:", self.linked.name, 1))
617139313Sjeff
618139313Sjeffconfigtypes.append(KsegrpRunq)
619139313Sjeff
620139313Sjeffclass Runq(StateEvent):
621139313Sjeff	name = "Runq"
622139313Sjeff	color = "yellow"
623139313Sjeff	enabled = 1
624139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, bythread):
625139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
626139313Sjeff		self.prio = prio
627139313Sjeff		self.linked = bythread
628139313Sjeff		self.textadd(("prio:", self.prio, 0))
629139313Sjeff		self.textadd(("by thread:", self.linked.name, 1))
630139313Sjeff
631139313Sjeffconfigtypes.append(Runq)
632139313Sjeff
633139313Sjeffclass Sched_exit(StateEvent):
634139313Sjeff	name = "exit"
635139313Sjeff	color = "grey"
636139313Sjeff	enabled = 0
637139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
638139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
639139313Sjeff		self.name = "sched_exit"
640139313Sjeff		self.prio = prio
641139313Sjeff		self.textadd(("prio:", self.prio, 0))
642139313Sjeff
643139313Sjeffconfigtypes.append(Sched_exit)
644139313Sjeff
645139313Sjeffclass Padevent(StateEvent):
646139313Sjeff	def __init__(self, thread, cpu, timestamp, last=0):
647139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp, last)
648139313Sjeff		self.name = "pad"
649139313Sjeff		self.real = 0
650139313Sjeff
651139313Sjeff	def draw(self, canvas, xpos, ypos):
652139313Sjeff		next = self.next()
653139313Sjeff		if (next == None):
654139313Sjeff			return (xpos)
655139313Sjeff		self.duration = next.timestamp - self.timestamp
656139313Sjeff		delta = self.duration / canvas.ratio
657139313Sjeff		return (xpos + delta)
658139313Sjeff
659139313Sjeffclass Tick(PointEvent):
660139313Sjeff	name = "tick"
661139313Sjeff	color = "black"
662139313Sjeff	enabled = 0
663139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, stathz):
664139313Sjeff		PointEvent.__init__(self, thread, cpu, timestamp)
665139313Sjeff		self.prio = prio
666139313Sjeff		self.textadd(("prio:", self.prio, 0))
667139313Sjeff
668139313Sjeffconfigtypes.append(Tick)
669139313Sjeff
670139313Sjeffclass Prio(PointEvent):
671139313Sjeff	name = "prio"
672139313Sjeff	color = "black"
673139313Sjeff	enabled = 0
674139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, newprio, bythread):
675139313Sjeff		PointEvent.__init__(self, thread, cpu, timestamp)
676139313Sjeff		self.prio = prio
677139313Sjeff		self.newprio = newprio
678139313Sjeff		self.linked = bythread
679139313Sjeff		self.textadd(("new prio:", self.newprio, 0))
680139313Sjeff		self.textadd(("prio:", self.prio, 0))
681139313Sjeff		if (self.linked != self.source):
682139313Sjeff			self.textadd(("by thread:", self.linked.name, 1))
683139313Sjeff		else:
684139313Sjeff			self.textadd(("by thread:", self.linked.name, 0))
685139313Sjeff
686139313Sjeffconfigtypes.append(Prio)
687139313Sjeff
688139313Sjeffclass Lend(PointEvent):
689139313Sjeff	name = "lend"
690139313Sjeff	color = "black"
691139313Sjeff	enabled = 0
692139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, tothread):
693139313Sjeff		PointEvent.__init__(self, thread, cpu, timestamp)
694139313Sjeff		self.prio = prio
695139313Sjeff		self.linked = tothread
696139313Sjeff		self.textadd(("prio:", self.prio, 0))
697139313Sjeff		self.textadd(("to thread:", self.linked.name, 1))
698139313Sjeff
699139313Sjeffconfigtypes.append(Lend)
700139313Sjeff
701139313Sjeffclass Wokeup(PointEvent):
702139313Sjeff	name = "wokeup"
703139313Sjeff	color = "black"
704139313Sjeff	enabled = 0
705139313Sjeff	def __init__(self, thread, cpu, timestamp, ranthread):
706139313Sjeff		PointEvent.__init__(self, thread, cpu, timestamp)
707139313Sjeff		self.linked = ranthread
708139313Sjeff		self.textadd(("ran thread:", self.linked.name, 1))
709139313Sjeff
710139313Sjeffconfigtypes.append(Wokeup)
711139313Sjeff
712139313Sjeffclass EventSource:
713139313Sjeff	def __init__(self, name):
714139313Sjeff		self.name = name
715139313Sjeff		self.events = []
716139313Sjeff		self.cpu = 0
717139313Sjeff		self.cpux = 0
718139313Sjeff
719139313Sjeff	def fixup(self):
720139313Sjeff		pass
721139313Sjeff
722139313Sjeff	def event(self, event):
723139313Sjeff		self.events.insert(0, event)
724139313Sjeff
725139313Sjeff	def remove(self, event):
726139313Sjeff		self.events.remove(event)
727139313Sjeff
728139313Sjeff	def lastevent(self, event):
729139313Sjeff		self.events.append(event)
730139313Sjeff
731139313Sjeff	def draw(self, canvas, ypos):
732139313Sjeff		xpos = 10
733139313Sjeff		self.cpux = 10
734139313Sjeff		self.cpu = self.events[1].cpu
735139313Sjeff		for i in range(0, len(self.events)):
736139313Sjeff			self.events[i].idx = i
737139313Sjeff		for event in self.events:
738139313Sjeff			if (event.cpu != self.cpu and event.cpu != -1):
739139313Sjeff				self.drawcpu(canvas, xpos, ypos)
740139313Sjeff				self.cpux = xpos
741139313Sjeff				self.cpu = event.cpu
742139313Sjeff			xpos = event.draw(canvas, xpos, ypos)
743139313Sjeff		self.drawcpu(canvas, xpos, ypos)
744139313Sjeff
745139313Sjeff	def drawname(self, canvas, ypos):
746139313Sjeff		ypos = ypos - (self.ysize() / 2)
747139313Sjeff		canvas.create_text(10, ypos, anchor="w", text=self.name)
748139313Sjeff
749139313Sjeff	def drawcpu(self, canvas, xpos, ypos):
750139313Sjeff		cpu = int(self.cpu)
751139313Sjeff		if (cpu == 0):
752139313Sjeff			color = 'light grey'
753139313Sjeff		elif (cpu == 1):
754139313Sjeff			color = 'dark grey'
755139313Sjeff		elif (cpu == 2):
756139313Sjeff			color = 'light blue'
757139313Sjeff		elif (cpu == 3):
758152131Srwatson			color = 'light green'
759165824Sjeff		elif (cpu == 4):
760165824Sjeff			color = 'blanched almond'
761165824Sjeff		elif (cpu == 5):
762165824Sjeff			color = 'slate grey'
763165824Sjeff		elif (cpu == 6):
764165824Sjeff			color = 'light slate blue'
765165824Sjeff		elif (cpu == 7):
766165824Sjeff			color = 'thistle'
767139313Sjeff		else:
768152131Srwatson			color = "white"
769139313Sjeff		l = canvas.create_rectangle(self.cpux,
770139313Sjeff		    ypos - self.ysize() - canvas.bdheight,
771139313Sjeff		    xpos, ypos + canvas.bdheight, fill=color, width=0,
772139313Sjeff		    tags=("all", "cpuinfo"))
773139313Sjeff
774139313Sjeff	def ysize(self):
775139313Sjeff		return (None)
776139313Sjeff
777139313Sjeff	def eventat(self, i):
778139313Sjeff		if (i >= len(self.events)):
779139313Sjeff			return (None)
780139313Sjeff		event = self.events[i]
781139313Sjeff		return (event)
782139313Sjeff
783139313Sjeff	def findevent(self, timestamp):
784139313Sjeff		for event in self.events:
785139313Sjeff			if (event.timestamp >= timestamp and event.real):
786139313Sjeff				return (event)
787139313Sjeff		return (None)
788139313Sjeff
789139313Sjeffclass Thread(EventSource):
790139313Sjeff	names = {}
791139313Sjeff	def __init__(self, td, pcomm):
792139313Sjeff		EventSource.__init__(self, pcomm)
793139313Sjeff		self.str = td
794139313Sjeff		try:
795139313Sjeff			cnt = Thread.names[pcomm]
796139313Sjeff		except:
797139313Sjeff			Thread.names[pcomm] = 0
798139313Sjeff			return
799139313Sjeff		Thread.names[pcomm] = cnt + 1
800139313Sjeff
801139313Sjeff	def fixup(self):
802139313Sjeff		cnt = Thread.names[self.name]
803139313Sjeff		if (cnt == 0):
804139313Sjeff			return
805139313Sjeff		cnt -= 1
806139313Sjeff		Thread.names[self.name] = cnt
807139313Sjeff		self.name += " td" + str(cnt)
808139313Sjeff
809139313Sjeff	def ysize(self):
810139313Sjeff		return (10)
811139313Sjeff
812139313Sjeffclass Counter(EventSource):
813139313Sjeff	max = 0
814139313Sjeff	def __init__(self, name):
815139313Sjeff		EventSource.__init__(self, name)
816139313Sjeff
817139313Sjeff	def event(self, event):
818139313Sjeff		EventSource.event(self, event)
819139313Sjeff		try:
820139313Sjeff			count = event.count
821139313Sjeff		except:
822139313Sjeff			return
823139313Sjeff		count = int(count)
824139313Sjeff		if (count > Counter.max):
825139313Sjeff			Counter.max = count
826139313Sjeff
827139313Sjeff	def ysize(self):
828139313Sjeff		return (80)
829139313Sjeff
830139313Sjeff	def yscale(self):
831139313Sjeff		return (self.ysize() / Counter.max)
832139313Sjeff
833139313Sjeff
834139313Sjeffclass KTRFile:
835139313Sjeff	def __init__(self, file):
836166209Sjeff		self.timestamp_first = {}
837166209Sjeff		self.timestamp_last = {}
838166209Sjeff		self.timestamp_adjust = {}
839166209Sjeff		self.timestamp_f = None
840166209Sjeff		self.timestamp_l = None
841139313Sjeff		self.lineno = -1
842139313Sjeff		self.threads = []
843139313Sjeff		self.sources = []
844139313Sjeff		self.ticks = {}
845139313Sjeff		self.load = {}
846152663Sscottl		self.crit = {}
847166209Sjeff		self.stathz = 0
848139313Sjeff
849139313Sjeff		self.parse(file)
850139313Sjeff		self.fixup()
851139313Sjeff		global ticksps
852166209Sjeff		print "first", self.timestamp_f, "last", self.timestamp_l
853166209Sjeff		print "time span", self.timespan()
854166209Sjeff		print "stathz", self.stathz
855139313Sjeff		ticksps = self.ticksps()
856166209Sjeff		print "Ticks per second", ticksps
857139313Sjeff
858139313Sjeff	def parse(self, file):
859139313Sjeff		try:
860139313Sjeff			ifp = open(file)
861139313Sjeff		except:
862139313Sjeff			print "Can't open", file
863139313Sjeff			sys.exit(1)
864139313Sjeff
865173568Sjeff		ktrhdr = "\s*\d+\s+(\d+)\s+(\d+)\s+"
866139313Sjeff		tdname = "(\S+)\(([^)]*)\)"
867152663Sscottl		crittdname = "(\S+)\s+\(\d+,\s+([^)]*)\)"
868139313Sjeff
869139313Sjeff		ktrstr = "mi_switch: " + tdname
870139313Sjeff		ktrstr += " prio (\d+) inhibit (\d+) wmesg (\S+) lock (\S+)"
871139313Sjeff		switchout_re = re.compile(ktrhdr + ktrstr)
872139313Sjeff
873139313Sjeff		ktrstr = "mi_switch: " + tdname + " prio (\d+) idle"
874139313Sjeff		idled_re = re.compile(ktrhdr + ktrstr)
875139313Sjeff
876139313Sjeff		ktrstr = "mi_switch: " + tdname + " prio (\d+) preempted by "
877139313Sjeff		ktrstr += tdname
878139313Sjeff		preempted_re = re.compile(ktrhdr + ktrstr)
879139313Sjeff
880139313Sjeff		ktrstr = "mi_switch: running " + tdname + " prio (\d+)"
881139313Sjeff		switchin_re = re.compile(ktrhdr + ktrstr)
882139313Sjeff
883139313Sjeff		ktrstr = "sched_add: " + tdname + " prio (\d+) by " + tdname
884139313Sjeff		sched_add_re = re.compile(ktrhdr + ktrstr)
885139313Sjeff
886139313Sjeff		ktrstr = "setrunqueue: " + tdname + " prio (\d+) by " + tdname
887139313Sjeff		setrunqueue_re = re.compile(ktrhdr + ktrstr)
888139313Sjeff
889139313Sjeff		ktrstr = "sched_rem: " + tdname + " prio (\d+) by " + tdname
890139313Sjeff		sched_rem_re = re.compile(ktrhdr + ktrstr)
891139313Sjeff
892139313Sjeff		ktrstr = "sched_exit_thread: " + tdname + " prio (\d+)"
893139313Sjeff		sched_exit_re = re.compile(ktrhdr + ktrstr)
894139313Sjeff
895139313Sjeff		ktrstr = "statclock: " + tdname + " prio (\d+)"
896139313Sjeff		ktrstr += " stathz (\d+)"
897139313Sjeff		sched_clock_re = re.compile(ktrhdr + ktrstr)
898139313Sjeff
899139313Sjeff		ktrstr = "sched_prio: " + tdname + " prio (\d+)"
900139313Sjeff		ktrstr += " newprio (\d+) by " + tdname
901139313Sjeff		sched_prio_re = re.compile(ktrhdr + ktrstr)
902139313Sjeff
903139319Sjeff		cpuload_re = re.compile(ktrhdr + "load: (\d+)")
904173568Sjeff		cpuload2_re = re.compile(ktrhdr + "cpu (\d+) load: (\d+)")
905139319Sjeff		loadglobal_re = re.compile(ktrhdr + "global load: (\d+)")
906139313Sjeff
907152663Sscottl		ktrstr = "critical_\S+ by thread " + crittdname + " to (\d+)"
908152663Sscottl		critsec_re = re.compile(ktrhdr + ktrstr)
909152663Sscottl
910139313Sjeff		parsers = [[cpuload_re, self.cpuload],
911173568Sjeff			   [cpuload2_re, self.cpuload2],
912139313Sjeff			   [loadglobal_re, self.loadglobal],
913139313Sjeff			   [switchin_re, self.switchin],
914139313Sjeff			   [switchout_re, self.switchout],
915139313Sjeff			   [sched_add_re, self.sched_add],
916139313Sjeff			   [setrunqueue_re, self.sched_rem],
917139313Sjeff			   [sched_prio_re, self.sched_prio],
918139313Sjeff			   [preempted_re, self.preempted],
919139313Sjeff			   [sched_rem_re, self.sched_rem],
920139313Sjeff			   [sched_exit_re, self.sched_exit],
921139313Sjeff			   [sched_clock_re, self.sched_clock],
922152663Sscottl			   [critsec_re, self.critsec],
923139313Sjeff			   [idled_re, self.idled]]
924139313Sjeff
925166209Sjeff		lines = ifp.readlines()
926166209Sjeff		self.synchstamp(lines)
927166209Sjeff		for line in lines:
928139313Sjeff			self.lineno += 1
929139313Sjeff			if ((self.lineno % 1024) == 0):
930139313Sjeff				status.startup("Parsing line " +
931139313Sjeff				    str(self.lineno))
932139313Sjeff			for p in parsers:
933139313Sjeff				m = p[0].match(line)
934139313Sjeff				if (m != None):
935139313Sjeff					p[1](*m.groups())
936139313Sjeff					break
937173568Sjeff			if (m == None):
938173568Sjeff				print line,
939139313Sjeff
940166209Sjeff	def synchstamp(self, lines):
941166209Sjeff		status.startup("Rationalizing Timestamps")
942166209Sjeff		tstamp_re = re.compile("\s+\d+\s+(\d+)\s+(\d+)\s+.*")
943166209Sjeff		for line in lines:
944166209Sjeff			m = tstamp_re.match(line)
945166209Sjeff			if (m != None):
946166209Sjeff				self.addstamp(*m.groups())
947166209Sjeff		self.pickstamp()
948166209Sjeff		self.monostamp(lines)
949166209Sjeff
950166209Sjeff
951166209Sjeff	def monostamp(self, lines):
952166209Sjeff		laststamp = None
953166209Sjeff		tstamp_re = re.compile("\s+\d+\s+(\d+)\s+(\d+)\s+.*")
954166209Sjeff		for line in lines:
955166209Sjeff			m = tstamp_re.match(line)
956166209Sjeff			if (m == None):
957166209Sjeff				continue
958166209Sjeff			(cpu, timestamp) = m.groups()
959166209Sjeff			timestamp = int(timestamp)
960166209Sjeff			cpu = int(cpu)
961166209Sjeff			timestamp -= self.timestamp_adjust[cpu]
962166209Sjeff			if (laststamp != None and timestamp > laststamp):
963166209Sjeff				self.timestamp_adjust[cpu] += timestamp - laststamp
964166209Sjeff			laststamp = timestamp
965166209Sjeff
966166209Sjeff	def addstamp(self, cpu, timestamp):
967139313Sjeff		timestamp = int(timestamp)
968166209Sjeff		cpu = int(cpu)
969166209Sjeff		try:
970166209Sjeff			if (timestamp > self.timestamp_first[cpu]):
971166209Sjeff				return
972166209Sjeff		except:
973166209Sjeff			self.timestamp_first[cpu] = timestamp
974166209Sjeff		self.timestamp_last[cpu] = timestamp
975166209Sjeff
976166209Sjeff	def pickstamp(self):
977166209Sjeff		base = self.timestamp_last[0]
978166209Sjeff		for i in range(0, len(self.timestamp_last)):
979166209Sjeff			if (self.timestamp_last[i] < base):
980166209Sjeff				base = self.timestamp_last[i]
981166209Sjeff
982166209Sjeff		print "Adjusting to base stamp", base
983166209Sjeff		for i in range(0, len(self.timestamp_last)):
984166209Sjeff			self.timestamp_adjust[i] = self.timestamp_last[i] - base;
985166209Sjeff			print "CPU ", i, "adjust by ", self.timestamp_adjust[i]
986166209Sjeff
987166209Sjeff		self.timestamp_f = 0
988166209Sjeff		for i in range(0, len(self.timestamp_first)):
989166209Sjeff			first = self.timestamp_first[i] - self.timestamp_adjust[i]
990166209Sjeff			if (first > self.timestamp_f):
991166209Sjeff				self.timestamp_f = first
992166209Sjeff
993166209Sjeff		self.timestamp_l = 0
994166209Sjeff		for i in range(0, len(self.timestamp_last)):
995166209Sjeff			last = self.timestamp_last[i] - self.timestamp_adjust[i]
996166209Sjeff			if (last > self.timestamp_l):
997166209Sjeff				self.timestamp_l = last
998166209Sjeff
999166209Sjeff
1000166209Sjeff	def checkstamp(self, cpu, timestamp):
1001166209Sjeff		cpu = int(cpu)
1002166209Sjeff		timestamp = int(timestamp)
1003166209Sjeff		if (timestamp > self.timestamp_first[cpu]):
1004139313Sjeff			print "Bad timestamp on line ", self.lineno
1005139313Sjeff			return (0)
1006166209Sjeff		timestamp -= self.timestamp_adjust[cpu]
1007166209Sjeff		return (timestamp)
1008139313Sjeff
1009139313Sjeff	def timespan(self):
1010166209Sjeff		return (self.timestamp_f - self.timestamp_l);
1011139313Sjeff
1012139313Sjeff	def ticksps(self):
1013139313Sjeff		return (self.timespan() / self.ticks[0]) * int(self.stathz)
1014139313Sjeff
1015139313Sjeff	def switchout(self, cpu, timestamp, td, pcomm, prio, inhibit, wmesg, lock):
1016139313Sjeff		TDI_SUSPENDED = 0x0001
1017139313Sjeff		TDI_SLEEPING = 0x0002
1018139313Sjeff		TDI_SWAPPED = 0x0004
1019139313Sjeff		TDI_LOCK = 0x0008
1020139313Sjeff		TDI_IWAIT = 0x0010
1021139313Sjeff
1022166209Sjeff		timestamp = self.checkstamp(cpu, timestamp)
1023166209Sjeff		if (timestamp == 0):
1024139313Sjeff			return
1025139313Sjeff		inhibit = int(inhibit)
1026139313Sjeff		thread = self.findtd(td, pcomm)
1027139313Sjeff		if (inhibit & TDI_SWAPPED):
1028139313Sjeff			Swapped(thread, cpu, timestamp, prio)
1029139313Sjeff		elif (inhibit & TDI_SLEEPING):
1030139313Sjeff			Sleep(thread, cpu, timestamp, prio, wmesg)
1031139313Sjeff		elif (inhibit & TDI_LOCK):
1032139313Sjeff			Blocked(thread, cpu, timestamp, prio, lock)
1033139313Sjeff		elif (inhibit & TDI_IWAIT):
1034139313Sjeff			Iwait(thread, cpu, timestamp, prio)
1035139313Sjeff		elif (inhibit & TDI_SUSPENDED):
1036139313Sjeff			Suspended(thread, cpu, timestamp, prio)
1037139313Sjeff		elif (inhibit == 0):
1038139313Sjeff			Yielding(thread, cpu, timestamp, prio)
1039139313Sjeff		else:
1040139313Sjeff			print "Unknown event", inhibit
1041139313Sjeff			sys.exit(1)
1042139313Sjeff
1043139313Sjeff	def idled(self, cpu, timestamp, td, pcomm, prio):
1044166209Sjeff		timestamp = self.checkstamp(cpu, timestamp)
1045166209Sjeff		if (timestamp == 0):
1046139313Sjeff			return
1047139313Sjeff		thread = self.findtd(td, pcomm)
1048139313Sjeff		Idle(thread, cpu, timestamp, prio)
1049139313Sjeff
1050139313Sjeff	def preempted(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
1051166209Sjeff		timestamp = self.checkstamp(cpu, timestamp)
1052166209Sjeff		if (timestamp == 0):
1053139313Sjeff			return
1054139313Sjeff		thread = self.findtd(td, pcomm)
1055139313Sjeff		Preempted(thread, cpu, timestamp, prio,
1056139313Sjeff		    self.findtd(bytd, bypcomm))
1057139313Sjeff
1058139313Sjeff	def switchin(self, cpu, timestamp, td, pcomm, prio):
1059166209Sjeff		timestamp = self.checkstamp(cpu, timestamp)
1060166209Sjeff		if (timestamp == 0):
1061139313Sjeff			return
1062139313Sjeff		thread = self.findtd(td, pcomm)
1063139313Sjeff		Running(thread, cpu, timestamp, prio)
1064139313Sjeff
1065139313Sjeff	def sched_add(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
1066166209Sjeff		timestamp = self.checkstamp(cpu, timestamp)
1067166209Sjeff		if (timestamp == 0):
1068139313Sjeff			return
1069139313Sjeff		thread = self.findtd(td, pcomm)
1070139313Sjeff		bythread = self.findtd(bytd, bypcomm)
1071139313Sjeff		Runq(thread, cpu, timestamp, prio, bythread)
1072139313Sjeff		Wokeup(bythread, cpu, timestamp, thread)
1073139313Sjeff
1074139313Sjeff	def sched_rem(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
1075166209Sjeff		timestamp = self.checkstamp(cpu, timestamp)
1076166209Sjeff		if (timestamp == 0):
1077139313Sjeff			return
1078139313Sjeff		thread = self.findtd(td, pcomm)
1079139313Sjeff		KsegrpRunq(thread, cpu, timestamp, prio,
1080139313Sjeff		    self.findtd(bytd, bypcomm))
1081139313Sjeff
1082139313Sjeff	def sched_exit(self, cpu, timestamp, td, pcomm, prio):
1083166209Sjeff		timestamp = self.checkstamp(cpu, timestamp)
1084166209Sjeff		if (timestamp == 0):
1085139313Sjeff			return
1086139313Sjeff		thread = self.findtd(td, pcomm)
1087139313Sjeff		Sched_exit(thread, cpu, timestamp, prio)
1088139313Sjeff
1089139313Sjeff	def sched_clock(self, cpu, timestamp, td, pcomm, prio, stathz):
1090166209Sjeff		timestamp = self.checkstamp(cpu, timestamp)
1091166209Sjeff		if (timestamp == 0):
1092139313Sjeff			return
1093139313Sjeff		self.stathz = stathz
1094139313Sjeff		cpu = int(cpu)
1095139313Sjeff		try:
1096139313Sjeff			ticks = self.ticks[cpu]
1097139313Sjeff		except:
1098139313Sjeff			self.ticks[cpu] = 0
1099139313Sjeff		self.ticks[cpu] += 1
1100139313Sjeff		thread = self.findtd(td, pcomm)
1101139313Sjeff		Tick(thread, cpu, timestamp, prio, stathz)
1102139313Sjeff
1103139313Sjeff	def sched_prio(self, cpu, timestamp, td, pcomm, prio, newprio, bytd, bypcomm):
1104139313Sjeff		if (prio == newprio):
1105139313Sjeff			return
1106166209Sjeff		timestamp = self.checkstamp(cpu, timestamp)
1107166209Sjeff		if (timestamp == 0):
1108139313Sjeff			return
1109139313Sjeff		thread = self.findtd(td, pcomm)
1110139313Sjeff		bythread = self.findtd(bytd, bypcomm)
1111139313Sjeff		Prio(thread, cpu, timestamp, prio, newprio, bythread)
1112139313Sjeff		Lend(bythread, cpu, timestamp, newprio, thread)
1113139313Sjeff
1114139313Sjeff	def cpuload(self, cpu, timestamp, count):
1115166209Sjeff		timestamp = self.checkstamp(cpu, timestamp)
1116166209Sjeff		if (timestamp == 0):
1117139320Sjeff			return
1118139313Sjeff		cpu = int(cpu)
1119139313Sjeff		try:
1120139313Sjeff			load = self.load[cpu]
1121139313Sjeff		except:
1122139313Sjeff			load = Counter("cpu" + str(cpu) + " load")
1123139313Sjeff			self.load[cpu] = load
1124139313Sjeff			self.sources.insert(0, load)
1125139313Sjeff		Count(load, cpu, timestamp, count)
1126139313Sjeff
1127173568Sjeff	def cpuload2(self, cpu, timestamp, ncpu, count):
1128173568Sjeff		timestamp = self.checkstamp(cpu, timestamp)
1129173568Sjeff		if (timestamp == 0):
1130173568Sjeff			return
1131173568Sjeff		cpu = int(ncpu)
1132173568Sjeff		try:
1133173568Sjeff			load = self.load[cpu]
1134173568Sjeff		except:
1135173568Sjeff			load = Counter("cpu" + str(cpu) + " load")
1136173568Sjeff			self.load[cpu] = load
1137173568Sjeff			self.sources.insert(0, load)
1138173568Sjeff		Count(load, cpu, timestamp, count)
1139173568Sjeff
1140139313Sjeff	def loadglobal(self, cpu, timestamp, count):
1141166209Sjeff		timestamp = self.checkstamp(cpu, timestamp)
1142166209Sjeff		if (timestamp == 0):
1143139320Sjeff			return
1144139313Sjeff		cpu = 0
1145139313Sjeff		try:
1146139313Sjeff			load = self.load[cpu]
1147139313Sjeff		except:
1148139313Sjeff			load = Counter("CPU load")
1149139313Sjeff			self.load[cpu] = load
1150139313Sjeff			self.sources.insert(0, load)
1151139313Sjeff		Count(load, cpu, timestamp, count)
1152139313Sjeff
1153152663Sscottl	def critsec(self, cpu, timestamp, td, pcomm, to):
1154166209Sjeff		timestamp = self.checkstamp(cpu, timestamp)
1155166209Sjeff		if (timestamp == 0):
1156152663Sscottl			return
1157152663Sscottl		cpu = int(cpu)
1158152663Sscottl		try:
1159152663Sscottl			crit = self.crit[cpu]
1160152663Sscottl		except:
1161152663Sscottl			crit = Counter("Critical Section")
1162152663Sscottl			self.crit[cpu] = crit
1163152663Sscottl			self.sources.insert(0, crit)
1164152663Sscottl		Count(crit, cpu, timestamp, to)
1165152663Sscottl
1166139313Sjeff	def findtd(self, td, pcomm):
1167139313Sjeff		for thread in self.threads:
1168139313Sjeff			if (thread.str == td and thread.name == pcomm):
1169139313Sjeff				return thread
1170139313Sjeff		thread = Thread(td, pcomm)
1171139313Sjeff		self.threads.append(thread)
1172139313Sjeff		self.sources.append(thread)
1173139313Sjeff		return (thread)
1174139313Sjeff
1175139313Sjeff	def fixup(self):
1176139313Sjeff		for source in self.sources:
1177166209Sjeff			Padevent(source, -1, self.timestamp_l)
1178166209Sjeff			Padevent(source, -1, self.timestamp_f, last=1)
1179139313Sjeff			source.fixup()
1180139313Sjeff
1181139313Sjeffclass SchedDisplay(Canvas):
1182139313Sjeff	def __init__(self, master):
1183139313Sjeff		self.ratio = 1
1184139313Sjeff		self.ktrfile = None
1185139313Sjeff		self.sources = None
1186139313Sjeff		self.bdheight = 10
1187139313Sjeff		self.events = {}
1188139313Sjeff
1189139313Sjeff		Canvas.__init__(self, master, width=800, height=500, bg='grey',
1190139313Sjeff		     scrollregion=(0, 0, 800, 500))
1191139313Sjeff
1192139313Sjeff	def setfile(self, ktrfile):
1193139313Sjeff		self.ktrfile = ktrfile
1194139313Sjeff		self.sources = ktrfile.sources
1195139313Sjeff
1196139313Sjeff	def draw(self):
1197139313Sjeff		ypos = 0
1198139313Sjeff		xsize = self.xsize()
1199139313Sjeff		for source in self.sources:
1200139313Sjeff			status.startup("Drawing " + source.name)
1201139313Sjeff			self.create_line(0, ypos, xsize, ypos,
1202139313Sjeff			    width=1, fill="black", tags=("all",))
1203139313Sjeff			ypos += self.bdheight
1204139313Sjeff			ypos += source.ysize()
1205139313Sjeff			source.draw(self, ypos)
1206139313Sjeff			ypos += self.bdheight
1207139313Sjeff			try:
1208139313Sjeff				self.tag_raise("point", "state")
1209139313Sjeff				self.tag_lower("cpuinfo", "all")
1210139313Sjeff			except:
1211139313Sjeff				pass
1212139313Sjeff		self.create_line(0, ypos, xsize, ypos,
1213139313Sjeff		    width=1, fill="black", tags=("all",))
1214139313Sjeff		self.tag_bind("event", "<Enter>", self.mouseenter)
1215139313Sjeff		self.tag_bind("event", "<Leave>", self.mouseexit)
1216139313Sjeff		self.tag_bind("event", "<Button-1>", self.mousepress)
1217139313Sjeff
1218139313Sjeff	def mouseenter(self, event):
1219139313Sjeff		item, = self.find_withtag(CURRENT)
1220139313Sjeff		event = self.events[item]
1221139313Sjeff		event.mouseenter(self, item)
1222139313Sjeff
1223139313Sjeff	def mouseexit(self, event):
1224139313Sjeff		item, = self.find_withtag(CURRENT)
1225139313Sjeff		event = self.events[item]
1226139313Sjeff		event.mouseexit(self, item)
1227139313Sjeff
1228139313Sjeff	def mousepress(self, event):
1229139313Sjeff		item, = self.find_withtag(CURRENT)
1230139313Sjeff		event = self.events[item]
1231139313Sjeff		event.mousepress(self, item)
1232139313Sjeff
1233139313Sjeff	def drawnames(self, canvas):
1234139313Sjeff		status.startup("Drawing names")
1235139313Sjeff		ypos = 0
1236139313Sjeff		canvas.configure(scrollregion=(0, 0,
1237139313Sjeff		    canvas["width"], self.ysize()))
1238139313Sjeff		for source in self.sources:
1239139313Sjeff			canvas.create_line(0, ypos, canvas["width"], ypos,
1240139313Sjeff			    width=1, fill="black", tags=("all",))
1241139313Sjeff			ypos += self.bdheight
1242139313Sjeff			ypos += source.ysize()
1243139313Sjeff			source.drawname(canvas, ypos)
1244139313Sjeff			ypos += self.bdheight
1245139313Sjeff		canvas.create_line(0, ypos, canvas["width"], ypos,
1246139313Sjeff		    width=1, fill="black", tags=("all",))
1247139313Sjeff
1248139313Sjeff	def xsize(self):
1249139313Sjeff		return ((self.ktrfile.timespan() / self.ratio) + 20)
1250139313Sjeff
1251139313Sjeff	def ysize(self):
1252139313Sjeff		ysize = 0
1253139313Sjeff		for source in self.sources:
1254139313Sjeff			ysize += source.ysize() + (self.bdheight * 2)
1255139313Sjeff		return (ysize)
1256139313Sjeff
1257139313Sjeff	def scaleset(self, ratio):
1258139313Sjeff		if (self.ktrfile == None):
1259139313Sjeff			return
1260139313Sjeff		oldratio = self.ratio
1261139313Sjeff		xstart, ystart = self.xview()
1262139313Sjeff		length = (float(self["width"]) / self.xsize())
1263139313Sjeff		middle = xstart + (length / 2)
1264139313Sjeff
1265139313Sjeff		self.ratio = ratio
1266139313Sjeff		self.configure(scrollregion=(0, 0, self.xsize(), self.ysize()))
1267139313Sjeff		self.scale("all", 0, 0, float(oldratio) / ratio, 1)
1268139313Sjeff
1269139313Sjeff		length = (float(self["width"]) / self.xsize())
1270139313Sjeff		xstart = middle - (length / 2)
1271139313Sjeff		self.xview_moveto(xstart)
1272139313Sjeff
1273139313Sjeff	def scaleget(self):
1274139313Sjeff		return self.ratio
1275139313Sjeff
1276139313Sjeff	def setcolor(self, tag, color):
1277139313Sjeff		self.itemconfigure(tag, state="normal", fill=color)
1278139313Sjeff
1279139313Sjeff	def hide(self, tag):
1280139313Sjeff		self.itemconfigure(tag, state="hidden")
1281139313Sjeff
1282139313Sjeffclass GraphMenu(Frame):
1283139313Sjeff	def __init__(self, master):
1284139313Sjeff		Frame.__init__(self, master, bd=2, relief=RAISED)
1285139313Sjeff		self.view = Menubutton(self, text="Configure")
1286139313Sjeff		self.viewmenu = Menu(self.view, tearoff=0)
1287139313Sjeff		self.viewmenu.add_command(label="Events",
1288139313Sjeff		    command=self.econf)
1289139313Sjeff		self.view["menu"] = self.viewmenu
1290139313Sjeff		self.view.pack(side=LEFT)
1291139313Sjeff
1292139313Sjeff	def econf(self):
1293139313Sjeff		EventConfigure()
1294139313Sjeff
1295139313Sjeff
1296139313Sjeffclass SchedGraph(Frame):
1297139313Sjeff	def __init__(self, master):
1298139313Sjeff		Frame.__init__(self, master)
1299139313Sjeff		self.menu = None
1300139313Sjeff		self.names = None
1301139313Sjeff		self.display = None
1302139313Sjeff		self.scale = None
1303139313Sjeff		self.status = None
1304139313Sjeff		self.pack(expand=1, fill="both")
1305139313Sjeff		self.buildwidgets()
1306139313Sjeff		self.layout()
1307139313Sjeff		self.draw(sys.argv[1])
1308139313Sjeff
1309139313Sjeff	def buildwidgets(self):
1310139313Sjeff		global status
1311139313Sjeff		self.menu = GraphMenu(self)
1312139313Sjeff		self.display = SchedDisplay(self)
1313139313Sjeff		self.names = Canvas(self,
1314139313Sjeff		    width=100, height=self.display["height"],
1315139313Sjeff		    bg='grey', scrollregion=(0, 0, 50, 100))
1316139313Sjeff		self.scale = Scaler(self, self.display)
1317139313Sjeff		status = self.status = Status(self)
1318139313Sjeff		self.scrollY = Scrollbar(self, orient="vertical",
1319139313Sjeff		    command=self.display_yview)
1320139313Sjeff		self.display.scrollX = Scrollbar(self, orient="horizontal",
1321139313Sjeff		    command=self.display.xview)
1322139313Sjeff		self.display["xscrollcommand"] = self.display.scrollX.set
1323139313Sjeff		self.display["yscrollcommand"] = self.scrollY.set
1324139313Sjeff		self.names["yscrollcommand"] = self.scrollY.set
1325139313Sjeff
1326139313Sjeff	def layout(self):
1327139313Sjeff		self.columnconfigure(1, weight=1)
1328139313Sjeff		self.rowconfigure(1, weight=1)
1329139313Sjeff		self.menu.grid(row=0, column=0, columnspan=3, sticky=E+W)
1330139313Sjeff		self.names.grid(row=1, column=0, sticky=N+S)
1331139313Sjeff		self.display.grid(row=1, column=1, sticky=W+E+N+S)
1332139313Sjeff		self.scrollY.grid(row=1, column=2, sticky=N+S)
1333139313Sjeff		self.display.scrollX.grid(row=2, column=0, columnspan=2,
1334139313Sjeff		    sticky=E+W)
1335139313Sjeff		self.scale.grid(row=3, column=0, columnspan=3, sticky=E+W)
1336139313Sjeff		self.status.grid(row=4, column=0, columnspan=3, sticky=E+W)
1337139313Sjeff
1338139313Sjeff	def draw(self, file):
1339139313Sjeff		self.master.update()
1340139313Sjeff		ktrfile = KTRFile(file)
1341139313Sjeff		self.display.setfile(ktrfile)
1342139313Sjeff		self.display.drawnames(self.names)
1343139313Sjeff		self.display.draw()
1344139313Sjeff		self.scale.set(250000)
1345139313Sjeff		self.display.xview_moveto(0)
1346139313Sjeff
1347139313Sjeff	def display_yview(self, *args):
1348139313Sjeff		self.names.yview(*args)
1349139313Sjeff		self.display.yview(*args)
1350139313Sjeff
1351139313Sjeff	def setcolor(self, tag, color):
1352139313Sjeff		self.display.setcolor(tag, color)
1353139313Sjeff
1354139313Sjeff	def hide(self, tag):
1355139313Sjeff		self.display.hide(tag)
1356139313Sjeff
1357139313Sjeffif (len(sys.argv) != 2):
1358139313Sjeff	print "usage:", sys.argv[0], "<ktr file>"
1359139313Sjeff	sys.exit(1)
1360139313Sjeff
1361139313Sjeffroot = Tk()
1362139313Sjeffroot.title("Scheduler Graph")
1363139313Sjeffgraph = SchedGraph(root)
1364139313Sjeffroot.mainloop()
1365