svn commit: r187358 - head/tools/sched

Jeff Roberson jeff at FreeBSD.org
Fri Jan 16 23:24:25 PST 2009


Author: jeff
Date: Sat Jan 17 07:24:25 2009
New Revision: 187358
URL: http://svn.freebsd.org/changeset/base/187358

Log:
   - Rewrite the parser to support the new generic schedgraph interface.
     This no longer requires any custom classes or parsers to support new
     event types.
   - Add an optional command line argument for specifying the clock frequency
     in ghz.  This is useful for traces that do not include KTR_SCHED.
  
  Sponsored by:	Nokia
  
   - Add support for sorting rows by clicking and dragging them to their new
     position.
   - Add support for configuring the cpu background colors.
   - Improve the scaling so a better center is maintained as you zoom.  This
     is not perfect due to precision loss with floats used in the window
     views.
   - Add new colors and a random assignment for unknown event types.  A table
     is used for known event types.  This is the only event specific
     information.

Modified:
  head/tools/sched/schedgraph.py

Modified: head/tools/sched/schedgraph.py
==============================================================================
--- head/tools/sched/schedgraph.py	Sat Jan 17 07:17:57 2009	(r187357)
+++ head/tools/sched/schedgraph.py	Sat Jan 17 07:24:25 2009	(r187358)
@@ -28,6 +28,7 @@
 
 import sys
 import re
+import random
 from Tkinter import *
 
 # To use:
@@ -53,30 +54,96 @@ from Tkinter import *
 #   while the workload is still running is to avoid wasting log entries on
 #   "idle" time at the end.
 # - Dump the trace to a file: 'ktrdump -ct > ktr.out'
-# - Run the python script: 'python schedgraph.py ktr.out'
+# - Run the python script: 'python schedgraph.py ktr.out' optionally provide
+#   your cpu frequency in ghz: 'python schedgraph.py ktr.out 2.4'
 #
 # To do:
-# 1)  Add a per-thread summary display
-# 2)  Add bounding box style zoom.
-# 3)  Click to center.
-# 4)  Implement some sorting mechanism.
-# 5)  Widget to display variable-range data (e.g. q length)
-# 6)  Reorder rows, hide rows, etc.
-# 7)  "Vertical rule" to help relate data in different rows
-# 8)  Mouse-over popup of full thread/event/row lable (currently truncated)
-# 9)  More visible anchors for popup event windows
+# Add a per-source summary display
+# Click to move.
+# Hide rows
+# "Vertical rule" to help relate data in different rows
+# Mouse-over popup of full thread/event/row label (currently truncated)
+# More visible anchors for popup event windows
 #
 # BUGS: 1) Only 8 CPUs are supported, more CPUs require more choices of
 #          colours to represent them ;-)
-#       2) Extremely short traces may cause a crash because the code
-#          assumes there is always at least one stathz entry logged, and
-#          the number of such events is used as a denominator
+
+eventcolors = [
+	("count",	"red"),
+	("running",	"green"),
+	("idle",	"grey"),
+	("yielding",	"yellow"),
+	("swapped",	"violet"),
+	("suspended",	"purple"),
+	("iwait",	"grey"),
+	("sleep",	"blue"),
+	("blocked",	"dark red"),
+	("runq add",	"yellow"),
+	("runq rem",	"yellow"),
+	("thread exit",	"grey"),
+	("proc exit",	"grey"),
+	("callwheel idle", "grey"),
+	("callout running", "green"),
+	("lock acquire", "blue"),
+	("lock contest", "purple"),
+	("failed lock try", "red"),
+	("lock release", "grey"),
+	("tick",	"black"),
+	("prio",	"black"),
+	("lend prio",	"black"),
+	("wokeup",	"black")
+]
+
+cpucolors = [
+	("CPU 0",	"light grey"),
+	("CPU 1",	"dark grey"),
+	("CPU 2",	"light blue"),
+	("CPU 3",	"light pink"),
+	("CPU 4",	"blanched almond"),
+	("CPU 5",	"slate grey"),
+	("CPU 6",	"tan"),
+	("CPU 7",	"thistle"),
+	("CPU 8",	"white")
+]
+
+colors = [
+	"white", "thistle", "blanched almond", "tan", "chartreuse",
+	"dark red", "red", "pale violet red", "pink", "light pink",
+	"dark orange", "orange", "coral", "light coral",
+	"goldenrod", "gold", "yellow", "light yellow",
+	"dark green", "green", "light green", "light sea green",
+	"dark blue", "blue", "light blue", "steel blue", "light slate blue",
+	"dark violet", "violet", "purple", "blue violet",
+	"dark grey", "slate grey", "light grey",
+	"black",
+]
+colors.sort()
 
 ticksps = None
 status = None
