Index: schedgraph.py =================================================================== --- schedgraph.py (revision 186911) +++ schedgraph.py (working copy) @@ -672,6 +672,86 @@ 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) @@ -839,6 +919,28 @@ def ysize(self): return (10) +class Callwheel(EventSource): + count = 0 + def __init__(self, cpu): + EventSource.__init__(self, "Callwheel") + self.wheel = cpu + Callwheel.count += 1 + + def 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) + + def ysize(self): + return (10) + class Counter(EventSource): max = 0 def __init__(self, name): @@ -866,10 +968,12 @@ class KTRFile: def __init__(self, file): self.timestamp_f = None self.timestamp_l = None self.threads = [] self.sources = [] + self.locks = {} + self.callwheels = {} self.ticks = {} self.load = {} self.crit = {} @@ -941,6 +1048,48 @@ 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], @@ -955,11 +1104,20 @@ [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 lineno = 0 for line in ifp.readlines(): lineno += 1 if ((lineno % 1024) == 0): status.startup("Parsing line " + str(lineno)) @@ -1144,6 +1364,74 @@ self.sources.insert(0, 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.insert(0, wheel) + return (wheel) + def findtd(self, td, pcomm): for thread in self.threads: if (thread.str == td and thread.name == pcomm):