- Add some rudimentary support for sorting the list of event sources

(threads, CPU load counters, etc.).  Each source is tagged with a group
  and an order similar to the SYSINIT SI_SUB_* and SI_ORDER_*.  After
  the file is parsed, all the sources are then sorted.  Currently, the only
  affects of this are that the CPU loads are now sorted by CPU ID (so
  CPU 0 is always first).  However, this makes it easier to add new types
  of event sources in the future and have them all clustered together
  instead of intertwined with threads.
- Python lists perform insertions at the tail much faster than insertions
  at the head.  For a trace that had a lot of events for a single event
  source, the constant insertions of new events to the head of the
  per-source event list caused a noticable slow down.  To compensate,
  append new events to the end of the list during parsing and then
  reverse the list prior to drawing.
- Somewhere in the tkinter internals the coordinates of a canvas are
  stored in a signed 32-bit integer.  As a result, if an the box for
  an event spans 2^31, it would actually end up having a negative
  X offset at one end.  The result was a single box that covered the
  entire event source.  Kris worked around this for some traces by
  bumping up the initial ticks/pixel ratio from 1 to 10.  However, a
  divisor of 10 can still be too small for large tracefiles (e.g.
  with 4 million entries).  Instead of hardcoding the initial scaling
  ratio, calculate it from the time span of the trace file.
- Add support for using the mouse wheel to scroll the graph window
  up and down.
This commit is contained in:
jhb 2009-01-13 16:33:10 +00:00
parent 89bdd3962a
commit d89e3d19c0

View File

@ -739,24 +739,36 @@ def __init__(self, thread, cpu, timestamp, ranthread):
configtypes.append(Wokeup)
(DEFAULT, LOAD, COUNT, THREAD) = range(4)
class EventSource:
def __init__(self, name):
def __init__(self, name, group=DEFAULT, order=0):
self.name = name
self.events = []
self.cpu = 0
self.cpux = 0
self.group = group
self.order = order
def __cmp__(self, other):
if (self.group == other.group):
return cmp(self.order, other.order)
return cmp(self.group, other.group)
# It is much faster to append items to a list then to insert them
# at the beginning. As a result, we add events in reverse order
# and then swap the list during fixup.
def fixup(self):
pass
self.events.reverse()
def event(self, event):
self.events.insert(0, event)
self.events.append(event)
def remove(self, event):
self.events.remove(event)
def lastevent(self, event):
self.events.append(event)
self.events.insert(0, event)
def draw(self, canvas, ypos):
xpos = 10
@ -819,7 +831,7 @@ def findevent(self, timestamp):
class Thread(EventSource):
names = {}
def __init__(self, td, pcomm):
EventSource.__init__(self, pcomm)
EventSource.__init__(self, pcomm, THREAD)
self.str = td
try:
cnt = Thread.names[pcomm]
@ -829,6 +841,7 @@ def __init__(self, td, pcomm):
Thread.names[pcomm] = cnt + 1
def fixup(self):
EventSource.fixup(self)
cnt = Thread.names[self.name]
if (cnt == 0):
return
@ -842,7 +855,7 @@ def ysize(self):
class Counter(EventSource):
max = 0
def __init__(self, name):
EventSource.__init__(self, name)
EventSource.__init__(self, name, COUNT)
def event(self, event):
EventSource.event(self, event)
@ -863,6 +876,11 @@ def ysize(self):
def yscale(self):
return (self.ysize() / Counter.max)
class CPULoad(Counter):
def __init__(self, cpu):
Counter.__init__(self, "cpu" + str(cpu) + " load")
self.group = LOAD
self.order = cpu
class KTRFile:
def __init__(self, file):
@ -1100,9 +1118,9 @@ def cpuload(self, cpu, timestamp, count):
try:
load = self.load[cpu]
except:
load = Counter("cpu" + str(cpu) + " load")
load = CPULoad(cpu)
self.load[cpu] = load
self.sources.insert(0, load)
self.sources.append(load)
Count(load, cpu, timestamp, count)
def cpuload2(self, cpu, timestamp, ncpu, count):
@ -1113,9 +1131,9 @@ def cpuload2(self, cpu, timestamp, ncpu, count):
try:
load = self.load[cpu]
except:
load = Counter("cpu" + str(cpu) + " load")
load = CPULoad(cpu)
self.load[cpu] = load
self.sources.insert(0, load)
self.sources.append(load)
Count(load, cpu, timestamp, count)
def loadglobal(self, cpu, timestamp, count):
@ -1128,7 +1146,7 @@ def loadglobal(self, cpu, timestamp, count):
except:
load = Counter("CPU load")
self.load[cpu] = load
self.sources.insert(0, load)
self.sources.append(load)
Count(load, cpu, timestamp, count)
def critsec(self, cpu, timestamp, td, pcomm, to):
@ -1141,7 +1159,7 @@ def critsec(self, cpu, timestamp, td, pcomm, to):
except:
crit = Counter("Critical Section")
self.crit[cpu] = crit
self.sources.insert(0, crit)
self.sources.append(crit)
Count(crit, cpu, timestamp, to)
def findtd(self, td, pcomm):
@ -1158,12 +1176,14 @@ def fixup(self):
Padevent(source, -1, self.timestamp_l)
Padevent(source, -1, self.timestamp_f, last=1)
source.fixup()
self.sources.sort()
class SchedDisplay(Canvas):
def __init__(self, master):
self.ratio = 10
self.ratio = 1
self.ktrfile = None
self.sources = None
self.parent = master
self.bdheight = 10
self.events = {}
@ -1174,6 +1194,11 @@ def setfile(self, ktrfile):
self.ktrfile = ktrfile
self.sources = ktrfile.sources
# Compute a ratio to ensure that the file's timespan fits into
# 2^31. Although python may handle larger values for X
# values, the Tk internals do not.
self.ratio = (ktrfile.timespan() - 1) / 2**31 + 1
def draw(self):
ypos = 0
xsize = self.xsize()
@ -1195,6 +1220,8 @@ def draw(self):
self.tag_bind("event", "<Enter>", self.mouseenter)
self.tag_bind("event", "<Leave>", self.mouseexit)
self.tag_bind("event", "<Button-1>", self.mousepress)
self.bind("<Button-4>", self.wheelup)
self.bind("<Button-5>", self.wheeldown)
def mouseenter(self, event):
item, = self.find_withtag(CURRENT)
@ -1211,6 +1238,12 @@ def mousepress(self, event):
event = self.events[item]
event.mousepress(self, item)
def wheeldown(self, event):
self.parent.display_yview("scroll", 1, "units")
def wheelup(self, event):
self.parent.display_yview("scroll", -1, "units")
def drawnames(self, canvas):
status.startup("Drawing names")
ypos = 0