-configtypes = []
+colormap = None
+ktrfile = None
+clockfreq = None
+sources = []
 lineno = -1
 
+class Colormap:
+	def __init__(self, table):
+		self.table = table
+		self.map = {}
+		for entry in table:
+			self.map[entry[0]] = entry[1]
+
+	def lookup(self, name):
+		try:
+			color = self.map[name]
+		except:
+			color = colors[random.randrange(0, len(colors))]
+			print "Picking random color", color, "for", name
+			self.map[name] = color
+			self.table.append((name, color))
+		return (color)
+
 def ticks2sec(ticks):
 	us = ticksps / 1000000
 	ticks /= us
@@ -124,9 +191,13 @@ class Status(Frame):
 		self.set(str)
 		root.update()
 
-class EventConf(Frame):
-	def __init__(self, master, name, color, enabled):
+class ColorConf(Frame):
+	def __init__(self, master, name, color):
 		Frame.__init__(self, master)
+		if (graph.getstate(name) == "hidden"):
+			enabled = 0
+		else:
+			enabled = 1
 		self.name = name
 		self.color = StringVar()
 		self.color_default = color
@@ -144,16 +215,8 @@ class EventConf(Frame):
 		    bg='grey')
 		self.rect = self.sample.create_rectangle(0, 0, 24, 24,
 		    fill=self.color.get())
-		self.list = OptionMenu(self, self.color,
-		    "dark red", "red", "pink",
-		    "dark orange", "orange",
-		    "yellow", "light yellow",
-		    "dark green", "green", "light green",
-		    "dark blue", "blue", "light blue",
-		    "dark violet", "violet", "purple",
-		    "dark grey", "light grey",
-		    "white", "black",
-		    command=self.setcolor)
+		self.list = OptionMenu(self, self.color, command=self.setcolor,
+		    *colors)
 		self.checkbox = Checkbutton(self, text="enabled",
 		    variable=self.enabled)
 		self.label.grid(row=0, column=0, sticky=E+W)
@@ -161,7 +224,7 @@ class EventConf(Frame):
 		self.list.grid(row=0, column=2, sticky=E+W)
 		self.checkbox.grid(row=0, column=3)
 		self.columnconfigure(0, weight=1)
-		self.columnconfigure(2, minsize=110)
+		self.columnconfigure(2, minsize=150)
 
 	def setcolor(self, color):
 		self.color.set(color)
@@ -186,19 +249,15 @@ class EventConf(Frame):
 			graph.setcolor(self.name, self.color_current)
 
 	def revert(self):
-		self.setcolor(self.color_current)
-		self.enabled.set(self.enabled_current)
-
-	def default(self):
 		self.setcolor(self.color_default)
 		self.enabled.set(self.enabled_default)
 
-class EventConfigure(Toplevel):
-	def __init__(self):
+class ColorConfigure(Toplevel):
+	def __init__(self, table, name):
 		Toplevel.__init__(self)
 		self.resizable(0, 0)
-		self.title("Event Configuration")
-		self.items = LabelFrame(self, text="Event Type")
+		self.title(name)
+		self.items = LabelFrame(self, text="Item Type")
 		self.buttons = Frame(self)
 		self.drawbuttons()
 		self.items.grid(row=0, column=0, sticky=E+W)
@@ -206,11 +265,13 @@ class EventConfigure(Toplevel):
 		self.buttons.grid(row=1, column=0, sticky=E+W)
 		self.types = []
 		self.irow = 0
-		for type in configtypes:
-			self.additem(type.name, type.color, type.enabled)
+		for type in table:
+			color = graph.getcolor(type[0])
+			if (color != ""):
+				self.additem(type[0], color)
 
-	def additem(self, name, color, enabled=1):
-		item = EventConf(self.items, name, color, enabled)
+	def additem(self, name, color):
+		item = ColorConf(self.items, name, color)
 		self.types.append(item)
 		item.grid(row=self.irow, column=0, sticky=E+W)
 		self.irow += 1
@@ -218,16 +279,12 @@ class EventConfigure(Toplevel):
 	def drawbuttons(self):
 		self.apply = Button(self.buttons, text="Apply",
 		    command=self.apress)
