Deleted Added
full compact
schedgraph.py (139319) schedgraph.py (139320)
1#!/usr/local/bin/python
2
3# Copyright (c) 2002-2003, Jeffrey Roberson <jeff@freebsd.org>
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10# notice unmodified, this list of conditions, and the following
11# disclaimer.
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.
15#
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.
26#
1#!/usr/local/bin/python
2
3# Copyright (c) 2002-2003, Jeffrey Roberson <jeff@freebsd.org>
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10# notice unmodified, this list of conditions, and the following
11# disclaimer.
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.
15#
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.
26#
27# $FreeBSD: head/tools/sched/schedgraph.py 139319 2004-12-26 01:18:49Z jeff $
27# $FreeBSD: head/tools/sched/schedgraph.py 139320 2004-12-26 02:02:34Z jeff $
28
29import sys
30import re
31from Tkinter import *
32
33# 1) Add a per-thread summary display
34# 2) Add bounding box style zoom.
35# 3) Click to center.
36# 4) Implement some sorting mechanism.
37
38ticksps = None
39status = None
40configtypes = []
41
42def ticks2sec(ticks):
43 ns = ticksps / 1000000000
44 ticks /= ns
45 if (ticks < 1000):
46 return (str(ticks) + "ns")
47 ticks /= 1000
48 if (ticks < 1000):
49 return (str(ticks) + "us")
50 ticks /= 1000
51 if (ticks < 1000):
52 return (str(ticks) + "ms")
53 ticks /= 1000
54 return (str(ticks) + "s")
55
56class Scaler(Frame):
57 def __init__(self, master, target):
58 Frame.__init__(self, master)
59 self.scale = Scale(self, command=self.scaleset,
60 from_=1000, to_=1000000, orient=HORIZONTAL, resolution=1000)
61 self.label = Label(self, text="Ticks per pixel")
62 self.label.pack(side=LEFT)
63 self.scale.pack(fill="both", expand=1)
64 self.target = target
65 self.scale.set(target.scaleget())
66 self.initialized = 1
67
68 def scaleset(self, value):
69 self.target.scaleset(int(value))
70
71 def set(self, value):
72 self.scale.set(value)
73
74class Status(Frame):
75 def __init__(self, master):
76 Frame.__init__(self, master)
77 self.label = Label(self, bd=1, relief=SUNKEN, anchor=W)
78 self.label.pack(fill="both", expand=1)
79 self.clear()
80
81 def set(self, str):
82 self.label.config(text=str)
83
84 def clear(self):
85 self.label.config(text="")
86
87 def startup(self, str):
88 self.set(str)
89 root.update()
90
91class EventConf(Frame):
92 def __init__(self, master, name, color, enabled):
93 Frame.__init__(self, master)
94 self.name = name
95 self.color = StringVar()
96 self.color_default = color
97 self.color_current = color
98 self.color.set(color)
99 self.enabled = IntVar()
100 self.enabled_default = enabled
101 self.enabled_current = enabled
102 self.enabled.set(enabled)
103 self.draw()
104
105 def draw(self):
106 self.label = Label(self, text=self.name, anchor=W)
107 self.sample = Canvas(self, width=24, height=24,
108 bg='grey')
109 self.rect = self.sample.create_rectangle(0, 0, 24, 24,
110 fill=self.color.get())
111 self.list = OptionMenu(self, self.color,
112 "dark red", "red", "pink",
113 "dark orange", "orange",
114 "yellow", "light yellow",
115 "dark green", "green", "light green",
116 "dark blue", "blue", "light blue",
117 "dark violet", "violet", "purple",
118 "dark grey", "light grey",
119 "white", "black",
120 command=self.setcolor)
121 self.checkbox = Checkbutton(self, text="enabled",
122 variable=self.enabled)
123 self.label.grid(row=0, column=0, sticky=E+W)
124 self.sample.grid(row=0, column=1)
125 self.list.grid(row=0, column=2, sticky=E+W)
126 self.checkbox.grid(row=0, column=3)
127 self.columnconfigure(0, weight=1)
128 self.columnconfigure(2, minsize=110)
129
130 def setcolor(self, color):
131 self.color.set(color)
132 self.sample.itemconfigure(self.rect, fill=color)
133
134 def apply(self):
135 cchange = 0
136 echange = 0
137 if (self.color_current != self.color.get()):
138 cchange = 1
139 if (self.enabled_current != self.enabled.get()):
140 echange = 1
141 self.color_current = self.color.get()
142 self.enabled_current = self.enabled.get()
143 if (echange != 0):
144 if (self.enabled_current):
145 graph.setcolor(self.name, self.color_current)
146 else:
147 graph.hide(self.name)
148 return
149 if (cchange != 0):
150 graph.setcolor(self.name, self.color_current)
151
152 def revert(self):
153 self.setcolor(self.color_current)
154 self.enabled.set(self.enabled_current)
155
156 def default(self):
157 self.setcolor(self.color_default)
158 self.enabled.set(self.enabled_default)
159
160class EventConfigure(Toplevel):
161 def __init__(self):
162 Toplevel.__init__(self)
163 self.resizable(0, 0)
164 self.title("Event Configuration")
165 self.items = LabelFrame(self, text="Event Type")
166 self.buttons = Frame(self)
167 self.drawbuttons()
168 self.items.grid(row=0, column=0, sticky=E+W)
169 self.columnconfigure(0, weight=1)
170 self.buttons.grid(row=1, column=0, sticky=E+W)
171 self.types = []
172 self.irow = 0
173 for type in configtypes:
174 self.additem(type.name, type.color, type.enabled)
175
176 def additem(self, name, color, enabled=1):
177 item = EventConf(self.items, name, color, enabled)
178 self.types.append(item)
179 item.grid(row=self.irow, column=0, sticky=E+W)
180 self.irow += 1
181
182 def drawbuttons(self):
183 self.apply = Button(self.buttons, text="Apply",
184 command=self.apress)
185 self.revert = Button(self.buttons, text="Revert",
186 command=self.rpress)
187 self.default = Button(self.buttons, text="Default",
188 command=self.dpress)
189 self.apply.grid(row=0, column=0, sticky=E+W)
190 self.revert.grid(row=0, column=1, sticky=E+W)
191 self.default.grid(row=0, column=2, sticky=E+W)
192 self.buttons.columnconfigure(0, weight=1)
193 self.buttons.columnconfigure(1, weight=1)
194 self.buttons.columnconfigure(2, weight=1)
195
196 def apress(self):
197 for item in self.types:
198 item.apply()
199
200 def rpress(self):
201 for item in self.types:
202 item.revert()
203
204 def dpress(self):
205 for item in self.types:
206 item.default()
207
208class EventView(Toplevel):
209 def __init__(self, event, canvas):
210 Toplevel.__init__(self)
211 self.resizable(0, 0)
212 self.title("Event")
213 self.event = event
214 self.frame = Frame(self)
215 self.frame.grid(row=0, column=0, sticky=N+S+E+W)
216 self.buttons = Frame(self)
217 self.buttons.grid(row=1, column=0, sticky=E+W)
218 self.canvas = canvas
219 self.drawlabels()
220 self.drawbuttons()
221 event.displayref(canvas)
222 self.bind("<Destroy>", self.destroycb)
223
224 def destroycb(self, event):
225 self.unbind("<Destroy>")
226 if (self.event != None):
227 self.event.displayunref(self.canvas)
228 self.event = None
229 self.destroy()
230
231 def clearlabels(self):
232 for label in self.frame.grid_slaves():
233 label.grid_remove()
234
235 def drawlabels(self):
236 ypos = 0
237 labels = self.event.labels()
238 while (len(labels) < 7):
239 labels.append(("", "", 0))
240 for label in labels:
241 name, value, linked = label
242 l = Label(self.frame, text=name, bd=1, width=15,
243 relief=SUNKEN, anchor=W)
244 if (linked):
245 fgcolor = "blue"
246 else:
247 fgcolor = "black"
248 r = Label(self.frame, text=value, bd=1,
249 relief=SUNKEN, anchor=W, fg=fgcolor)
250 l.grid(row=ypos, column=0, sticky=E+W)
251 r.grid(row=ypos, column=1, sticky=E+W)
252 if (linked):
253 r.bind("<Button-1>", self.linkpress)
254 ypos += 1
255 self.frame.columnconfigure(1, minsize=80)
256
257 def drawbuttons(self):
258 self.back = Button(self.buttons, text="<", command=self.bpress)
259 self.forw = Button(self.buttons, text=">", command=self.fpress)
260 self.new = Button(self.buttons, text="new", command=self.npress)
261 self.back.grid(row=0, column=0, sticky=E+W)
262 self.forw.grid(row=0, column=1, sticky=E+W)
263 self.new.grid(row=0, column=2, sticky=E+W)
264 self.buttons.columnconfigure(2, weight=1)
265
266 def newevent(self, event):
267 self.event.displayunref(self.canvas)
268 self.clearlabels()
269 self.event = event
270 self.event.displayref(self.canvas)
271 self.drawlabels()
272
273 def npress(self):
274 EventView(self.event, self.canvas)
275
276 def bpress(self):
277 prev = self.event.prev()
278 if (prev == None):
279 return
280 while (prev.real == 0):
281 prev = prev.prev()
282 if (prev == None):
283 return
284 self.newevent(prev)
285
286 def fpress(self):
287 next = self.event.next()
288 if (next == None):
289 return
290 while (next.real == 0):
291 next = next.next()
292 if (next == None):
293 return
294 self.newevent(next)
295
296 def linkpress(self, wevent):
297 event = self.event.getlinked()
298 if (event != None):
299 self.newevent(event)
300
301class Event:
302 name = "none"
303 color = "grey"
304 def __init__(self, source, cpu, timestamp, last=0):
305 self.source = source
306 self.cpu = cpu
307 self.timestamp = int(timestamp)
308 self.entries = []
309 self.real = 1
310 self.idx = None
311 self.state = 0
312 self.item = None
313 self.dispcnt = 0
314 self.linked = None
315 if (last):
316 source.lastevent(self)
317 else:
318 source.event(self)
319
320 def status(self):
321 statstr = self.name + " " + self.source.name
322 statstr += " on: cpu" + str(self.cpu)
323 statstr += " at: " + str(self.timestamp)
324 statstr += self.stattxt()
325 status.set(statstr)
326
327 def stattxt(self):
328 return ""
329
330 def textadd(self, tuple):
331 pass
332 self.entries.append(tuple)
333
334 def labels(self):
335 return [("Source:", self.source.name, 0),
336 ("Event:", self.name, 0),
337 ("CPU:", self.cpu, 0),
338 ("Timestamp:", self.timestamp, 0)] + self.entries
339 def mouseenter(self, canvas, item):
340 self.displayref(canvas)
341 self.status()
342
343 def mouseexit(self, canvas, item):
344 self.displayunref(canvas)
345 status.clear()
346
347 def mousepress(self, canvas, item):
348 EventView(self, canvas)
349
350 def next(self):
351 return self.source.eventat(self.idx + 1)
352
353 def prev(self):
354 return self.source.eventat(self.idx - 1)
355
356 def displayref(self, canvas):
357 if (self.dispcnt == 0):
358 canvas.itemconfigure(self.item, width=2)
359 self.dispcnt += 1
360
361 def displayunref(self, canvas):
362 self.dispcnt -= 1
363 if (self.dispcnt == 0):
364 canvas.itemconfigure(self.item, width=0)
365 canvas.tag_raise("point", "state")
366
367 def getlinked(self):
368 return self.linked.findevent(self.timestamp)
369
370class PointEvent(Event):
371 def __init__(self, thread, cpu, timestamp, last=0):
372 Event.__init__(self, thread, cpu, timestamp, last)
373
374 def draw(self, canvas, xpos, ypos):
375 l = canvas.create_oval(xpos - 6, ypos + 1, xpos + 6, ypos - 11,
376 fill=self.color, tags=("all", "point", "event")
377 + (self.name,), width=0)
378 canvas.events[l] = self
379 self.item = l
380 if (self.enabled == 0):
381 canvas.itemconfigure(l, state="hidden")
382
383 return (xpos)
384
385class StateEvent(Event):
386 def __init__(self, thread, cpu, timestamp, last=0):
387 Event.__init__(self, thread, cpu, timestamp, last)
388 self.duration = 0
389 self.skipnext = 0
390 self.skipself = 0
391 self.state = 1
392
393 def draw(self, canvas, xpos, ypos):
394 next = self.nextstate()
395 if (self.skipself == 1 or next == None):
396 return (xpos)
397 if (self.skipnext):
398 skipped = next
399 next.skipself = 1
400 next.real = 0
401 next = next.nextstate()
402 if (next == None):
403 next = skipped
404 self.duration = next.timestamp - self.timestamp
405 delta = self.duration / canvas.ratio
406 l = canvas.create_rectangle(xpos, ypos,
407 xpos + delta, ypos - 10, fill=self.color, width=0,
408 tags=("all", "state", "event") + (self.name,))
409 canvas.events[l] = self
410 self.item = l
411 if (self.enabled == 0):
412 canvas.itemconfigure(l, state="hidden")
413
414 return (xpos + delta)
415
416 def stattxt(self):
417 return " duration: " + ticks2sec(self.duration)
418
419 def nextstate(self):
420 next = self.next()
421 while (next != None and next.state == 0):
422 next = next.next()
423 return (next)
424
425 def labels(self):
426 return [("Source:", self.source.name, 0),
427 ("Event:", self.name, 0),
428 ("Timestamp:", self.timestamp, 0),
429 ("CPU:", self.cpu, 0),
430 ("Duration:", ticks2sec(self.duration), 0)] \
431 + self.entries
432
433class Count(Event):
434 name = "Count"
435 color = "red"
436 enabled = 1
437 def __init__(self, source, cpu, timestamp, count):
438 self.count = int(count)
439 Event.__init__(self, source, cpu, timestamp)
440 self.duration = 0
441 self.textadd(("count:", self.count, 0))
442
443 def draw(self, canvas, xpos, ypos):
444 next = self.next()
445 self.duration = next.timestamp - self.timestamp
446 delta = self.duration / canvas.ratio
447 yhight = self.source.yscale() * self.count
448 l = canvas.create_rectangle(xpos, ypos - yhight,
449 xpos + delta, ypos, fill=self.color, width=0,
450 tags=("all", "count", "event") + (self.name,))
451 canvas.events[l] = self
452 self.item = l
453 if (self.enabled == 0):
454 canvas.itemconfigure(l, state="hidden")
455 return (xpos + delta)
456
457 def stattxt(self):
458 return " count: " + str(self.count)
459
460configtypes.append(Count)
461
462class Running(StateEvent):
463 name = "running"
464 color = "green"
465 enabled = 1
466 def __init__(self, thread, cpu, timestamp, prio):
467 StateEvent.__init__(self, thread, cpu, timestamp)
468 self.prio = prio
469 self.textadd(("prio:", self.prio, 0))
470
471configtypes.append(Running)
472
473class Idle(StateEvent):
474 name = "idle"
475 color = "grey"
476 enabled = 0
477 def __init__(self, thread, cpu, timestamp, prio):
478 StateEvent.__init__(self, thread, cpu, timestamp)
479 self.prio = prio
480 self.textadd(("prio:", self.prio, 0))
481
482configtypes.append(Idle)
483
484class Yielding(StateEvent):
485 name = "yielding"
486 color = "yellow"
487 enabled = 1
488 def __init__(self, thread, cpu, timestamp, prio):
489 StateEvent.__init__(self, thread, cpu, timestamp)
490 self.skipnext = 1
491 self.prio = prio
492 self.textadd(("prio:", self.prio, 0))
493
494configtypes.append(Yielding)
495
496class Swapped(StateEvent):
497 name = "swapped"
498 color = "violet"
499 enabled = 1
500 def __init__(self, thread, cpu, timestamp, prio):
501 StateEvent.__init__(self, thread, cpu, timestamp)
502 self.prio = prio
503 self.textadd(("prio:", self.prio, 0))
504
505configtypes.append(Swapped)
506
507class Suspended(StateEvent):
508 name = "suspended"
509 color = "purple"
510 enabled = 1
511 def __init__(self, thread, cpu, timestamp, prio):
512 StateEvent.__init__(self, thread, cpu, timestamp)
513 self.prio = prio
514 self.textadd(("prio:", self.prio, 0))
515
516configtypes.append(Suspended)
517
518class Iwait(StateEvent):
519 name = "iwait"
520 color = "grey"
521 enabled = 0
522 def __init__(self, thread, cpu, timestamp, prio):
523 StateEvent.__init__(self, thread, cpu, timestamp)
524 self.prio = prio
525 self.textadd(("prio:", self.prio, 0))
526
527configtypes.append(Iwait)
528
529class Preempted(StateEvent):
530 name = "preempted"
531 color = "red"
532 enabled = 1
533 def __init__(self, thread, cpu, timestamp, prio, bythread):
534 StateEvent.__init__(self, thread, cpu, timestamp)
535 self.skipnext = 1
536 self.prio = prio
537 self.linked = bythread
538 self.textadd(("prio:", self.prio, 0))
539 self.textadd(("by thread:", self.linked.name, 1))
540
541configtypes.append(Preempted)
542
543class Sleep(StateEvent):
544 name = "sleep"
545 color = "blue"
546 enabled = 1
547 def __init__(self, thread, cpu, timestamp, prio, wmesg):
548 StateEvent.__init__(self, thread, cpu, timestamp)
549 self.prio = prio
550 self.wmesg = wmesg
551 self.textadd(("prio:", self.prio, 0))
552 self.textadd(("wmesg:", self.wmesg, 0))
553
554 def stattxt(self):
555 statstr = StateEvent.stattxt(self)
556 statstr += " sleeping on: " + self.wmesg
557 return (statstr)
558
559configtypes.append(Sleep)
560
561class Blocked(StateEvent):
562 name = "blocked"
563 color = "dark red"
564 enabled = 1
565 def __init__(self, thread, cpu, timestamp, prio, lock):
566 StateEvent.__init__(self, thread, cpu, timestamp)
567 self.prio = prio
568 self.lock = lock
569 self.textadd(("prio:", self.prio, 0))
570 self.textadd(("lock:", self.lock, 0))
571
572 def stattxt(self):
573 statstr = StateEvent.stattxt(self)
574 statstr += " blocked on: " + self.lock
575 return (statstr)
576
577configtypes.append(Blocked)
578
579class KsegrpRunq(StateEvent):
580 name = "KsegrpRunq"
581 color = "orange"
582 enabled = 1
583 def __init__(self, thread, cpu, timestamp, prio, bythread):
584 StateEvent.__init__(self, thread, cpu, timestamp)
585 self.prio = prio
586 self.linked = bythread
587 self.textadd(("prio:", self.prio, 0))
588 self.textadd(("by thread:", self.linked.name, 1))
589
590configtypes.append(KsegrpRunq)
591
592class Runq(StateEvent):
593 name = "Runq"
594 color = "yellow"
595 enabled = 1
596 def __init__(self, thread, cpu, timestamp, prio, bythread):
597 StateEvent.__init__(self, thread, cpu, timestamp)
598 self.prio = prio
599 self.linked = bythread
600 self.textadd(("prio:", self.prio, 0))
601 self.textadd(("by thread:", self.linked.name, 1))
602
603configtypes.append(Runq)
604
605class Sched_exit(StateEvent):
606 name = "exit"
607 color = "grey"
608 enabled = 0
609 def __init__(self, thread, cpu, timestamp, prio):
610 StateEvent.__init__(self, thread, cpu, timestamp)
611 self.name = "sched_exit"
612 self.prio = prio
613 self.textadd(("prio:", self.prio, 0))
614
615configtypes.append(Sched_exit)
616
617class Padevent(StateEvent):
618 def __init__(self, thread, cpu, timestamp, last=0):
619 StateEvent.__init__(self, thread, cpu, timestamp, last)
620 self.name = "pad"
621 self.real = 0
622
623 def draw(self, canvas, xpos, ypos):
624 next = self.next()
625 if (next == None):
626 return (xpos)
627 self.duration = next.timestamp - self.timestamp
628 delta = self.duration / canvas.ratio
629 return (xpos + delta)
630
631class Tick(PointEvent):
632 name = "tick"
633 color = "black"
634 enabled = 0
635 def __init__(self, thread, cpu, timestamp, prio, stathz):
636 PointEvent.__init__(self, thread, cpu, timestamp)
637 self.prio = prio
638 self.textadd(("prio:", self.prio, 0))
639
640configtypes.append(Tick)
641
642class Prio(PointEvent):
643 name = "prio"
644 color = "black"
645 enabled = 0
646 def __init__(self, thread, cpu, timestamp, prio, newprio, bythread):
647 PointEvent.__init__(self, thread, cpu, timestamp)
648 self.prio = prio
649 self.newprio = newprio
650 self.linked = bythread
651 self.textadd(("new prio:", self.newprio, 0))
652 self.textadd(("prio:", self.prio, 0))
653 if (self.linked != self.source):
654 self.textadd(("by thread:", self.linked.name, 1))
655 else:
656 self.textadd(("by thread:", self.linked.name, 0))
657
658configtypes.append(Prio)
659
660class Lend(PointEvent):
661 name = "lend"
662 color = "black"
663 enabled = 0
664 def __init__(self, thread, cpu, timestamp, prio, tothread):
665 PointEvent.__init__(self, thread, cpu, timestamp)
666 self.prio = prio
667 self.linked = tothread
668 self.textadd(("prio:", self.prio, 0))
669 self.textadd(("to thread:", self.linked.name, 1))
670
671configtypes.append(Lend)
672
673class Wokeup(PointEvent):
674 name = "wokeup"
675 color = "black"
676 enabled = 0
677 def __init__(self, thread, cpu, timestamp, ranthread):
678 PointEvent.__init__(self, thread, cpu, timestamp)
679 self.linked = ranthread
680 self.textadd(("ran thread:", self.linked.name, 1))
681
682configtypes.append(Wokeup)
683
684class EventSource:
685 def __init__(self, name):
686 self.name = name
687 self.events = []
688 self.cpu = 0
689 self.cpux = 0
690
691 def fixup(self):
692 pass
693
694 def event(self, event):
695 self.events.insert(0, event)
696
697 def remove(self, event):
698 self.events.remove(event)
699
700 def lastevent(self, event):
701 self.events.append(event)
702
703 def draw(self, canvas, ypos):
704 xpos = 10
705 self.cpux = 10
706 self.cpu = self.events[1].cpu
707 for i in range(0, len(self.events)):
708 self.events[i].idx = i
709 for event in self.events:
710 if (event.cpu != self.cpu and event.cpu != -1):
711 self.drawcpu(canvas, xpos, ypos)
712 self.cpux = xpos
713 self.cpu = event.cpu
714 xpos = event.draw(canvas, xpos, ypos)
715 self.drawcpu(canvas, xpos, ypos)
716
717 def drawname(self, canvas, ypos):
718 ypos = ypos - (self.ysize() / 2)
719 canvas.create_text(10, ypos, anchor="w", text=self.name)
720
721 def drawcpu(self, canvas, xpos, ypos):
722 cpu = int(self.cpu)
723 if (cpu == 0):
724 color = 'light grey'
725 elif (cpu == 1):
726 color = 'dark grey'
727 elif (cpu == 2):
728 color = 'light blue'
729 elif (cpu == 3):
730 color == 'light green'
731 else:
732 color == "white"
733 l = canvas.create_rectangle(self.cpux,
734 ypos - self.ysize() - canvas.bdheight,
735 xpos, ypos + canvas.bdheight, fill=color, width=0,
736 tags=("all", "cpuinfo"))
737
738 def ysize(self):
739 return (None)
740
741 def eventat(self, i):
742 if (i >= len(self.events)):
743 return (None)
744 event = self.events[i]
745 return (event)
746
747 def findevent(self, timestamp):
748 for event in self.events:
749 if (event.timestamp >= timestamp and event.real):
750 return (event)
751 return (None)
752
753class Thread(EventSource):
754 names = {}
755 def __init__(self, td, pcomm):
756 EventSource.__init__(self, pcomm)
757 self.str = td
758 try:
759 cnt = Thread.names[pcomm]
760 except:
761 Thread.names[pcomm] = 0
762 return
763 Thread.names[pcomm] = cnt + 1
764
765 def fixup(self):
766 cnt = Thread.names[self.name]
767 if (cnt == 0):
768 return
769 cnt -= 1
770 Thread.names[self.name] = cnt
771 self.name += " td" + str(cnt)
772
773 def ysize(self):
774 return (10)
775
776class Counter(EventSource):
777 max = 0
778 def __init__(self, name):
779 EventSource.__init__(self, name)
780
781 def event(self, event):
782 EventSource.event(self, event)
783 try:
784 count = event.count
785 except:
786 return
787 count = int(count)
788 if (count > Counter.max):
789 Counter.max = count
790
791 def ysize(self):
792 return (80)
793
794 def yscale(self):
795 return (self.ysize() / Counter.max)
796
797
798class KTRFile:
799 def __init__(self, file):
800 self.timestamp_first = None
801 self.timestamp_last = None
802 self.lineno = -1
803 self.threads = []
804 self.sources = []
805 self.ticks = {}
806 self.load = {}
807
808 self.parse(file)
809 self.fixup()
810 global ticksps
811 ticksps = self.ticksps()
812
813 def parse(self, file):
814 try:
815 ifp = open(file)
816 except:
817 print "Can't open", file
818 sys.exit(1)
819
820 ktrhdr = "\s+\d+\s+(\d+)\s+(\d+)\s+"
821 tdname = "(\S+)\(([^)]*)\)"
822
823 ktrstr = "mi_switch: " + tdname
824 ktrstr += " prio (\d+) inhibit (\d+) wmesg (\S+) lock (\S+)"
825 switchout_re = re.compile(ktrhdr + ktrstr)
826
827 ktrstr = "mi_switch: " + tdname + " prio (\d+) idle"
828 idled_re = re.compile(ktrhdr + ktrstr)
829
830 ktrstr = "mi_switch: " + tdname + " prio (\d+) preempted by "
831 ktrstr += tdname
832 preempted_re = re.compile(ktrhdr + ktrstr)
833
834 ktrstr = "mi_switch: running " + tdname + " prio (\d+)"
835 switchin_re = re.compile(ktrhdr + ktrstr)
836
837 ktrstr = "sched_add: " + tdname + " prio (\d+) by " + tdname
838 sched_add_re = re.compile(ktrhdr + ktrstr)
839
840 ktrstr = "setrunqueue: " + tdname + " prio (\d+) by " + tdname
841 setrunqueue_re = re.compile(ktrhdr + ktrstr)
842
843 ktrstr = "sched_rem: " + tdname + " prio (\d+) by " + tdname
844 sched_rem_re = re.compile(ktrhdr + ktrstr)
845
846 ktrstr = "sched_exit_thread: " + tdname + " prio (\d+)"
847 sched_exit_re = re.compile(ktrhdr + ktrstr)
848
849 ktrstr = "statclock: " + tdname + " prio (\d+)"
850 ktrstr += " stathz (\d+)"
851 sched_clock_re = re.compile(ktrhdr + ktrstr)
852
853 ktrstr = "sched_prio: " + tdname + " prio (\d+)"
854 ktrstr += " newprio (\d+) by " + tdname
855 sched_prio_re = re.compile(ktrhdr + ktrstr)
856
857 cpuload_re = re.compile(ktrhdr + "load: (\d+)")
858 loadglobal_re = re.compile(ktrhdr + "global load: (\d+)")
859
860 parsers = [[cpuload_re, self.cpuload],
861 [loadglobal_re, self.loadglobal],
862 [switchin_re, self.switchin],
863 [switchout_re, self.switchout],
864 [sched_add_re, self.sched_add],
865 [setrunqueue_re, self.sched_rem],
866 [sched_prio_re, self.sched_prio],
867 [preempted_re, self.preempted],
868 [sched_rem_re, self.sched_rem],
869 [sched_exit_re, self.sched_exit],
870 [sched_clock_re, self.sched_clock],
871 [idled_re, self.idled]]
872
873 for line in ifp.readlines():
874 self.lineno += 1
875 if ((self.lineno % 1024) == 0):
876 status.startup("Parsing line " +
877 str(self.lineno))
878 for p in parsers:
879 m = p[0].match(line)
880 if (m != None):
881 p[1](*m.groups())
882 break
883 # if (m == None):
884 # print line,
885
886 def checkstamp(self, timestamp):
887 timestamp = int(timestamp)
888 if (self.timestamp_first == None):
889 self.timestamp_first = timestamp
890 if (timestamp > self.timestamp_first):
891 print "Bad timestamp on line ", self.lineno
892 return (0)
893 self.timestamp_last = timestamp
894 return (1)
895
896 def timespan(self):
897 return (self.timestamp_first - self.timestamp_last);
898
899 def ticksps(self):
900 return (self.timespan() / self.ticks[0]) * int(self.stathz)
901
902 def switchout(self, cpu, timestamp, td, pcomm, prio, inhibit, wmesg, lock):
903 TDI_SUSPENDED = 0x0001
904 TDI_SLEEPING = 0x0002
905 TDI_SWAPPED = 0x0004
906 TDI_LOCK = 0x0008
907 TDI_IWAIT = 0x0010
908
909 if (self.checkstamp(timestamp) == 0):
910 return
911 inhibit = int(inhibit)
912 thread = self.findtd(td, pcomm)
913 if (inhibit & TDI_SWAPPED):
914 Swapped(thread, cpu, timestamp, prio)
915 elif (inhibit & TDI_SLEEPING):
916 Sleep(thread, cpu, timestamp, prio, wmesg)
917 elif (inhibit & TDI_LOCK):
918 Blocked(thread, cpu, timestamp, prio, lock)
919 elif (inhibit & TDI_IWAIT):
920 Iwait(thread, cpu, timestamp, prio)
921 elif (inhibit & TDI_SUSPENDED):
922 Suspended(thread, cpu, timestamp, prio)
923 elif (inhibit == 0):
924 Yielding(thread, cpu, timestamp, prio)
925 else:
926 print "Unknown event", inhibit
927 sys.exit(1)
928
929 def idled(self, cpu, timestamp, td, pcomm, prio):
930 if (self.checkstamp(timestamp) == 0):
931 return
932 thread = self.findtd(td, pcomm)
933 Idle(thread, cpu, timestamp, prio)
934
935 def preempted(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
936 if (self.checkstamp(timestamp) == 0):
937 return
938 thread = self.findtd(td, pcomm)
939 Preempted(thread, cpu, timestamp, prio,
940 self.findtd(bytd, bypcomm))
941
942 def switchin(self, cpu, timestamp, td, pcomm, prio):
943 if (self.checkstamp(timestamp) == 0):
944 return
945 thread = self.findtd(td, pcomm)
946 Running(thread, cpu, timestamp, prio)
947
948 def sched_add(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
949 if (self.checkstamp(timestamp) == 0):
950 return
951 thread = self.findtd(td, pcomm)
952 bythread = self.findtd(bytd, bypcomm)
953 Runq(thread, cpu, timestamp, prio, bythread)
954 Wokeup(bythread, cpu, timestamp, thread)
955
956 def sched_rem(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
957 if (self.checkstamp(timestamp) == 0):
958 return
959 thread = self.findtd(td, pcomm)
960 KsegrpRunq(thread, cpu, timestamp, prio,
961 self.findtd(bytd, bypcomm))
962
963 def sched_exit(self, cpu, timestamp, td, pcomm, prio):
964 if (self.checkstamp(timestamp) == 0):
965 return
966 thread = self.findtd(td, pcomm)
967 Sched_exit(thread, cpu, timestamp, prio)
968
969 def sched_clock(self, cpu, timestamp, td, pcomm, prio, stathz):
970 if (self.checkstamp(timestamp) == 0):
971 return
972 self.stathz = stathz
973 cpu = int(cpu)
974 try:
975 ticks = self.ticks[cpu]
976 except:
977 self.ticks[cpu] = 0
978 self.ticks[cpu] += 1
979 thread = self.findtd(td, pcomm)
980 Tick(thread, cpu, timestamp, prio, stathz)
981
982 def sched_prio(self, cpu, timestamp, td, pcomm, prio, newprio, bytd, bypcomm):
983 if (prio == newprio):
984 return
985 if (self.checkstamp(timestamp) == 0):
986 return
987 thread = self.findtd(td, pcomm)
988 bythread = self.findtd(bytd, bypcomm)
989 Prio(thread, cpu, timestamp, prio, newprio, bythread)
990 Lend(bythread, cpu, timestamp, newprio, thread)
991
992 def cpuload(self, cpu, timestamp, count):
28
29import sys
30import re
31from Tkinter import *
32
33# 1) Add a per-thread summary display
34# 2) Add bounding box style zoom.
35# 3) Click to center.
36# 4) Implement some sorting mechanism.
37
38ticksps = None
39status = None
40configtypes = []
41
42def ticks2sec(ticks):
43 ns = ticksps / 1000000000
44 ticks /= ns
45 if (ticks < 1000):
46 return (str(ticks) + "ns")
47 ticks /= 1000
48 if (ticks < 1000):
49 return (str(ticks) + "us")
50 ticks /= 1000
51 if (ticks < 1000):
52 return (str(ticks) + "ms")
53 ticks /= 1000
54 return (str(ticks) + "s")
55
56class Scaler(Frame):
57 def __init__(self, master, target):
58 Frame.__init__(self, master)
59 self.scale = Scale(self, command=self.scaleset,
60 from_=1000, to_=1000000, orient=HORIZONTAL, resolution=1000)
61 self.label = Label(self, text="Ticks per pixel")
62 self.label.pack(side=LEFT)
63 self.scale.pack(fill="both", expand=1)
64 self.target = target
65 self.scale.set(target.scaleget())
66 self.initialized = 1
67
68 def scaleset(self, value):
69 self.target.scaleset(int(value))
70
71 def set(self, value):
72 self.scale.set(value)
73
74class Status(Frame):
75 def __init__(self, master):
76 Frame.__init__(self, master)
77 self.label = Label(self, bd=1, relief=SUNKEN, anchor=W)
78 self.label.pack(fill="both", expand=1)
79 self.clear()
80
81 def set(self, str):
82 self.label.config(text=str)
83
84 def clear(self):
85 self.label.config(text="")
86
87 def startup(self, str):
88 self.set(str)
89 root.update()
90
91class EventConf(Frame):
92 def __init__(self, master, name, color, enabled):
93 Frame.__init__(self, master)
94 self.name = name
95 self.color = StringVar()
96 self.color_default = color
97 self.color_current = color
98 self.color.set(color)
99 self.enabled = IntVar()
100 self.enabled_default = enabled
101 self.enabled_current = enabled
102 self.enabled.set(enabled)
103 self.draw()
104
105 def draw(self):
106 self.label = Label(self, text=self.name, anchor=W)
107 self.sample = Canvas(self, width=24, height=24,
108 bg='grey')
109 self.rect = self.sample.create_rectangle(0, 0, 24, 24,
110 fill=self.color.get())
111 self.list = OptionMenu(self, self.color,
112 "dark red", "red", "pink",
113 "dark orange", "orange",
114 "yellow", "light yellow",
115 "dark green", "green", "light green",
116 "dark blue", "blue", "light blue",
117 "dark violet", "violet", "purple",
118 "dark grey", "light grey",
119 "white", "black",
120 command=self.setcolor)
121 self.checkbox = Checkbutton(self, text="enabled",
122 variable=self.enabled)
123 self.label.grid(row=0, column=0, sticky=E+W)
124 self.sample.grid(row=0, column=1)
125 self.list.grid(row=0, column=2, sticky=E+W)
126 self.checkbox.grid(row=0, column=3)
127 self.columnconfigure(0, weight=1)
128 self.columnconfigure(2, minsize=110)
129
130 def setcolor(self, color):
131 self.color.set(color)
132 self.sample.itemconfigure(self.rect, fill=color)
133
134 def apply(self):
135 cchange = 0
136 echange = 0
137 if (self.color_current != self.color.get()):
138 cchange = 1
139 if (self.enabled_current != self.enabled.get()):
140 echange = 1
141 self.color_current = self.color.get()
142 self.enabled_current = self.enabled.get()
143 if (echange != 0):
144 if (self.enabled_current):
145 graph.setcolor(self.name, self.color_current)
146 else:
147 graph.hide(self.name)
148 return
149 if (cchange != 0):
150 graph.setcolor(self.name, self.color_current)
151
152 def revert(self):
153 self.setcolor(self.color_current)
154 self.enabled.set(self.enabled_current)
155
156 def default(self):
157 self.setcolor(self.color_default)
158 self.enabled.set(self.enabled_default)
159
160class EventConfigure(Toplevel):
161 def __init__(self):
162 Toplevel.__init__(self)
163 self.resizable(0, 0)
164 self.title("Event Configuration")
165 self.items = LabelFrame(self, text="Event Type")
166 self.buttons = Frame(self)
167 self.drawbuttons()
168 self.items.grid(row=0, column=0, sticky=E+W)
169 self.columnconfigure(0, weight=1)
170 self.buttons.grid(row=1, column=0, sticky=E+W)
171 self.types = []
172 self.irow = 0
173 for type in configtypes:
174 self.additem(type.name, type.color, type.enabled)
175
176 def additem(self, name, color, enabled=1):
177 item = EventConf(self.items, name, color, enabled)
178 self.types.append(item)
179 item.grid(row=self.irow, column=0, sticky=E+W)
180 self.irow += 1
181
182 def drawbuttons(self):
183 self.apply = Button(self.buttons, text="Apply",
184 command=self.apress)
185 self.revert = Button(self.buttons, text="Revert",
186 command=self.rpress)
187 self.default = Button(self.buttons, text="Default",
188 command=self.dpress)
189 self.apply.grid(row=0, column=0, sticky=E+W)
190 self.revert.grid(row=0, column=1, sticky=E+W)
191 self.default.grid(row=0, column=2, sticky=E+W)
192 self.buttons.columnconfigure(0, weight=1)
193 self.buttons.columnconfigure(1, weight=1)
194 self.buttons.columnconfigure(2, weight=1)
195
196 def apress(self):
197 for item in self.types:
198 item.apply()
199
200 def rpress(self):
201 for item in self.types:
202 item.revert()
203
204 def dpress(self):
205 for item in self.types:
206 item.default()
207
208class EventView(Toplevel):
209 def __init__(self, event, canvas):
210 Toplevel.__init__(self)
211 self.resizable(0, 0)
212 self.title("Event")
213 self.event = event
214 self.frame = Frame(self)
215 self.frame.grid(row=0, column=0, sticky=N+S+E+W)
216 self.buttons = Frame(self)
217 self.buttons.grid(row=1, column=0, sticky=E+W)
218 self.canvas = canvas
219 self.drawlabels()
220 self.drawbuttons()
221 event.displayref(canvas)
222 self.bind("<Destroy>", self.destroycb)
223
224 def destroycb(self, event):
225 self.unbind("<Destroy>")
226 if (self.event != None):
227 self.event.displayunref(self.canvas)
228 self.event = None
229 self.destroy()
230
231 def clearlabels(self):
232 for label in self.frame.grid_slaves():
233 label.grid_remove()
234
235 def drawlabels(self):
236 ypos = 0
237 labels = self.event.labels()
238 while (len(labels) < 7):
239 labels.append(("", "", 0))
240 for label in labels:
241 name, value, linked = label
242 l = Label(self.frame, text=name, bd=1, width=15,
243 relief=SUNKEN, anchor=W)
244 if (linked):
245 fgcolor = "blue"
246 else:
247 fgcolor = "black"
248 r = Label(self.frame, text=value, bd=1,
249 relief=SUNKEN, anchor=W, fg=fgcolor)
250 l.grid(row=ypos, column=0, sticky=E+W)
251 r.grid(row=ypos, column=1, sticky=E+W)
252 if (linked):
253 r.bind("<Button-1>", self.linkpress)
254 ypos += 1
255 self.frame.columnconfigure(1, minsize=80)
256
257 def drawbuttons(self):
258 self.back = Button(self.buttons, text="<", command=self.bpress)
259 self.forw = Button(self.buttons, text=">", command=self.fpress)
260 self.new = Button(self.buttons, text="new", command=self.npress)
261 self.back.grid(row=0, column=0, sticky=E+W)
262 self.forw.grid(row=0, column=1, sticky=E+W)
263 self.new.grid(row=0, column=2, sticky=E+W)
264 self.buttons.columnconfigure(2, weight=1)
265
266 def newevent(self, event):
267 self.event.displayunref(self.canvas)
268 self.clearlabels()
269 self.event = event
270 self.event.displayref(self.canvas)
271 self.drawlabels()
272
273 def npress(self):
274 EventView(self.event, self.canvas)
275
276 def bpress(self):
277 prev = self.event.prev()
278 if (prev == None):
279 return
280 while (prev.real == 0):
281 prev = prev.prev()
282 if (prev == None):
283 return
284 self.newevent(prev)
285
286 def fpress(self):
287 next = self.event.next()
288 if (next == None):
289 return
290 while (next.real == 0):
291 next = next.next()
292 if (next == None):
293 return
294 self.newevent(next)
295
296 def linkpress(self, wevent):
297 event = self.event.getlinked()
298 if (event != None):
299 self.newevent(event)
300
301class Event:
302 name = "none"
303 color = "grey"
304 def __init__(self, source, cpu, timestamp, last=0):
305 self.source = source
306 self.cpu = cpu
307 self.timestamp = int(timestamp)
308 self.entries = []
309 self.real = 1
310 self.idx = None
311 self.state = 0
312 self.item = None
313 self.dispcnt = 0
314 self.linked = None
315 if (last):
316 source.lastevent(self)
317 else:
318 source.event(self)
319
320 def status(self):
321 statstr = self.name + " " + self.source.name
322 statstr += " on: cpu" + str(self.cpu)
323 statstr += " at: " + str(self.timestamp)
324 statstr += self.stattxt()
325 status.set(statstr)
326
327 def stattxt(self):
328 return ""
329
330 def textadd(self, tuple):
331 pass
332 self.entries.append(tuple)
333
334 def labels(self):
335 return [("Source:", self.source.name, 0),
336 ("Event:", self.name, 0),
337 ("CPU:", self.cpu, 0),
338 ("Timestamp:", self.timestamp, 0)] + self.entries
339 def mouseenter(self, canvas, item):
340 self.displayref(canvas)
341 self.status()
342
343 def mouseexit(self, canvas, item):
344 self.displayunref(canvas)
345 status.clear()
346
347 def mousepress(self, canvas, item):
348 EventView(self, canvas)
349
350 def next(self):
351 return self.source.eventat(self.idx + 1)
352
353 def prev(self):
354 return self.source.eventat(self.idx - 1)
355
356 def displayref(self, canvas):
357 if (self.dispcnt == 0):
358 canvas.itemconfigure(self.item, width=2)
359 self.dispcnt += 1
360
361 def displayunref(self, canvas):
362 self.dispcnt -= 1
363 if (self.dispcnt == 0):
364 canvas.itemconfigure(self.item, width=0)
365 canvas.tag_raise("point", "state")
366
367 def getlinked(self):
368 return self.linked.findevent(self.timestamp)
369
370class PointEvent(Event):
371 def __init__(self, thread, cpu, timestamp, last=0):
372 Event.__init__(self, thread, cpu, timestamp, last)
373
374 def draw(self, canvas, xpos, ypos):
375 l = canvas.create_oval(xpos - 6, ypos + 1, xpos + 6, ypos - 11,
376 fill=self.color, tags=("all", "point", "event")
377 + (self.name,), width=0)
378 canvas.events[l] = self
379 self.item = l
380 if (self.enabled == 0):
381 canvas.itemconfigure(l, state="hidden")
382
383 return (xpos)
384
385class StateEvent(Event):
386 def __init__(self, thread, cpu, timestamp, last=0):
387 Event.__init__(self, thread, cpu, timestamp, last)
388 self.duration = 0
389 self.skipnext = 0
390 self.skipself = 0
391 self.state = 1
392
393 def draw(self, canvas, xpos, ypos):
394 next = self.nextstate()
395 if (self.skipself == 1 or next == None):
396 return (xpos)
397 if (self.skipnext):
398 skipped = next
399 next.skipself = 1
400 next.real = 0
401 next = next.nextstate()
402 if (next == None):
403 next = skipped
404 self.duration = next.timestamp - self.timestamp
405 delta = self.duration / canvas.ratio
406 l = canvas.create_rectangle(xpos, ypos,
407 xpos + delta, ypos - 10, fill=self.color, width=0,
408 tags=("all", "state", "event") + (self.name,))
409 canvas.events[l] = self
410 self.item = l
411 if (self.enabled == 0):
412 canvas.itemconfigure(l, state="hidden")
413
414 return (xpos + delta)
415
416 def stattxt(self):
417 return " duration: " + ticks2sec(self.duration)
418
419 def nextstate(self):
420 next = self.next()
421 while (next != None and next.state == 0):
422 next = next.next()
423 return (next)
424
425 def labels(self):
426 return [("Source:", self.source.name, 0),
427 ("Event:", self.name, 0),
428 ("Timestamp:", self.timestamp, 0),
429 ("CPU:", self.cpu, 0),
430 ("Duration:", ticks2sec(self.duration), 0)] \
431 + self.entries
432
433class Count(Event):
434 name = "Count"
435 color = "red"
436 enabled = 1
437 def __init__(self, source, cpu, timestamp, count):
438 self.count = int(count)
439 Event.__init__(self, source, cpu, timestamp)
440 self.duration = 0
441 self.textadd(("count:", self.count, 0))
442
443 def draw(self, canvas, xpos, ypos):
444 next = self.next()
445 self.duration = next.timestamp - self.timestamp
446 delta = self.duration / canvas.ratio
447 yhight = self.source.yscale() * self.count
448 l = canvas.create_rectangle(xpos, ypos - yhight,
449 xpos + delta, ypos, fill=self.color, width=0,
450 tags=("all", "count", "event") + (self.name,))
451 canvas.events[l] = self
452 self.item = l
453 if (self.enabled == 0):
454 canvas.itemconfigure(l, state="hidden")
455 return (xpos + delta)
456
457 def stattxt(self):
458 return " count: " + str(self.count)
459
460configtypes.append(Count)
461
462class Running(StateEvent):
463 name = "running"
464 color = "green"
465 enabled = 1
466 def __init__(self, thread, cpu, timestamp, prio):
467 StateEvent.__init__(self, thread, cpu, timestamp)
468 self.prio = prio
469 self.textadd(("prio:", self.prio, 0))
470
471configtypes.append(Running)
472
473class Idle(StateEvent):
474 name = "idle"
475 color = "grey"
476 enabled = 0
477 def __init__(self, thread, cpu, timestamp, prio):
478 StateEvent.__init__(self, thread, cpu, timestamp)
479 self.prio = prio
480 self.textadd(("prio:", self.prio, 0))
481
482configtypes.append(Idle)
483
484class Yielding(StateEvent):
485 name = "yielding"
486 color = "yellow"
487 enabled = 1
488 def __init__(self, thread, cpu, timestamp, prio):
489 StateEvent.__init__(self, thread, cpu, timestamp)
490 self.skipnext = 1
491 self.prio = prio
492 self.textadd(("prio:", self.prio, 0))
493
494configtypes.append(Yielding)
495
496class Swapped(StateEvent):
497 name = "swapped"
498 color = "violet"
499 enabled = 1
500 def __init__(self, thread, cpu, timestamp, prio):
501 StateEvent.__init__(self, thread, cpu, timestamp)
502 self.prio = prio
503 self.textadd(("prio:", self.prio, 0))
504
505configtypes.append(Swapped)
506
507class Suspended(StateEvent):
508 name = "suspended"
509 color = "purple"
510 enabled = 1
511 def __init__(self, thread, cpu, timestamp, prio):
512 StateEvent.__init__(self, thread, cpu, timestamp)
513 self.prio = prio
514 self.textadd(("prio:", self.prio, 0))
515
516configtypes.append(Suspended)
517
518class Iwait(StateEvent):
519 name = "iwait"
520 color = "grey"
521 enabled = 0
522 def __init__(self, thread, cpu, timestamp, prio):
523 StateEvent.__init__(self, thread, cpu, timestamp)
524 self.prio = prio
525 self.textadd(("prio:", self.prio, 0))
526
527configtypes.append(Iwait)
528
529class Preempted(StateEvent):
530 name = "preempted"
531 color = "red"
532 enabled = 1
533 def __init__(self, thread, cpu, timestamp, prio, bythread):
534 StateEvent.__init__(self, thread, cpu, timestamp)
535 self.skipnext = 1
536 self.prio = prio
537 self.linked = bythread
538 self.textadd(("prio:", self.prio, 0))
539 self.textadd(("by thread:", self.linked.name, 1))
540
541configtypes.append(Preempted)
542
543class Sleep(StateEvent):
544 name = "sleep"
545 color = "blue"
546 enabled = 1
547 def __init__(self, thread, cpu, timestamp, prio, wmesg):
548 StateEvent.__init__(self, thread, cpu, timestamp)
549 self.prio = prio
550 self.wmesg = wmesg
551 self.textadd(("prio:", self.prio, 0))
552 self.textadd(("wmesg:", self.wmesg, 0))
553
554 def stattxt(self):
555 statstr = StateEvent.stattxt(self)
556 statstr += " sleeping on: " + self.wmesg
557 return (statstr)
558
559configtypes.append(Sleep)
560
561class Blocked(StateEvent):
562 name = "blocked"
563 color = "dark red"
564 enabled = 1
565 def __init__(self, thread, cpu, timestamp, prio, lock):
566 StateEvent.__init__(self, thread, cpu, timestamp)
567 self.prio = prio
568 self.lock = lock
569 self.textadd(("prio:", self.prio, 0))
570 self.textadd(("lock:", self.lock, 0))
571
572 def stattxt(self):
573 statstr = StateEvent.stattxt(self)
574 statstr += " blocked on: " + self.lock
575 return (statstr)
576
577configtypes.append(Blocked)
578
579class KsegrpRunq(StateEvent):
580 name = "KsegrpRunq"
581 color = "orange"
582 enabled = 1
583 def __init__(self, thread, cpu, timestamp, prio, bythread):
584 StateEvent.__init__(self, thread, cpu, timestamp)
585 self.prio = prio
586 self.linked = bythread
587 self.textadd(("prio:", self.prio, 0))
588 self.textadd(("by thread:", self.linked.name, 1))
589
590configtypes.append(KsegrpRunq)
591
592class Runq(StateEvent):
593 name = "Runq"
594 color = "yellow"
595 enabled = 1
596 def __init__(self, thread, cpu, timestamp, prio, bythread):
597 StateEvent.__init__(self, thread, cpu, timestamp)
598 self.prio = prio
599 self.linked = bythread
600 self.textadd(("prio:", self.prio, 0))
601 self.textadd(("by thread:", self.linked.name, 1))
602
603configtypes.append(Runq)
604
605class Sched_exit(StateEvent):
606 name = "exit"
607 color = "grey"
608 enabled = 0
609 def __init__(self, thread, cpu, timestamp, prio):
610 StateEvent.__init__(self, thread, cpu, timestamp)
611 self.name = "sched_exit"
612 self.prio = prio
613 self.textadd(("prio:", self.prio, 0))
614
615configtypes.append(Sched_exit)
616
617class Padevent(StateEvent):
618 def __init__(self, thread, cpu, timestamp, last=0):
619 StateEvent.__init__(self, thread, cpu, timestamp, last)
620 self.name = "pad"
621 self.real = 0
622
623 def draw(self, canvas, xpos, ypos):
624 next = self.next()
625 if (next == None):
626 return (xpos)
627 self.duration = next.timestamp - self.timestamp
628 delta = self.duration / canvas.ratio
629 return (xpos + delta)
630
631class Tick(PointEvent):
632 name = "tick"
633 color = "black"
634 enabled = 0
635 def __init__(self, thread, cpu, timestamp, prio, stathz):
636 PointEvent.__init__(self, thread, cpu, timestamp)
637 self.prio = prio
638 self.textadd(("prio:", self.prio, 0))
639
640configtypes.append(Tick)
641
642class Prio(PointEvent):
643 name = "prio"
644 color = "black"
645 enabled = 0
646 def __init__(self, thread, cpu, timestamp, prio, newprio, bythread):
647 PointEvent.__init__(self, thread, cpu, timestamp)
648 self.prio = prio
649 self.newprio = newprio
650 self.linked = bythread
651 self.textadd(("new prio:", self.newprio, 0))
652 self.textadd(("prio:", self.prio, 0))
653 if (self.linked != self.source):
654 self.textadd(("by thread:", self.linked.name, 1))
655 else:
656 self.textadd(("by thread:", self.linked.name, 0))
657
658configtypes.append(Prio)
659
660class Lend(PointEvent):
661 name = "lend"
662 color = "black"
663 enabled = 0
664 def __init__(self, thread, cpu, timestamp, prio, tothread):
665 PointEvent.__init__(self, thread, cpu, timestamp)
666 self.prio = prio
667 self.linked = tothread
668 self.textadd(("prio:", self.prio, 0))
669 self.textadd(("to thread:", self.linked.name, 1))
670
671configtypes.append(Lend)
672
673class Wokeup(PointEvent):
674 name = "wokeup"
675 color = "black"
676 enabled = 0
677 def __init__(self, thread, cpu, timestamp, ranthread):
678 PointEvent.__init__(self, thread, cpu, timestamp)
679 self.linked = ranthread
680 self.textadd(("ran thread:", self.linked.name, 1))
681
682configtypes.append(Wokeup)
683
684class EventSource:
685 def __init__(self, name):
686 self.name = name
687 self.events = []
688 self.cpu = 0
689 self.cpux = 0
690
691 def fixup(self):
692 pass
693
694 def event(self, event):
695 self.events.insert(0, event)
696
697 def remove(self, event):
698 self.events.remove(event)
699
700 def lastevent(self, event):
701 self.events.append(event)
702
703 def draw(self, canvas, ypos):
704 xpos = 10
705 self.cpux = 10
706 self.cpu = self.events[1].cpu
707 for i in range(0, len(self.events)):
708 self.events[i].idx = i
709 for event in self.events:
710 if (event.cpu != self.cpu and event.cpu != -1):
711 self.drawcpu(canvas, xpos, ypos)
712 self.cpux = xpos
713 self.cpu = event.cpu
714 xpos = event.draw(canvas, xpos, ypos)
715 self.drawcpu(canvas, xpos, ypos)
716
717 def drawname(self, canvas, ypos):
718 ypos = ypos - (self.ysize() / 2)
719 canvas.create_text(10, ypos, anchor="w", text=self.name)
720
721 def drawcpu(self, canvas, xpos, ypos):
722 cpu = int(self.cpu)
723 if (cpu == 0):
724 color = 'light grey'
725 elif (cpu == 1):
726 color = 'dark grey'
727 elif (cpu == 2):
728 color = 'light blue'
729 elif (cpu == 3):
730 color == 'light green'
731 else:
732 color == "white"
733 l = canvas.create_rectangle(self.cpux,
734 ypos - self.ysize() - canvas.bdheight,
735 xpos, ypos + canvas.bdheight, fill=color, width=0,
736 tags=("all", "cpuinfo"))
737
738 def ysize(self):
739 return (None)
740
741 def eventat(self, i):
742 if (i >= len(self.events)):
743 return (None)
744 event = self.events[i]
745 return (event)
746
747 def findevent(self, timestamp):
748 for event in self.events:
749 if (event.timestamp >= timestamp and event.real):
750 return (event)
751 return (None)
752
753class Thread(EventSource):
754 names = {}
755 def __init__(self, td, pcomm):
756 EventSource.__init__(self, pcomm)
757 self.str = td
758 try:
759 cnt = Thread.names[pcomm]
760 except:
761 Thread.names[pcomm] = 0
762 return
763 Thread.names[pcomm] = cnt + 1
764
765 def fixup(self):
766 cnt = Thread.names[self.name]
767 if (cnt == 0):
768 return
769 cnt -= 1
770 Thread.names[self.name] = cnt
771 self.name += " td" + str(cnt)
772
773 def ysize(self):
774 return (10)
775
776class Counter(EventSource):
777 max = 0
778 def __init__(self, name):
779 EventSource.__init__(self, name)
780
781 def event(self, event):
782 EventSource.event(self, event)
783 try:
784 count = event.count
785 except:
786 return
787 count = int(count)
788 if (count > Counter.max):
789 Counter.max = count
790
791 def ysize(self):
792 return (80)
793
794 def yscale(self):
795 return (self.ysize() / Counter.max)
796
797
798class KTRFile:
799 def __init__(self, file):
800 self.timestamp_first = None
801 self.timestamp_last = None
802 self.lineno = -1
803 self.threads = []
804 self.sources = []
805 self.ticks = {}
806 self.load = {}
807
808 self.parse(file)
809 self.fixup()
810 global ticksps
811 ticksps = self.ticksps()
812
813 def parse(self, file):
814 try:
815 ifp = open(file)
816 except:
817 print "Can't open", file
818 sys.exit(1)
819
820 ktrhdr = "\s+\d+\s+(\d+)\s+(\d+)\s+"
821 tdname = "(\S+)\(([^)]*)\)"
822
823 ktrstr = "mi_switch: " + tdname
824 ktrstr += " prio (\d+) inhibit (\d+) wmesg (\S+) lock (\S+)"
825 switchout_re = re.compile(ktrhdr + ktrstr)
826
827 ktrstr = "mi_switch: " + tdname + " prio (\d+) idle"
828 idled_re = re.compile(ktrhdr + ktrstr)
829
830 ktrstr = "mi_switch: " + tdname + " prio (\d+) preempted by "
831 ktrstr += tdname
832 preempted_re = re.compile(ktrhdr + ktrstr)
833
834 ktrstr = "mi_switch: running " + tdname + " prio (\d+)"
835 switchin_re = re.compile(ktrhdr + ktrstr)
836
837 ktrstr = "sched_add: " + tdname + " prio (\d+) by " + tdname
838 sched_add_re = re.compile(ktrhdr + ktrstr)
839
840 ktrstr = "setrunqueue: " + tdname + " prio (\d+) by " + tdname
841 setrunqueue_re = re.compile(ktrhdr + ktrstr)
842
843 ktrstr = "sched_rem: " + tdname + " prio (\d+) by " + tdname
844 sched_rem_re = re.compile(ktrhdr + ktrstr)
845
846 ktrstr = "sched_exit_thread: " + tdname + " prio (\d+)"
847 sched_exit_re = re.compile(ktrhdr + ktrstr)
848
849 ktrstr = "statclock: " + tdname + " prio (\d+)"
850 ktrstr += " stathz (\d+)"
851 sched_clock_re = re.compile(ktrhdr + ktrstr)
852
853 ktrstr = "sched_prio: " + tdname + " prio (\d+)"
854 ktrstr += " newprio (\d+) by " + tdname
855 sched_prio_re = re.compile(ktrhdr + ktrstr)
856
857 cpuload_re = re.compile(ktrhdr + "load: (\d+)")
858 loadglobal_re = re.compile(ktrhdr + "global load: (\d+)")
859
860 parsers = [[cpuload_re, self.cpuload],
861 [loadglobal_re, self.loadglobal],
862 [switchin_re, self.switchin],
863 [switchout_re, self.switchout],
864 [sched_add_re, self.sched_add],
865 [setrunqueue_re, self.sched_rem],
866 [sched_prio_re, self.sched_prio],
867 [preempted_re, self.preempted],
868 [sched_rem_re, self.sched_rem],
869 [sched_exit_re, self.sched_exit],
870 [sched_clock_re, self.sched_clock],
871 [idled_re, self.idled]]
872
873 for line in ifp.readlines():
874 self.lineno += 1
875 if ((self.lineno % 1024) == 0):
876 status.startup("Parsing line " +
877 str(self.lineno))
878 for p in parsers:
879 m = p[0].match(line)
880 if (m != None):
881 p[1](*m.groups())
882 break
883 # if (m == None):
884 # print line,
885
886 def checkstamp(self, timestamp):
887 timestamp = int(timestamp)
888 if (self.timestamp_first == None):
889 self.timestamp_first = timestamp
890 if (timestamp > self.timestamp_first):
891 print "Bad timestamp on line ", self.lineno
892 return (0)
893 self.timestamp_last = timestamp
894 return (1)
895
896 def timespan(self):
897 return (self.timestamp_first - self.timestamp_last);
898
899 def ticksps(self):
900 return (self.timespan() / self.ticks[0]) * int(self.stathz)
901
902 def switchout(self, cpu, timestamp, td, pcomm, prio, inhibit, wmesg, lock):
903 TDI_SUSPENDED = 0x0001
904 TDI_SLEEPING = 0x0002
905 TDI_SWAPPED = 0x0004
906 TDI_LOCK = 0x0008
907 TDI_IWAIT = 0x0010
908
909 if (self.checkstamp(timestamp) == 0):
910 return
911 inhibit = int(inhibit)
912 thread = self.findtd(td, pcomm)
913 if (inhibit & TDI_SWAPPED):
914 Swapped(thread, cpu, timestamp, prio)
915 elif (inhibit & TDI_SLEEPING):
916 Sleep(thread, cpu, timestamp, prio, wmesg)
917 elif (inhibit & TDI_LOCK):
918 Blocked(thread, cpu, timestamp, prio, lock)
919 elif (inhibit & TDI_IWAIT):
920 Iwait(thread, cpu, timestamp, prio)
921 elif (inhibit & TDI_SUSPENDED):
922 Suspended(thread, cpu, timestamp, prio)
923 elif (inhibit == 0):
924 Yielding(thread, cpu, timestamp, prio)
925 else:
926 print "Unknown event", inhibit
927 sys.exit(1)
928
929 def idled(self, cpu, timestamp, td, pcomm, prio):
930 if (self.checkstamp(timestamp) == 0):
931 return
932 thread = self.findtd(td, pcomm)
933 Idle(thread, cpu, timestamp, prio)
934
935 def preempted(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
936 if (self.checkstamp(timestamp) == 0):
937 return
938 thread = self.findtd(td, pcomm)
939 Preempted(thread, cpu, timestamp, prio,
940 self.findtd(bytd, bypcomm))
941
942 def switchin(self, cpu, timestamp, td, pcomm, prio):
943 if (self.checkstamp(timestamp) == 0):
944 return
945 thread = self.findtd(td, pcomm)
946 Running(thread, cpu, timestamp, prio)
947
948 def sched_add(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
949 if (self.checkstamp(timestamp) == 0):
950 return
951 thread = self.findtd(td, pcomm)
952 bythread = self.findtd(bytd, bypcomm)
953 Runq(thread, cpu, timestamp, prio, bythread)
954 Wokeup(bythread, cpu, timestamp, thread)
955
956 def sched_rem(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm):
957 if (self.checkstamp(timestamp) == 0):
958 return
959 thread = self.findtd(td, pcomm)
960 KsegrpRunq(thread, cpu, timestamp, prio,
961 self.findtd(bytd, bypcomm))
962
963 def sched_exit(self, cpu, timestamp, td, pcomm, prio):
964 if (self.checkstamp(timestamp) == 0):
965 return
966 thread = self.findtd(td, pcomm)
967 Sched_exit(thread, cpu, timestamp, prio)
968
969 def sched_clock(self, cpu, timestamp, td, pcomm, prio, stathz):
970 if (self.checkstamp(timestamp) == 0):
971 return
972 self.stathz = stathz
973 cpu = int(cpu)
974 try:
975 ticks = self.ticks[cpu]
976 except:
977 self.ticks[cpu] = 0
978 self.ticks[cpu] += 1
979 thread = self.findtd(td, pcomm)
980 Tick(thread, cpu, timestamp, prio, stathz)
981
982 def sched_prio(self, cpu, timestamp, td, pcomm, prio, newprio, bytd, bypcomm):
983 if (prio == newprio):
984 return
985 if (self.checkstamp(timestamp) == 0):
986 return
987 thread = self.findtd(td, pcomm)
988 bythread = self.findtd(bytd, bypcomm)
989 Prio(thread, cpu, timestamp, prio, newprio, bythread)
990 Lend(bythread, cpu, timestamp, newprio, thread)
991
992 def cpuload(self, cpu, timestamp, count):
993 if (self.checkstamp(timestamp) == 0):
994 return
993 cpu = int(cpu)
994 try:
995 load = self.load[cpu]
996 except:
997 load = Counter("cpu" + str(cpu) + " load")
998 self.load[cpu] = load
999 self.sources.insert(0, load)
1000 Count(load, cpu, timestamp, count)
1001
1002 def loadglobal(self, cpu, timestamp, count):
995 cpu = int(cpu)
996 try:
997 load = self.load[cpu]
998 except:
999 load = Counter("cpu" + str(cpu) + " load")
1000 self.load[cpu] = load
1001 self.sources.insert(0, load)
1002 Count(load, cpu, timestamp, count)
1003
1004 def loadglobal(self, cpu, timestamp, count):
1005 if (self.checkstamp(timestamp) == 0):
1006 return
1003 cpu = 0
1004 try:
1005 load = self.load[cpu]
1006 except:
1007 load = Counter("CPU load")
1008 self.load[cpu] = load
1009 self.sources.insert(0, load)
1010 Count(load, cpu, timestamp, count)
1011
1012 def findtd(self, td, pcomm):
1013 for thread in self.threads:
1014 if (thread.str == td and thread.name == pcomm):
1015 return thread
1016 thread = Thread(td, pcomm)
1017 self.threads.append(thread)
1018 self.sources.append(thread)
1019 return (thread)
1020
1021 def fixup(self):
1022 for source in self.sources:
1023 Padevent(source, -1, self.timestamp_last)
1024 Padevent(source, -1, self.timestamp_first, last=1)
1025 source.fixup()
1026
1027class SchedDisplay(Canvas):
1028 def __init__(self, master):
1029 self.ratio = 1
1030 self.ktrfile = None
1031 self.sources = None
1032 self.bdheight = 10
1033 self.events = {}
1034
1035 Canvas.__init__(self, master, width=800, height=500, bg='grey',
1036 scrollregion=(0, 0, 800, 500))
1037
1038 def setfile(self, ktrfile):
1039 self.ktrfile = ktrfile
1040 self.sources = ktrfile.sources
1041
1042 def draw(self):
1043 ypos = 0
1044 xsize = self.xsize()
1045 for source in self.sources:
1046 status.startup("Drawing " + source.name)
1047 self.create_line(0, ypos, xsize, ypos,
1048 width=1, fill="black", tags=("all",))
1049 ypos += self.bdheight
1050 ypos += source.ysize()
1051 source.draw(self, ypos)
1052 ypos += self.bdheight
1053 try:
1054 self.tag_raise("point", "state")
1055 self.tag_lower("cpuinfo", "all")
1056 except:
1057 pass
1058 self.create_line(0, ypos, xsize, ypos,
1059 width=1, fill="black", tags=("all",))
1060 self.tag_bind("event", "<Enter>", self.mouseenter)
1061 self.tag_bind("event", "<Leave>", self.mouseexit)
1062 self.tag_bind("event", "<Button-1>", self.mousepress)
1063
1064 def mouseenter(self, event):
1065 item, = self.find_withtag(CURRENT)
1066 event = self.events[item]
1067 event.mouseenter(self, item)
1068
1069 def mouseexit(self, event):
1070 item, = self.find_withtag(CURRENT)
1071 event = self.events[item]
1072 event.mouseexit(self, item)
1073
1074 def mousepress(self, event):
1075 item, = self.find_withtag(CURRENT)
1076 event = self.events[item]
1077 event.mousepress(self, item)
1078
1079 def drawnames(self, canvas):
1080 status.startup("Drawing names")
1081 ypos = 0
1082 canvas.configure(scrollregion=(0, 0,
1083 canvas["width"], self.ysize()))
1084 for source in self.sources:
1085 canvas.create_line(0, ypos, canvas["width"], ypos,
1086 width=1, fill="black", tags=("all",))
1087 ypos += self.bdheight
1088 ypos += source.ysize()
1089 source.drawname(canvas, ypos)
1090 ypos += self.bdheight
1091 canvas.create_line(0, ypos, canvas["width"], ypos,
1092 width=1, fill="black", tags=("all",))
1093
1094 def xsize(self):
1095 return ((self.ktrfile.timespan() / self.ratio) + 20)
1096
1097 def ysize(self):
1098 ysize = 0
1099 for source in self.sources:
1100 ysize += source.ysize() + (self.bdheight * 2)
1101 return (ysize)
1102
1103 def scaleset(self, ratio):
1104 if (self.ktrfile == None):
1105 return
1106 oldratio = self.ratio
1107 xstart, ystart = self.xview()
1108 length = (float(self["width"]) / self.xsize())
1109 middle = xstart + (length / 2)
1110
1111 self.ratio = ratio
1112 self.configure(scrollregion=(0, 0, self.xsize(), self.ysize()))
1113 self.scale("all", 0, 0, float(oldratio) / ratio, 1)
1114
1115 length = (float(self["width"]) / self.xsize())
1116 xstart = middle - (length / 2)
1117 self.xview_moveto(xstart)
1118
1119 def scaleget(self):
1120 return self.ratio
1121
1122 def setcolor(self, tag, color):
1123 self.itemconfigure(tag, state="normal", fill=color)
1124
1125 def hide(self, tag):
1126 self.itemconfigure(tag, state="hidden")
1127
1128class GraphMenu(Frame):
1129 def __init__(self, master):
1130 Frame.__init__(self, master, bd=2, relief=RAISED)
1131 self.view = Menubutton(self, text="Configure")
1132 self.viewmenu = Menu(self.view, tearoff=0)
1133 self.viewmenu.add_command(label="Events",
1134 command=self.econf)
1135 self.view["menu"] = self.viewmenu
1136 self.view.pack(side=LEFT)
1137
1138 def econf(self):
1139 EventConfigure()
1140
1141
1142class SchedGraph(Frame):
1143 def __init__(self, master):
1144 Frame.__init__(self, master)
1145 self.menu = None
1146 self.names = None
1147 self.display = None
1148 self.scale = None
1149 self.status = None
1150 self.pack(expand=1, fill="both")
1151 self.buildwidgets()
1152 self.layout()
1153 self.draw(sys.argv[1])
1154
1155 def buildwidgets(self):
1156 global status
1157 self.menu = GraphMenu(self)
1158 self.display = SchedDisplay(self)
1159 self.names = Canvas(self,
1160 width=100, height=self.display["height"],
1161 bg='grey', scrollregion=(0, 0, 50, 100))
1162 self.scale = Scaler(self, self.display)
1163 status = self.status = Status(self)
1164 self.scrollY = Scrollbar(self, orient="vertical",
1165 command=self.display_yview)
1166 self.display.scrollX = Scrollbar(self, orient="horizontal",
1167 command=self.display.xview)
1168 self.display["xscrollcommand"] = self.display.scrollX.set
1169 self.display["yscrollcommand"] = self.scrollY.set
1170 self.names["yscrollcommand"] = self.scrollY.set
1171
1172 def layout(self):
1173 self.columnconfigure(1, weight=1)
1174 self.rowconfigure(1, weight=1)
1175 self.menu.grid(row=0, column=0, columnspan=3, sticky=E+W)
1176 self.names.grid(row=1, column=0, sticky=N+S)
1177 self.display.grid(row=1, column=1, sticky=W+E+N+S)
1178 self.scrollY.grid(row=1, column=2, sticky=N+S)
1179 self.display.scrollX.grid(row=2, column=0, columnspan=2,
1180 sticky=E+W)
1181 self.scale.grid(row=3, column=0, columnspan=3, sticky=E+W)
1182 self.status.grid(row=4, column=0, columnspan=3, sticky=E+W)
1183
1184 def draw(self, file):
1185 self.master.update()
1186 ktrfile = KTRFile(file)
1187 self.display.setfile(ktrfile)
1188 self.display.drawnames(self.names)
1189 self.display.draw()
1190 self.scale.set(250000)
1191 self.display.xview_moveto(0)
1192
1193 def display_yview(self, *args):
1194 self.names.yview(*args)
1195 self.display.yview(*args)
1196
1197 def setcolor(self, tag, color):
1198 self.display.setcolor(tag, color)
1199
1200 def hide(self, tag):
1201 self.display.hide(tag)
1202
1203if (len(sys.argv) != 2):
1204 print "usage:", sys.argv[0], "<ktr file>"
1205 sys.exit(1)
1206
1207root = Tk()
1208root.title("Scheduler Graph")
1209graph = SchedGraph(root)
1210root.mainloop()
1007 cpu = 0
1008 try:
1009 load = self.load[cpu]
1010 except:
1011 load = Counter("CPU load")
1012 self.load[cpu] = load
1013 self.sources.insert(0, load)
1014 Count(load, cpu, timestamp, count)
1015
1016 def findtd(self, td, pcomm):
1017 for thread in self.threads:
1018 if (thread.str == td and thread.name == pcomm):
1019 return thread
1020 thread = Thread(td, pcomm)
1021 self.threads.append(thread)
1022 self.sources.append(thread)
1023 return (thread)
1024
1025 def fixup(self):
1026 for source in self.sources:
1027 Padevent(source, -1, self.timestamp_last)
1028 Padevent(source, -1, self.timestamp_first, last=1)
1029 source.fixup()
1030
1031class SchedDisplay(Canvas):
1032 def __init__(self, master):
1033 self.ratio = 1
1034 self.ktrfile = None
1035 self.sources = None
1036 self.bdheight = 10
1037 self.events = {}
1038
1039 Canvas.__init__(self, master, width=800, height=500, bg='grey',
1040 scrollregion=(0, 0, 800, 500))
1041
1042 def setfile(self, ktrfile):
1043 self.ktrfile = ktrfile
1044 self.sources = ktrfile.sources
1045
1046 def draw(self):
1047 ypos = 0
1048 xsize = self.xsize()
1049 for source in self.sources:
1050 status.startup("Drawing " + source.name)
1051 self.create_line(0, ypos, xsize, ypos,
1052 width=1, fill="black", tags=("all",))
1053 ypos += self.bdheight
1054 ypos += source.ysize()
1055 source.draw(self, ypos)
1056 ypos += self.bdheight
1057 try:
1058 self.tag_raise("point", "state")
1059 self.tag_lower("cpuinfo", "all")
1060 except:
1061 pass
1062 self.create_line(0, ypos, xsize, ypos,
1063 width=1, fill="black", tags=("all",))
1064 self.tag_bind("event", "<Enter>", self.mouseenter)
1065 self.tag_bind("event", "<Leave>", self.mouseexit)
1066 self.tag_bind("event", "<Button-1>", self.mousepress)
1067
1068 def mouseenter(self, event):
1069 item, = self.find_withtag(CURRENT)
1070 event = self.events[item]
1071 event.mouseenter(self, item)
1072
1073 def mouseexit(self, event):
1074 item, = self.find_withtag(CURRENT)
1075 event = self.events[item]
1076 event.mouseexit(self, item)
1077
1078 def mousepress(self, event):
1079 item, = self.find_withtag(CURRENT)
1080 event = self.events[item]
1081 event.mousepress(self, item)
1082
1083 def drawnames(self, canvas):
1084 status.startup("Drawing names")
1085 ypos = 0
1086 canvas.configure(scrollregion=(0, 0,
1087 canvas["width"], self.ysize()))
1088 for source in self.sources:
1089 canvas.create_line(0, ypos, canvas["width"], ypos,
1090 width=1, fill="black", tags=("all",))
1091 ypos += self.bdheight
1092 ypos += source.ysize()
1093 source.drawname(canvas, ypos)
1094 ypos += self.bdheight
1095 canvas.create_line(0, ypos, canvas["width"], ypos,
1096 width=1, fill="black", tags=("all",))
1097
1098 def xsize(self):
1099 return ((self.ktrfile.timespan() / self.ratio) + 20)
1100
1101 def ysize(self):
1102 ysize = 0
1103 for source in self.sources:
1104 ysize += source.ysize() + (self.bdheight * 2)
1105 return (ysize)
1106
1107 def scaleset(self, ratio):
1108 if (self.ktrfile == None):
1109 return
1110 oldratio = self.ratio
1111 xstart, ystart = self.xview()
1112 length = (float(self["width"]) / self.xsize())
1113 middle = xstart + (length / 2)
1114
1115 self.ratio = ratio
1116 self.configure(scrollregion=(0, 0, self.xsize(), self.ysize()))
1117 self.scale("all", 0, 0, float(oldratio) / ratio, 1)
1118
1119 length = (float(self["width"]) / self.xsize())
1120 xstart = middle - (length / 2)
1121 self.xview_moveto(xstart)
1122
1123 def scaleget(self):
1124 return self.ratio
1125
1126 def setcolor(self, tag, color):
1127 self.itemconfigure(tag, state="normal", fill=color)
1128
1129 def hide(self, tag):
1130 self.itemconfigure(tag, state="hidden")
1131
1132class GraphMenu(Frame):
1133 def __init__(self, master):
1134 Frame.__init__(self, master, bd=2, relief=RAISED)
1135 self.view = Menubutton(self, text="Configure")
1136 self.viewmenu = Menu(self.view, tearoff=0)
1137 self.viewmenu.add_command(label="Events",
1138 command=self.econf)
1139 self.view["menu"] = self.viewmenu
1140 self.view.pack(side=LEFT)
1141
1142 def econf(self):
1143 EventConfigure()
1144
1145
1146class SchedGraph(Frame):
1147 def __init__(self, master):
1148 Frame.__init__(self, master)
1149 self.menu = None
1150 self.names = None
1151 self.display = None
1152 self.scale = None
1153 self.status = None
1154 self.pack(expand=1, fill="both")
1155 self.buildwidgets()
1156 self.layout()
1157 self.draw(sys.argv[1])
1158
1159 def buildwidgets(self):
1160 global status
1161 self.menu = GraphMenu(self)
1162 self.display = SchedDisplay(self)
1163 self.names = Canvas(self,
1164 width=100, height=self.display["height"],
1165 bg='grey', scrollregion=(0, 0, 50, 100))
1166 self.scale = Scaler(self, self.display)
1167 status = self.status = Status(self)
1168 self.scrollY = Scrollbar(self, orient="vertical",
1169 command=self.display_yview)
1170 self.display.scrollX = Scrollbar(self, orient="horizontal",
1171 command=self.display.xview)
1172 self.display["xscrollcommand"] = self.display.scrollX.set
1173 self.display["yscrollcommand"] = self.scrollY.set
1174 self.names["yscrollcommand"] = self.scrollY.set
1175
1176 def layout(self):
1177 self.columnconfigure(1, weight=1)
1178 self.rowconfigure(1, weight=1)
1179 self.menu.grid(row=0, column=0, columnspan=3, sticky=E+W)
1180 self.names.grid(row=1, column=0, sticky=N+S)
1181 self.display.grid(row=1, column=1, sticky=W+E+N+S)
1182 self.scrollY.grid(row=1, column=2, sticky=N+S)
1183 self.display.scrollX.grid(row=2, column=0, columnspan=2,
1184 sticky=E+W)
1185 self.scale.grid(row=3, column=0, columnspan=3, sticky=E+W)
1186 self.status.grid(row=4, column=0, columnspan=3, sticky=E+W)
1187
1188 def draw(self, file):
1189 self.master.update()
1190 ktrfile = KTRFile(file)
1191 self.display.setfile(ktrfile)
1192 self.display.drawnames(self.names)
1193 self.display.draw()
1194 self.scale.set(250000)
1195 self.display.xview_moveto(0)
1196
1197 def display_yview(self, *args):
1198 self.names.yview(*args)
1199 self.display.yview(*args)
1200
1201 def setcolor(self, tag, color):
1202 self.display.setcolor(tag, color)
1203
1204 def hide(self, tag):
1205 self.display.hide(tag)
1206
1207if (len(sys.argv) != 2):
1208 print "usage:", sys.argv[0], "<ktr file>"
1209 sys.exit(1)
1210
1211root = Tk()
1212root.title("Scheduler Graph")
1213graph = SchedGraph(root)
1214root.mainloop()