schedgraph.py revision 152131
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 152131 2005-11-06 17:43:25Z rwatson $
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.
38139366Sarr# - Rebuild kernel with proper changes to KERNCONF.
39139366Sarr# - Dump the trace to a file: 'ktrdump -ct > ktr.out'
40139366Sarr# - Run the python script: 'python schedgraph.py ktr.out'
41139366Sarr#
42139366Sarr# To do:
43139313Sjeff# 1)  Add a per-thread summary display
44139313Sjeff# 2)  Add bounding box style zoom.
45139313Sjeff# 3)  Click to center.
46139313Sjeff# 4)  Implement some sorting mechanism.
47139313Sjeff
48139313Sjeffticksps = None
49139313Sjeffstatus = None
50139313Sjeffconfigtypes = []
51139313Sjeff
52139313Sjeffdef ticks2sec(ticks):
53139313Sjeff	ns = ticksps / 1000000000
54139313Sjeff	ticks /= ns
55139313Sjeff	if (ticks < 1000):
56139313Sjeff		return (str(ticks) + "ns")
57139313Sjeff	ticks /= 1000
58139313Sjeff	if (ticks < 1000):
59139313Sjeff		return (str(ticks) + "us")
60139313Sjeff	ticks /= 1000
61139313Sjeff	if (ticks < 1000):
62139313Sjeff		return (str(ticks) + "ms")
63139313Sjeff	ticks /= 1000
64139313Sjeff	return (str(ticks) + "s")
65139313Sjeff
66139313Sjeffclass Scaler(Frame):
67139313Sjeff	def __init__(self, master, target):
68139313Sjeff		Frame.__init__(self, master)
69139313Sjeff		self.scale = Scale(self, command=self.scaleset,
70139313Sjeff		    from_=1000, to_=1000000, orient=HORIZONTAL, resolution=1000)
71139313Sjeff		self.label = Label(self, text="Ticks per pixel")
72139313Sjeff		self.label.pack(side=LEFT)
73139313Sjeff		self.scale.pack(fill="both", expand=1)
74139313Sjeff		self.target = target
75139313Sjeff		self.scale.set(target.scaleget())
76139313Sjeff		self.initialized = 1
77139313Sjeff
78139313Sjeff	def scaleset(self, value):
79139313Sjeff		self.target.scaleset(int(value))
80139313Sjeff
81139313Sjeff	def set(self, value):
82139313Sjeff		self.scale.set(value)
83139313Sjeff
84139313Sjeffclass Status(Frame):
85139313Sjeff	def __init__(self, master):
86139313Sjeff		Frame.__init__(self, master)
87139313Sjeff		self.label = Label(self, bd=1, relief=SUNKEN, anchor=W)
88139313Sjeff		self.label.pack(fill="both", expand=1)
89139313Sjeff		self.clear()
90139313Sjeff
91139313Sjeff	def set(self, str):
92139313Sjeff		self.label.config(text=str)
93139313Sjeff
94139313Sjeff	def clear(self):
95139313Sjeff		self.label.config(text="")
96139313Sjeff
97139313Sjeff	def startup(self, str):
98139313Sjeff		self.set(str)
99139313Sjeff		root.update()
100139313Sjeff
101139313Sjeffclass EventConf(Frame):
102139313Sjeff	def __init__(self, master, name, color, enabled):
103139313Sjeff		Frame.__init__(self, master)
104139313Sjeff		self.name = name
105139313Sjeff		self.color = StringVar()
106139313Sjeff		self.color_default = color
107139313Sjeff		self.color_current = color
108139313Sjeff		self.color.set(color)
109139313Sjeff		self.enabled = IntVar()
110139313Sjeff		self.enabled_default = enabled
111139313Sjeff		self.enabled_current = enabled
112139313Sjeff		self.enabled.set(enabled)
113139313Sjeff		self.draw()
114139313Sjeff
115139313Sjeff	def draw(self):
116139313Sjeff		self.label = Label(self, text=self.name, anchor=W)
117139313Sjeff		self.sample = Canvas(self, width=24, height=24,
118139313Sjeff		    bg='grey')
119139313Sjeff		self.rect = self.sample.create_rectangle(0, 0, 24, 24,
120139313Sjeff		    fill=self.color.get())
121139313Sjeff		self.list = OptionMenu(self, self.color,
122139313Sjeff		    "dark red", "red", "pink",
123139313Sjeff		    "dark orange", "orange",
124139313Sjeff		    "yellow", "light yellow",
125139313Sjeff		    "dark green", "green", "light green",
126139313Sjeff		    "dark blue", "blue", "light blue",
127139313Sjeff		    "dark violet", "violet", "purple",
128139313Sjeff		    "dark grey", "light grey",
129139313Sjeff		    "white", "black",
130139313Sjeff		    command=self.setcolor)
131139313Sjeff		self.checkbox = Checkbutton(self, text="enabled",
132139313Sjeff		    variable=self.enabled)
133139313Sjeff		self.label.grid(row=0, column=0, sticky=E+W)
134139313Sjeff		self.sample.grid(row=0, column=1)
135139313Sjeff		self.list.grid(row=0, column=2, sticky=E+W)
136139313Sjeff		self.checkbox.grid(row=0, column=3)
137139313Sjeff		self.columnconfigure(0, weight=1)
138139313Sjeff		self.columnconfigure(2, minsize=110)
139139313Sjeff
140139313Sjeff	def setcolor(self, color):
141139313Sjeff		self.color.set(color)
142139313Sjeff		self.sample.itemconfigure(self.rect, fill=color)
143139313Sjeff
144139313Sjeff	def apply(self):
145139313Sjeff		cchange = 0
146139313Sjeff		echange = 0
147139313Sjeff		if (self.color_current != self.color.get()):
148139313Sjeff			cchange = 1
149139313Sjeff		if (self.enabled_current != self.enabled.get()):
150139313Sjeff			echange = 1
151139313Sjeff		self.color_current = self.color.get()
152139313Sjeff		self.enabled_current = self.enabled.get()
153139313Sjeff		if (echange != 0):
154139313Sjeff			if (self.enabled_current):
155139313Sjeff				graph.setcolor(self.name, self.color_current)
156139313Sjeff			else:
157139313Sjeff				graph.hide(self.name)
158139313Sjeff			return
159139313Sjeff		if (cchange != 0):
160139313Sjeff			graph.setcolor(self.name, self.color_current)
161139313Sjeff
162139313Sjeff	def revert(self):
163139313Sjeff		self.setcolor(self.color_current)
164139313Sjeff		self.enabled.set(self.enabled_current)
165139313Sjeff
166139313Sjeff	def default(self):
167139313Sjeff		self.setcolor(self.color_default)
168139313Sjeff		self.enabled.set(self.enabled_default)
169139313Sjeff
170139313Sjeffclass EventConfigure(Toplevel):
171139313Sjeff	def __init__(self):
172139313Sjeff		Toplevel.__init__(self)
173139313Sjeff		self.resizable(0, 0)
174139313Sjeff		self.title("Event Configuration")
175139313Sjeff		self.items = LabelFrame(self, text="Event Type")
176139313Sjeff		self.buttons = Frame(self)
177139313Sjeff		self.drawbuttons()
178139313Sjeff		self.items.grid(row=0, column=0, sticky=E+W)
179139313Sjeff		self.columnconfigure(0, weight=1)
180139313Sjeff		self.buttons.grid(row=1, column=0, sticky=E+W)
181139313Sjeff		self.types = []
182139313Sjeff		self.irow = 0
183139313Sjeff		for type in configtypes:
184139313Sjeff			self.additem(type.name, type.color, type.enabled)
185139313Sjeff
186139313Sjeff	def additem(self, name, color, enabled=1):
187139313Sjeff		item = EventConf(self.items, name, color, enabled)
188139313Sjeff		self.types.append(item)
189139313Sjeff		item.grid(row=self.irow, column=0, sticky=E+W)
190139313Sjeff		self.irow += 1
191139313Sjeff
192139313Sjeff	def drawbuttons(self):
193139313Sjeff		self.apply = Button(self.buttons, text="Apply",
194139313Sjeff		    command=self.apress)
195139313Sjeff		self.revert = Button(self.buttons, text="Revert",
196139313Sjeff		    command=self.rpress)
197139313Sjeff		self.default = Button(self.buttons, text="Default",
198139313Sjeff		    command=self.dpress)
199139313Sjeff		self.apply.grid(row=0, column=0, sticky=E+W)
200139313Sjeff		self.revert.grid(row=0, column=1, sticky=E+W)
201139313Sjeff		self.default.grid(row=0, column=2, sticky=E+W)
202139313Sjeff		self.buttons.columnconfigure(0, weight=1)
203139313Sjeff		self.buttons.columnconfigure(1, weight=1)
204139313Sjeff		self.buttons.columnconfigure(2, weight=1)
205139313Sjeff
206139313Sjeff	def apress(self):
207139313Sjeff		for item in self.types:
208139313Sjeff			item.apply()
209139313Sjeff
210139313Sjeff	def rpress(self):
211139313Sjeff		for item in self.types:
212139313Sjeff			item.revert()
213139313Sjeff
214139313Sjeff	def dpress(self):
215139313Sjeff		for item in self.types:
216139313Sjeff			item.default()
217139313Sjeff
218139313Sjeffclass EventView(Toplevel):
219139313Sjeff	def __init__(self, event, canvas):
220139313Sjeff		Toplevel.__init__(self)
221139313Sjeff		self.resizable(0, 0)
222139313Sjeff		self.title("Event")
223139313Sjeff		self.event = event
224139313Sjeff		self.frame = Frame(self)
225139313Sjeff		self.frame.grid(row=0, column=0, sticky=N+S+E+W)
226139313Sjeff		self.buttons = Frame(self)
227139313Sjeff		self.buttons.grid(row=1, column=0, sticky=E+W)
228139313Sjeff		self.canvas = canvas
229139313Sjeff		self.drawlabels()
230139313Sjeff		self.drawbuttons()
231139313Sjeff		event.displayref(canvas)
232139313Sjeff		self.bind("<Destroy>", self.destroycb)
233139313Sjeff
234139313Sjeff	def destroycb(self, event):
235139313Sjeff		self.unbind("<Destroy>")
236139313Sjeff		if (self.event != None):
237139313Sjeff			self.event.displayunref(self.canvas)
238139313Sjeff			self.event = None
239139313Sjeff		self.destroy()
240139313Sjeff
241139313Sjeff	def clearlabels(self):
242139313Sjeff		for label in self.frame.grid_slaves():
243139313Sjeff			label.grid_remove()
244139313Sjeff
245139313Sjeff	def drawlabels(self):
246139313Sjeff		ypos = 0
247139313Sjeff		labels = self.event.labels()
248139313Sjeff		while (len(labels) < 7):
249139313Sjeff			labels.append(("", "", 0))
250139313Sjeff		for label in labels:
251139313Sjeff			name, value, linked = label
252139313Sjeff			l = Label(self.frame, text=name, bd=1, width=15,
253139313Sjeff			    relief=SUNKEN, anchor=W)
254139313Sjeff			if (linked):
255139313Sjeff				fgcolor = "blue"
256139313Sjeff			else:
257139313Sjeff				fgcolor = "black"
258139313Sjeff			r = Label(self.frame, text=value, bd=1,
259139313Sjeff			    relief=SUNKEN, anchor=W, fg=fgcolor)
260139313Sjeff			l.grid(row=ypos, column=0, sticky=E+W)
261139313Sjeff			r.grid(row=ypos, column=1, sticky=E+W)
262139313Sjeff			if (linked):
263139313Sjeff				r.bind("<Button-1>", self.linkpress)
264139313Sjeff			ypos += 1
265139313Sjeff		self.frame.columnconfigure(1, minsize=80)
266139313Sjeff
267139313Sjeff	def drawbuttons(self):
268139313Sjeff		self.back = Button(self.buttons, text="<", command=self.bpress)
269139313Sjeff		self.forw = Button(self.buttons, text=">", command=self.fpress)
270139313Sjeff		self.new = Button(self.buttons, text="new", command=self.npress)
271139313Sjeff		self.back.grid(row=0, column=0, sticky=E+W)
272139313Sjeff		self.forw.grid(row=0, column=1, sticky=E+W)
273139313Sjeff		self.new.grid(row=0, column=2, sticky=E+W)
274139313Sjeff		self.buttons.columnconfigure(2, weight=1)
275139313Sjeff
276139313Sjeff	def newevent(self, event):
277139313Sjeff		self.event.displayunref(self.canvas)
278139313Sjeff		self.clearlabels()
279139313Sjeff		self.event = event
280139313Sjeff		self.event.displayref(self.canvas)
281139313Sjeff		self.drawlabels()
282139313Sjeff
283139313Sjeff	def npress(self):
284139313Sjeff		EventView(self.event, self.canvas)
285139313Sjeff
286139313Sjeff	def bpress(self):
287139313Sjeff		prev = self.event.prev()
288139313Sjeff		if (prev == None):
289139313Sjeff			return
290139313Sjeff		while (prev.real == 0):
291139313Sjeff			prev = prev.prev()
292139313Sjeff			if (prev == None):
293139313Sjeff				return
294139313Sjeff		self.newevent(prev)
295139313Sjeff
296139313Sjeff	def fpress(self):
297139313Sjeff		next = self.event.next()
298139313Sjeff		if (next == None):
299139313Sjeff			return
300139313Sjeff		while (next.real == 0):
301139313Sjeff			next = next.next()
302139313Sjeff			if (next == None):
303139313Sjeff				return
304139313Sjeff		self.newevent(next)
305139313Sjeff
306139313Sjeff	def linkpress(self, wevent):
307139313Sjeff		event = self.event.getlinked()
308139313Sjeff		if (event != None):
309139313Sjeff			self.newevent(event)
310139313Sjeff
311139313Sjeffclass Event:
312139313Sjeff	name = "none"
313139313Sjeff	color = "grey"
314139313Sjeff	def __init__(self, source, cpu, timestamp, last=0):
315139313Sjeff		self.source = source
316139313Sjeff		self.cpu = cpu
317139313Sjeff		self.timestamp = int(timestamp)
318139313Sjeff		self.entries = []
319139313Sjeff		self.real = 1
320139313Sjeff		self.idx = None
321139313Sjeff		self.state = 0
322139313Sjeff		self.item = None
323139313Sjeff		self.dispcnt = 0
324139313Sjeff		self.linked = None
325139313Sjeff		if (last):
326139313Sjeff			source.lastevent(self)
327139313Sjeff		else:
328139313Sjeff			source.event(self)
329139313Sjeff
330139313Sjeff	def status(self):
331139313Sjeff		statstr = self.name + " " + self.source.name
332139313Sjeff		statstr += " on: cpu" + str(self.cpu)
333139313Sjeff		statstr += " at: " + str(self.timestamp)
334139313Sjeff		statstr += self.stattxt()
335139313Sjeff		status.set(statstr)
336139313Sjeff
337139313Sjeff	def stattxt(self):
338139313Sjeff		return ""
339139313Sjeff
340139313Sjeff	def textadd(self, tuple):
341139313Sjeff		pass
342139313Sjeff		self.entries.append(tuple)
343139313Sjeff
344139313Sjeff	def labels(self):
345139313Sjeff		return [("Source:", self.source.name, 0),
346139313Sjeff				("Event:", self.name, 0),
347139313Sjeff				("CPU:", self.cpu, 0),
348139313Sjeff				("Timestamp:", self.timestamp, 0)] + self.entries
349139313Sjeff	def mouseenter(self, canvas, item):
350139313Sjeff		self.displayref(canvas)
351139313Sjeff		self.status()
352139313Sjeff
353139313Sjeff	def mouseexit(self, canvas, item):
354139313Sjeff		self.displayunref(canvas)
355139313Sjeff		status.clear()
356139313Sjeff
357139313Sjeff	def mousepress(self, canvas, item):
358139313Sjeff		EventView(self, canvas)
359139313Sjeff
360139313Sjeff	def next(self):
361139313Sjeff		return self.source.eventat(self.idx + 1)
362139313Sjeff
363139313Sjeff	def prev(self):
364139313Sjeff		return self.source.eventat(self.idx - 1)
365139313Sjeff
366139313Sjeff	def displayref(self, canvas):
367139313Sjeff		if (self.dispcnt == 0):
368139313Sjeff			canvas.itemconfigure(self.item, width=2)
369139313Sjeff		self.dispcnt += 1
370139313Sjeff
371139313Sjeff	def displayunref(self, canvas):
372139313Sjeff		self.dispcnt -= 1
373139313Sjeff		if (self.dispcnt == 0):
374139313Sjeff			canvas.itemconfigure(self.item, width=0)
375139313Sjeff			canvas.tag_raise("point", "state")
376139313Sjeff
377139313Sjeff	def getlinked(self):
378139313Sjeff		return self.linked.findevent(self.timestamp)
379139313Sjeff
380139313Sjeffclass PointEvent(Event):
381139313Sjeff	def __init__(self, thread, cpu, timestamp, last=0):
382139313Sjeff		Event.__init__(self, thread, cpu, timestamp, last)
383139313Sjeff
384139313Sjeff	def draw(self, canvas, xpos, ypos):
385139313Sjeff		l = canvas.create_oval(xpos - 6, ypos + 1, xpos + 6, ypos - 11,
386139313Sjeff		    fill=self.color, tags=("all", "point", "event")
387139313Sjeff		    + (self.name,), width=0)
388139313Sjeff		canvas.events[l] = self
389139313Sjeff		self.item = l
390139313Sjeff		if (self.enabled == 0):
391139313Sjeff			canvas.itemconfigure(l, state="hidden")
392139313Sjeff
393139313Sjeff		return (xpos)
394139313Sjeff
395139313Sjeffclass StateEvent(Event):
396139313Sjeff	def __init__(self, thread, cpu, timestamp, last=0):
397139313Sjeff		Event.__init__(self, thread, cpu, timestamp, last)
398139313Sjeff		self.duration = 0
399139313Sjeff		self.skipnext = 0
400139313Sjeff		self.skipself = 0
401139313Sjeff		self.state = 1
402139313Sjeff
403139313Sjeff	def draw(self, canvas, xpos, ypos):
404139313Sjeff		next = self.nextstate()
405139313Sjeff		if (self.skipself == 1 or next == None):
406139313Sjeff			return (xpos)
407139321Sjeff		while (self.skipnext):
408139313Sjeff			skipped = next
409139313Sjeff			next.skipself = 1
410139313Sjeff			next.real = 0
411139313Sjeff			next = next.nextstate()
412139313Sjeff			if (next == None):
413139313Sjeff				next = skipped
414139321Sjeff			self.skipnext -= 1
415139313Sjeff		self.duration = next.timestamp - self.timestamp
416139313Sjeff		delta = self.duration / canvas.ratio
417139313Sjeff		l = canvas.create_rectangle(xpos, ypos,
418139313Sjeff		    xpos + delta, ypos - 10, fill=self.color, width=0,
419139313Sjeff		    tags=("all", "state", "event") + (self.name,))
420139313Sjeff		canvas.events[l] = self
421139313Sjeff		self.item = l
422139313Sjeff		if (self.enabled == 0):
423139313Sjeff			canvas.itemconfigure(l, state="hidden")
424139313Sjeff
425139313Sjeff		return (xpos + delta)
426139313Sjeff
427139313Sjeff	def stattxt(self):
428139313Sjeff		return " duration: " + ticks2sec(self.duration)
429139313Sjeff
430139313Sjeff	def nextstate(self):
431139313Sjeff		next = self.next()
432139313Sjeff		while (next != None and next.state == 0):
433139313Sjeff			next = next.next()
434139313Sjeff		return (next)
435139313Sjeff
436139313Sjeff	def labels(self):
437139313Sjeff		return [("Source:", self.source.name, 0),
438139313Sjeff				("Event:", self.name, 0),
439139313Sjeff				("Timestamp:", self.timestamp, 0),
440139313Sjeff				("CPU:", self.cpu, 0),
441139313Sjeff				("Duration:", ticks2sec(self.duration), 0)] \
442139313Sjeff				 + self.entries
443139313Sjeff
444139313Sjeffclass Count(Event):
445139313Sjeff	name = "Count"
446139313Sjeff	color = "red"
447139313Sjeff	enabled = 1
448139313Sjeff	def __init__(self, source, cpu, timestamp, count):
449139313Sjeff		self.count = int(count)
450139313Sjeff		Event.__init__(self, source, cpu, timestamp)
451139313Sjeff		self.duration = 0
452139313Sjeff		self.textadd(("count:", self.count, 0))
453139313Sjeff
454139313Sjeff	def draw(self, canvas, xpos, ypos):
455139313Sjeff		next = self.next()
456139313Sjeff		self.duration = next.timestamp - self.timestamp
457139313Sjeff		delta = self.duration / canvas.ratio
458139313Sjeff		yhight = self.source.yscale() * self.count
459139313Sjeff		l = canvas.create_rectangle(xpos, ypos - yhight,
460139313Sjeff		    xpos + delta, ypos, fill=self.color, width=0,
461139313Sjeff		    tags=("all", "count", "event") + (self.name,))
462139313Sjeff		canvas.events[l] = self
463139313Sjeff		self.item = l
464139313Sjeff		if (self.enabled == 0):
465139313Sjeff			canvas.itemconfigure(l, state="hidden")
466139313Sjeff		return (xpos + delta)
467139313Sjeff
468139313Sjeff	def stattxt(self):
469139313Sjeff		return " count: " + str(self.count)
470139313Sjeff
471139313Sjeffconfigtypes.append(Count)
472139313Sjeff
473139313Sjeffclass Running(StateEvent):
474139313Sjeff	name = "running"
475139313Sjeff	color = "green"
476139313Sjeff	enabled = 1
477139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
478139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
479139313Sjeff		self.prio = prio
480139313Sjeff		self.textadd(("prio:", self.prio, 0))
481139313Sjeff
482139313Sjeffconfigtypes.append(Running)
483139313Sjeff
484139313Sjeffclass Idle(StateEvent):
485139313Sjeff	name = "idle"
486139313Sjeff	color = "grey"
487139313Sjeff	enabled = 0
488139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
489139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
490139313Sjeff		self.prio = prio
491139313Sjeff		self.textadd(("prio:", self.prio, 0))
492139313Sjeff
493139313Sjeffconfigtypes.append(Idle)
494139313Sjeff
495139313Sjeffclass Yielding(StateEvent):
496139313Sjeff	name = "yielding"
497139313Sjeff	color = "yellow"
498139313Sjeff	enabled = 1
499139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
500139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
501139321Sjeff		self.skipnext = 2
502139313Sjeff		self.prio = prio
503139313Sjeff		self.textadd(("prio:", self.prio, 0))
504139313Sjeff
505139313Sjeffconfigtypes.append(Yielding)
506139313Sjeff
507139313Sjeffclass Swapped(StateEvent):
508139313Sjeff	name = "swapped"
509139313Sjeff	color = "violet"
510139313Sjeff	enabled = 1
511139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
512139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
513139313Sjeff		self.prio = prio
514139313Sjeff		self.textadd(("prio:", self.prio, 0))
515139313Sjeff
516139313Sjeffconfigtypes.append(Swapped)
517139313Sjeff
518139313Sjeffclass Suspended(StateEvent):
519139313Sjeff	name = "suspended"
520139313Sjeff	color = "purple"
521139313Sjeff	enabled = 1
522139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
523139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
524139313Sjeff		self.prio = prio
525139313Sjeff		self.textadd(("prio:", self.prio, 0))
526139313Sjeff
527139313Sjeffconfigtypes.append(Suspended)
528139313Sjeff
529139313Sjeffclass Iwait(StateEvent):
530139313Sjeff	name = "iwait"
531139313Sjeff	color = "grey"
532139313Sjeff	enabled = 0
533139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
534139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
535139313Sjeff		self.prio = prio
536139313Sjeff		self.textadd(("prio:", self.prio, 0))
537139313Sjeff
538139313Sjeffconfigtypes.append(Iwait)
539139313Sjeff
540139313Sjeffclass Preempted(StateEvent):
541139313Sjeff	name = "preempted"
542139313Sjeff	color = "red"
543139313Sjeff	enabled = 1
544139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, bythread):
545139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
546139321Sjeff		self.skipnext = 2
547139313Sjeff		self.prio = prio
548139313Sjeff		self.linked = bythread
549139313Sjeff		self.textadd(("prio:", self.prio, 0))
550139313Sjeff		self.textadd(("by thread:", self.linked.name, 1))
551139313Sjeff
552139313Sjeffconfigtypes.append(Preempted)
553139313Sjeff
554139313Sjeffclass Sleep(StateEvent):
555139313Sjeff	name = "sleep"
556139313Sjeff	color = "blue"
557139313Sjeff	enabled = 1
558139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, wmesg):
559139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
560139313Sjeff		self.prio = prio
561139313Sjeff		self.wmesg = wmesg
562139313Sjeff		self.textadd(("prio:", self.prio, 0))
563139313Sjeff		self.textadd(("wmesg:", self.wmesg, 0))
564139313Sjeff
565139313Sjeff	def stattxt(self):
566139313Sjeff		statstr = StateEvent.stattxt(self)
567139313Sjeff		statstr += " sleeping on: " + self.wmesg
568139313Sjeff		return (statstr)
569139313Sjeff
570139313Sjeffconfigtypes.append(Sleep)
571139313Sjeff
572139313Sjeffclass Blocked(StateEvent):
573139313Sjeff	name = "blocked"
574139313Sjeff	color = "dark red"
575139313Sjeff	enabled = 1
576139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, lock):
577139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
578139313Sjeff		self.prio = prio
579139313Sjeff		self.lock = lock
580139313Sjeff		self.textadd(("prio:", self.prio, 0))
581139313Sjeff		self.textadd(("lock:", self.lock, 0))
582139313Sjeff
583139313Sjeff	def stattxt(self):
584139313Sjeff		statstr = StateEvent.stattxt(self)
585139313Sjeff		statstr += " blocked on: " + self.lock
586139313Sjeff		return (statstr)
587139313Sjeff
588139313Sjeffconfigtypes.append(Blocked)
589139313Sjeff
590139313Sjeffclass KsegrpRunq(StateEvent):
591139313Sjeff	name = "KsegrpRunq"
592139313Sjeff	color = "orange"
593139313Sjeff	enabled = 1
594139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, bythread):
595139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
596139313Sjeff		self.prio = prio
597139313Sjeff		self.linked = bythread
598139313Sjeff		self.textadd(("prio:", self.prio, 0))
599139313Sjeff		self.textadd(("by thread:", self.linked.name, 1))
600139313Sjeff
601139313Sjeffconfigtypes.append(KsegrpRunq)
602139313Sjeff
603139313Sjeffclass Runq(StateEvent):
604139313Sjeff	name = "Runq"
605139313Sjeff	color = "yellow"
606139313Sjeff	enabled = 1
607139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, bythread):
608139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
609139313Sjeff		self.prio = prio
610139313Sjeff		self.linked = bythread
611139313Sjeff		self.textadd(("prio:", self.prio, 0))
612139313Sjeff		self.textadd(("by thread:", self.linked.name, 1))
613139313Sjeff
614139313Sjeffconfigtypes.append(Runq)
615139313Sjeff
616139313Sjeffclass Sched_exit(StateEvent):
617139313Sjeff	name = "exit"
618139313Sjeff	color = "grey"
619139313Sjeff	enabled = 0
620139313Sjeff	def __init__(self, thread, cpu, timestamp, prio):
621139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp)
622139313Sjeff		self.name = "sched_exit"
623139313Sjeff		self.prio = prio
624139313Sjeff		self.textadd(("prio:", self.prio, 0))
625139313Sjeff
626139313Sjeffconfigtypes.append(Sched_exit)
627139313Sjeff
628139313Sjeffclass Padevent(StateEvent):
629139313Sjeff	def __init__(self, thread, cpu, timestamp, last=0):
630139313Sjeff		StateEvent.__init__(self, thread, cpu, timestamp, last)
631139313Sjeff		self.name = "pad"
632139313Sjeff		self.real = 0
633139313Sjeff
634139313Sjeff	def draw(self, canvas, xpos, ypos):
635139313Sjeff		next = self.next()
636139313Sjeff		if (next == None):
637139313Sjeff			return (xpos)
638139313Sjeff		self.duration = next.timestamp - self.timestamp
639139313Sjeff		delta = self.duration / canvas.ratio
640139313Sjeff		return (xpos + delta)
641139313Sjeff
642139313Sjeffclass Tick(PointEvent):
643139313Sjeff	name = "tick"
644139313Sjeff	color = "black"
645139313Sjeff	enabled = 0
646139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, stathz):
647139313Sjeff		PointEvent.__init__(self, thread, cpu, timestamp)
648139313Sjeff		self.prio = prio
649139313Sjeff		self.textadd(("prio:", self.prio, 0))
650139313Sjeff
651139313Sjeffconfigtypes.append(Tick)
652139313Sjeff
653139313Sjeffclass Prio(PointEvent):
654139313Sjeff	name = "prio"
655139313Sjeff	color = "black"
656139313Sjeff	enabled = 0
657139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, newprio, bythread):
658139313Sjeff		PointEvent.__init__(self, thread, cpu, timestamp)
659139313Sjeff		self.prio = prio
660139313Sjeff		self.newprio = newprio
661139313Sjeff		self.linked = bythread
662139313Sjeff		self.textadd(("new prio:", self.newprio, 0))
663139313Sjeff		self.textadd(("prio:", self.prio, 0))
664139313Sjeff		if (self.linked != self.source):
665139313Sjeff			self.textadd(("by thread:", self.linked.name, 1))
666139313Sjeff		else:
667139313Sjeff			self.textadd(("by thread:", self.linked.name, 0))
668139313Sjeff
669139313Sjeffconfigtypes.append(Prio)
670139313Sjeff
671139313Sjeffclass Lend(PointEvent):
672139313Sjeff	name = "lend"
673139313Sjeff	color = "black"
674139313Sjeff	enabled = 0
675139313Sjeff	def __init__(self, thread, cpu, timestamp, prio, tothread):
676139313Sjeff		PointEvent.__init__(self, thread, cpu, timestamp)
677139313Sjeff		self.prio = prio
678139313Sjeff		self.linked = tothread
679139313Sjeff		self.textadd(("prio:", self.prio, 0))
680139313Sjeff		self.textadd(("to thread:", self.linked.name, 1))
681139313Sjeff
682139313Sjeffconfigtypes.append(Lend)
683139313Sjeff
684139313Sjeffclass Wokeup(PointEvent):
685139313Sjeff	name = "wokeup"
686139313Sjeff	color = "black"
687139313Sjeff	enabled = 0
688139313Sjeff	def __init__(self, thread, cpu, timestamp, ranthread):
689139313Sjeff		PointEvent.__init__(self, thread, cpu, timestamp)
690139313Sjeff		self.linked = ranthread
691139313Sjeff		self.textadd(("ran thread:", self.linked.name, 1))
692139313Sjeff
693139313Sjeffconfigtypes.append(Wokeup)
694139313Sjeff
695139313Sjeffclass EventSource:
696139313Sjeff	def __init__(self, name):
697139313Sjeff		self.name = name
698139313Sjeff		self.events = []
699139313Sjeff		self.cpu = 0
700139313Sjeff		self.cpux = 0
701139313Sjeff
702139313Sjeff	def fixup(self):
703139313Sjeff		pass
704139313Sjeff
705139313Sjeff	def event(self, event):
706139313Sjeff		self.events.insert(0, event)
707139313Sjeff
708139313Sjeff	def remove(self, event):
709139313Sjeff		self.events.remove(event)
710139313Sjeff
711139313Sjeff	def lastevent(self, event):
712139313Sjeff		self.events.append(event)
713139313Sjeff
714139313Sjeff	def draw(self, canvas, ypos):
715139313Sjeff		xpos = 10
716139313Sjeff		self.cpux = 10
717139313Sjeff		self.cpu = self.events[1].cpu
718139313Sjeff		for i in range(0, len(self.events)):
719139313Sjeff			self.events[i].idx = i
720139313Sjeff		for event in self.events:
721139313Sjeff			if (event.cpu != self.cpu and event.cpu != -1):
722139313Sjeff				self.drawcpu(canvas, xpos, ypos)
723139313Sjeff				self.cpux = xpos
724139313Sjeff				self.cpu = event.cpu
725139313Sjeff			xpos = event.draw(canvas, xpos, ypos)
726139313Sjeff		self.drawcpu(canvas, xpos, ypos)
727139313Sjeff
728139313Sjeff	def drawname(self, canvas, ypos):
729139313Sjeff		ypos = ypos - (self.ysize() / 2)
730139313Sjeff		canvas.create_text(10, ypos, anchor="w", text=self.name)
731139313Sjeff
732139313Sjeff	def drawcpu(self, canvas, xpos, ypos):
733139313Sjeff		cpu = int(self.cpu)
734139313Sjeff		if (cpu == 0):
735139313Sjeff			color = 'light grey'
736139313Sjeff		elif (cpu == 1):
737139313Sjeff			color = 'dark grey'
738139313Sjeff		elif (cpu == 2):
739139313Sjeff			color = 'light blue'
740139313Sjeff		elif (cpu == 3):
741152131Srwatson			color = 'light green'
742139313Sjeff		else:
743152131Srwatson			color = "white"
744139313Sjeff		l = canvas.create_rectangle(self.cpux,
745139313Sjeff		    ypos - self.ysize() - canvas.bdheight,
746139313Sjeff		    xpos, ypos + canvas.bdheight, fill=color, width=0,
747139313Sjeff		    tags=("all", "cpuinfo"))
748139313Sjeff
749139313Sjeff	def ysize(self):
750139313Sjeff		return (None)
751139313Sjeff
752139313Sjeff	def eventat(self, i):
753139313Sjeff		if (i >= len(self.events)):
754139313Sjeff			return (None)
755139313Sjeff		event = self.events[i]
756139313Sjeff		return (event)
757139313Sjeff
758139313Sjeff	def findevent(self, timestamp):
759139313Sjeff		for event in self.events:
760139313Sjeff			if (event.timestamp >= timestamp and event.real):
761139313Sjeff				return (event)
762139313Sjeff		return (None)
763139313Sjeff
764139313Sjeffclass Thread(EventSource):
765139313Sjeff	names = {}
766139313Sjeff	def __init__(self, td, pcomm):
767139313Sjeff		EventSource.__init__(self, pcomm)
768139313Sjeff		self.str = td
769139313Sjeff		try:
770139313Sjeff			cnt = Thread.names[pcomm]
771139313Sjeff		except:
772139313Sjeff			Thread.names[pcomm] = 0
773139313Sjeff			return
774139313Sjeff		Thread.names[pcomm] = cnt + 1
775139313Sjeff
776139313Sjeff	def fixup(self):
777139313Sjeff		cnt = Thread.names[self.name]
778139313Sjeff		if (cnt == 0):
779139313Sjeff			return
780139313Sjeff		cnt -= 1
781139313Sjeff		Thread.names[self.name] = cnt
782139313Sjeff		self.name += " td" + str(cnt)
783139313Sjeff
784139313Sjeff	def ysize(self):
785139313Sjeff		return (10)
786139313Sjeff
787139313Sjeffclass Counter(EventSource):
788139313Sjeff	max = 0
789139313Sjeff	def __init__(self, name):
790139313Sjeff		EventSource.__init__(self, name)
791139313Sjeff
792139313Sjeff	def event(self, event):
793139313Sjeff		EventSource.event(self, event)
794139313Sjeff		try:
795139313Sjeff			count = event.count
796139313Sjeff		except:
797139313Sjeff			return
798139313Sjeff		count = int(count)
799139313Sjeff		if (count > Counter.max):
800139313Sjeff			Counter.max = count
801139313Sjeff
802139313Sjeff	def ysize(self):
803139313Sjeff		return (80)
804139313Sjeff
805139313Sjeff	def yscale(self):
806139313Sjeff		return (self.ysize() / Counter.max)
807139313Sjeff
808139313Sjeff
809139313Sjeffclass KTRFile:
810139313Sjeff	def __init__(self, file):
811139313Sjeff		self.timestamp_first = None
812139313Sjeff		self.timestamp_last = None
813139313Sjeff		self.lineno = -1
814139313Sjeff		self.threads = []
815139313Sjeff		self.sources = []
816139313Sjeff		self.ticks = {}
817139313Sjeff		self.load = {}
818139313Sjeff
819139313Sjeff		self.parse(file)
820139313Sjeff		self.fixup()
821139313Sjeff		global ticksps
822139313Sjeff		ticksps = self.ticksps()
823139313Sjeff
824139313Sjeff	def parse(self, file):
825139313Sjeff		try:
826139313Sjeff			ifp = open(file)
827139313Sjeff		except:
828139313Sjeff			print "Can't open", file
829139313Sjeff			sys.exit(1)
830139313Sjeff
831139313Sjeff		ktrhdr = "\s+\d+\s+(\d+)\s+(\d+)\s+"
832139313Sjeff		tdname = "(\S+)\(([^)]*)\)"
833139313Sjeff
834139313Sjeff		ktrstr = "mi_switch: " + tdname
835139313Sjeff		ktrstr += " prio (\d+) inhibit (\d+) wmesg (\S+) lock (\S+)"
836139313Sjeff		switchout_re = re.compile(ktrhdr + ktrstr)
837139313Sjeff
838139313Sjeff		ktrstr = "mi_switch: " + tdname + " prio (\d+) idle"
839139313Sjeff		idled_re = re.compile(ktrhdr + ktrstr)
840139313Sjeff
841139313Sjeff		ktrstr = "mi_switch: " + tdname + " prio (\d+) preempted by "
842139313Sjeff		ktrstr += tdname
843139313Sjeff		preempted_re = re.compile(ktrhdr + ktrstr)
844139313Sjeff
845139313Sjeff		ktrstr = "mi_switch: running " + tdname + " prio (\d+)"
846139313Sjeff		switchin_re = re.compile(ktrhdr + ktrstr)
847139313Sjeff
848139313Sjeff		ktrstr = "sched_add: " + tdname + " prio (\d+) by " + tdname
849139313Sjeff		sched_add_re = re.compile(ktrhdr + ktrstr)
850139313Sjeff
851139313Sjeff		ktrstr = "setrunqueue: " + tdname + " prio (\d+) by " + tdname
852139313Sjeff		setrunqueue_re = re.compile(ktrhdr + ktrstr)
853139313Sjeff
854139313Sjeff		ktrstr = "sched_rem: " + tdname + " prio (\d+) by " + tdname
855139313Sjeff		sched_rem_re = re.compile(ktrhdr + ktrstr)
856139313Sjeff
857139313Sjeff		ktrstr = "sched_exit_thread: " + tdname + " prio (\d+)"
858139313Sjeff		sched_exit_re = re.compile(ktrhdr + ktrstr)
859139313Sjeff
860139313Sjeff		ktrstr = "statclock: " + tdname + " prio (\d+)"
861139313Sjeff		ktrstr += " stathz (\d+)"
862139313Sjeff		sched_clock_re = re.compile(ktrhdr + ktrstr)
863139313Sjeff
864139313Sjeff		ktrstr = "sched_prio: " + tdname + " prio (\d+)"
865139313Sjeff		ktrstr += " newprio (\d+) by " + tdname
866139313Sjeff		sched_prio_re = re.compile(ktrhdr + ktrstr)
867139313Sjeff
868139319Sjeff		cpuload_re = re.compile(ktrhdr + "load: (\d+)")
869139319Sjeff		loadglobal_re = re.compile(ktrhdr + "global load: (\d+)")
870139313Sjeff
871139313Sjeff		parsers = [[cpuload_re, self.cpuload],
872139313Sjeff			   [loadglobal_re, self.loadglobal],
873139313Sjeff			   [switchin_re, self.switchin],
874139313Sjeff			   [switchout_re, self.switchout],
875139313Sjeff			   [sched_add_re, self.sched_add],
876139313Sjeff			   [setrunqueue_re, self.sched_rem],
877139313Sjeff			   [sched_prio_re, self.sched_prio],
878139313Sjeff			   [preempted_re, self.preempted],
879139313Sjeff			   [sched_rem_re, self.sched_rem],
880139313Sjeff			   [sched_exit_re, self.sched_exit],
881139313Sjeff			   [sched_clock_re, self.sched_clock],
882139313Sjeff			   [idled_re, self.idled]]
883139313Sjeff
884139313Sjeff		for line in ifp.readlines():
885139313Sjeff			self.lineno += 1
886139313Sjeff			if ((self.lineno % 1024) == 0):
887139313Sjeff				status.startup("Parsing line " +
888139313Sjeff				    str(self.lineno))
889139313Sjeff			for p in parsers:
890139313Sjeff				m = p[0].match(line)
891139313Sjeff				if (m != None):
892139313Sjeff					p[1](*m.groups())
893139313Sjeff					break
894139313Sjeff			# if (m == None):
895139313Sjeff			# 	print line,
896139313Sjeff
897139313Sjeff	def checkstamp(self, timestamp):
898139313Sjeff		timestamp = int(timestamp)
899139313Sjeff		if (self.timestamp_first == None):
900139313Sjeff			self.timestamp_first = timestamp
901139313Sjeff		if (timestamp > self.timestamp_first):
902139313Sjeff			print "Bad timestamp on line ", self.lineno
903139313Sjeff			return (0)
904139313Sjeff		self.timestamp_last = timestamp
905139313Sjeff		return (1)
906139313Sjeff
907139313Sjeff	def timespan(self):
908139313Sjeff		return (self.timestamp_first - self.timestamp_last);
909139313Sjeff
910139313Sjeff	def ticksps(self):
911139313Sjeff		return (self.timespan() / self.ticks[0]) * int(self.stathz)
912139313Sjeff
913139313Sjeff	def switchout(self, cpu, timestamp, td, pcomm, prio, inhibit, wmesg, lock):
914139313Sjeff		TDI_SUSPENDED = 0x0001
915139313Sjeff		TDI_SLEEPING = 0x0002
916139313Sjeff		TDI_SWAPPED = 0x0004
917139313Sjeff		TDI_LOCK = 0x0008
918139313Sjeff		TDI_IWAIT = 0x0010
919139313Sjeff
920139313Sjeff		if (self.checkstamp(timestamp) == 0):
921139313Sjeff			return
922139313Sjeff		inhibit = int(inhibit)
923139313Sjeff		thread = self.findtd(td, pcomm)
924139313Sjeff		if (inhibit & TDI_SWAPPED):
925139313Sjeff			Swapped(thread, cpu, timestamp, prio)
926139313Sjeff		elif (inhibit & TDI_SLEEPING):
927139313Sjeff			Sleep(thread, cpu, timestamp, prio, wmesg)
928139313Sjeff		elif (inhibit & TDI_LOCK):
929139313Sjeff			Blocked(thread, cpu, timestamp, prio, lock)
930139313Sjeff		elif (inhibit & TDI_IWAIT):
931139313Sjeff			Iwait(thread, cpu, timestamp, prio)
932139313Sjeff		elif (inhibit & TDI_SUSPENDED):
933139313Sjeff			Suspended(thread, cpu, timestamp, prio)
934139313Sjeff		elif (inhibit == 0):
935139313Sjeff			Yielding(thread, cpu, timestamp, prio)
936139313Sjeff		else:
937139313Sjeff			print "Unknown event", inhibit
938139313Sjeff			sys.exit(1)
939139313Sjeff
940139313Sjeff	def idled(self, cpu, timestamp, td, pcomm, prio):
941139313Sjeff		if (self.checkstamp(timestamp) == 0):
942139313Sjeff			return
943139313Sjeff		thread = self.findtd(td, pcomm)
944139313Sjeff		Idle(thread, cpu, timestamp, prio)
945139313Sjeff
946139313Sjeff	def preempted(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
947139313Sjeff		if (self.checkstamp(timestamp) == 0):
948139313Sjeff			return
949139313Sjeff		thread = self.findtd(td, pcomm)
950139313Sjeff		Preempted(thread, cpu, timestamp, prio,
951139313Sjeff		    self.findtd(bytd, bypcomm))
952139313Sjeff
953139313Sjeff	def switchin(self, cpu, timestamp, td, pcomm, prio):
954139313Sjeff		if (self.checkstamp(timestamp) == 0):
955139313Sjeff			return
956139313Sjeff		thread = self.findtd(td, pcomm)
957139313Sjeff		Running(thread, cpu, timestamp, prio)
958139313Sjeff
959139313Sjeff	def sched_add(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
960139313Sjeff		if (self.checkstamp(timestamp) == 0):
961139313Sjeff			return
962139313Sjeff		thread = self.findtd(td, pcomm)
963139313Sjeff		bythread = self.findtd(bytd, bypcomm)
964139313Sjeff		Runq(thread, cpu, timestamp, prio, bythread)
965139313Sjeff		Wokeup(bythread, cpu, timestamp, thread)
966139313Sjeff
967139313Sjeff	def sched_rem(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
968139313Sjeff		if (self.checkstamp(timestamp) == 0):
969139313Sjeff			return
970139313Sjeff		thread = self.findtd(td, pcomm)
971139313Sjeff		KsegrpRunq(thread, cpu, timestamp, prio,
972139313Sjeff		    self.findtd(bytd, bypcomm))
973139313Sjeff
974139313Sjeff	def sched_exit(self, cpu, timestamp, td, pcomm, prio):
975139313Sjeff		if (self.checkstamp(timestamp) == 0):
976139313Sjeff			return
977139313Sjeff		thread = self.findtd(td, pcomm)
978139313Sjeff		Sched_exit(thread, cpu, timestamp, prio)
979139313Sjeff
980139313Sjeff	def sched_clock(self, cpu, timestamp, td, pcomm, prio, stathz):
981139313Sjeff		if (self.checkstamp(timestamp) == 0):
982139313Sjeff			return
983139313Sjeff		self.stathz = stathz
984139313Sjeff		cpu = int(cpu)
985139313Sjeff		try:
986139313Sjeff			ticks = self.ticks[cpu]
987139313Sjeff		except:
988139313Sjeff			self.ticks[cpu] = 0
989139313Sjeff		self.ticks[cpu] += 1
990139313Sjeff		thread = self.findtd(td, pcomm)
991139313Sjeff		Tick(thread, cpu, timestamp, prio, stathz)
992139313Sjeff
993139313Sjeff	def sched_prio(self, cpu, timestamp, td, pcomm, prio, newprio, bytd, bypcomm):
994139313Sjeff		if (prio == newprio):
995139313Sjeff			return
996139313Sjeff		if (self.checkstamp(timestamp) == 0):
997139313Sjeff			return
998139313Sjeff		thread = self.findtd(td, pcomm)
999139313Sjeff		bythread = self.findtd(bytd, bypcomm)
1000139313Sjeff		Prio(thread, cpu, timestamp, prio, newprio, bythread)
1001139313Sjeff		Lend(bythread, cpu, timestamp, newprio, thread)
1002139313Sjeff
1003139313Sjeff	def cpuload(self, cpu, timestamp, count):
1004139320Sjeff		if (self.checkstamp(timestamp) == 0):
1005139320Sjeff			return
1006139313Sjeff		cpu = int(cpu)
1007139313Sjeff		try:
1008139313Sjeff			load = self.load[cpu]
1009139313Sjeff		except:
1010139313Sjeff			load = Counter("cpu" + str(cpu) + " load")
1011139313Sjeff			self.load[cpu] = load
1012139313Sjeff			self.sources.insert(0, load)
1013139313Sjeff		Count(load, cpu, timestamp, count)
1014139313Sjeff
1015139313Sjeff	def loadglobal(self, cpu, timestamp, count):
1016139320Sjeff		if (self.checkstamp(timestamp) == 0):
1017139320Sjeff			return
1018139313Sjeff		cpu = 0
1019139313Sjeff		try:
1020139313Sjeff			load = self.load[cpu]
1021139313Sjeff		except:
1022139313Sjeff			load = Counter("CPU load")
1023139313Sjeff			self.load[cpu] = load
1024139313Sjeff			self.sources.insert(0, load)
1025139313Sjeff		Count(load, cpu, timestamp, count)
1026139313Sjeff
1027139313Sjeff	def findtd(self, td, pcomm):
1028139313Sjeff		for thread in self.threads:
1029139313Sjeff			if (thread.str == td and thread.name == pcomm):
1030139313Sjeff				return thread
1031139313Sjeff		thread = Thread(td, pcomm)
1032139313Sjeff		self.threads.append(thread)
1033139313Sjeff		self.sources.append(thread)
1034139313Sjeff		return (thread)
1035139313Sjeff
1036139313Sjeff	def fixup(self):
1037139313Sjeff		for source in self.sources:
1038139313Sjeff			Padevent(source, -1, self.timestamp_last)
1039139313Sjeff			Padevent(source, -1, self.timestamp_first, last=1)
1040139313Sjeff			source.fixup()
1041139313Sjeff
1042139313Sjeffclass SchedDisplay(Canvas):
1043139313Sjeff	def __init__(self, master):
1044139313Sjeff		self.ratio = 1
1045139313Sjeff		self.ktrfile = None
1046139313Sjeff		self.sources = None
1047139313Sjeff		self.bdheight = 10
1048139313Sjeff		self.events = {}
1049139313Sjeff
1050139313Sjeff		Canvas.__init__(self, master, width=800, height=500, bg='grey',
1051139313Sjeff		     scrollregion=(0, 0, 800, 500))
1052139313Sjeff
1053139313Sjeff	def setfile(self, ktrfile):
1054139313Sjeff		self.ktrfile = ktrfile
1055139313Sjeff		self.sources = ktrfile.sources
1056139313Sjeff
1057139313Sjeff	def draw(self):
1058139313Sjeff		ypos = 0
1059139313Sjeff		xsize = self.xsize()
1060139313Sjeff		for source in self.sources:
1061139313Sjeff			status.startup("Drawing " + source.name)
1062139313Sjeff			self.create_line(0, ypos, xsize, ypos,
1063139313Sjeff			    width=1, fill="black", tags=("all",))
1064139313Sjeff			ypos += self.bdheight
1065139313Sjeff			ypos += source.ysize()
1066139313Sjeff			source.draw(self, ypos)
1067139313Sjeff			ypos += self.bdheight
1068139313Sjeff			try:
1069139313Sjeff				self.tag_raise("point", "state")
1070139313Sjeff				self.tag_lower("cpuinfo", "all")
1071139313Sjeff			except:
1072139313Sjeff				pass
1073139313Sjeff		self.create_line(0, ypos, xsize, ypos,
1074139313Sjeff		    width=1, fill="black", tags=("all",))
1075139313Sjeff		self.tag_bind("event", "<Enter>", self.mouseenter)
1076139313Sjeff		self.tag_bind("event", "<Leave>", self.mouseexit)
1077139313Sjeff		self.tag_bind("event", "<Button-1>", self.mousepress)
1078139313Sjeff
1079139313Sjeff	def mouseenter(self, event):
1080139313Sjeff		item, = self.find_withtag(CURRENT)
1081139313Sjeff		event = self.events[item]
1082139313Sjeff		event.mouseenter(self, item)
1083139313Sjeff
1084139313Sjeff	def mouseexit(self, event):
1085139313Sjeff		item, = self.find_withtag(CURRENT)
1086139313Sjeff		event = self.events[item]
1087139313Sjeff		event.mouseexit(self, item)
1088139313Sjeff
1089139313Sjeff	def mousepress(self, event):
1090139313Sjeff		item, = self.find_withtag(CURRENT)
1091139313Sjeff		event = self.events[item]
1092139313Sjeff		event.mousepress(self, item)
1093139313Sjeff
1094139313Sjeff	def drawnames(self, canvas):
1095139313Sjeff		status.startup("Drawing names")
1096139313Sjeff		ypos = 0
1097139313Sjeff		canvas.configure(scrollregion=(0, 0,
1098139313Sjeff		    canvas["width"], self.ysize()))
1099139313Sjeff		for source in self.sources:
1100139313Sjeff			canvas.create_line(0, ypos, canvas["width"], ypos,
1101139313Sjeff			    width=1, fill="black", tags=("all",))
1102139313Sjeff			ypos += self.bdheight
1103139313Sjeff			ypos += source.ysize()
1104139313Sjeff			source.drawname(canvas, ypos)
1105139313Sjeff			ypos += self.bdheight
1106139313Sjeff		canvas.create_line(0, ypos, canvas["width"], ypos,
1107139313Sjeff		    width=1, fill="black", tags=("all",))
1108139313Sjeff
1109139313Sjeff	def xsize(self):
1110139313Sjeff		return ((self.ktrfile.timespan() / self.ratio) + 20)
1111139313Sjeff
1112139313Sjeff	def ysize(self):
1113139313Sjeff		ysize = 0
1114139313Sjeff		for source in self.sources:
1115139313Sjeff			ysize += source.ysize() + (self.bdheight * 2)
1116139313Sjeff		return (ysize)
1117139313Sjeff
1118139313Sjeff	def scaleset(self, ratio):
1119139313Sjeff		if (self.ktrfile == None):
1120139313Sjeff			return
1121139313Sjeff		oldratio = self.ratio
1122139313Sjeff		xstart, ystart = self.xview()
1123139313Sjeff		length = (float(self["width"]) / self.xsize())
1124139313Sjeff		middle = xstart + (length / 2)
1125139313Sjeff
1126139313Sjeff		self.ratio = ratio
1127139313Sjeff		self.configure(scrollregion=(0, 0, self.xsize(), self.ysize()))
1128139313Sjeff		self.scale("all", 0, 0, float(oldratio) / ratio, 1)
1129139313Sjeff
1130139313Sjeff		length = (float(self["width"]) / self.xsize())
1131139313Sjeff		xstart = middle - (length / 2)
1132139313Sjeff		self.xview_moveto(xstart)
1133139313Sjeff
1134139313Sjeff	def scaleget(self):
1135139313Sjeff		return self.ratio
1136139313Sjeff
1137139313Sjeff	def setcolor(self, tag, color):
1138139313Sjeff		self.itemconfigure(tag, state="normal", fill=color)
1139139313Sjeff
1140139313Sjeff	def hide(self, tag):
1141139313Sjeff		self.itemconfigure(tag, state="hidden")
1142139313Sjeff
1143139313Sjeffclass GraphMenu(Frame):
1144139313Sjeff	def __init__(self, master):
1145139313Sjeff		Frame.__init__(self, master, bd=2, relief=RAISED)
1146139313Sjeff		self.view = Menubutton(self, text="Configure")
1147139313Sjeff		self.viewmenu = Menu(self.view, tearoff=0)
1148139313Sjeff		self.viewmenu.add_command(label="Events",
1149139313Sjeff		    command=self.econf)
1150139313Sjeff		self.view["menu"] = self.viewmenu
1151139313Sjeff		self.view.pack(side=LEFT)
1152139313Sjeff
1153139313Sjeff	def econf(self):
1154139313Sjeff		EventConfigure()
1155139313Sjeff
1156139313Sjeff
1157139313Sjeffclass SchedGraph(Frame):
1158139313Sjeff	def __init__(self, master):
1159139313Sjeff		Frame.__init__(self, master)
1160139313Sjeff		self.menu = None
1161139313Sjeff		self.names = None
1162139313Sjeff		self.display = None
1163139313Sjeff		self.scale = None
1164139313Sjeff		self.status = None
1165139313Sjeff		self.pack(expand=1, fill="both")
1166139313Sjeff		self.buildwidgets()
1167139313Sjeff		self.layout()
1168139313Sjeff		self.draw(sys.argv[1])
1169139313Sjeff
1170139313Sjeff	def buildwidgets(self):
1171139313Sjeff		global status
1172139313Sjeff		self.menu = GraphMenu(self)
1173139313Sjeff		self.display = SchedDisplay(self)
1174139313Sjeff		self.names = Canvas(self,
1175139313Sjeff		    width=100, height=self.display["height"],
1176139313Sjeff		    bg='grey', scrollregion=(0, 0, 50, 100))
1177139313Sjeff		self.scale = Scaler(self, self.display)
1178139313Sjeff		status = self.status = Status(self)
1179139313Sjeff		self.scrollY = Scrollbar(self, orient="vertical",
1180139313Sjeff		    command=self.display_yview)
1181139313Sjeff		self.display.scrollX = Scrollbar(self, orient="horizontal",
1182139313Sjeff		    command=self.display.xview)
1183139313Sjeff		self.display["xscrollcommand"] = self.display.scrollX.set
1184139313Sjeff		self.display["yscrollcommand"] = self.scrollY.set
1185139313Sjeff		self.names["yscrollcommand"] = self.scrollY.set
1186139313Sjeff
1187139313Sjeff	def layout(self):
1188139313Sjeff		self.columnconfigure(1, weight=1)
1189139313Sjeff		self.rowconfigure(1, weight=1)
1190139313Sjeff		self.menu.grid(row=0, column=0, columnspan=3, sticky=E+W)
1191139313Sjeff		self.names.grid(row=1, column=0, sticky=N+S)
1192139313Sjeff		self.display.grid(row=1, column=1, sticky=W+E+N+S)
1193139313Sjeff		self.scrollY.grid(row=1, column=2, sticky=N+S)
1194139313Sjeff		self.display.scrollX.grid(row=2, column=0, columnspan=2,
1195139313Sjeff		    sticky=E+W)
1196139313Sjeff		self.scale.grid(row=3, column=0, columnspan=3, sticky=E+W)
1197139313Sjeff		self.status.grid(row=4, column=0, columnspan=3, sticky=E+W)
1198139313Sjeff
1199139313Sjeff	def draw(self, file):
1200139313Sjeff		self.master.update()
1201139313Sjeff		ktrfile = KTRFile(file)
1202139313Sjeff		self.display.setfile(ktrfile)
1203139313Sjeff		self.display.drawnames(self.names)
1204139313Sjeff		self.display.draw()
1205139313Sjeff		self.scale.set(250000)
1206139313Sjeff		self.display.xview_moveto(0)
1207139313Sjeff
1208139313Sjeff	def display_yview(self, *args):
1209139313Sjeff		self.names.yview(*args)
1210139313Sjeff		self.display.yview(*args)
1211139313Sjeff
1212139313Sjeff	def setcolor(self, tag, color):
1213139313Sjeff		self.display.setcolor(tag, color)
1214139313Sjeff
1215139313Sjeff	def hide(self, tag):
1216139313Sjeff		self.display.hide(tag)
1217139313Sjeff
1218139313Sjeffif (len(sys.argv) != 2):
1219139313Sjeff	print "usage:", sys.argv[0], "<ktr file>"
1220139313Sjeff	sys.exit(1)
1221139313Sjeff
1222139313Sjeffroot = Tk()
1223139313Sjeffroot.title("Scheduler Graph")
1224139313Sjeffgraph = SchedGraph(root)
1225139313Sjeffroot.mainloop()
1226