-		self.revert = Button(self.buttons, text="Revert",
+		self.default = Button(self.buttons, text="Revert",
 		    command=self.rpress)
-		self.default = Button(self.buttons, text="Default",
-		    command=self.dpress)
 		self.apply.grid(row=0, column=0, sticky=E+W)
-		self.revert.grid(row=0, column=1, sticky=E+W)
-		self.default.grid(row=0, column=2, sticky=E+W)
+		self.default.grid(row=0, column=1, sticky=E+W)
 		self.buttons.columnconfigure(0, weight=1)
 		self.buttons.columnconfigure(1, weight=1)
-		self.buttons.columnconfigure(2, weight=1)
 
 	def apress(self):
 		for item in self.types:
@@ -237,20 +294,16 @@ class EventConfigure(Toplevel):
 		for item in self.types:
 			item.revert()
 
-	def dpress(self):
-		for item in self.types:
-			item.default()
-
 class EventView(Toplevel):
 	def __init__(self, event, canvas):
 		Toplevel.__init__(self)
 		self.resizable(0, 0)
 		self.title("Event")
 		self.event = event
-		self.frame = Frame(self)
-		self.frame.grid(row=0, column=0, sticky=N+S+E+W)
 		self.buttons = Frame(self)
-		self.buttons.grid(row=1, column=0, sticky=E+W)
+		self.buttons.grid(row=0, column=0, sticky=E+W)
+		self.frame = Frame(self)
+		self.frame.grid(row=1, column=0, sticky=N+S+E+W)
 		self.canvas = canvas
 		self.drawlabels()
 		self.drawbuttons()
@@ -272,9 +325,12 @@ class EventView(Toplevel):
 		ypos = 0
 		labels = self.event.labels()
 		while (len(labels) < 7):
-			labels.append(("", "", 0))
+			labels.append(("", ""))
 		for label in labels:
-			name, value, linked = label
+			name, value = label
+			linked = 0
+			if (name == "linkedto"):
+				linked = 1
 			l = Label(self.frame, text=name, bd=1, width=15,
 			    relief=SUNKEN, anchor=W)
 			if (linked):
@@ -313,7 +369,7 @@ class EventView(Toplevel):
 		prev = self.event.prev()
 		if (prev == None):
 			return
-		while (prev.real == 0):
+		while (prev.type == "pad"):
 			prev = prev.prev()
 			if (prev == None):
 				return
@@ -323,7 +379,7 @@ class EventView(Toplevel):
 		next = self.event.next()
 		if (next == None):
 			return
-		while (next.real == 0):
+		while (next.type == "pad"):
 			next = next.next()
 			if (next == None):
 				return
@@ -335,60 +391,67 @@ class EventView(Toplevel):
 			self.newevent(event)
 
 class Event:
-	name = "none"
-	color = "grey"
-	def __init__(self, source, cpu, timestamp, last=0):
+	def __init__(self, source, name, cpu, timestamp, attrs):
 		self.source = source
+		self.name = name
 		self.cpu = cpu
 		self.timestamp = int(timestamp)
-		self.entries = []
-		self.real = 1
+		self.attrs = attrs
 		self.idx = None
-		self.state = 0
 		self.item = None
 		self.dispcnt = 0
-		self.linked = None
 		self.recno = lineno
-		if (last):
-			source.lastevent(self)
-		else:
-			source.event(self)
 
 	def status(self):
 		statstr = self.name + " " + self.source.name
 		statstr += " on: cpu" + str(self.cpu)
 		statstr += " at: " + str(self.timestamp)
-		statstr += self.stattxt()
+		statstr += " attributes: "
+		for i in range(0, len(self.attrs)):
+			attr = self.attrs[i]
+			statstr += attr[0] + ": " + str(attr[1])
+			if (i != len(self.attrs) - 1):
+				statstr += ", "
 		status.set(statstr)
 
-	def stattxt(self):
-		return ""
-
-	def textadd(self, tuple):
-		pass
-		self.entries.append(tuple)
-
 	def labels(self):
-		return [("Source:", self.source.name, 0),
-			("Event:", self.name, 0),
-			("CPU:", self.cpu, 0),
-			("Timestamp:", self.timestamp, 0),
-			("Record: ", self.recno, 0)
-		] + self.entries
-	def mouseenter(self, canvas, item):
+		return [("Source", self.source.name),
+			("Event", self.name),
+			("CPU", self.cpu),
+			("Timestamp", self.timestamp),
+			("KTR Line ", self.recno)
+		] + self.attrs
+
+	def mouseenter(self, canvas):
 		self.displayref(canvas)
 		self.status()
 
-	def mouseexit(self, canvas, item):
+	def mouseexit(self, canvas):
 		self.displayunref(canvas)
 		status.clear()
 
-	def mousepress(self, canvas, item):
+	def mousepress(self, canvas):
 		EventView(self, canvas)
 
+	def draw(self, canvas, xpos, ypos, item):
+		self.item = item
+		if (item != None):
+			canvas.items[item] = self
+
+	def move(self, canvas, x, y):
+		if (self.item == None):
+			return;
+		canvas.move(self.item, x, y);
+
 	def next(self):
 		return self.source.eventat(self.idx + 1)
 
+	def nexttype(self, type):
+		next = self.next()
+		while (next != None and next.type != type):
+			next = next.next()
+		return (next)
+
 	def prev(self):
 		return self.source.eventat(self.idx - 1)
 
@@ -404,435 +467,106 @@ class Event:
 			canvas.tag_raise("point", "state")
 
 	def getlinked(self):
-		return self.linked.findevent(self.timestamp)
+		for attr in self.attrs:
+			if (attr[0] != "linkedto"):
+				continue
+			source = ktrfile.findid(attr[1])
+			return source.findevent(self.timestamp)
+		return None
 
 class PointEvent(Event):
-	def __init__(self, thread, cpu, timestamp, last=0):
-		Event.__init__(self, thread, cpu, timestamp, last)
+	type = "point"
+	def __init__(self, source, name, cpu, timestamp, attrs):
+		Event.__init__(self, source, name, cpu, timestamp, attrs)
 
 	def draw(self, canvas, xpos, ypos):
+		color = colormap.lookup(self.name)
 		l = canvas.create_oval(xpos - 6, ypos + 1, xpos + 6, ypos - 11,
-		    fill=self.color, tags=("all", "point", "event")
-		    + (self.name,), width=0)
-		canvas.events[l] = self
-		self.item = l
-		if (self.enabled == 0):
-			canvas.itemconfigure(l, state="hidden")
+		    fill=color, tags=("all", "point", "event", self.name),
+		    width=0)
+		Event.draw(self, canvas, xpos, ypos, l)
 
