o expand usage comments; add cut&paste items for bozo's like me

o add things i want to TODO list
o add Record entry to each event which back-maps to the line # in the ktr file;
  useful for finding local context when the ktr file has lots of items that
  schedgraph doesn't grok
o add missing KTR_SCHED event handlers
o expose Counter max value through a ymax method for widget building
o show timestamps in records rejected 'cuz time goes backwards
This commit is contained in:
sam 2007-11-19 04:46:37 +00:00
parent c0f07cdcc9
commit 6ea4f452e3

View File

@ -31,10 +31,17 @@
from Tkinter import *
# To use:
# - Install the ports/x11-toolkits/py-tkinter package.
# - Add KTR_SCHED to KTR_COMPILE and KTR_MASK in your KERNCONF
# - It is encouraged to increase KTR_ENTRIES size to 32768 to gather
# enough information for analysis.
# - Install the ports/x11-toolkits/py-tkinter package; e.g.
# portinstall x11-toolkits/py-tkinter package
# - Add KTR_SCHED to KTR_COMPILE and KTR_MASK in your KERNCONF; e.g.
# options KTR
# options KTR_ENTRIES=32768
# options KTR_COMPILE=(KTR_SCHED)
# options KTR_MASK=(KTR_SCHED)
# options KTR_CPUMASK=0x3
# - It is encouraged to increase KTR_ENTRIES size to gather enough
# information for analysis; e.g.
# options KTR_ENTRIES=262144
# - Rebuild kernel with proper changes to KERNCONF and boot new kernel.
# - Run your workload to be profiled.
# - While the workload is continuing (i.e. before it finishes), disable
@ -52,6 +59,11 @@
# 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
#
# BUGS: 1) Only 8 CPUs are supported, more CPUs require more choices of
# colours to represent them ;-)
@ -62,6 +74,7 @@
ticksps = None
status = None
configtypes = []
lineno = -1
def ticks2sec(ticks):
us = ticksps / 1000000
@ -334,6 +347,7 @@ def __init__(self, source, cpu, timestamp, last=0):
self.item = None
self.dispcnt = 0
self.linked = None
self.recno = lineno
if (last):
source.lastevent(self)
else:
@ -355,9 +369,11 @@ def textadd(self, tuple):
def labels(self):
return [("Source:", self.source.name, 0),
("Event:", self.name, 0),
("CPU:", self.cpu, 0),
("Timestamp:", self.timestamp, 0)] + self.entries
("Event:", self.name, 0),
("CPU:", self.cpu, 0),
("Timestamp:", self.timestamp, 0),
("Record: ", self.recno, 0)
] + self.entries
def mouseenter(self, canvas, item):
self.displayref(canvas)
self.status()
@ -452,11 +468,12 @@ def nextstate(self):
def labels(self):
return [("Source:", self.source.name, 0),
("Event:", self.name, 0),
("Timestamp:", self.timestamp, 0),
("CPU:", self.cpu, 0),
("Duration:", ticks2sec(self.duration), 0)] \
+ self.entries
("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"
@ -630,6 +647,18 @@ def __init__(self, thread, cpu, timestamp, prio, bythread):
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"
@ -824,6 +853,9 @@ def event(self, event):
if (count > Counter.max):
Counter.max = count
def ymax(self):
return (Counter.max)
def ysize(self):
return (80)
@ -838,7 +870,6 @@ def __init__(self, file):
self.timestamp_adjust = {}
self.timestamp_f = None
self.timestamp_l = None
self.lineno = -1
self.threads = []
self.sources = []
self.ticks = {}
@ -866,6 +897,8 @@ def parse(self, file):
tdname = "(\S+)\(([^)]*)\)"
crittdname = "(\S+)\s+\(\d+,\s+([^)]*)\)"
# XXX doesn't handle:
# 371 0 61628682318 mi_switch: 0xc075c070(swapper) prio 180 inhibit 2 wmesg ATA request done lock (null)
ktrstr = "mi_switch: " + tdname
ktrstr += " prio (\d+) inhibit (\d+) wmesg (\S+) lock (\S+)"
switchout_re = re.compile(ktrhdr + ktrstr)
@ -890,6 +923,9 @@ def parse(self, file):
sched_rem_re = re.compile(ktrhdr + ktrstr)
ktrstr = "sched_exit_thread: " + tdname + " prio (\d+)"
sched_exit_thread_re = re.compile(ktrhdr + ktrstr)
ktrstr = "sched_exit: " + tdname + " prio (\d+)"
sched_exit_re = re.compile(ktrhdr + ktrstr)
ktrstr = "statclock: " + tdname + " prio (\d+)"
@ -917,18 +953,20 @@ def parse(self, file):
[sched_prio_re, self.sched_prio],
[preempted_re, self.preempted],
[sched_rem_re, self.sched_rem],
[sched_exit_thread_re, self.sched_exit_thread],
[sched_exit_re, self.sched_exit],
[sched_clock_re, self.sched_clock],
[critsec_re, self.critsec],
[idled_re, self.idled]]
global lineno
lineno = 0
lines = ifp.readlines()
self.synchstamp(lines)
for line in lines:
self.lineno += 1
if ((self.lineno % 1024) == 0):
status.startup("Parsing line " +
str(self.lineno))
lineno += 1
if ((lineno % 1024) == 0):
status.startup("Parsing line " + str(lineno))
for p in parsers:
m = p[0].match(line)
if (m != None):
@ -1001,7 +1039,7 @@ def checkstamp(self, cpu, timestamp):
cpu = int(cpu)
timestamp = int(timestamp)
if (timestamp > self.timestamp_first[cpu]):
print "Bad timestamp on line ", self.lineno
print "Bad timestamp on line ", lineno, " (", timestamp, " > ", self.timestamp_first[cpu], ")"
return (0)
timestamp -= self.timestamp_adjust[cpu]
return (timestamp)
@ -1079,6 +1117,13 @@ def sched_rem(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
KsegrpRunq(thread, cpu, timestamp, prio,
self.findtd(bytd, bypcomm))
def sched_exit_thread(self, cpu, timestamp, td, pcomm, prio):
timestamp = self.checkstamp(cpu, timestamp)
if (timestamp == 0):
return
thread = self.findtd(td, pcomm)
Sched_exit_thread(thread, cpu, timestamp, prio)
def sched_exit(self, cpu, timestamp, td, pcomm, prio):
timestamp = self.checkstamp(cpu, timestamp)
if (timestamp == 0):