Add support for two new event source types:

- Callwheels traced via KTR_CALLOUT.  Each CPU is assigned a callwheel
  source.  The events on this source are the execution of individual callout
  routines.  Each routine shows up as a green rectangle while it is executed
  and the event details include the function pointer and argument.
- Locks traced via KTR_LOCK.  Currently, each lock name is assigned an event
  source (since the existing KTR_LOCK traces only include lock names and
  not pointers).  This does mean that if multiple locks of the same name are
  manipulated, the source line for that name may be confusing.  However, for
  many cases this can be useful.  Locks are blue when they are held and
  purple when contested.  The contention support is a bit weak due to
  limitations in the rw_rlock() and mtx_lock_spin() logging messages
  currently.  I also have not added support for contention on lockmgr,
  sx, or rmlocks yet.  What is there now can be profitably used to examine
  activity on Giant however.
- Expand the width of the event source names column a bit to allow for some
  of the longer names of these new source types.
This commit is contained in:
jhb 2009-01-13 16:44:18 +00:00
parent d89e3d19c0
commit 43a484c528

View File

@ -672,6 +672,86 @@ def __init__(self, thread, cpu, timestamp, prio):
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)
@ -739,7 +819,7 @@ def __init__(self, thread, cpu, timestamp, ranthread):
configtypes.append(Wokeup)
(DEFAULT, LOAD, COUNT, THREAD) = range(4)
(DEFAULT, LOAD, COUNT, CALLWHEEL, LOCK, THREAD) = range(6)
class EventSource:
def __init__(self, name, group=DEFAULT, order=0):
@ -852,6 +932,29 @@ def fixup(self):
def ysize(self):
return (10)
class Callwheel(EventSource):
count = 0
def __init__(self, cpu):
EventSource.__init__(self, "Callwheel", CALLWHEEL, cpu)
self.wheel = cpu
Callwheel.count += 1
def fixup(self):
EventSource.fixup(self)
if (Callwheel.count == 1):
return
self.name += " (CPU %d)" % (self.wheel)
def ysize(self):
return (10)
class Lock(EventSource):
def __init__(self, lock):
EventSource.__init__(self, lock, LOCK)
def ysize(self):
return (10)
class Counter(EventSource):
max = 0
def __init__(self, name):
@ -888,6 +991,8 @@ def __init__(self, file):
self.timestamp_l = None
self.threads = []
self.sources = []
self.locks = {}
self.callwheels = {}
self.ticks = {}
self.load = {}
self.crit = {}
@ -959,6 +1064,46 @@ def parse(self, file):
ktrstr = "critical_\S+ by thread " + crittdname + " to (\d+)"
critsec_re = re.compile(ktrhdr + ktrstr)
ktrstr = "callout 0x[a-f\d]+ "
ktrstr += "func (0x[a-f\d]+) arg (0x[a-f\d]+)"
callout_start_re = re.compile(ktrhdr + ktrstr)
ktrstr = "callout mpsafe 0x[a-f\d]+ "
ktrstr += "func (0x[a-f\d]+) arg (0x[a-f\d]+)"
callout_mpsafe_re = re.compile(ktrhdr + ktrstr)
ktrstr = "callout mtx 0x[a-f\d]+ "
ktrstr += "func (0x[a-f\d]+) arg (0x[a-f\d]+)"
callout_mtx_re = re.compile(ktrhdr + ktrstr)
ktrstr = "callout 0x[a-f\d]+ finished"
callout_stop_re = re.compile(ktrhdr + ktrstr)
ktrstr = "TRY_([RSWX]?LOCK) \(.*\) (.*) r = ([0-9]+)"
ktrstr += " at (?:\.\./)*(.*):([0-9]+)"
lock_try_re = re.compile(ktrhdr + ktrstr)
ktrstr = "([RSWX]?UNLOCK) \(.*\) (.*) r = ([0-9]+)"
ktrstr += " at (?:\.\./)*(.*):([0-9]+)"
lock_release_re = re.compile(ktrhdr + ktrstr)
ktrstr = "([RSWX]?LOCK) \(.*\) (.*) r = ([0-9]+)"
ktrstr += " at (?:\.\./)*(.*):([0-9]+)"
lock_acquire_re = re.compile(ktrhdr + ktrstr)
ktrstr = "_mtx_lock_sleep: (.*) contested \(lock=0x?[0-9a-f]*\)"
ktrstr += " at (?:\.\./)*(.*):([0-9]+)"
mtx_contested_re = re.compile(ktrhdr + ktrstr)
# XXX: Spin lock traces don't have lock name or file/line
ktrstr = "_rw_wlock_hard: (.*) contested \(lock=0x?[0-9a-f]*\)"
ktrstr += " at (?:\.\./)*(.*):([0-9]+)"
rw_contested_re = re.compile(ktrhdr + ktrstr)
# XXX: Read lock traces for rwlocks contesting don't have
# lock name or file/line
parsers = [[cpuload_re, self.cpuload],
[cpuload2_re, self.cpuload2],
[loadglobal_re, self.loadglobal],
@ -973,6 +1118,15 @@ def parse(self, file):
[sched_exit_re, self.sched_exit],
[sched_clock_re, self.sched_clock],
[critsec_re, self.critsec],
[callout_start_re, self.callout_start],
[callout_mpsafe_re, self.callout_start],
[callout_mtx_re, self.callout_start],
[callout_stop_re, self.callout_stop],
[lock_try_re, self.lock_try],
[lock_release_re, self.lock_release],
[lock_acquire_re, self.lock_acquire],
[mtx_contested_re, self.lock_contest],
[rw_contested_re, self.lock_contest],
[idled_re, self.idled]]
global lineno
@ -1162,6 +1316,74 @@ def critsec(self, cpu, timestamp, td, pcomm, to):
self.sources.append(crit)
Count(crit, cpu, timestamp, to)
def callout_start(self, cpu, timestamp, func, arg):
timestamp = self.checkstamp(cpu, timestamp)
if (timestamp == 0):
return
wheel = self.findwheel(cpu)
CalloutRunning(wheel, cpu, timestamp, func, arg)
def callout_stop(self, cpu, timestamp):
timestamp = self.checkstamp(cpu, timestamp)
if (timestamp == 0):
return
wheel = self.findwheel(cpu)
CalloutIdle(wheel, cpu, timestamp)
def lock_try(self, cpu, timestamp, op, name, result, file, line):
timestamp = self.checkstamp(cpu, timestamp)
if (timestamp == 0):
return
lock = self.findlock(name)
if (int(result) == 0):
LockFailedTry(lock, cpu, timestamp, file, line)
else:
LockAcquire(lock, cpu, timestamp, file, line)
def lock_acquire(self, cpu, timestamp, op, name, recurse, file, line):
if (int(recurse) != 0):
return
timestamp = self.checkstamp(cpu, timestamp)
if (timestamp == 0):
return
lock = self.findlock(name)
LockAcquire(lock, cpu, timestamp, file, line)
def lock_release(self, cpu, timestamp, op, name, recurse, file, line):
if (int(recurse) != 0):
return
timestamp = self.checkstamp(cpu, timestamp)
if (timestamp == 0):
return
lock = self.findlock(name)
LockRelease(lock, cpu, timestamp, file, line)
def lock_contest(self, cpu, timestamp, name, file, line):
timestamp = self.checkstamp(cpu, timestamp)
if (timestamp == 0):
return
lock = self.findlock(name)
LockContest(lock, cpu, timestamp, file, line)
def findlock(self, name):
try:
lock = self.locks[name]
except:
lock = Lock(name)
self.locks[name] = lock
self.sources.append(lock)
return (lock)
def findwheel(self, cpu):
cpu = int(cpu)
try:
wheel = self.callwheels[cpu]
except:
wheel = Callwheel(cpu)
self.callwheels[cpu] = wheel
self.sources.append(wheel)
return (wheel)
def findtd(self, td, pcomm):
for thread in self.threads:
if (thread.str == td and thread.name == pcomm):
@ -1325,7 +1547,7 @@ def buildwidgets(self):
self.menu = GraphMenu(self)
self.display = SchedDisplay(self)
self.names = Canvas(self,
width=100, height=self.display["height"],
width=120, height=self.display["height"],
bg='grey', scrollregion=(0, 0, 50, 100))
self.scale = Scaler(self, self.display)
status = self.status = Status(self)