-		return (xpos)
+		return xpos
 
 class StateEvent(Event):
-	def __init__(self, thread, cpu, timestamp, last=0):
-		Event.__init__(self, thread, cpu, timestamp, last)
-		self.duration = 0
-		self.skipnext = 0
-		self.skipself = 0
-		self.state = 1
+	type = "state"
+	def __init__(self, source, name, cpu, timestamp, attrs):
+		Event.__init__(self, source, name, cpu, timestamp, attrs)
 
 	def draw(self, canvas, xpos, ypos):
-		next = self.nextstate()
-		if (self.skipself == 1 or next == None):
+		next = self.nexttype("state")
+		if (next == None):
 			return (xpos)
-		while (self.skipnext):
-			skipped = next
-			next.skipself = 1
-			next.real = 0
-			next = next.nextstate()
-			if (next == None):
-				next = skipped
-			self.skipnext -= 1
-		self.duration = next.timestamp - self.timestamp
-		if (self.duration < 0):
-			self.duration = 0
+		duration = next.timestamp - self.timestamp
+		self.attrs.insert(0, ("duration", ticks2sec(duration)))
+		color = colormap.lookup(self.name)
+		if (duration < 0):
+			duration = 0
 			print "Unsynchronized timestamp"
 			print self.cpu, self.timestamp
 			print next.cpu, next.timestamp
-		delta = self.duration / canvas.ratio
+		delta = duration / canvas.ratio
 		l = canvas.create_rectangle(xpos, ypos,
-		    xpos + delta, ypos - 10, fill=self.color, width=0,
-		    tags=("all", "state", "event") + (self.name,))
-		canvas.events[l] = self
-		self.item = l
-		if (self.enabled == 0):
-			canvas.itemconfigure(l, state="hidden")
+		    xpos + delta, ypos - 10, fill=color, width=0,
+		    tags=("all", "state", "event", self.name))
+		Event.draw(self, canvas, xpos, ypos, l)
 
 		return (xpos + delta)
 
