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
822 ticksps = self.ticksps()
824 def parse(self, file):
828 print "Can't open", file
831 ktrhdr = "\s+\d+\s+(\d+)\s+(\d+)\s+"
832 tdname = "(\S+)\(([^)]*)\)"
834 ktrstr = "mi_switch: " + tdname
835 ktrstr += " prio (\d+) inhibit (\d+) wmesg (\S+) lock (\S+)"
836 switchout_re = re.compile(ktrhdr + ktrstr)
838 ktrstr = "mi_switch: " + tdname + " prio (\d+) idle"
839 idled_re = re.compile(ktrhdr + ktrstr)
841 ktrstr = "mi_switch: " + tdname + " prio (\d+) preempted by "
843 preempted_re = re.compile(ktrhdr + ktrstr)
845 ktrstr = "mi_switch: running " + tdname + " prio (\d+)"
846 switchin_re = re.compile(ktrhdr + ktrstr)
848 ktrstr = "sched_add: " + tdname + " prio (\d+) by " + tdname
849 sched_add_re = re.compile(ktrhdr + ktrstr)
851 ktrstr = "setrunqueue: " + tdname + " prio (\d+) by " + tdname
852 setrunqueue_re = re.compile(ktrhdr + ktrstr)
854 ktrstr = "sched_rem: " + tdname + " prio (\d+) by " + tdname
855 sched_rem_re = re.compile(ktrhdr + ktrstr)
857 ktrstr = "sched_exit_thread: " + tdname + " prio (\d+)"
858 sched_exit_re = re.compile(ktrhdr + ktrstr)
860 ktrstr = "statclock: " + tdname + " prio (\d+)"
861 ktrstr += " stathz (\d+)"
862 sched_clock_re = re.compile(ktrhdr + ktrstr)
864 ktrstr = "sched_prio: " + tdname + " prio (\d+)"
865 ktrstr += " newprio (\d+) by " + tdname
866 sched_prio_re = re.compile(ktrhdr + ktrstr)
868 cpuload_re = re.compile(ktrhdr + "load: (\d+)")
869 loadglobal_re = re.compile(ktrhdr + "global load: (\d+)")
871 parsers = [[cpuload_re, self.cpuload],
872 [loadglobal_re, self.loadglobal],
873 [switchin_re, self.switchin],
874 [switchout_re, self.switchout],
875 [sched_add_re, self.sched_add],
876 [setrunqueue_re, self.sched_rem],
877 [sched_prio_re, self.sched_prio],
878 [preempted_re, self.preempted],
879 [sched_rem_re, self.sched_rem],
880 [sched_exit_re, self.sched_exit],
881 [sched_clock_re, self.sched_clock],
882 [idled_re, self.idled]]
884 for line in ifp.readlines():
886 if ((self.lineno % 1024) == 0):
887 status.startup("Parsing line " +
897 def checkstamp(self, timestamp):
898 timestamp = int(timestamp)
899 if (self.timestamp_first == None):
900 self.timestamp_first = timestamp
901 if (timestamp > self.timestamp_first):
902 print "Bad timestamp on line ", self.lineno
904 self.timestamp_last = timestamp
908 return (self.timestamp_first - self.timestamp_last);
911 return (self.timespan() / self.ticks[0]) * int(self.stathz)
913 def switchout(self, cpu, timestamp, td, pcomm, prio, inhibit, wmesg, lock):
914 TDI_SUSPENDED = 0x0001
915 TDI_SLEEPING = 0x0002
920 if (self.checkstamp(timestamp) == 0):
922 inhibit = int(inhibit)
923 thread = self.findtd(td, pcomm)
924 if (inhibit & TDI_SWAPPED):
925 Swapped(thread, cpu, timestamp, prio)
926 elif (inhibit & TDI_SLEEPING):
927 Sleep(thread, cpu, timestamp, prio, wmesg)
928 elif (inhibit & TDI_LOCK):
929 Blocked(thread, cpu, timestamp, prio, lock)
930 elif (inhibit & TDI_IWAIT):
931 Iwait(thread, cpu, timestamp, prio)
932 elif (inhibit & TDI_SUSPENDED):
933 Suspended(thread, cpu, timestamp, prio)
935 Yielding(thread, cpu, timestamp, prio)
937 print "Unknown event", inhibit
940 def idled(self, cpu, timestamp, td, pcomm, prio):
941 if (self.checkstamp(timestamp) == 0):
943 thread = self.findtd(td, pcomm)
944 Idle(thread, cpu, timestamp, prio)
946 def preempted(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
947 if (self.checkstamp(timestamp) == 0):
949 thread = self.findtd(td, pcomm)
950 Preempted(thread, cpu, timestamp, prio,
951 self.findtd(bytd, bypcomm))
953 def switchin(self, cpu, timestamp, td, pcomm, prio):
954 if (self.checkstamp(timestamp) == 0):
956 thread = self.findtd(td, pcomm)
957 Running(thread, cpu, timestamp, prio)
959 def sched_add(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
960 if (self.checkstamp(timestamp) == 0):
962 thread = self.findtd(td, pcomm)
963 bythread = self.findtd(bytd, bypcomm)
964 Runq(thread, cpu, timestamp, prio, bythread)
965 Wokeup(bythread, cpu, timestamp, thread)
967 def sched_rem(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
968 if (self.checkstamp(timestamp) == 0):
970 thread = self.findtd(td, pcomm)
971 KsegrpRunq(thread, cpu, timestamp, prio,
972 self.findtd(bytd, bypcomm))
974 def sched_exit(self, cpu, timestamp, td, pcomm, prio):
975 if (self.checkstamp(timestamp) == 0):
977 thread = self.findtd(td, pcomm)
978 Sched_exit(thread, cpu, timestamp, prio)
980 def sched_clock(self, cpu, timestamp, td, pcomm, prio, stathz):
981 if (self.checkstamp(timestamp) == 0):
986 ticks = self.ticks[cpu]
990 thread = self.findtd(td, pcomm)
991 Tick(thread, cpu, timestamp, prio, stathz)
993 def sched_prio(self, cpu, timestamp, td, pcomm, prio, newprio, bytd, bypcomm):
994 if (prio == newprio):
996 if (self.checkstamp(timestamp) == 0):
998 thread = self.findtd(td, pcomm)
999 bythread = self.findtd(bytd, bypcomm)
1000 Prio(thread, cpu, timestamp, prio, newprio, bythread)
1001 Lend(bythread, cpu, timestamp, newprio, thread)
1003 def cpuload(self, cpu, timestamp, count):
1004 if (self.checkstamp(timestamp) == 0):
1008 load = self.load[cpu]
1010 load = Counter("cpu" + str(cpu) + " load")
1011 self.load[cpu] = load
1012 self.sources.insert(0, load)
1013 Count(load, cpu, timestamp, count)
1015 def loadglobal(self, cpu, timestamp, count):
1016 if (self.checkstamp(timestamp) == 0):
1020 load = self.load[cpu]
1022 load = Counter("CPU load")
1023 self.load[cpu] = load
1024 self.sources.insert(0, load)
1025 Count(load, cpu, timestamp, count)
1027 def findtd(self, td, pcomm):
1028 for thread in self.threads:
1029 if (thread.str == td and thread.name == pcomm):
1031 thread = Thread(td, pcomm)
1032 self.threads.append(thread)
1033 self.sources.append(thread)
1037 for source in self.sources:
1038 Padevent(source, -1, self.timestamp_last)
1039 Padevent(source, -1, self.timestamp_first, last=1)
1042 class SchedDisplay(Canvas):
1043 def __init__(self, master):
1050 Canvas.__init__(self, master, width=800, height=500, bg='grey',
1051 scrollregion=(0, 0, 800, 500))
1053 def setfile(self, ktrfile):
1054 self.ktrfile = ktrfile
1055 self.sources = ktrfile.sources
1059 xsize = self.xsize()
1060 for source in self.sources:
1061 status.startup("Drawing " + source.name)
1062 self.create_line(0, ypos, xsize, ypos,
1063 width=1, fill="black", tags=("all",))
1064 ypos += self.bdheight
1065 ypos += source.ysize()
1066 source.draw(self, ypos)
1067 ypos += self.bdheight
1069 self.tag_raise("point", "state")
1070 self.tag_lower("cpuinfo", "all")
1073 self.create_line(0, ypos, xsize, ypos,
1074 width=1, fill="black", tags=("all",))
1075 self.tag_bind("event", "<Enter>", self.mouseenter)
1076 self.tag_bind("event", "<Leave>", self.mouseexit)
1077 self.tag_bind("event", "<Button-1>", self.mousepress)
1079 def mouseenter(self, event):
1080 item, = self.find_withtag(CURRENT)
1081 event = self.events[item]
1082 event.mouseenter(self, item)
1084 def mouseexit(self, event):
1085 item, = self.find_withtag(CURRENT)
1086 event = self.events[item]
1087 event.mouseexit(self, item)
1089 def mousepress(self, event):
1090 item, = self.find_withtag(CURRENT)
1091 event = self.events[item]
1092 event.mousepress(self, item)
1094 def drawnames(self, canvas):
1095 status.startup("Drawing names")
1097 canvas.configure(scrollregion=(0, 0,
1098 canvas["width"], self.ysize()))
1099 for source in self.sources:
1100 canvas.create_line(0, ypos, canvas["width"], ypos,
1101 width=1, fill="black", tags=("all",))
1102 ypos += self.bdheight
1103 ypos += source.ysize()
1104 source.drawname(canvas, ypos)
1105 ypos += self.bdheight
1106 canvas.create_line(0, ypos, canvas["width"], ypos,
1107 width=1, fill="black", tags=("all",))
1110 return ((self.ktrfile.timespan() / self.ratio) + 20)
1114 for source in self.sources:
1115 ysize += source.ysize() + (self.bdheight * 2)
1118 def scaleset(self, ratio):
1119 if (self.ktrfile == None):
1121 oldratio = self.ratio
1122 xstart, ystart = self.xview()
1123 length = (float(self["width"]) / self.xsize())
1124 middle = xstart + (length / 2)
1127 self.configure(scrollregion=(0, 0, self.xsize(), self.ysize()))
1128 self.scale("all", 0, 0, float(oldratio) / ratio, 1)
1130 length = (float(self["width"]) / self.xsize())
1131 xstart = middle - (length / 2)
1132 self.xview_moveto(xstart)
1137 def setcolor(self, tag, color):
1138 self.itemconfigure(tag, state="normal", fill=color)
1140 def hide(self, tag):
1141 self.itemconfigure(tag, state="hidden")
1143 class GraphMenu(Frame):
1144 def __init__(self, master):
1145 Frame.__init__(self, master, bd=2, relief=RAISED)
1146 self.view = Menubutton(self, text="Configure")
1147 self.viewmenu = Menu(self.view, tearoff=0)
1148 self.viewmenu.add_command(label="Events",
1150 self.view["menu"] = self.viewmenu
1151 self.view.pack(side=LEFT)
1157 class SchedGraph(Frame):
1158 def __init__(self, master):
1159 Frame.__init__(self, master)
1165 self.pack(expand=1, fill="both")
1168 self.draw(sys.argv[1])
1170 def buildwidgets(self):
1172 self.menu = GraphMenu(self)
1173 self.display = SchedDisplay(self)
1174 self.names = Canvas(self,
1175 width=100, height=self.display["height"],
1176 bg='grey', scrollregion=(0, 0, 50, 100))
1177 self.scale = Scaler(self, self.display)
1178 status = self.status = Status(self)
1179 self.scrollY = Scrollbar(self, orient="vertical",
1180 command=self.display_yview)
1181 self.display.scrollX = Scrollbar(self, orient="horizontal",
1182 command=self.display.xview)
1183 self.display["xscrollcommand"] = self.display.scrollX.set
1184 self.display["yscrollcommand"] = self.scrollY.set
1185 self.names["yscrollcommand"] = self.scrollY.set
1188 self.columnconfigure(1, weight=1)
1189 self.rowconfigure(1, weight=1)
1190 self.menu.grid(row=0, column=0, columnspan=3, sticky=E+W)
1191 self.names.grid(row=1, column=0, sticky=N+S)
1192 self.display.grid(row=1, column=1, sticky=W+E+N+S)
1193 self.scrollY.grid(row=1, column=2, sticky=N+S)
1194 self.display.scrollX.grid(row=2, column=0, columnspan=2,
1196 self.scale.grid(row=3, column=0, columnspan=3, sticky=E+W)
1197 self.status.grid(row=4, column=0, columnspan=3, sticky=E+W)
1199 def draw(self, file):
1200 self.master.update()
1201 ktrfile = KTRFile(file)
1202 self.display.setfile(ktrfile)
1203 self.display.drawnames(self.names)
1205 self.scale.set(250000)
1206 self.display.xview_moveto(0)
1208 def display_yview(self, *args):
1209 self.names.yview(*args)
1210 self.display.yview(*args)
1212 def setcolor(self, tag, color):
1213 self.display.setcolor(tag, color)
1215 def hide(self, tag):
1216 self.display.hide(tag)
1218 if (len(sys.argv) != 2):
1219 print "usage:", sys.argv[0], "<ktr file>"
1223 root.title("Scheduler Graph")
1224 graph = SchedGraph(root)