1 #!/usr/local/bin/python
3 # Copyright (c) 2002-2003, Jeffrey Roberson <jeff@freebsd.org>
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
9 # 1. Redistributions of source code must retain the above copyright
10 # notice unmodified, this list of conditions, and the following
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
16 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 # - Install the ports/x11-toolkits/py-tkinter package.
35 # - Add KTR_SCHED to KTR_COMPILE and KTR_MASK in your KERNCONF
36 # - It is encouraged to increase KTR_ENTRIES size to 32768 to gather
37 # enough information for analysis.
38 # - Rebuild kernel with proper changes to KERNCONF.
39 # - Dump the trace to a file: 'ktrdump -ct > ktr.out'
40 # - Run the python script: 'python schedgraph.py ktr.out'
43 # 1) Add a per-thread summary display
44 # 2) Add bounding box style zoom.
46 # 4) Implement some sorting mechanism.
53 ns = ticksps / 1000000000
56 return (str(ticks) + "ns")
59 return (str(ticks) + "us")
62 return (str(ticks) + "ms")
64 return (str(ticks) + "s")
67 def __init__(self, master, target):
68 Frame.__init__(self, master)
69 self.scale = Scale(self, command=self.scaleset,
70 from_=1000, to_=1000000, orient=HORIZONTAL, resolution=1000)
71 self.label = Label(self, text="Ticks per pixel")
72 self.label.pack(side=LEFT)
73 self.scale.pack(fill="both", expand=1)
75 self.scale.set(target.scaleget())
78 def scaleset(self, value):
79 self.target.scaleset(int(value))
85 def __init__(self, master):
86 Frame.__init__(self, master)
87 self.label = Label(self, bd=1, relief=SUNKEN, anchor=W)
88 self.label.pack(fill="both", expand=1)
92 self.label.config(text=str)
95 self.label.config(text="")
97 def startup(self, str):
101 class EventConf(Frame):
102 def __init__(self, master, name, color, enabled):
103 Frame.__init__(self, master)
105 self.color = StringVar()
106 self.color_default = color
107 self.color_current = color
108 self.color.set(color)
109 self.enabled = IntVar()
110 self.enabled_default = enabled
111 self.enabled_current = enabled
112 self.enabled.set(enabled)
116 self.label = Label(self, text=self.name, anchor=W)
117 self.sample = Canvas(self, width=24, height=24,
119 self.rect = self.sample.create_rectangle(0, 0, 24, 24,
120 fill=self.color.get())
121 self.list = OptionMenu(self, self.color,
122 "dark red", "red", "pink",
123 "dark orange", "orange",
124 "yellow", "light yellow",
125 "dark green", "green", "light green",
126 "dark blue", "blue", "light blue",
127 "dark violet", "violet", "purple",
128 "dark grey", "light grey",
130 command=self.setcolor)
131 self.checkbox = Checkbutton(self, text="enabled",
132 variable=self.enabled)
133 self.label.grid(row=0, column=0, sticky=E+W)
134 self.sample.grid(row=0, column=1)
135 self.list.grid(row=0, column=2, sticky=E+W)
136 self.checkbox.grid(row=0, column=3)
137 self.columnconfigure(0, weight=1)
138 self.columnconfigure(2, minsize=110)
140 def setcolor(self, color):
141 self.color.set(color)
142 self.sample.itemconfigure(self.rect, fill=color)
147 if (self.color_current != self.color.get()):
149 if (self.enabled_current != self.enabled.get()):
151 self.color_current = self.color.get()
152 self.enabled_current = self.enabled.get()
154 if (self.enabled_current):
155 graph.setcolor(self.name, self.color_current)
157 graph.hide(self.name)
160 graph.setcolor(self.name, self.color_current)
163 self.setcolor(self.color_current)
164 self.enabled.set(self.enabled_current)
167 self.setcolor(self.color_default)
168 self.enabled.set(self.enabled_default)
170 class EventConfigure(Toplevel):
172 Toplevel.__init__(self)
174 self.title("Event Configuration")
175 self.items = LabelFrame(self, text="Event Type")
176 self.buttons = Frame(self)
178 self.items.grid(row=0, column=0, sticky=E+W)
179 self.columnconfigure(0, weight=1)
180 self.buttons.grid(row=1, column=0, sticky=E+W)
183 for type in configtypes:
184 self.additem(type.name, type.color, type.enabled)
186 def additem(self, name, color, enabled=1):
187 item = EventConf(self.items, name, color, enabled)
188 self.types.append(item)
189 item.grid(row=self.irow, column=0, sticky=E+W)
192 def drawbuttons(self):
193 self.apply = Button(self.buttons, text="Apply",
195 self.revert = Button(self.buttons, text="Revert",
197 self.default = Button(self.buttons, text="Default",
199 self.apply.grid(row=0, column=0, sticky=E+W)
200 self.revert.grid(row=0, column=1, sticky=E+W)
201 self.default.grid(row=0, column=2, sticky=E+W)
202 self.buttons.columnconfigure(0, weight=1)
203 self.buttons.columnconfigure(1, weight=1)
204 self.buttons.columnconfigure(2, weight=1)
207 for item in self.types:
211 for item in self.types:
215 for item in self.types:
218 class EventView(Toplevel):
219 def __init__(self, event, canvas):
220 Toplevel.__init__(self)
224 self.frame = Frame(self)
225 self.frame.grid(row=0, column=0, sticky=N+S+E+W)
226 self.buttons = Frame(self)
227 self.buttons.grid(row=1, column=0, sticky=E+W)
231 event.displayref(canvas)
232 self.bind("<Destroy>", self.destroycb)
234 def destroycb(self, event):
235 self.unbind("<Destroy>")
236 if (self.event != None):
237 self.event.displayunref(self.canvas)
241 def clearlabels(self):
242 for label in self.frame.grid_slaves():
245 def drawlabels(self):
247 labels = self.event.labels()
248 while (len(labels) < 7):
249 labels.append(("", "", 0))
251 name, value, linked = label
252 l = Label(self.frame, text=name, bd=1, width=15,
253 relief=SUNKEN, anchor=W)
258 r = Label(self.frame, text=value, bd=1,
259 relief=SUNKEN, anchor=W, fg=fgcolor)
260 l.grid(row=ypos, column=0, sticky=E+W)
261 r.grid(row=ypos, column=1, sticky=E+W)
263 r.bind("<Button-1>", self.linkpress)
265 self.frame.columnconfigure(1, minsize=80)
267 def drawbuttons(self):
268 self.back = Button(self.buttons, text="<", command=self.bpress)
269 self.forw = Button(self.buttons, text=">", command=self.fpress)
270 self.new = Button(self.buttons, text="new", command=self.npress)
271 self.back.grid(row=0, column=0, sticky=E+W)
272 self.forw.grid(row=0, column=1, sticky=E+W)
273 self.new.grid(row=0, column=2, sticky=E+W)
274 self.buttons.columnconfigure(2, weight=1)
276 def newevent(self, event):
277 self.event.displayunref(self.canvas)
280 self.event.displayref(self.canvas)
284 EventView(self.event, self.canvas)
287 prev = self.event.prev()
290 while (prev.real == 0):
297 next = self.event.next()
300 while (next.real == 0):
306 def linkpress(self, wevent):
307 event = self.event.getlinked()
314 def __init__(self, source, cpu, timestamp, last=0):
317 self.timestamp = int(timestamp)
326 source.lastevent(self)
331 statstr = self.name + " " + self.source.name
332 statstr += " on: cpu" + str(self.cpu)
333 statstr += " at: " + str(self.timestamp)
334 statstr += self.stattxt()
340 def textadd(self, tuple):
342 self.entries.append(tuple)
345 return [("Source:", self.source.name, 0),
346 ("Event:", self.name, 0),
347 ("CPU:", self.cpu, 0),
348 ("Timestamp:", self.timestamp, 0)] + self.entries
349 def mouseenter(self, canvas, item):
350 self.displayref(canvas)
353 def mouseexit(self, canvas, item):
354 self.displayunref(canvas)
357 def mousepress(self, canvas, item):
358 EventView(self, canvas)
361 return self.source.eventat(self.idx + 1)
364 return self.source.eventat(self.idx - 1)
366 def displayref(self, canvas):
367 if (self.dispcnt == 0):
368 canvas.itemconfigure(self.item, width=2)
371 def displayunref(self, canvas):
373 if (self.dispcnt == 0):
374 canvas.itemconfigure(self.item, width=0)
375 canvas.tag_raise("point", "state")
378 return self.linked.findevent(self.timestamp)
380 class PointEvent(Event):
381 def __init__(self, thread, cpu, timestamp, last=0):
382 Event.__init__(self, thread, cpu, timestamp, last)
384 def draw(self, canvas, xpos, ypos):
385 l = canvas.create_oval(xpos - 6, ypos + 1, xpos + 6, ypos - 11,
386 fill=self.color, tags=("all", "point", "event")
387 + (self.name,), width=0)
388 canvas.events[l] = self
390 if (self.enabled == 0):
391 canvas.itemconfigure(l, state="hidden")
395 class StateEvent(Event):
396 def __init__(self, thread, cpu, timestamp, last=0):
397 Event.__init__(self, thread, cpu, timestamp, last)
403 def draw(self, canvas, xpos, ypos):
404 next = self.nextstate()
405 if (self.skipself == 1 or next == None):
407 while (self.skipnext):
411 next = next.nextstate()
415 self.duration = next.timestamp - self.timestamp
416 delta = self.duration / canvas.ratio
417 l = canvas.create_rectangle(xpos, ypos,
418 xpos + delta, ypos - 10, fill=self.color, width=0,
419 tags=("all", "state", "event") + (self.name,))
420 canvas.events[l] = self
422 if (self.enabled == 0):
423 canvas.itemconfigure(l, state="hidden")
425 return (xpos + delta)
428 return " duration: " + ticks2sec(self.duration)
432 while (next != None and next.state == 0):
437 return [("Source:", self.source.name, 0),
438 ("Event:", self.name, 0),
439 ("Timestamp:", self.timestamp, 0),
440 ("CPU:", self.cpu, 0),
441 ("Duration:", ticks2sec(self.duration), 0)] \
448 def __init__(self, source, cpu, timestamp, count):
449 self.count = int(count)
450 Event.__init__(self, source, cpu, timestamp)
452 self.textadd(("count:", self.count, 0))
454 def draw(self, canvas, xpos, ypos):
456 self.duration = next.timestamp - self.timestamp
457 delta = self.duration / canvas.ratio
458 yhight = self.source.yscale() * self.count
459 l = canvas.create_rectangle(xpos, ypos - yhight,
460 xpos + delta, ypos, fill=self.color, width=0,
461 tags=("all", "count", "event") + (self.name,))
462 canvas.events[l] = self
464 if (self.enabled == 0):
465 canvas.itemconfigure(l, state="hidden")
466 return (xpos + delta)
469 return " count: " + str(self.count)
471 configtypes.append(Count)
473 class Running(StateEvent):
477 def __init__(self, thread, cpu, timestamp, prio):
478 StateEvent.__init__(self, thread, cpu, timestamp)
480 self.textadd(("prio:", self.prio, 0))
482 configtypes.append(Running)
484 class Idle(StateEvent):
488 def __init__(self, thread, cpu, timestamp, prio):
489 StateEvent.__init__(self, thread, cpu, timestamp)
491 self.textadd(("prio:", self.prio, 0))
493 configtypes.append(Idle)
495 class Yielding(StateEvent):
499 def __init__(self, thread, cpu, timestamp, prio):
500 StateEvent.__init__(self, thread, cpu, timestamp)
503 self.textadd(("prio:", self.prio, 0))
505 configtypes.append(Yielding)
507 class Swapped(StateEvent):
511 def __init__(self, thread, cpu, timestamp, prio):
512 StateEvent.__init__(self, thread, cpu, timestamp)
514 self.textadd(("prio:", self.prio, 0))
516 configtypes.append(Swapped)
518 class Suspended(StateEvent):
522 def __init__(self, thread, cpu, timestamp, prio):
523 StateEvent.__init__(self, thread, cpu, timestamp)
525 self.textadd(("prio:", self.prio, 0))
527 configtypes.append(Suspended)
529 class Iwait(StateEvent):
533 def __init__(self, thread, cpu, timestamp, prio):
534 StateEvent.__init__(self, thread, cpu, timestamp)
536 self.textadd(("prio:", self.prio, 0))
538 configtypes.append(Iwait)
540 class Preempted(StateEvent):
544 def __init__(self, thread, cpu, timestamp, prio, bythread):
545 StateEvent.__init__(self, thread, cpu, timestamp)
548 self.linked = bythread
549 self.textadd(("prio:", self.prio, 0))
550 self.textadd(("by thread:", self.linked.name, 1))
552 configtypes.append(Preempted)
554 class Sleep(StateEvent):
558 def __init__(self, thread, cpu, timestamp, prio, wmesg):
559 StateEvent.__init__(self, thread, cpu, timestamp)
562 self.textadd(("prio:", self.prio, 0))
563 self.textadd(("wmesg:", self.wmesg, 0))
566 statstr = StateEvent.stattxt(self)
567 statstr += " sleeping on: " + self.wmesg
570 configtypes.append(Sleep)
572 class Blocked(StateEvent):
576 def __init__(self, thread, cpu, timestamp, prio, lock):
577 StateEvent.__init__(self, thread, cpu, timestamp)
580 self.textadd(("prio:", self.prio, 0))
581 self.textadd(("lock:", self.lock, 0))
584 statstr = StateEvent.stattxt(self)
585 statstr += " blocked on: " + self.lock
588 configtypes.append(Blocked)
590 class KsegrpRunq(StateEvent):
594 def __init__(self, thread, cpu, timestamp, prio, bythread):
595 StateEvent.__init__(self, thread, cpu, timestamp)
597 self.linked = bythread
598 self.textadd(("prio:", self.prio, 0))
599 self.textadd(("by thread:", self.linked.name, 1))
601 configtypes.append(KsegrpRunq)
603 class Runq(StateEvent):
607 def __init__(self, thread, cpu, timestamp, prio, bythread):
608 StateEvent.__init__(self, thread, cpu, timestamp)
610 self.linked = bythread
611 self.textadd(("prio:", self.prio, 0))
612 self.textadd(("by thread:", self.linked.name, 1))
614 configtypes.append(Runq)
616 class Sched_exit(StateEvent):
620 def __init__(self, thread, cpu, timestamp, prio):
621 StateEvent.__init__(self, thread, cpu, timestamp)
622 self.name = "sched_exit"
624 self.textadd(("prio:", self.prio, 0))
626 configtypes.append(Sched_exit)
628 class Padevent(StateEvent):
629 def __init__(self, thread, cpu, timestamp, last=0):
630 StateEvent.__init__(self, thread, cpu, timestamp, last)
634 def draw(self, canvas, xpos, ypos):
638 self.duration = next.timestamp - self.timestamp
639 delta = self.duration / canvas.ratio
640 return (xpos + delta)
642 class Tick(PointEvent):
646 def __init__(self, thread, cpu, timestamp, prio, stathz):
647 PointEvent.__init__(self, thread, cpu, timestamp)
649 self.textadd(("prio:", self.prio, 0))
651 configtypes.append(Tick)
653 class Prio(PointEvent):
657 def __init__(self, thread, cpu, timestamp, prio, newprio, bythread):
658 PointEvent.__init__(self, thread, cpu, timestamp)
660 self.newprio = newprio
661 self.linked = bythread
662 self.textadd(("new prio:", self.newprio, 0))
663 self.textadd(("prio:", self.prio, 0))
664 if (self.linked != self.source):
665 self.textadd(("by thread:", self.linked.name, 1))
667 self.textadd(("by thread:", self.linked.name, 0))
669 configtypes.append(Prio)
671 class Lend(PointEvent):
675 def __init__(self, thread, cpu, timestamp, prio, tothread):
676 PointEvent.__init__(self, thread, cpu, timestamp)
678 self.linked = tothread
679 self.textadd(("prio:", self.prio, 0))
680 self.textadd(("to thread:", self.linked.name, 1))
682 configtypes.append(Lend)
684 class Wokeup(PointEvent):
688 def __init__(self, thread, cpu, timestamp, ranthread):
689 PointEvent.__init__(self, thread, cpu, timestamp)
690 self.linked = ranthread
691 self.textadd(("ran thread:", self.linked.name, 1))
693 configtypes.append(Wokeup)
696 def __init__(self, name):
705 def event(self, event):
706 self.events.insert(0, event)
708 def remove(self, event):
709 self.events.remove(event)
711 def lastevent(self, event):
712 self.events.append(event)
714 def draw(self, canvas, ypos):
717 self.cpu = self.events[1].cpu
718 for i in range(0, len(self.events)):
719 self.events[i].idx = i
720 for event in self.events:
721 if (event.cpu != self.cpu and event.cpu != -1):
722 self.drawcpu(canvas, xpos, ypos)
725 xpos = event.draw(canvas, xpos, ypos)
726 self.drawcpu(canvas, xpos, ypos)
728 def drawname(self, canvas, ypos):
729 ypos = ypos - (self.ysize() / 2)
730 canvas.create_text(10, ypos, anchor="w", text=self.name)
732 def drawcpu(self, canvas, xpos, ypos):
741 color = 'light green'
744 l = canvas.create_rectangle(self.cpux,
745 ypos - self.ysize() - canvas.bdheight,
746 xpos, ypos + canvas.bdheight, fill=color, width=0,
747 tags=("all", "cpuinfo"))
752 def eventat(self, i):
753 if (i >= len(self.events)):
755 event = self.events[i]
758 def findevent(self, timestamp):
759 for event in self.events:
760 if (event.timestamp >= timestamp and event.real):
764 class Thread(EventSource):
766 def __init__(self, td, pcomm):
767 EventSource.__init__(self, pcomm)
770 cnt = Thread.names[pcomm]
772 Thread.names[pcomm] = 0
774 Thread.names[pcomm] = cnt + 1
777 cnt = Thread.names[self.name]
781 Thread.names[self.name] = cnt
782 self.name += " td" + str(cnt)
787 class Counter(EventSource):
789 def __init__(self, name):
790 EventSource.__init__(self, name)
792 def event(self, event):
793 EventSource.event(self, event)
799 if (count > Counter.max):
806 return (self.ysize() / Counter.max)
810 def __init__(self, file):
811 self.timestamp_first = None
812 self.timestamp_last = None
823 ticksps = self.ticksps()
825 def parse(self, file):
829 print "Can't open", file
832 ktrhdr = "\s+\d+\s+(\d+)\s+(\d+)\s+"
833 tdname = "(\S+)\(([^)]*)\)"
834 crittdname = "(\S+)\s+\(\d+,\s+([^)]*)\)"
836 ktrstr = "mi_switch: " + tdname
837 ktrstr += " prio (\d+) inhibit (\d+) wmesg (\S+) lock (\S+)"
838 switchout_re = re.compile(ktrhdr + ktrstr)
840 ktrstr = "mi_switch: " + tdname + " prio (\d+) idle"
841 idled_re = re.compile(ktrhdr + ktrstr)
843 ktrstr = "mi_switch: " + tdname + " prio (\d+) preempted by "
845 preempted_re = re.compile(ktrhdr + ktrstr)
847 ktrstr = "mi_switch: running " + tdname + " prio (\d+)"
848 switchin_re = re.compile(ktrhdr + ktrstr)
850 ktrstr = "sched_add: " + tdname + " prio (\d+) by " + tdname
851 sched_add_re = re.compile(ktrhdr + ktrstr)
853 ktrstr = "setrunqueue: " + tdname + " prio (\d+) by " + tdname
854 setrunqueue_re = re.compile(ktrhdr + ktrstr)
856 ktrstr = "sched_rem: " + tdname + " prio (\d+) by " + tdname
857 sched_rem_re = re.compile(ktrhdr + ktrstr)
859 ktrstr = "sched_exit_thread: " + tdname + " prio (\d+)"
860 sched_exit_re = re.compile(ktrhdr + ktrstr)
862 ktrstr = "statclock: " + tdname + " prio (\d+)"
863 ktrstr += " stathz (\d+)"
864 sched_clock_re = re.compile(ktrhdr + ktrstr)
866 ktrstr = "sched_prio: " + tdname + " prio (\d+)"
867 ktrstr += " newprio (\d+) by " + tdname
868 sched_prio_re = re.compile(ktrhdr + ktrstr)
870 cpuload_re = re.compile(ktrhdr + "load: (\d+)")
871 loadglobal_re = re.compile(ktrhdr + "global load: (\d+)")
873 ktrstr = "critical_\S+ by thread " + crittdname + " to (\d+)"
874 critsec_re = re.compile(ktrhdr + ktrstr)
876 parsers = [[cpuload_re, self.cpuload],
877 [loadglobal_re, self.loadglobal],
878 [switchin_re, self.switchin],
879 [switchout_re, self.switchout],
880 [sched_add_re, self.sched_add],
881 [setrunqueue_re, self.sched_rem],
882 [sched_prio_re, self.sched_prio],
883 [preempted_re, self.preempted],
884 [sched_rem_re, self.sched_rem],
885 [sched_exit_re, self.sched_exit],
886 [sched_clock_re, self.sched_clock],
887 [critsec_re, self.critsec],
888 [idled_re, self.idled]]
890 for line in ifp.readlines():
892 if ((self.lineno % 1024) == 0):
893 status.startup("Parsing line " +
903 def checkstamp(self, timestamp):
904 timestamp = int(timestamp)
905 if (self.timestamp_first == None):
906 self.timestamp_first = timestamp
907 if (timestamp > self.timestamp_first):
908 print "Bad timestamp on line ", self.lineno
910 self.timestamp_last = timestamp
914 return (self.timestamp_first - self.timestamp_last);
917 return (self.timespan() / self.ticks[0]) * int(self.stathz)
919 def switchout(self, cpu, timestamp, td, pcomm, prio, inhibit, wmesg, lock):
920 TDI_SUSPENDED = 0x0001
921 TDI_SLEEPING = 0x0002
926 if (self.checkstamp(timestamp) == 0):
928 inhibit = int(inhibit)
929 thread = self.findtd(td, pcomm)
930 if (inhibit & TDI_SWAPPED):
931 Swapped(thread, cpu, timestamp, prio)
932 elif (inhibit & TDI_SLEEPING):
933 Sleep(thread, cpu, timestamp, prio, wmesg)
934 elif (inhibit & TDI_LOCK):
935 Blocked(thread, cpu, timestamp, prio, lock)
936 elif (inhibit & TDI_IWAIT):
937 Iwait(thread, cpu, timestamp, prio)
938 elif (inhibit & TDI_SUSPENDED):
939 Suspended(thread, cpu, timestamp, prio)
941 Yielding(thread, cpu, timestamp, prio)
943 print "Unknown event", inhibit
946 def idled(self, cpu, timestamp, td, pcomm, prio):
947 if (self.checkstamp(timestamp) == 0):
949 thread = self.findtd(td, pcomm)
950 Idle(thread, cpu, timestamp, prio)
952 def preempted(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
953 if (self.checkstamp(timestamp) == 0):
955 thread = self.findtd(td, pcomm)
956 Preempted(thread, cpu, timestamp, prio,
957 self.findtd(bytd, bypcomm))
959 def switchin(self, cpu, timestamp, td, pcomm, prio):
960 if (self.checkstamp(timestamp) == 0):
962 thread = self.findtd(td, pcomm)
963 Running(thread, cpu, timestamp, prio)
965 def sched_add(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
966 if (self.checkstamp(timestamp) == 0):
968 thread = self.findtd(td, pcomm)
969 bythread = self.findtd(bytd, bypcomm)
970 Runq(thread, cpu, timestamp, prio, bythread)
971 Wokeup(bythread, cpu, timestamp, thread)
973 def sched_rem(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
974 if (self.checkstamp(timestamp) == 0):
976 thread = self.findtd(td, pcomm)
977 KsegrpRunq(thread, cpu, timestamp, prio,
978 self.findtd(bytd, bypcomm))
980 def sched_exit(self, cpu, timestamp, td, pcomm, prio):
981 if (self.checkstamp(timestamp) == 0):
983 thread = self.findtd(td, pcomm)
984 Sched_exit(thread, cpu, timestamp, prio)
986 def sched_clock(self, cpu, timestamp, td, pcomm, prio, stathz):
987 if (self.checkstamp(timestamp) == 0):
992 ticks = self.ticks[cpu]
996 thread = self.findtd(td, pcomm)
997 Tick(thread, cpu, timestamp, prio, stathz)
999 def sched_prio(self, cpu, timestamp, td, pcomm, prio, newprio, bytd, bypcomm):
1000 if (prio == newprio):
1002 if (self.checkstamp(timestamp) == 0):
1004 thread = self.findtd(td, pcomm)
1005 bythread = self.findtd(bytd, bypcomm)
1006 Prio(thread, cpu, timestamp, prio, newprio, bythread)
1007 Lend(bythread, cpu, timestamp, newprio, thread)
1009 def cpuload(self, cpu, timestamp, count):
1010 if (self.checkstamp(timestamp) == 0):
1014 load = self.load[cpu]
1016 load = Counter("cpu" + str(cpu) + " load")
1017 self.load[cpu] = load
1018 self.sources.insert(0, load)
1019 Count(load, cpu, timestamp, count)
1021 def loadglobal(self, cpu, timestamp, count):
1022 if (self.checkstamp(timestamp) == 0):
1026 load = self.load[cpu]
1028 load = Counter("CPU load")
1029 self.load[cpu] = load
1030 self.sources.insert(0, load)
1031 Count(load, cpu, timestamp, count)
1033 def critsec(self, cpu, timestamp, td, pcomm, to):
1034 if (self.checkstamp(timestamp) == 0):
1038 crit = self.crit[cpu]
1040 crit = Counter("Critical Section")
1041 self.crit[cpu] = crit
1042 self.sources.insert(0, crit)
1043 Count(crit, cpu, timestamp, to)
1045 def findtd(self, td, pcomm):
1046 for thread in self.threads:
1047 if (thread.str == td and thread.name == pcomm):
1049 thread = Thread(td, pcomm)
1050 self.threads.append(thread)
1051 self.sources.append(thread)
1055 for source in self.sources:
1056 Padevent(source, -1, self.timestamp_last)
1057 Padevent(source, -1, self.timestamp_first, last=1)
1060 class SchedDisplay(Canvas):
1061 def __init__(self, master):
1068 Canvas.__init__(self, master, width=800, height=500, bg='grey',
1069 scrollregion=(0, 0, 800, 500))
1071 def setfile(self, ktrfile):
1072 self.ktrfile = ktrfile
1073 self.sources = ktrfile.sources
1077 xsize = self.xsize()
1078 for source in self.sources:
1079 status.startup("Drawing " + source.name)
1080 self.create_line(0, ypos, xsize, ypos,
1081 width=1, fill="black", tags=("all",))
1082 ypos += self.bdheight
1083 ypos += source.ysize()
1084 source.draw(self, ypos)
1085 ypos += self.bdheight
1087 self.tag_raise("point", "state")
1088 self.tag_lower("cpuinfo", "all")
1091 self.create_line(0, ypos, xsize, ypos,
1092 width=1, fill="black", tags=("all",))
1093 self.tag_bind("event", "<Enter>", self.mouseenter)
1094 self.tag_bind("event", "<Leave>", self.mouseexit)
1095 self.tag_bind("event", "<Button-1>", self.mousepress)
1097 def mouseenter(self, event):
1098 item, = self.find_withtag(CURRENT)
1099 event = self.events[item]
1100 event.mouseenter(self, item)
1102 def mouseexit(self, event):
1103 item, = self.find_withtag(CURRENT)
1104 event = self.events[item]
1105 event.mouseexit(self, item)
1107 def mousepress(self, event):
1108 item, = self.find_withtag(CURRENT)
1109 event = self.events[item]
1110 event.mousepress(self, item)
1112 def drawnames(self, canvas):
1113 status.startup("Drawing names")
1115 canvas.configure(scrollregion=(0, 0,
1116 canvas["width"], self.ysize()))
1117 for source in self.sources:
1118 canvas.create_line(0, ypos, canvas["width"], ypos,
1119 width=1, fill="black", tags=("all",))
1120 ypos += self.bdheight
1121 ypos += source.ysize()
1122 source.drawname(canvas, ypos)
1123 ypos += self.bdheight
1124 canvas.create_line(0, ypos, canvas["width"], ypos,
1125 width=1, fill="black", tags=("all",))
1128 return ((self.ktrfile.timespan() / self.ratio) + 20)
1132 for source in self.sources:
1133 ysize += source.ysize() + (self.bdheight * 2)
1136 def scaleset(self, ratio):
1137 if (self.ktrfile == None):
1139 oldratio = self.ratio
1140 xstart, ystart = self.xview()
1141 length = (float(self["width"]) / self.xsize())
1142 middle = xstart + (length / 2)
1145 self.configure(scrollregion=(0, 0, self.xsize(), self.ysize()))
1146 self.scale("all", 0, 0, float(oldratio) / ratio, 1)
1148 length = (float(self["width"]) / self.xsize())
1149 xstart = middle - (length / 2)
1150 self.xview_moveto(xstart)
1155 def setcolor(self, tag, color):
1156 self.itemconfigure(tag, state="normal", fill=color)
1158 def hide(self, tag):
1159 self.itemconfigure(tag, state="hidden")
1161 class GraphMenu(Frame):
1162 def __init__(self, master):
1163 Frame.__init__(self, master, bd=2, relief=RAISED)
1164 self.view = Menubutton(self, text="Configure")
1165 self.viewmenu = Menu(self.view, tearoff=0)
1166 self.viewmenu.add_command(label="Events",
1168 self.view["menu"] = self.viewmenu
1169 self.view.pack(side=LEFT)
1175 class SchedGraph(Frame):
1176 def __init__(self, master):
1177 Frame.__init__(self, master)
1183 self.pack(expand=1, fill="both")
1186 self.draw(sys.argv[1])
1188 def buildwidgets(self):
1190 self.menu = GraphMenu(self)
1191 self.display = SchedDisplay(self)
1192 self.names = Canvas(self,
1193 width=100, height=self.display["height"],
1194 bg='grey', scrollregion=(0, 0, 50, 100))
1195 self.scale = Scaler(self, self.display)
1196 status = self.status = Status(self)
1197 self.scrollY = Scrollbar(self, orient="vertical",
1198 command=self.display_yview)
1199 self.display.scrollX = Scrollbar(self, orient="horizontal",
1200 command=self.display.xview)
1201 self.display["xscrollcommand"] = self.display.scrollX.set
1202 self.display["yscrollcommand"] = self.scrollY.set
1203 self.names["yscrollcommand"] = self.scrollY.set
1206 self.columnconfigure(1, weight=1)
1207 self.rowconfigure(1, weight=1)
1208 self.menu.grid(row=0, column=0, columnspan=3, sticky=E+W)
1209 self.names.grid(row=1, column=0, sticky=N+S)
1210 self.display.grid(row=1, column=1, sticky=W+E+N+S)
1211 self.scrollY.grid(row=1, column=2, sticky=N+S)
1212 self.display.scrollX.grid(row=2, column=0, columnspan=2,
1214 self.scale.grid(row=3, column=0, columnspan=3, sticky=E+W)
1215 self.status.grid(row=4, column=0, columnspan=3, sticky=E+W)
1217 def draw(self, file):
1218 self.master.update()
1219 ktrfile = KTRFile(file)
1220 self.display.setfile(ktrfile)
1221 self.display.drawnames(self.names)
1223 self.scale.set(250000)
1224 self.display.xview_moveto(0)
1226 def display_yview(self, *args):
1227 self.names.yview(*args)
1228 self.display.yview(*args)
1230 def setcolor(self, tag, color):
1231 self.display.setcolor(tag, color)
1233 def hide(self, tag):
1234 self.display.hide(tag)
1236 if (len(sys.argv) != 2):
1237 print "usage:", sys.argv[0], "<ktr file>"
1241 root.title("Scheduler Graph")
1242 graph = SchedGraph(root)