-	def stattxt(self):
-		return " duration: " + ticks2sec(self.duration)
-
-	def nextstate(self):
-		next = self.next()
-		while (next != None and next.state == 0):
-			next = next.next()
-		return (next)
-
-	def labels(self):
-		return [("Source:", self.source.name, 0),
-			("Event:", self.name, 0),
-			("Timestamp:", self.timestamp, 0),
-			("CPU:", self.cpu, 0),
-			("Record:", self.recno, 0),
-			("Duration:", ticks2sec(self.duration), 0)
-		] + self.entries
-
-class Count(Event):
-	name = "Count"
-	color = "red"
-	enabled = 1
-	def __init__(self, source, cpu, timestamp, count):
-		self.count = int(count)
-		Event.__init__(self, source, cpu, timestamp)
-		self.duration = 0
-		self.textadd(("count:", self.count, 0))
+class CountEvent(Event):
+	type = "count"
+	def __init__(self, source, count, cpu, timestamp, attrs):
+		count = int(count)
+		self.count = count
+		Event.__init__(self, source, "count", cpu, timestamp, attrs)
 
 	def draw(self, canvas, xpos, ypos):
-		next = self.next()
-		self.duration = next.timestamp - self.timestamp
-		delta = self.duration / canvas.ratio
+		next = self.nexttype("count")
+		if (next == None):
+			return (xpos)
+		color = colormap.lookup("count")
+		duration = next.timestamp - self.timestamp
+		self.attrs.insert(0, ("count", self.count))
+		self.attrs.insert(1, ("duration", ticks2sec(duration)))
+		delta = duration / canvas.ratio
 		yhight = self.source.yscale() * self.count
 		l = canvas.create_rectangle(xpos, ypos - yhight,
-		    xpos + delta, ypos, fill=self.color, width=0,
-		    tags=("all", "count", "event") + (self.name,))
-		canvas.events[l] = self
-		self.item = l
-		if (self.enabled == 0):
-			canvas.itemconfigure(l, state="hidden")
+		    xpos + delta, ypos, fill=color, width=0,
+		    tags=("all", "count", "event", self.name))
+		Event.draw(self, canvas, xpos, ypos, l)
 		return (xpos + delta)
 
