From owner-svn-src-head@FreeBSD.ORG Sat Jan 17 07:24:25 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5DBF2106564A; Sat, 17 Jan 2009 07:24:25 +0000 (UTC) (envelope-from jeff@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 497E38FC0A; Sat, 17 Jan 2009 07:24:25 +0000 (UTC) (envelope-from jeff@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n0H7OPBv030714; Sat, 17 Jan 2009 07:24:25 GMT (envelope-from jeff@svn.freebsd.org) Received: (from jeff@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n0H7OP7h030713; Sat, 17 Jan 2009 07:24:25 GMT (envelope-from jeff@svn.freebsd.org) Message-Id: <200901170724.n0H7OP7h030713@svn.freebsd.org> From: Jeff Roberson Date: Sat, 17 Jan 2009 07:24:25 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r187358 - head/tools/sched X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 17 Jan 2009 07:24:25 -0000 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 ***