-	def stattxt(self):
-		return " count: " + str(self.count)
-
-configtypes.append(Count)
-
-class Running(StateEvent):
-	name = "running"
-	color = "green"
-	enabled = 1
-	def __init__(self, thread, cpu, timestamp, prio):
-		StateEvent.__init__(self, thread, cpu, timestamp)
-		self.prio = prio
-		self.textadd(("prio:", self.prio, 0))
-
-configtypes.append(Running)
-
-class Idle(StateEvent):
-	name = "idle"
-	color = "grey"
-	enabled = 0
-	def __init__(self, thread, cpu, timestamp, prio):
-		StateEvent.__init__(self, thread, cpu, timestamp)
-		self.prio = prio
-		self.textadd(("prio:", self.prio, 0))
-
-configtypes.append(Idle)
-
-class Yielding(StateEvent):
-	name = "yielding"
-	color = "yellow"
-	enabled = 1
-	def __init__(self, thread, cpu, timestamp, prio):
-		StateEvent.__init__(self, thread, cpu, timestamp)
-		self.skipnext = 0
-		self.prio = prio
-		self.textadd(("prio:", self.prio, 0))
-
-configtypes.append(Yielding)
-
-class Swapped(StateEvent):
-	name = "swapped"
-	color = "violet"
-	enabled = 1
-	def __init__(self, thread, cpu, timestamp, prio):
-		StateEvent.__init__(self, thread, cpu, timestamp)
-		self.prio = prio
-		self.textadd(("prio:", self.prio, 0))
-
-configtypes.append(Swapped)
-
-class Suspended(StateEvent):
-	name = "suspended"
-	color = "purple"
-	enabled = 1
-	def __init__(self, thread, cpu, timestamp, prio):
-		StateEvent.__init__(self, thread, cpu, timestamp)
-		self.prio = prio
-		self.textadd(("prio:", self.prio, 0))
-
-configtypes.append(Suspended)
-
-class Iwait(StateEvent):
-	name = "iwait"
-	color = "grey"
-	enabled = 0
-	def __init__(self, thread, cpu, timestamp, prio):
-		StateEvent.__init__(self, thread, cpu, timestamp)
-		self.prio = prio
-		self.textadd(("prio:", self.prio, 0))
-
-configtypes.append(Iwait)
-
-class Preempted(StateEvent):
-	name = "preempted"
-	color = "red"
-	enabled = 1
-	def __init__(self, thread, cpu, timestamp, prio, bythread):
-		StateEvent.__init__(self, thread, cpu, timestamp)
-		self.skipnext = 1
-		self.prio = prio
-		self.linked = bythread
-		self.textadd(("prio:", self.prio, 0))
-		self.textadd(("by thread:", self.linked.name, 1))
-
-configtypes.append(Preempted)
-
-class Sleep(StateEvent):
-	name = "sleep"
-	color = "blue"
-	enabled = 1
-	def __init__(self, thread, cpu, timestamp, prio, wmesg):
-		StateEvent.__init__(self, thread, cpu, timestamp)
-		self.prio = prio
-		self.wmesg = wmesg
-		self.textadd(("prio:", self.prio, 0))
-		self.textadd(("wmesg:", self.wmesg, 0))
-
-	def stattxt(self):
-		statstr = StateEvent.stattxt(self)
-		statstr += " sleeping on: " + self.wmesg
-		return (statstr)
-
-configtypes.append(Sleep)
-
-class Blocked(StateEvent):
-	name = "blocked"
-	color = "dark red"
-	enabled = 1
-	def __init__(self, thread, cpu, timestamp, prio, lock):
-		StateEvent.__init__(self, thread, cpu, timestamp)
-		self.prio = prio
-		self.lock = lock
-		self.textadd(("prio:", self.prio, 0))
-		self.textadd(("lock:", self.lock, 0))
-
-	def stattxt(self):
-		statstr = StateEvent.stattxt(self)
-		statstr += " blocked on: " + self.lock
-		return (statstr)
-
-configtypes.append(Blocked)
-
-class KsegrpRunq(StateEvent):
-	name = "KsegrpRunq"
-	color = "orange"
-	enabled = 1
-	def __init__(self, thread, cpu, timestamp, prio, bythread):
-		StateEvent.__init__(self, thread, cpu, timestamp)
-		self.prio = prio
-		self.linked = bythread
-		self.textadd(("prio:", self.prio, 0))
-		self.textadd(("by thread:", self.linked.name, 1))
-
-configtypes.append(KsegrpRunq)
-
-class Runq(StateEvent):
-	name = "Runq"
-	color = "yellow"
-	enabled = 1
-	def __init__(self, thread, cpu, timestamp, prio, bythread):
-		StateEvent.__init__(self, thread, cpu, timestamp)
-		self.prio = prio
-		self.linked = bythread
-		self.textadd(("prio:", self.prio, 0))
-		self.textadd(("by thread:", self.linked.name, 1))
-
-configtypes.append(Runq)
-
-class Sched_exit_thread(StateEvent):
-	name = "exit_thread"
-	color = "grey"
-	enabled = 0
-	def __init__(self, thread, cpu, timestamp, prio):
-		StateEvent.__init__(self, thread, cpu, timestamp)
-		self.name = "sched_exit_thread"
-		self.prio = prio
-		self.textadd(("prio:", self.prio, 0))
-
-configtypes.append(Sched_exit_thread)
-
-class Sched_exit(StateEvent):
-	name = "exit"
-	color = "grey"
-	enabled = 0
-	def __init__(self, thread, cpu, timestamp, prio):
-		StateEvent.__init__(self, thread, cpu, timestamp)
-		self.name = "sched_exit"
-		self.prio = prio
-		self.textadd(("prio:", self.prio, 0))
-
-configtypes.append(Sched_exit)
-
-# Events for running callout routines
-
-class CalloutIdle(StateEvent):
-	name = "callwheel idle"
-	color = "grey"
-	enabled = 0
-	def __init__(self, wheel, cpu, timestamp):
-		StateEvent.__init__(self, wheel, cpu, timestamp)
-
-configtypes.append(CalloutIdle)
-
-class CalloutRunning(StateEvent):
-	name = "callout running"
-	color = "green"
-	enabled = 1
-	def __init__(self, wheel, cpu, timestamp, func, arg):
-		StateEvent.__init__(self, wheel, cpu, timestamp)
-		self.textadd(("function:", func, 0))
-		self.textadd(("argument:", arg, 0))
-		self.arg = arg
-		self.func = func
-
-	def stattxt(self):
-		statstr = StateEvent.stattxt(self)
-		statstr += " executing %s(%s)" % (self.func, self.arg)
-		return (statstr)
-
-configtypes.append(CalloutRunning)
-
-# Events on locks
-#
-# XXX: No support for upgrade/downgrade currently or differentiating
-# between read/write in general.
-#
-# XXX: Point events for recursion perhaps?
-
-class LockAcquire(StateEvent):
-	name = "lock acquire"
-	color = "blue"
-	enabled = 1
-	def __init__(self, lock, cpu, timestamp, file, line):
-		StateEvent.__init__(self, lock, cpu, timestamp)
-		self.textadd(("file:", file, 0))
-		self.textadd(("line:", line, 0))
-
-configtypes.append(LockAcquire)
-
-class LockContest(StateEvent):
-	name = "lock contest"
-	color = "purple"
-	enabled = 1
-	def __init__(self, lock, cpu, timestamp, file, line):
-		StateEvent.__init__(self, lock, cpu, timestamp)
-		self.textadd(("file:", file, 0))
-		self.textadd(("line:", line, 0))
-
-configtypes.append(LockContest)
-
-class LockFailedTry(PointEvent):
-	name = "failed lock try"
-	color = "red"
-	enabled = 1
-	def __init__(self, lock, cpu, timestamp, file, line):
-		PointEvent.__init__(self, lock, cpu, timestamp)
-		self.textadd(("file:", file, 0))
-		self.textadd(("line:", line, 0))
-
-configtypes.append(LockFailedTry)
-
-class LockRelease(StateEvent):
-	name = "lock release"
-	color = "grey"
-	enabled = 0
-	def __init__(self, lock, cpu, timestamp, file, line):
-		StateEvent.__init__(self, lock, cpu, timestamp)
-		self.textadd(("file:", file, 0))
-		self.textadd(("line:", line, 0))
-
-configtypes.append(LockRelease)
-
-class Padevent(StateEvent):
-	def __init__(self, thread, cpu, timestamp, last=0):
-		StateEvent.__init__(self, thread, cpu, timestamp, last)
-		self.name = "pad"
-		self.real = 0
-
+class PadEvent(StateEvent):
+	type = "pad"
+	def __init__(self, source, cpu, timestamp, last=0):
+		if (last):
+			cpu = source.events[len(source.events) -1].cpu
+		else:
+			cpu = source.events[0].cpu
+		StateEvent.__init__(self, source, "pad", cpu, timestamp, [])
 	def draw(self, canvas, xpos, ypos):
 		next = self.next()
 		if (next == None):
 			return (xpos)
-		self.duration = next.timestamp - self.timestamp
-		delta = self.duration / canvas.ratio
+		duration = next.timestamp - self.timestamp
+		delta = duration / canvas.ratio
+		Event.draw(self, canvas, xpos, ypos, None)
 		return (xpos + delta)
 
-class Tick(PointEvent):
-	name = "tick"
-	color = "black"
-	enabled = 0
-	def __init__(self, thread, cpu, timestamp, prio, stathz):
-		PointEvent.__init__(self, thread, cpu, timestamp)
-		self.prio = prio
-		self.textadd(("prio:", self.prio, 0))
-
-configtypes.append(Tick)
-
-class Prio(PointEvent):
-	name = "prio"
-	color = "black"
-	enabled = 0
-	def __init__(self, thread, cpu, timestamp, prio, newprio, bythread):
-		PointEvent.__init__(self, thread, cpu, timestamp)
-		self.prio = prio
-		self.newprio = newprio
-		self.linked = bythread
-		self.textadd(("new prio:", self.newprio, 0))
-		self.textadd(("prio:", self.prio, 0))
-		if (self.linked != self.source):
-			self.textadd(("by thread:", self.linked.name, 1))
-		else:
-			self.textadd(("by thread:", self.linked.name, 0))
-
-configtypes.append(Prio)
-
-class Lend(PointEvent):
-	name = "lend"
-	color = "black"
-	enabled = 0
-	def __init__(self, thread, cpu, timestamp, prio, tothread):
-		PointEvent.__init__(self, thread, cpu, timestamp)
-		self.prio = prio
-		self.linked = tothread
-		self.textadd(("prio:", self.prio, 0))
-		self.textadd(("to thread:", self.linked.name, 1))
-
-configtypes.append(Lend)
-
-class Wokeup(PointEvent):
-	name = "wokeup"
-	color = "black"
-	enabled = 0
-	def __init__(self, thread, cpu, timestamp, ranthread):
-		PointEvent.__init__(self, thread, cpu, timestamp)
-		self.linked = ranthread
-		self.textadd(("ran thread:", self.linked.name, 1))
-
-configtypes.append(Wokeup)
-
-(DEFAULT, LOAD, COUNT, CALLWHEEL, LOCK, THREAD) = range(6)
-
 class EventSource:
-	def __init__(self, name, group=DEFAULT, order=0):
-		self.name = name
+	def __init__(self, group, id):
+		self.name = id
 		self.events = []
-		self.cpu = 0
-		self.cpux = 0
+		self.cpuitems = []
 		self.group = group
-		self.order = order
+		self.y = 0
+		self.item = None
 
 	def __cmp__(self, other):
+		if (other == None):
+			return -1
 		if (self.group == other.group):
-			return cmp(self.order, other.order)
+			return cmp(self.name, other.name)
 		return cmp(self.group, other.group)
 
 	# It is much faster to append items to a list then to insert them
@@ -841,60 +575,54 @@ class EventSource:
 	def fixup(self):
 		self.events.reverse()
 
-	def event(self, event):
+	def addevent(self, event):
 		self.events.append(event)
 
-	def remove(self, event):
-		self.events.remove(event)
-
-	def lastevent(self, event):
+	def addlastevent(self, event):
 		self.events.insert(0, event)
 
 	def draw(self, canvas, ypos):
 		xpos = 10
-		self.cpux = 10
-		self.cpu = self.events[1].cpu
+		cpux = 10
+		cpu = self.events[1].cpu
 		for i in range(0, len(self.events)):
 			self.events[i].idx = i
 		for event in self.events:
-			if (event.cpu != self.cpu and event.cpu != -1):
-				self.drawcpu(canvas, xpos, ypos)
-				self.cpux = xpos
-				self.cpu = event.cpu
+			if (event.cpu != cpu and event.cpu != -1):
+				self.drawcpu(canvas, cpu, cpux, xpos, ypos)
+				cpux = xpos
+				cpu = event.cpu
 			xpos = event.draw(canvas, xpos, ypos)
-		self.drawcpu(canvas, xpos, ypos)
+		self.drawcpu(canvas, cpu, cpux, xpos, ypos)
 
 	def drawname(self, canvas, ypos):
+		self.y = ypos
 		ypos = ypos - (self.ysize() / 2)
-		canvas.create_text(10, ypos, anchor="w", text=self.name)
+		self.item = canvas.create_text(10, ypos, anchor="w", text=self.name)
+		return (self.item)
 
-	def drawcpu(self, canvas, xpos, ypos):
-		cpu = int(self.cpu)
-		if (cpu == 0):
-			color = 'light grey'
-		elif (cpu == 1):
-			color = 'dark grey'
-		elif (cpu == 2):
-			color = 'light blue'
-		elif (cpu == 3):
-			color = 'light green'
-		elif (cpu == 4):
-			color = 'blanched almond'
-		elif (cpu == 5):
-			color = 'slate grey'
-		elif (cpu == 6):
-			color = 'light slate blue'
-		elif (cpu == 7):
-			color = 'thistle'
-		else:
-			color = "white"
-		l = canvas.create_rectangle(self.cpux,
+	def drawcpu(self, canvas, cpu, fromx, tox, ypos):
+		cpu = "CPU " + str(cpu)
+		color = cpucolormap.lookup(cpu)
+		# Create the cpu background colors default to hidden
+		l = canvas.create_rectangle(fromx,
 		    ypos - self.ysize() - canvas.bdheight,
-		    xpos, ypos + canvas.bdheight, fill=color, width=0,
-		    tags=("all", "cpuinfo"))
+		    tox, ypos + canvas.bdheight, fill=color, width=0,
+		    tags=("all", "cpuinfo", cpu), state="hidden")
+		self.cpuitems.append(l)
+
+	def move(self, canvas, xpos, ypos):
+		for event in self.events:
+			event.move(canvas, xpos, ypos)
+		for item in self.cpuitems:
+			canvas.move(item, xpos, ypos)
+
+	def movename(self, canvas, xpos, ypos):
+		self.y += ypos
+		canvas.move(self.item, xpos, ypos)
 
 	def ysize(self):
-		return (None)
+		return (10)
 
 	def eventat(self, i):
 		if (i >= len(self.events)):
@@ -904,93 +632,45 @@ class EventSource:
 
 	def findevent(self, timestamp):
 		for event in self.events:
-			if (event.timestamp >= timestamp and event.real):
+			if (event.timestamp >= timestamp and event.type != "pad"):
 				return (event)
 		return (None)
 
-class Thread(EventSource):
-	names = {}
-	def __init__(self, td, pcomm):
-		EventSource.__init__(self, pcomm, THREAD)
-		self.str = td
+class Counter(EventSource):
+	#
+	# Store a hash of counter groups that keeps the max value
+	# for a counter in this group for scaling purposes.
+	#
+	groups = {}
+	def __init__(self, group, id):
 		try:
-			cnt = Thread.names[pcomm]
+			Counter.cnt = Counter.groups[group]
 		except:
-			Thread.names[pcomm] = 0
-			return
-		Thread.names[pcomm] = cnt + 1
-

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list