schedgraph.py (187156) | schedgraph.py (187358) |
---|---|
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: --- 10 unchanged lines hidden (view full) --- 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: --- 10 unchanged lines hidden (view full) --- 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 187156 2009-01-13 16:44:18Z jhb $ | 27# $FreeBSD: head/tools/sched/schedgraph.py 187358 2009-01-17 07:24:25Z jeff $ |
28 29import sys 30import re | 28 29import sys 30import re |
31import random |
|
31from Tkinter import * 32 33# To use: 34# - Install the ports/x11-toolkits/py-tkinter package; e.g. 35# portinstall x11-toolkits/py-tkinter package 36# - Add KTR_SCHED to KTR_COMPILE and KTR_MASK in your KERNCONF; e.g. 37# options KTR 38# options KTR_ENTRIES=32768 --- 9 unchanged lines hidden (view full) --- 48# - While the workload is continuing (i.e. before it finishes), disable 49# KTR tracing by setting 'sysctl debug.ktr.mask=0'. This is necessary 50# to avoid a race condition while running ktrdump, i.e. the KTR ring buffer 51# will cycle a bit while ktrdump runs, and this confuses schedgraph because 52# the timestamps appear to go backwards at some point. Stopping KTR logging 53# while the workload is still running is to avoid wasting log entries on 54# "idle" time at the end. 55# - Dump the trace to a file: 'ktrdump -ct > ktr.out' | 32from Tkinter import * 33 34# To use: 35# - Install the ports/x11-toolkits/py-tkinter package; e.g. 36# portinstall x11-toolkits/py-tkinter package 37# - Add KTR_SCHED to KTR_COMPILE and KTR_MASK in your KERNCONF; e.g. 38# options KTR 39# options KTR_ENTRIES=32768 --- 9 unchanged lines hidden (view full) --- 49# - While the workload is continuing (i.e. before it finishes), disable 50# KTR tracing by setting 'sysctl debug.ktr.mask=0'. This is necessary 51# to avoid a race condition while running ktrdump, i.e. the KTR ring buffer 52# will cycle a bit while ktrdump runs, and this confuses schedgraph because 53# the timestamps appear to go backwards at some point. Stopping KTR logging 54# while the workload is still running is to avoid wasting log entries on 55# "idle" time at the end. 56# - Dump the trace to a file: 'ktrdump -ct > ktr.out' |
56# - Run the python script: 'python schedgraph.py ktr.out' | 57# - Run the python script: 'python schedgraph.py ktr.out' optionally provide 58# your cpu frequency in ghz: 'python schedgraph.py ktr.out 2.4' |
57# 58# To do: | 59# 60# To do: |
59# 1) Add a per-thread summary display 60# 2) Add bounding box style zoom. 61# 3) Click to center. 62# 4) Implement some sorting mechanism. 63# 5) Widget to display variable-range data (e.g. q length) 64# 6) Reorder rows, hide rows, etc. 65# 7) "Vertical rule" to help relate data in different rows 66# 8) Mouse-over popup of full thread/event/row lable (currently truncated) 67# 9) More visible anchors for popup event windows | 61# Add a per-source summary display 62# Click to move. 63# Hide rows 64# "Vertical rule" to help relate data in different rows 65# Mouse-over popup of full thread/event/row label (currently truncated) 66# More visible anchors for popup event windows |
68# 69# BUGS: 1) Only 8 CPUs are supported, more CPUs require more choices of 70# colours to represent them ;-) | 67# 68# BUGS: 1) Only 8 CPUs are supported, more CPUs require more choices of 69# colours to represent them ;-) |
71# 2) Extremely short traces may cause a crash because the code 72# assumes there is always at least one stathz entry logged, and 73# the number of such events is used as a denominator | |
74 | 70 |
71eventcolors = [ 72 ("count", "red"), 73 ("running", "green"), 74 ("idle", "grey"), 75 ("yielding", "yellow"), 76 ("swapped", "violet"), 77 ("suspended", "purple"), 78 ("iwait", "grey"), 79 ("sleep", "blue"), 80 ("blocked", "dark red"), 81 ("runq add", "yellow"), 82 ("runq rem", "yellow"), 83 ("thread exit", "grey"), 84 ("proc exit", "grey"), 85 ("callwheel idle", "grey"), 86 ("callout running", "green"), 87 ("lock acquire", "blue"), 88 ("lock contest", "purple"), 89 ("failed lock try", "red"), 90 ("lock release", "grey"), 91 ("tick", "black"), 92 ("prio", "black"), 93 ("lend prio", "black"), 94 ("wokeup", "black") 95] 96 97cpucolors = [ 98 ("CPU 0", "light grey"), 99 ("CPU 1", "dark grey"), 100 ("CPU 2", "light blue"), 101 ("CPU 3", "light pink"), 102 ("CPU 4", "blanched almond"), 103 ("CPU 5", "slate grey"), 104 ("CPU 6", "tan"), 105 ("CPU 7", "thistle"), 106 ("CPU 8", "white") 107] 108 109colors = [ 110 "white", "thistle", "blanched almond", "tan", "chartreuse", 111 "dark red", "red", "pale violet red", "pink", "light pink", 112 "dark orange", "orange", "coral", "light coral", 113 "goldenrod", "gold", "yellow", "light yellow", 114 "dark green", "green", "light green", "light sea green", 115 "dark blue", "blue", "light blue", "steel blue", "light slate blue", 116 "dark violet", "violet", "purple", "blue violet", 117 "dark grey", "slate grey", "light grey", 118 "black", 119] 120colors.sort() 121 |
|
75ticksps = None 76status = None | 122ticksps = None 123status = None |
77configtypes = [] | 124colormap = None 125ktrfile = None 126clockfreq = None 127sources = [] |
78lineno = -1 79 | 128lineno = -1 129 |
130class Colormap: 131 def __init__(self, table): 132 self.table = table 133 self.map = {} 134 for entry in table: 135 self.map[entry[0]] = entry[1] 136 137 def lookup(self, name): 138 try: 139 color = self.map[name] 140 except: 141 color = colors[random.randrange(0, len(colors))] 142 print "Picking random color", color, "for", name 143 self.map[name] = color 144 self.table.append((name, color)) 145 return (color) 146 |
|
80def ticks2sec(ticks): 81 us = ticksps / 1000000 82 ticks /= us 83 if (ticks < 1000): 84 return (str(ticks) + "us") 85 ticks /= 1000 86 if (ticks < 1000): 87 return (str(ticks) + "ms") --- 31 unchanged lines hidden (view full) --- 119 120 def clear(self): 121 self.label.config(text="") 122 123 def startup(self, str): 124 self.set(str) 125 root.update() 126 | 147def ticks2sec(ticks): 148 us = ticksps / 1000000 149 ticks /= us 150 if (ticks < 1000): 151 return (str(ticks) + "us") 152 ticks /= 1000 153 if (ticks < 1000): 154 return (str(ticks) + "ms") --- 31 unchanged lines hidden (view full) --- 186 187 def clear(self): 188 self.label.config(text="") 189 190 def startup(self, str): 191 self.set(str) 192 root.update() 193 |
127class EventConf(Frame): 128 def __init__(self, master, name, color, enabled): | 194class ColorConf(Frame): 195 def __init__(self, master, name, color): |
129 Frame.__init__(self, master) | 196 Frame.__init__(self, master) |
197 if (graph.getstate(name) == "hidden"): 198 enabled = 0 199 else: 200 enabled = 1 |
|
130 self.name = name 131 self.color = StringVar() 132 self.color_default = color 133 self.color_current = color 134 self.color.set(color) 135 self.enabled = IntVar() 136 self.enabled_default = enabled 137 self.enabled_current = enabled 138 self.enabled.set(enabled) 139 self.draw() 140 141 def draw(self): 142 self.label = Label(self, text=self.name, anchor=W) 143 self.sample = Canvas(self, width=24, height=24, 144 bg='grey') 145 self.rect = self.sample.create_rectangle(0, 0, 24, 24, 146 fill=self.color.get()) | 201 self.name = name 202 self.color = StringVar() 203 self.color_default = color 204 self.color_current = color 205 self.color.set(color) 206 self.enabled = IntVar() 207 self.enabled_default = enabled 208 self.enabled_current = enabled 209 self.enabled.set(enabled) 210 self.draw() 211 212 def draw(self): 213 self.label = Label(self, text=self.name, anchor=W) 214 self.sample = Canvas(self, width=24, height=24, 215 bg='grey') 216 self.rect = self.sample.create_rectangle(0, 0, 24, 24, 217 fill=self.color.get()) |
147 self.list = OptionMenu(self, self.color, 148 "dark red", "red", "pink", 149 "dark orange", "orange", 150 "yellow", "light yellow", 151 "dark green", "green", "light green", 152 "dark blue", "blue", "light blue", 153 "dark violet", "violet", "purple", 154 "dark grey", "light grey", 155 "white", "black", 156 command=self.setcolor) | 218 self.list = OptionMenu(self, self.color, command=self.setcolor, 219 *colors) |
157 self.checkbox = Checkbutton(self, text="enabled", 158 variable=self.enabled) 159 self.label.grid(row=0, column=0, sticky=E+W) 160 self.sample.grid(row=0, column=1) 161 self.list.grid(row=0, column=2, sticky=E+W) 162 self.checkbox.grid(row=0, column=3) 163 self.columnconfigure(0, weight=1) | 220 self.checkbox = Checkbutton(self, text="enabled", 221 variable=self.enabled) 222 self.label.grid(row=0, column=0, sticky=E+W) 223 self.sample.grid(row=0, column=1) 224 self.list.grid(row=0, column=2, sticky=E+W) 225 self.checkbox.grid(row=0, column=3) 226 self.columnconfigure(0, weight=1) |
164 self.columnconfigure(2, minsize=110) | 227 self.columnconfigure(2, minsize=150) |
165 166 def setcolor(self, color): 167 self.color.set(color) 168 self.sample.itemconfigure(self.rect, fill=color) 169 170 def apply(self): 171 cchange = 0 172 echange = 0 --- 8 unchanged lines hidden (view full) --- 181 graph.setcolor(self.name, self.color_current) 182 else: 183 graph.hide(self.name) 184 return 185 if (cchange != 0): 186 graph.setcolor(self.name, self.color_current) 187 188 def revert(self): | 228 229 def setcolor(self, color): 230 self.color.set(color) 231 self.sample.itemconfigure(self.rect, fill=color) 232 233 def apply(self): 234 cchange = 0 235 echange = 0 --- 8 unchanged lines hidden (view full) --- 244 graph.setcolor(self.name, self.color_current) 245 else: 246 graph.hide(self.name) 247 return 248 if (cchange != 0): 249 graph.setcolor(self.name, self.color_current) 250 251 def revert(self): |
189 self.setcolor(self.color_current) 190 self.enabled.set(self.enabled_current) 191 192 def default(self): | |
193 self.setcolor(self.color_default) 194 self.enabled.set(self.enabled_default) 195 | 252 self.setcolor(self.color_default) 253 self.enabled.set(self.enabled_default) 254 |
196class EventConfigure(Toplevel): 197 def __init__(self): | 255class ColorConfigure(Toplevel): 256 def __init__(self, table, name): |
198 Toplevel.__init__(self) 199 self.resizable(0, 0) | 257 Toplevel.__init__(self) 258 self.resizable(0, 0) |
200 self.title("Event Configuration") 201 self.items = LabelFrame(self, text="Event Type") | 259 self.title(name) 260 self.items = LabelFrame(self, text="Item Type") |
202 self.buttons = Frame(self) 203 self.drawbuttons() 204 self.items.grid(row=0, column=0, sticky=E+W) 205 self.columnconfigure(0, weight=1) 206 self.buttons.grid(row=1, column=0, sticky=E+W) 207 self.types = [] 208 self.irow = 0 | 261 self.buttons = Frame(self) 262 self.drawbuttons() 263 self.items.grid(row=0, column=0, sticky=E+W) 264 self.columnconfigure(0, weight=1) 265 self.buttons.grid(row=1, column=0, sticky=E+W) 266 self.types = [] 267 self.irow = 0 |
209 for type in configtypes: 210 self.additem(type.name, type.color, type.enabled) | 268 for type in table: 269 color = graph.getcolor(type[0]) 270 if (color != ""): 271 self.additem(type[0], color) |
211 | 272 |
212 def additem(self, name, color, enabled=1): 213 item = EventConf(self.items, name, color, enabled) | 273 def additem(self, name, color): 274 item = ColorConf(self.items, name, color) |
214 self.types.append(item) 215 item.grid(row=self.irow, column=0, sticky=E+W) 216 self.irow += 1 217 218 def drawbuttons(self): 219 self.apply = Button(self.buttons, text="Apply", 220 command=self.apress) | 275 self.types.append(item) 276 item.grid(row=self.irow, column=0, sticky=E+W) 277 self.irow += 1 278 279 def drawbuttons(self): 280 self.apply = Button(self.buttons, text="Apply", 281 command=self.apress) |
221 self.revert = Button(self.buttons, text="Revert", | 282 self.default = Button(self.buttons, text="Revert", |
222 command=self.rpress) | 283 command=self.rpress) |
223 self.default = Button(self.buttons, text="Default", 224 command=self.dpress) | |
225 self.apply.grid(row=0, column=0, sticky=E+W) | 284 self.apply.grid(row=0, column=0, sticky=E+W) |
226 self.revert.grid(row=0, column=1, sticky=E+W) 227 self.default.grid(row=0, column=2, sticky=E+W) | 285 self.default.grid(row=0, column=1, sticky=E+W) |
228 self.buttons.columnconfigure(0, weight=1) 229 self.buttons.columnconfigure(1, weight=1) | 286 self.buttons.columnconfigure(0, weight=1) 287 self.buttons.columnconfigure(1, weight=1) |
230 self.buttons.columnconfigure(2, weight=1) | |
231 232 def apress(self): 233 for item in self.types: 234 item.apply() 235 236 def rpress(self): 237 for item in self.types: 238 item.revert() 239 | 288 289 def apress(self): 290 for item in self.types: 291 item.apply() 292 293 def rpress(self): 294 for item in self.types: 295 item.revert() 296 |
240 def dpress(self): 241 for item in self.types: 242 item.default() 243 | |
244class EventView(Toplevel): 245 def __init__(self, event, canvas): 246 Toplevel.__init__(self) 247 self.resizable(0, 0) 248 self.title("Event") 249 self.event = event | 297class EventView(Toplevel): 298 def __init__(self, event, canvas): 299 Toplevel.__init__(self) 300 self.resizable(0, 0) 301 self.title("Event") 302 self.event = event |
250 self.frame = Frame(self) 251 self.frame.grid(row=0, column=0, sticky=N+S+E+W) | |
252 self.buttons = Frame(self) | 303 self.buttons = Frame(self) |
253 self.buttons.grid(row=1, column=0, sticky=E+W) | 304 self.buttons.grid(row=0, column=0, sticky=E+W) 305 self.frame = Frame(self) 306 self.frame.grid(row=1, column=0, sticky=N+S+E+W) |
254 self.canvas = canvas 255 self.drawlabels() 256 self.drawbuttons() 257 event.displayref(canvas) 258 self.bind("<Destroy>", self.destroycb) 259 260 def destroycb(self, event): 261 self.unbind("<Destroy>") --- 5 unchanged lines hidden (view full) --- 267 def clearlabels(self): 268 for label in self.frame.grid_slaves(): 269 label.grid_remove() 270 271 def drawlabels(self): 272 ypos = 0 273 labels = self.event.labels() 274 while (len(labels) < 7): | 307 self.canvas = canvas 308 self.drawlabels() 309 self.drawbuttons() 310 event.displayref(canvas) 311 self.bind("<Destroy>", self.destroycb) 312 313 def destroycb(self, event): 314 self.unbind("<Destroy>") --- 5 unchanged lines hidden (view full) --- 320 def clearlabels(self): 321 for label in self.frame.grid_slaves(): 322 label.grid_remove() 323 324 def drawlabels(self): 325 ypos = 0 326 labels = self.event.labels() 327 while (len(labels) < 7): |
275 labels.append(("", "", 0)) | 328 labels.append(("", "")) |
276 for label in labels: | 329 for label in labels: |
277 name, value, linked = label | 330 name, value = label 331 linked = 0 332 if (name == "linkedto"): 333 linked = 1 |
278 l = Label(self.frame, text=name, bd=1, width=15, 279 relief=SUNKEN, anchor=W) 280 if (linked): 281 fgcolor = "blue" 282 else: 283 fgcolor = "black" 284 r = Label(self.frame, text=value, bd=1, 285 relief=SUNKEN, anchor=W, fg=fgcolor) --- 22 unchanged lines hidden (view full) --- 308 309 def npress(self): 310 EventView(self.event, self.canvas) 311 312 def bpress(self): 313 prev = self.event.prev() 314 if (prev == None): 315 return | 334 l = Label(self.frame, text=name, bd=1, width=15, 335 relief=SUNKEN, anchor=W) 336 if (linked): 337 fgcolor = "blue" 338 else: 339 fgcolor = "black" 340 r = Label(self.frame, text=value, bd=1, 341 relief=SUNKEN, anchor=W, fg=fgcolor) --- 22 unchanged lines hidden (view full) --- 364 365 def npress(self): 366 EventView(self.event, self.canvas) 367 368 def bpress(self): 369 prev = self.event.prev() 370 if (prev == None): 371 return |
316 while (prev.real == 0): | 372 while (prev.type == "pad"): |
317 prev = prev.prev() 318 if (prev == None): 319 return 320 self.newevent(prev) 321 322 def fpress(self): 323 next = self.event.next() 324 if (next == None): 325 return | 373 prev = prev.prev() 374 if (prev == None): 375 return 376 self.newevent(prev) 377 378 def fpress(self): 379 next = self.event.next() 380 if (next == None): 381 return |
326 while (next.real == 0): | 382 while (next.type == "pad"): |
327 next = next.next() 328 if (next == None): 329 return 330 self.newevent(next) 331 332 def linkpress(self, wevent): 333 event = self.event.getlinked() 334 if (event != None): 335 self.newevent(event) 336 337class Event: | 383 next = next.next() 384 if (next == None): 385 return 386 self.newevent(next) 387 388 def linkpress(self, wevent): 389 event = self.event.getlinked() 390 if (event != None): 391 self.newevent(event) 392 393class Event: |
338 name = "none" 339 color = "grey" 340 def __init__(self, source, cpu, timestamp, last=0): | 394 def __init__(self, source, name, cpu, timestamp, attrs): |
341 self.source = source | 395 self.source = source |
396 self.name = name |
|
342 self.cpu = cpu 343 self.timestamp = int(timestamp) | 397 self.cpu = cpu 398 self.timestamp = int(timestamp) |
344 self.entries = [] 345 self.real = 1 | 399 self.attrs = attrs |
346 self.idx = None | 400 self.idx = None |
347 self.state = 0 | |
348 self.item = None 349 self.dispcnt = 0 | 401 self.item = None 402 self.dispcnt = 0 |
350 self.linked = None | |
351 self.recno = lineno | 403 self.recno = lineno |
352 if (last): 353 source.lastevent(self) 354 else: 355 source.event(self) | |
356 357 def status(self): 358 statstr = self.name + " " + self.source.name 359 statstr += " on: cpu" + str(self.cpu) 360 statstr += " at: " + str(self.timestamp) | 404 405 def status(self): 406 statstr = self.name + " " + self.source.name 407 statstr += " on: cpu" + str(self.cpu) 408 statstr += " at: " + str(self.timestamp) |
361 statstr += self.stattxt() | 409 statstr += " attributes: " 410 for i in range(0, len(self.attrs)): 411 attr = self.attrs[i] 412 statstr += attr[0] + ": " + str(attr[1]) 413 if (i != len(self.attrs) - 1): 414 statstr += ", " |
362 status.set(statstr) 363 | 415 status.set(statstr) 416 |
364 def stattxt(self): 365 return "" 366 367 def textadd(self, tuple): 368 pass 369 self.entries.append(tuple) 370 | |
371 def labels(self): | 417 def labels(self): |
372 return [("Source:", self.source.name, 0), 373 ("Event:", self.name, 0), 374 ("CPU:", self.cpu, 0), 375 ("Timestamp:", self.timestamp, 0), 376 ("Record: ", self.recno, 0) 377 ] + self.entries 378 def mouseenter(self, canvas, item): | 418 return [("Source", self.source.name), 419 ("Event", self.name), 420 ("CPU", self.cpu), 421 ("Timestamp", self.timestamp), 422 ("KTR Line ", self.recno) 423 ] + self.attrs 424 425 def mouseenter(self, canvas): |
379 self.displayref(canvas) 380 self.status() 381 | 426 self.displayref(canvas) 427 self.status() 428 |
382 def mouseexit(self, canvas, item): | 429 def mouseexit(self, canvas): |
383 self.displayunref(canvas) 384 status.clear() 385 | 430 self.displayunref(canvas) 431 status.clear() 432 |
386 def mousepress(self, canvas, item): | 433 def mousepress(self, canvas): |
387 EventView(self, canvas) 388 | 434 EventView(self, canvas) 435 |
436 def draw(self, canvas, xpos, ypos, item): 437 self.item = item 438 if (item != None): 439 canvas.items[item] = self 440 441 def move(self, canvas, x, y): 442 if (self.item == None): 443 return; 444 canvas.move(self.item, x, y); 445 |
|
389 def next(self): 390 return self.source.eventat(self.idx + 1) 391 | 446 def next(self): 447 return self.source.eventat(self.idx + 1) 448 |
449 def nexttype(self, type): 450 next = self.next() 451 while (next != None and next.type != type): 452 next = next.next() 453 return (next) 454 |
|
392 def prev(self): 393 return self.source.eventat(self.idx - 1) 394 395 def displayref(self, canvas): 396 if (self.dispcnt == 0): 397 canvas.itemconfigure(self.item, width=2) 398 self.dispcnt += 1 399 400 def displayunref(self, canvas): 401 self.dispcnt -= 1 402 if (self.dispcnt == 0): 403 canvas.itemconfigure(self.item, width=0) 404 canvas.tag_raise("point", "state") 405 406 def getlinked(self): | 455 def prev(self): 456 return self.source.eventat(self.idx - 1) 457 458 def displayref(self, canvas): 459 if (self.dispcnt == 0): 460 canvas.itemconfigure(self.item, width=2) 461 self.dispcnt += 1 462 463 def displayunref(self, canvas): 464 self.dispcnt -= 1 465 if (self.dispcnt == 0): 466 canvas.itemconfigure(self.item, width=0) 467 canvas.tag_raise("point", "state") 468 469 def getlinked(self): |
407 return self.linked.findevent(self.timestamp) | 470 for attr in self.attrs: 471 if (attr[0] != "linkedto"): 472 continue 473 source = ktrfile.findid(attr[1]) 474 return source.findevent(self.timestamp) 475 return None |
408 409class PointEvent(Event): | 476 477class PointEvent(Event): |
410 def __init__(self, thread, cpu, timestamp, last=0): 411 Event.__init__(self, thread, cpu, timestamp, last) | 478 type = "point" 479 def __init__(self, source, name, cpu, timestamp, attrs): 480 Event.__init__(self, source, name, cpu, timestamp, attrs) |
412 413 def draw(self, canvas, xpos, ypos): | 481 482 def draw(self, canvas, xpos, ypos): |
483 color = colormap.lookup(self.name) |
|
414 l = canvas.create_oval(xpos - 6, ypos + 1, xpos + 6, ypos - 11, | 484 l = canvas.create_oval(xpos - 6, ypos + 1, xpos + 6, ypos - 11, |
415 fill=self.color, tags=("all", "point", "event") 416 + (self.name,), width=0) 417 canvas.events[l] = self 418 self.item = l 419 if (self.enabled == 0): 420 canvas.itemconfigure(l, state="hidden") | 485 fill=color, tags=("all", "point", "event", self.name), 486 width=0) 487 Event.draw(self, canvas, xpos, ypos, l) |
421 | 488 |
422 return (xpos) | 489 return xpos |
423 424class StateEvent(Event): | 490 491class StateEvent(Event): |
425 def __init__(self, thread, cpu, timestamp, last=0): 426 Event.__init__(self, thread, cpu, timestamp, last) 427 self.duration = 0 428 self.skipnext = 0 429 self.skipself = 0 430 self.state = 1 | 492 type = "state" 493 def __init__(self, source, name, cpu, timestamp, attrs): 494 Event.__init__(self, source, name, cpu, timestamp, attrs) |
431 432 def draw(self, canvas, xpos, ypos): | 495 496 def draw(self, canvas, xpos, ypos): |
433 next = self.nextstate() 434 if (self.skipself == 1 or next == None): | 497 next = self.nexttype("state") 498 if (next == None): |
435 return (xpos) | 499 return (xpos) |
436 while (self.skipnext): 437 skipped = next 438 next.skipself = 1 439 next.real = 0 440 next = next.nextstate() 441 if (next == None): 442 next = skipped 443 self.skipnext -= 1 444 self.duration = next.timestamp - self.timestamp 445 if (self.duration < 0): 446 self.duration = 0 | 500 duration = next.timestamp - self.timestamp 501 self.attrs.insert(0, ("duration", ticks2sec(duration))) 502 color = colormap.lookup(self.name) 503 if (duration < 0): 504 duration = 0 |
447 print "Unsynchronized timestamp" 448 print self.cpu, self.timestamp 449 print next.cpu, next.timestamp | 505 print "Unsynchronized timestamp" 506 print self.cpu, self.timestamp 507 print next.cpu, next.timestamp |
450 delta = self.duration / canvas.ratio | 508 delta = duration / canvas.ratio |
451 l = canvas.create_rectangle(xpos, ypos, | 509 l = canvas.create_rectangle(xpos, ypos, |
452 xpos + delta, ypos - 10, fill=self.color, width=0, 453 tags=("all", "state", "event") + (self.name,)) 454 canvas.events[l] = self 455 self.item = l 456 if (self.enabled == 0): 457 canvas.itemconfigure(l, state="hidden") | 510 xpos + delta, ypos - 10, fill=color, width=0, 511 tags=("all", "state", "event", self.name)) 512 Event.draw(self, canvas, xpos, ypos, l) |
458 459 return (xpos + delta) 460 | 513 514 return (xpos + delta) 515 |
461 def stattxt(self): 462 return " duration: " + ticks2sec(self.duration) | 516class CountEvent(Event): 517 type = "count" 518 def __init__(self, source, count, cpu, timestamp, attrs): 519 count = int(count) 520 self.count = count 521 Event.__init__(self, source, "count", cpu, timestamp, attrs) |
463 | 522 |
464 def nextstate(self): 465 next = self.next() 466 while (next != None and next.state == 0): 467 next = next.next() 468 return (next) 469 470 def labels(self): 471 return [("Source:", self.source.name, 0), 472 ("Event:", self.name, 0), 473 ("Timestamp:", self.timestamp, 0), 474 ("CPU:", self.cpu, 0), 475 ("Record:", self.recno, 0), 476 ("Duration:", ticks2sec(self.duration), 0) 477 ] + self.entries 478 479class Count(Event): 480 name = "Count" 481 color = "red" 482 enabled = 1 483 def __init__(self, source, cpu, timestamp, count): 484 self.count = int(count) 485 Event.__init__(self, source, cpu, timestamp) 486 self.duration = 0 487 self.textadd(("count:", self.count, 0)) 488 | |
489 def draw(self, canvas, xpos, ypos): | 523 def draw(self, canvas, xpos, ypos): |
490 next = self.next() 491 self.duration = next.timestamp - self.timestamp 492 delta = self.duration / canvas.ratio | 524 next = self.nexttype("count") 525 if (next == None): 526 return (xpos) 527 color = colormap.lookup("count") 528 duration = next.timestamp - self.timestamp 529 self.attrs.insert(0, ("count", self.count)) 530 self.attrs.insert(1, ("duration", ticks2sec(duration))) 531 delta = duration / canvas.ratio |
493 yhight = self.source.yscale() * self.count 494 l = canvas.create_rectangle(xpos, ypos - yhight, | 532 yhight = self.source.yscale() * self.count 533 l = canvas.create_rectangle(xpos, ypos - yhight, |
495 xpos + delta, ypos, fill=self.color, width=0, 496 tags=("all", "count", "event") + (self.name,)) 497 canvas.events[l] = self 498 self.item = l 499 if (self.enabled == 0): 500 canvas.itemconfigure(l, state="hidden") | 534 xpos + delta, ypos, fill=color, width=0, 535 tags=("all", "count", "event", self.name)) 536 Event.draw(self, canvas, xpos, ypos, l) |
501 return (xpos + delta) 502 | 537 return (xpos + delta) 538 |
503 def stattxt(self): 504 return " count: " + str(self.count) 505 506configtypes.append(Count) 507 508class Running(StateEvent): 509 name = "running" 510 color = "green" 511 enabled = 1 512 def __init__(self, thread, cpu, timestamp, prio): 513 StateEvent.__init__(self, thread, cpu, timestamp) 514 self.prio = prio 515 self.textadd(("prio:", self.prio, 0)) 516 517configtypes.append(Running) 518 519class Idle(StateEvent): 520 name = "idle" 521 color = "grey" 522 enabled = 0 523 def __init__(self, thread, cpu, timestamp, prio): 524 StateEvent.__init__(self, thread, cpu, timestamp) 525 self.prio = prio 526 self.textadd(("prio:", self.prio, 0)) 527 528configtypes.append(Idle) 529 530class Yielding(StateEvent): 531 name = "yielding" 532 color = "yellow" 533 enabled = 1 534 def __init__(self, thread, cpu, timestamp, prio): 535 StateEvent.__init__(self, thread, cpu, timestamp) 536 self.skipnext = 0 537 self.prio = prio 538 self.textadd(("prio:", self.prio, 0)) 539 540configtypes.append(Yielding) 541 542class Swapped(StateEvent): 543 name = "swapped" 544 color = "violet" 545 enabled = 1 546 def __init__(self, thread, cpu, timestamp, prio): 547 StateEvent.__init__(self, thread, cpu, timestamp) 548 self.prio = prio 549 self.textadd(("prio:", self.prio, 0)) 550 551configtypes.append(Swapped) 552 553class Suspended(StateEvent): 554 name = "suspended" 555 color = "purple" 556 enabled = 1 557 def __init__(self, thread, cpu, timestamp, prio): 558 StateEvent.__init__(self, thread, cpu, timestamp) 559 self.prio = prio 560 self.textadd(("prio:", self.prio, 0)) 561 562configtypes.append(Suspended) 563 564class Iwait(StateEvent): 565 name = "iwait" 566 color = "grey" 567 enabled = 0 568 def __init__(self, thread, cpu, timestamp, prio): 569 StateEvent.__init__(self, thread, cpu, timestamp) 570 self.prio = prio 571 self.textadd(("prio:", self.prio, 0)) 572 573configtypes.append(Iwait) 574 575class Preempted(StateEvent): 576 name = "preempted" 577 color = "red" 578 enabled = 1 579 def __init__(self, thread, cpu, timestamp, prio, bythread): 580 StateEvent.__init__(self, thread, cpu, timestamp) 581 self.skipnext = 1 582 self.prio = prio 583 self.linked = bythread 584 self.textadd(("prio:", self.prio, 0)) 585 self.textadd(("by thread:", self.linked.name, 1)) 586 587configtypes.append(Preempted) 588 589class Sleep(StateEvent): 590 name = "sleep" 591 color = "blue" 592 enabled = 1 593 def __init__(self, thread, cpu, timestamp, prio, wmesg): 594 StateEvent.__init__(self, thread, cpu, timestamp) 595 self.prio = prio 596 self.wmesg = wmesg 597 self.textadd(("prio:", self.prio, 0)) 598 self.textadd(("wmesg:", self.wmesg, 0)) 599 600 def stattxt(self): 601 statstr = StateEvent.stattxt(self) 602 statstr += " sleeping on: " + self.wmesg 603 return (statstr) 604 605configtypes.append(Sleep) 606 607class Blocked(StateEvent): 608 name = "blocked" 609 color = "dark red" 610 enabled = 1 611 def __init__(self, thread, cpu, timestamp, prio, lock): 612 StateEvent.__init__(self, thread, cpu, timestamp) 613 self.prio = prio 614 self.lock = lock 615 self.textadd(("prio:", self.prio, 0)) 616 self.textadd(("lock:", self.lock, 0)) 617 618 def stattxt(self): 619 statstr = StateEvent.stattxt(self) 620 statstr += " blocked on: " + self.lock 621 return (statstr) 622 623configtypes.append(Blocked) 624 625class KsegrpRunq(StateEvent): 626 name = "KsegrpRunq" 627 color = "orange" 628 enabled = 1 629 def __init__(self, thread, cpu, timestamp, prio, bythread): 630 StateEvent.__init__(self, thread, cpu, timestamp) 631 self.prio = prio 632 self.linked = bythread 633 self.textadd(("prio:", self.prio, 0)) 634 self.textadd(("by thread:", self.linked.name, 1)) 635 636configtypes.append(KsegrpRunq) 637 638class Runq(StateEvent): 639 name = "Runq" 640 color = "yellow" 641 enabled = 1 642 def __init__(self, thread, cpu, timestamp, prio, bythread): 643 StateEvent.__init__(self, thread, cpu, timestamp) 644 self.prio = prio 645 self.linked = bythread 646 self.textadd(("prio:", self.prio, 0)) 647 self.textadd(("by thread:", self.linked.name, 1)) 648 649configtypes.append(Runq) 650 651class Sched_exit_thread(StateEvent): 652 name = "exit_thread" 653 color = "grey" 654 enabled = 0 655 def __init__(self, thread, cpu, timestamp, prio): 656 StateEvent.__init__(self, thread, cpu, timestamp) 657 self.name = "sched_exit_thread" 658 self.prio = prio 659 self.textadd(("prio:", self.prio, 0)) 660 661configtypes.append(Sched_exit_thread) 662 663class Sched_exit(StateEvent): 664 name = "exit" 665 color = "grey" 666 enabled = 0 667 def __init__(self, thread, cpu, timestamp, prio): 668 StateEvent.__init__(self, thread, cpu, timestamp) 669 self.name = "sched_exit" 670 self.prio = prio 671 self.textadd(("prio:", self.prio, 0)) 672 673configtypes.append(Sched_exit) 674 675# Events for running callout routines 676 677class CalloutIdle(StateEvent): 678 name = "callwheel idle" 679 color = "grey" 680 enabled = 0 681 def __init__(self, wheel, cpu, timestamp): 682 StateEvent.__init__(self, wheel, cpu, timestamp) 683 684configtypes.append(CalloutIdle) 685 686class CalloutRunning(StateEvent): 687 name = "callout running" 688 color = "green" 689 enabled = 1 690 def __init__(self, wheel, cpu, timestamp, func, arg): 691 StateEvent.__init__(self, wheel, cpu, timestamp) 692 self.textadd(("function:", func, 0)) 693 self.textadd(("argument:", arg, 0)) 694 self.arg = arg 695 self.func = func 696 697 def stattxt(self): 698 statstr = StateEvent.stattxt(self) 699 statstr += " executing %s(%s)" % (self.func, self.arg) 700 return (statstr) 701 702configtypes.append(CalloutRunning) 703 704# Events on locks 705# 706# XXX: No support for upgrade/downgrade currently or differentiating 707# between read/write in general. 708# 709# XXX: Point events for recursion perhaps? 710 711class LockAcquire(StateEvent): 712 name = "lock acquire" 713 color = "blue" 714 enabled = 1 715 def __init__(self, lock, cpu, timestamp, file, line): 716 StateEvent.__init__(self, lock, cpu, timestamp) 717 self.textadd(("file:", file, 0)) 718 self.textadd(("line:", line, 0)) 719 720configtypes.append(LockAcquire) 721 722class LockContest(StateEvent): 723 name = "lock contest" 724 color = "purple" 725 enabled = 1 726 def __init__(self, lock, cpu, timestamp, file, line): 727 StateEvent.__init__(self, lock, cpu, timestamp) 728 self.textadd(("file:", file, 0)) 729 self.textadd(("line:", line, 0)) 730 731configtypes.append(LockContest) 732 733class LockFailedTry(PointEvent): 734 name = "failed lock try" 735 color = "red" 736 enabled = 1 737 def __init__(self, lock, cpu, timestamp, file, line): 738 PointEvent.__init__(self, lock, cpu, timestamp) 739 self.textadd(("file:", file, 0)) 740 self.textadd(("line:", line, 0)) 741 742configtypes.append(LockFailedTry) 743 744class LockRelease(StateEvent): 745 name = "lock release" 746 color = "grey" 747 enabled = 0 748 def __init__(self, lock, cpu, timestamp, file, line): 749 StateEvent.__init__(self, lock, cpu, timestamp) 750 self.textadd(("file:", file, 0)) 751 self.textadd(("line:", line, 0)) 752 753configtypes.append(LockRelease) 754 755class Padevent(StateEvent): 756 def __init__(self, thread, cpu, timestamp, last=0): 757 StateEvent.__init__(self, thread, cpu, timestamp, last) 758 self.name = "pad" 759 self.real = 0 760 | 539class PadEvent(StateEvent): 540 type = "pad" 541 def __init__(self, source, cpu, timestamp, last=0): 542 if (last): 543 cpu = source.events[len(source.events) -1].cpu 544 else: 545 cpu = source.events[0].cpu 546 StateEvent.__init__(self, source, "pad", cpu, timestamp, []) |
761 def draw(self, canvas, xpos, ypos): 762 next = self.next() 763 if (next == None): 764 return (xpos) | 547 def draw(self, canvas, xpos, ypos): 548 next = self.next() 549 if (next == None): 550 return (xpos) |
765 self.duration = next.timestamp - self.timestamp 766 delta = self.duration / canvas.ratio | 551 duration = next.timestamp - self.timestamp 552 delta = duration / canvas.ratio 553 Event.draw(self, canvas, xpos, ypos, None) |
767 return (xpos + delta) 768 | 554 return (xpos + delta) 555 |
769class Tick(PointEvent): 770 name = "tick" 771 color = "black" 772 enabled = 0 773 def __init__(self, thread, cpu, timestamp, prio, stathz): 774 PointEvent.__init__(self, thread, cpu, timestamp) 775 self.prio = prio 776 self.textadd(("prio:", self.prio, 0)) 777 778configtypes.append(Tick) 779 780class Prio(PointEvent): 781 name = "prio" 782 color = "black" 783 enabled = 0 784 def __init__(self, thread, cpu, timestamp, prio, newprio, bythread): 785 PointEvent.__init__(self, thread, cpu, timestamp) 786 self.prio = prio 787 self.newprio = newprio 788 self.linked = bythread 789 self.textadd(("new prio:", self.newprio, 0)) 790 self.textadd(("prio:", self.prio, 0)) 791 if (self.linked != self.source): 792 self.textadd(("by thread:", self.linked.name, 1)) 793 else: 794 self.textadd(("by thread:", self.linked.name, 0)) 795 796configtypes.append(Prio) 797 798class Lend(PointEvent): 799 name = "lend" 800 color = "black" 801 enabled = 0 802 def __init__(self, thread, cpu, timestamp, prio, tothread): 803 PointEvent.__init__(self, thread, cpu, timestamp) 804 self.prio = prio 805 self.linked = tothread 806 self.textadd(("prio:", self.prio, 0)) 807 self.textadd(("to thread:", self.linked.name, 1)) 808 809configtypes.append(Lend) 810 811class Wokeup(PointEvent): 812 name = "wokeup" 813 color = "black" 814 enabled = 0 815 def __init__(self, thread, cpu, timestamp, ranthread): 816 PointEvent.__init__(self, thread, cpu, timestamp) 817 self.linked = ranthread 818 self.textadd(("ran thread:", self.linked.name, 1)) 819 820configtypes.append(Wokeup) 821 822(DEFAULT, LOAD, COUNT, CALLWHEEL, LOCK, THREAD) = range(6) 823 | |
824class EventSource: | 556class EventSource: |
825 def __init__(self, name, group=DEFAULT, order=0): 826 self.name = name | 557 def __init__(self, group, id): 558 self.name = id |
827 self.events = [] | 559 self.events = [] |
828 self.cpu = 0 829 self.cpux = 0 | 560 self.cpuitems = [] |
830 self.group = group | 561 self.group = group |
831 self.order = order | 562 self.y = 0 563 self.item = None |
832 833 def __cmp__(self, other): | 564 565 def __cmp__(self, other): |
566 if (other == None): 567 return -1 |
|
834 if (self.group == other.group): | 568 if (self.group == other.group): |
835 return cmp(self.order, other.order) | 569 return cmp(self.name, other.name) |
836 return cmp(self.group, other.group) 837 838 # It is much faster to append items to a list then to insert them 839 # at the beginning. As a result, we add events in reverse order 840 # and then swap the list during fixup. 841 def fixup(self): 842 self.events.reverse() 843 | 570 return cmp(self.group, other.group) 571 572 # It is much faster to append items to a list then to insert them 573 # at the beginning. As a result, we add events in reverse order 574 # and then swap the list during fixup. 575 def fixup(self): 576 self.events.reverse() 577 |
844 def event(self, event): | 578 def addevent(self, event): |
845 self.events.append(event) 846 | 579 self.events.append(event) 580 |
847 def remove(self, event): 848 self.events.remove(event) 849 850 def lastevent(self, event): | 581 def addlastevent(self, event): |
851 self.events.insert(0, event) 852 853 def draw(self, canvas, ypos): 854 xpos = 10 | 582 self.events.insert(0, event) 583 584 def draw(self, canvas, ypos): 585 xpos = 10 |
855 self.cpux = 10 856 self.cpu = self.events[1].cpu | 586 cpux = 10 587 cpu = self.events[1].cpu |
857 for i in range(0, len(self.events)): 858 self.events[i].idx = i 859 for event in self.events: | 588 for i in range(0, len(self.events)): 589 self.events[i].idx = i 590 for event in self.events: |
860 if (event.cpu != self.cpu and event.cpu != -1): 861 self.drawcpu(canvas, xpos, ypos) 862 self.cpux = xpos 863 self.cpu = event.cpu | 591 if (event.cpu != cpu and event.cpu != -1): 592 self.drawcpu(canvas, cpu, cpux, xpos, ypos) 593 cpux = xpos 594 cpu = event.cpu |
864 xpos = event.draw(canvas, xpos, ypos) | 595 xpos = event.draw(canvas, xpos, ypos) |
865 self.drawcpu(canvas, xpos, ypos) | 596 self.drawcpu(canvas, cpu, cpux, xpos, ypos) |
866 867 def drawname(self, canvas, ypos): | 597 598 def drawname(self, canvas, ypos): |
599 self.y = ypos |
|
868 ypos = ypos - (self.ysize() / 2) | 600 ypos = ypos - (self.ysize() / 2) |
869 canvas.create_text(10, ypos, anchor="w", text=self.name) | 601 self.item = canvas.create_text(10, ypos, anchor="w", text=self.name) 602 return (self.item) |
870 | 603 |
871 def drawcpu(self, canvas, xpos, ypos): 872 cpu = int(self.cpu) 873 if (cpu == 0): 874 color = 'light grey' 875 elif (cpu == 1): 876 color = 'dark grey' 877 elif (cpu == 2): 878 color = 'light blue' 879 elif (cpu == 3): 880 color = 'light green' 881 elif (cpu == 4): 882 color = 'blanched almond' 883 elif (cpu == 5): 884 color = 'slate grey' 885 elif (cpu == 6): 886 color = 'light slate blue' 887 elif (cpu == 7): 888 color = 'thistle' 889 else: 890 color = "white" 891 l = canvas.create_rectangle(self.cpux, | 604 def drawcpu(self, canvas, cpu, fromx, tox, ypos): 605 cpu = "CPU " + str(cpu) 606 color = cpucolormap.lookup(cpu) 607 # Create the cpu background colors default to hidden 608 l = canvas.create_rectangle(fromx, |
892 ypos - self.ysize() - canvas.bdheight, | 609 ypos - self.ysize() - canvas.bdheight, |
893 xpos, ypos + canvas.bdheight, fill=color, width=0, 894 tags=("all", "cpuinfo")) | 610 tox, ypos + canvas.bdheight, fill=color, width=0, 611 tags=("all", "cpuinfo", cpu), state="hidden") 612 self.cpuitems.append(l) |
895 | 613 |
614 def move(self, canvas, xpos, ypos): 615 for event in self.events: 616 event.move(canvas, xpos, ypos) 617 for item in self.cpuitems: 618 canvas.move(item, xpos, ypos) 619 620 def movename(self, canvas, xpos, ypos): 621 self.y += ypos 622 canvas.move(self.item, xpos, ypos) 623 |
|
896 def ysize(self): | 624 def ysize(self): |
897 return (None) | 625 return (10) |
898 899 def eventat(self, i): 900 if (i >= len(self.events)): 901 return (None) 902 event = self.events[i] 903 return (event) 904 905 def findevent(self, timestamp): 906 for event in self.events: | 626 627 def eventat(self, i): 628 if (i >= len(self.events)): 629 return (None) 630 event = self.events[i] 631 return (event) 632 633 def findevent(self, timestamp): 634 for event in self.events: |
907 if (event.timestamp >= timestamp and event.real): | 635 if (event.timestamp >= timestamp and event.type != "pad"): |
908 return (event) 909 return (None) 910 | 636 return (event) 637 return (None) 638 |
911class Thread(EventSource): 912 names = {} 913 def __init__(self, td, pcomm): 914 EventSource.__init__(self, pcomm, THREAD) 915 self.str = td | 639class Counter(EventSource): 640 # 641 # Store a hash of counter groups that keeps the max value 642 # for a counter in this group for scaling purposes. 643 # 644 groups = {} 645 def __init__(self, group, id): |
916 try: | 646 try: |
917 cnt = Thread.names[pcomm] | 647 Counter.cnt = Counter.groups[group] |
918 except: | 648 except: |
919 Thread.names[pcomm] = 0 920 return 921 Thread.names[pcomm] = cnt + 1 | 649 Counter.groups[group] = 0 650 EventSource.__init__(self, group, id) |
922 923 def fixup(self): | 651 652 def fixup(self): |
653 for event in self.events: 654 if (event.type != "count"): 655 continue; 656 count = int(event.count) 657 if (count > Counter.groups[self.group]): 658 Counter.groups[self.group] = count |
|
924 EventSource.fixup(self) | 659 EventSource.fixup(self) |
925 cnt = Thread.names[self.name] 926 if (cnt == 0): 927 return 928 cnt -= 1 929 Thread.names[self.name] = cnt 930 self.name += " td" + str(cnt) | |
931 | 660 |
932 def ysize(self): 933 return (10) 934 935class Callwheel(EventSource): 936 count = 0 937 def __init__(self, cpu): 938 EventSource.__init__(self, "Callwheel", CALLWHEEL, cpu) 939 self.wheel = cpu 940 Callwheel.count += 1 941 942 def fixup(self): 943 EventSource.fixup(self) 944 if (Callwheel.count == 1): 945 return 946 self.name += " (CPU %d)" % (self.wheel) 947 948 def ysize(self): 949 return (10) 950 951class Lock(EventSource): 952 def __init__(self, lock): 953 EventSource.__init__(self, lock, LOCK) 954 955 def ysize(self): 956 return (10) 957 958class Counter(EventSource): 959 max = 0 960 def __init__(self, name): 961 EventSource.__init__(self, name, COUNT) 962 963 def event(self, event): 964 EventSource.event(self, event) 965 try: 966 count = event.count 967 except: 968 return 969 count = int(count) 970 if (count > Counter.max): 971 Counter.max = count 972 | |
973 def ymax(self): | 661 def ymax(self): |
974 return (Counter.max) | 662 return (Counter.groups[self.group]) |
975 976 def ysize(self): 977 return (80) 978 979 def yscale(self): | 663 664 def ysize(self): 665 return (80) 666 667 def yscale(self): |
980 return (self.ysize() / Counter.max) | 668 return (self.ysize() / self.ymax()) |
981 | 669 |
982class CPULoad(Counter): 983 def __init__(self, cpu): 984 Counter.__init__(self, "cpu" + str(cpu) + " load") 985 self.group = LOAD 986 self.order = cpu 987 | |
988class KTRFile: 989 def __init__(self, file): 990 self.timestamp_f = None 991 self.timestamp_l = None | 670class KTRFile: 671 def __init__(self, file): 672 self.timestamp_f = None 673 self.timestamp_l = None |
992 self.threads = [] 993 self.sources = [] | |
994 self.locks = {} 995 self.callwheels = {} 996 self.ticks = {} 997 self.load = {} 998 self.crit = {} 999 self.stathz = 0 1000 1001 self.parse(file) 1002 self.fixup() 1003 global ticksps | 674 self.locks = {} 675 self.callwheels = {} 676 self.ticks = {} 677 self.load = {} 678 self.crit = {} 679 self.stathz = 0 680 681 self.parse(file) 682 self.fixup() 683 global ticksps |
1004 print "first", self.timestamp_f, "last", self.timestamp_l 1005 print "time span", self.timespan() 1006 print "stathz", self.stathz | |
1007 ticksps = self.ticksps() | 684 ticksps = self.ticksps() |
685 timespan = self.timespan() 686 print "first tick", self.timestamp_f, 687 print "last tick", self.timestamp_l |
|
1008 print "Ticks per second", ticksps | 688 print "Ticks per second", ticksps |
689 print "time span", timespan, "ticks", ticks2sec(timespan) |
|
1009 1010 def parse(self, file): 1011 try: 1012 ifp = open(file) 1013 except: 1014 print "Can't open", file 1015 sys.exit(1) 1016 | 690 691 def parse(self, file): 692 try: 693 ifp = open(file) 694 except: 695 print "Can't open", file 696 sys.exit(1) 697 |
1017 ktrhdr = "\s*\d+\s+(\d+)\s+(\d+)\s+" 1018 tdname = "(\S+)\(([^)]*)\)" 1019 crittdname = "(\S+)\s+\(\d+,\s+([^)]*)\)" | 698 # quoteexp matches a quoted string, no escaping 699 quoteexp = "\"([^\"]*)\"" |
1020 | 700 |
1021# XXX doesn't handle: 1022# 371 0 61628682318 mi_switch: 0xc075c070(swapper) prio 180 inhibit 2 wmesg ATA request done lock (null) 1023 ktrstr = "mi_switch: " + tdname 1024 ktrstr += " prio (\d+) inhibit (\d+) wmesg (\S+) lock (\S+)" 1025 switchout_re = re.compile(ktrhdr + ktrstr) | 701 # 702 # commaexp matches a quoted string OR the string up 703 # to the first ',' 704 # 705 commaexp = "(?:" + quoteexp + "|([^,]+))" |
1026 | 706 |
1027 ktrstr = "mi_switch: " + tdname + " prio (\d+) idle" 1028 idled_re = re.compile(ktrhdr + ktrstr) | 707 # 708 # colonstr matches a quoted string OR the string up 709 # to the first ':' 710 # 711 colonexp = "(?:" + quoteexp + "|([^:]+))" |
1029 | 712 |
1030 ktrstr = "mi_switch: " + tdname + " prio (\d+) preempted by " 1031 ktrstr += tdname 1032 preempted_re = re.compile(ktrhdr + ktrstr) | 713 # 714 # Match various manditory parts of the KTR string this is 715 # fairly inflexible until you get to attributes to make 716 # parsing faster. 717 # 718 hdrexp = "\s*(\d+)\s+(\d+)\s+(\d+)\s+" 719 groupexp = "KTRGRAPH group:" + quoteexp + ", " 720 idexp = "id:" + quoteexp + ", " 721 typeexp = "([^:]+):" + commaexp + ", " 722 attribexp = "attributes: (.*)" |
1033 | 723 |
1034 ktrstr = "mi_switch: running " + tdname + " prio (\d+)" 1035 switchin_re = re.compile(ktrhdr + ktrstr) | 724 # 725 # Matches optional attributes in the KTR string. This 726 # tolerates more variance as the users supply these values. 727 # 728 attrexp = colonexp + "\s*:\s*(?:" + commaexp + ", (.*)|" 729 attrexp += quoteexp +"|(.*))" |
1036 | 730 |
1037 ktrstr = "sched_add: " + tdname + " prio (\d+) by " + tdname 1038 sched_add_re = re.compile(ktrhdr + ktrstr) | 731 # Precompile regexp 732 ktrre = re.compile(hdrexp + groupexp + idexp + typeexp + attribexp) 733 attrre = re.compile(attrexp) |
1039 | 734 |
1040 ktrstr = "setrunqueue: " + tdname + " prio (\d+) by " + tdname 1041 setrunqueue_re = re.compile(ktrhdr + ktrstr) 1042 1043 ktrstr = "sched_rem: " + tdname + " prio (\d+) by " + tdname 1044 sched_rem_re = re.compile(ktrhdr + ktrstr) 1045 1046 ktrstr = "sched_exit_thread: " + tdname + " prio (\d+)" 1047 sched_exit_thread_re = re.compile(ktrhdr + ktrstr) 1048 1049 ktrstr = "sched_exit: " + tdname + " prio (\d+)" 1050 sched_exit_re = re.compile(ktrhdr + ktrstr) 1051 1052 ktrstr = "statclock: " + tdname + " prio (\d+)" 1053 ktrstr += " stathz (\d+)" 1054 sched_clock_re = re.compile(ktrhdr + ktrstr) 1055 1056 ktrstr = "sched_prio: " + tdname + " prio (\d+)" 1057 ktrstr += " newprio (\d+) by " + tdname 1058 sched_prio_re = re.compile(ktrhdr + ktrstr) 1059 1060 cpuload_re = re.compile(ktrhdr + "load: (\d+)") 1061 cpuload2_re = re.compile(ktrhdr + "cpu (\d+) load: (\d+)") 1062 loadglobal_re = re.compile(ktrhdr + "global load: (\d+)") 1063 1064 ktrstr = "critical_\S+ by thread " + crittdname + " to (\d+)" 1065 critsec_re = re.compile(ktrhdr + ktrstr) 1066 1067 ktrstr = "callout 0x[a-f\d]+ " 1068 ktrstr += "func (0x[a-f\d]+) arg (0x[a-f\d]+)" 1069 callout_start_re = re.compile(ktrhdr + ktrstr) 1070 1071 ktrstr = "callout mpsafe 0x[a-f\d]+ " 1072 ktrstr += "func (0x[a-f\d]+) arg (0x[a-f\d]+)" 1073 callout_mpsafe_re = re.compile(ktrhdr + ktrstr) 1074 1075 ktrstr = "callout mtx 0x[a-f\d]+ " 1076 ktrstr += "func (0x[a-f\d]+) arg (0x[a-f\d]+)" 1077 callout_mtx_re = re.compile(ktrhdr + ktrstr) 1078 1079 ktrstr = "callout 0x[a-f\d]+ finished" 1080 callout_stop_re = re.compile(ktrhdr + ktrstr) 1081 1082 ktrstr = "TRY_([RSWX]?LOCK) \(.*\) (.*) r = ([0-9]+)" 1083 ktrstr += " at (?:\.\./)*(.*):([0-9]+)" 1084 lock_try_re = re.compile(ktrhdr + ktrstr) 1085 1086 ktrstr = "([RSWX]?UNLOCK) \(.*\) (.*) r = ([0-9]+)" 1087 ktrstr += " at (?:\.\./)*(.*):([0-9]+)" 1088 lock_release_re = re.compile(ktrhdr + ktrstr) 1089 1090 ktrstr = "([RSWX]?LOCK) \(.*\) (.*) r = ([0-9]+)" 1091 ktrstr += " at (?:\.\./)*(.*):([0-9]+)" 1092 lock_acquire_re = re.compile(ktrhdr + ktrstr) 1093 1094 ktrstr = "_mtx_lock_sleep: (.*) contested \(lock=0x?[0-9a-f]*\)" 1095 ktrstr += " at (?:\.\./)*(.*):([0-9]+)" 1096 mtx_contested_re = re.compile(ktrhdr + ktrstr) 1097 1098 # XXX: Spin lock traces don't have lock name or file/line 1099 1100 ktrstr = "_rw_wlock_hard: (.*) contested \(lock=0x?[0-9a-f]*\)" 1101 ktrstr += " at (?:\.\./)*(.*):([0-9]+)" 1102 rw_contested_re = re.compile(ktrhdr + ktrstr) 1103 1104 # XXX: Read lock traces for rwlocks contesting don't have 1105 # lock name or file/line 1106 1107 parsers = [[cpuload_re, self.cpuload], 1108 [cpuload2_re, self.cpuload2], 1109 [loadglobal_re, self.loadglobal], 1110 [switchin_re, self.switchin], 1111 [switchout_re, self.switchout], 1112 [sched_add_re, self.sched_add], 1113 [setrunqueue_re, self.sched_rem], 1114 [sched_prio_re, self.sched_prio], 1115 [preempted_re, self.preempted], 1116 [sched_rem_re, self.sched_rem], 1117 [sched_exit_thread_re, self.sched_exit_thread], 1118 [sched_exit_re, self.sched_exit], 1119 [sched_clock_re, self.sched_clock], 1120 [critsec_re, self.critsec], 1121 [callout_start_re, self.callout_start], 1122 [callout_mpsafe_re, self.callout_start], 1123 [callout_mtx_re, self.callout_start], 1124 [callout_stop_re, self.callout_stop], 1125 [lock_try_re, self.lock_try], 1126 [lock_release_re, self.lock_release], 1127 [lock_acquire_re, self.lock_acquire], 1128 [mtx_contested_re, self.lock_contest], 1129 [rw_contested_re, self.lock_contest], 1130 [idled_re, self.idled]] 1131 | |
1132 global lineno 1133 lineno = 0 1134 for line in ifp.readlines(): 1135 lineno += 1 | 735 global lineno 736 lineno = 0 737 for line in ifp.readlines(): 738 lineno += 1 |
1136 if ((lineno % 1024) == 0): | 739 if ((lineno % 2048) == 0): |
1137 status.startup("Parsing line " + str(lineno)) | 740 status.startup("Parsing line " + str(lineno)) |
1138 for p in parsers: 1139 m = p[0].match(line) 1140 if (m != None): 1141 p[1](*m.groups()) 1142 break | 741 m = ktrre.match(line); |
1143 if (m == None): | 742 if (m == None): |
1144 print line, | 743 print "Can't parse", lineno, line, 744 continue; 745 (index, cpu, timestamp, group, id, type, dat, dat1, attrstring) = m.groups(); 746 if (dat == None): 747 dat = dat1 748 if (self.checkstamp(timestamp) == 0): 749 print "Bad timestamp at", lineno, ":", line, 750 continue 751 # 752 # Build the table of optional attributes 753 # 754 attrs = [] 755 while (attrstring != None): 756 m = attrre.match(attrstring.strip()) 757 if (m == None): 758 break; 759 # 760 # Name may or may not be quoted. 761 # 762 # For val we have four cases: 763 # 1) quotes followed by comma and more 764 # attributes. 765 # 2) no quotes followed by comma and more 766 # attributes. 767 # 3) no more attributes or comma with quotes. 768 # 4) no more attributes or comma without quotes. 769 # 770 (name, name1, val, val1, attrstring, end, end1) = m.groups(); 771 if (name == None): 772 name = name1 773 if (end == None): 774 end = end1 775 if (val == None): 776 val = val1 777 if (val == None): 778 val = end 779 if (name == "stathz"): 780 self.setstathz(val, cpu) 781 attrs.append((name, val)) 782 args = (dat, cpu, timestamp, attrs) 783 e = self.makeevent(group, id, type, args) 784 if (e == None): 785 print "Unknown type", type, lineno, line, |
1145 | 786 |
1146 def checkstamp(self, cpu, timestamp): 1147 timestamp = int(timestamp) 1148 if (self.timestamp_f == None): 1149 self.timestamp_f = timestamp; 1150 if (self.timestamp_l != None and timestamp > self.timestamp_l): 1151 return (0) 1152 self.timestamp_l = timestamp; 1153 return (timestamp) | 787 def makeevent(self, group, id, type, args): 788 e = None 789 source = self.makeid(group, id, type) 790 if (type == "state"): 791 e = StateEvent(source, *args) 792 elif (type == "counter"): 793 e = CountEvent(source, *args) 794 elif (type == "point"): 795 e = PointEvent(source, *args) 796 if (e != None): 797 source.addevent(e); 798 return e |
1154 | 799 |
1155 def timespan(self): 1156 return (self.timestamp_f - self.timestamp_l); 1157 1158 def ticksps(self): 1159 return (self.timespan() / self.ticks[0]) * int(self.stathz) 1160 1161 def switchout(self, cpu, timestamp, td, pcomm, prio, inhibit, wmesg, lock): 1162 TDI_SUSPENDED = 0x0001 1163 TDI_SLEEPING = 0x0002 1164 TDI_SWAPPED = 0x0004 1165 TDI_LOCK = 0x0008 1166 TDI_IWAIT = 0x0010 1167 1168 timestamp = self.checkstamp(cpu, timestamp) 1169 if (timestamp == 0): 1170 return 1171 inhibit = int(inhibit) 1172 thread = self.findtd(td, pcomm) 1173 if (inhibit & TDI_SWAPPED): 1174 Swapped(thread, cpu, timestamp, prio) 1175 elif (inhibit & TDI_SLEEPING): 1176 Sleep(thread, cpu, timestamp, prio, wmesg) 1177 elif (inhibit & TDI_LOCK): 1178 Blocked(thread, cpu, timestamp, prio, lock) 1179 elif (inhibit & TDI_IWAIT): 1180 Iwait(thread, cpu, timestamp, prio) 1181 elif (inhibit & TDI_SUSPENDED): 1182 Suspended(thread, cpu, timestamp, prio) 1183 elif (inhibit == 0): 1184 Yielding(thread, cpu, timestamp, prio) 1185 else: 1186 print "Unknown event", inhibit 1187 sys.exit(1) 1188 1189 def idled(self, cpu, timestamp, td, pcomm, prio): 1190 timestamp = self.checkstamp(cpu, timestamp) 1191 if (timestamp == 0): 1192 return 1193 thread = self.findtd(td, pcomm) 1194 Idle(thread, cpu, timestamp, prio) 1195 1196 def preempted(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm): 1197 timestamp = self.checkstamp(cpu, timestamp) 1198 if (timestamp == 0): 1199 return 1200 thread = self.findtd(td, pcomm) 1201 Preempted(thread, cpu, timestamp, prio, 1202 self.findtd(bytd, bypcomm)) 1203 1204 def switchin(self, cpu, timestamp, td, pcomm, prio): 1205 timestamp = self.checkstamp(cpu, timestamp) 1206 if (timestamp == 0): 1207 return 1208 thread = self.findtd(td, pcomm) 1209 Running(thread, cpu, timestamp, prio) 1210 1211 def sched_add(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm): 1212 timestamp = self.checkstamp(cpu, timestamp) 1213 if (timestamp == 0): 1214 return 1215 thread = self.findtd(td, pcomm) 1216 bythread = self.findtd(bytd, bypcomm) 1217 Runq(thread, cpu, timestamp, prio, bythread) 1218 Wokeup(bythread, cpu, timestamp, thread) 1219 1220 def sched_rem(self, cpu, timestamp, td, pcomm, prio, bytd, bypcomm): 1221 timestamp = self.checkstamp(cpu, timestamp) 1222 if (timestamp == 0): 1223 return 1224 thread = self.findtd(td, pcomm) 1225 KsegrpRunq(thread, cpu, timestamp, prio, 1226 self.findtd(bytd, bypcomm)) 1227 1228 def sched_exit_thread(self, cpu, timestamp, td, pcomm, prio): 1229 timestamp = self.checkstamp(cpu, timestamp) 1230 if (timestamp == 0): 1231 return 1232 thread = self.findtd(td, pcomm) 1233 Sched_exit_thread(thread, cpu, timestamp, prio) 1234 1235 def sched_exit(self, cpu, timestamp, td, pcomm, prio): 1236 timestamp = self.checkstamp(cpu, timestamp) 1237 if (timestamp == 0): 1238 return 1239 thread = self.findtd(td, pcomm) 1240 Sched_exit(thread, cpu, timestamp, prio) 1241 1242 def sched_clock(self, cpu, timestamp, td, pcomm, prio, stathz): 1243 timestamp = self.checkstamp(cpu, timestamp) 1244 if (timestamp == 0): 1245 return 1246 self.stathz = stathz | 800 def setstathz(self, val, cpu): 801 self.stathz = int(val) |
1247 cpu = int(cpu) 1248 try: 1249 ticks = self.ticks[cpu] 1250 except: 1251 self.ticks[cpu] = 0 1252 self.ticks[cpu] += 1 | 802 cpu = int(cpu) 803 try: 804 ticks = self.ticks[cpu] 805 except: 806 self.ticks[cpu] = 0 807 self.ticks[cpu] += 1 |
1253 thread = self.findtd(td, pcomm) 1254 Tick(thread, cpu, timestamp, prio, stathz) | |
1255 | 808 |
1256 def sched_prio(self, cpu, timestamp, td, pcomm, prio, newprio, bytd, bypcomm): 1257 if (prio == newprio): 1258 return 1259 timestamp = self.checkstamp(cpu, timestamp) 1260 if (timestamp == 0): 1261 return 1262 thread = self.findtd(td, pcomm) 1263 bythread = self.findtd(bytd, bypcomm) 1264 Prio(thread, cpu, timestamp, prio, newprio, bythread) 1265 Lend(bythread, cpu, timestamp, newprio, thread) | 809 def checkstamp(self, timestamp): 810 timestamp = int(timestamp) 811 if (self.timestamp_f == None): 812 self.timestamp_f = timestamp; 813 if (self.timestamp_l != None and timestamp > self.timestamp_l): 814 return (0) 815 self.timestamp_l = timestamp; 816 return (1) |
1266 | 817 |
1267 def cpuload(self, cpu, timestamp, count): 1268 timestamp = self.checkstamp(cpu, timestamp) 1269 if (timestamp == 0): 1270 return 1271 cpu = int(cpu) 1272 try: 1273 load = self.load[cpu] 1274 except: 1275 load = CPULoad(cpu) 1276 self.load[cpu] = load 1277 self.sources.append(load) 1278 Count(load, cpu, timestamp, count) | 818 def makeid(self, group, id, type): 819 for source in sources: 820 if (source.name == id and source.group == group): 821 return source 822 if (type == "counter"): 823 source = Counter(group, id) 824 else: 825 source = EventSource(group, id) 826 sources.append(source) 827 return (source) |
1279 | 828 |
1280 def cpuload2(self, cpu, timestamp, ncpu, count): 1281 timestamp = self.checkstamp(cpu, timestamp) 1282 if (timestamp == 0): 1283 return 1284 cpu = int(ncpu) 1285 try: 1286 load = self.load[cpu] 1287 except: 1288 load = CPULoad(cpu) 1289 self.load[cpu] = load 1290 self.sources.append(load) 1291 Count(load, cpu, timestamp, count) | 829 def findid(self, id): 830 for source in sources: 831 if (source.name == id): 832 return source 833 return (None) |
1292 | 834 |
1293 def loadglobal(self, cpu, timestamp, count): 1294 timestamp = self.checkstamp(cpu, timestamp) 1295 if (timestamp == 0): 1296 return 1297 cpu = 0 1298 try: 1299 load = self.load[cpu] 1300 except: 1301 load = Counter("CPU load") 1302 self.load[cpu] = load 1303 self.sources.append(load) 1304 Count(load, cpu, timestamp, count) | 835 def timespan(self): 836 return (self.timestamp_f - self.timestamp_l); |
1305 | 837 |
1306 def critsec(self, cpu, timestamp, td, pcomm, to): 1307 timestamp = self.checkstamp(cpu, timestamp) 1308 if (timestamp == 0): 1309 return 1310 cpu = int(cpu) 1311 try: 1312 crit = self.crit[cpu] 1313 except: 1314 crit = Counter("Critical Section") 1315 self.crit[cpu] = crit 1316 self.sources.append(crit) 1317 Count(crit, cpu, timestamp, to) | 838 def ticksps(self): 839 oneghz = 1000000000 840 # Use user supplied clock first 841 if (clockfreq != None): 842 return int(clockfreq * oneghz) |
1318 | 843 |
1319 def callout_start(self, cpu, timestamp, func, arg): 1320 timestamp = self.checkstamp(cpu, timestamp) 1321 if (timestamp == 0): 1322 return 1323 wheel = self.findwheel(cpu) 1324 CalloutRunning(wheel, cpu, timestamp, func, arg) | 844 # Check for a discovered clock 845 if (self.stathz != None): 846 return (self.timespan() / self.ticks[0]) * int(self.stathz) 847 # Pretend we have a 1ns clock 848 print "WARNING: No clock discovered and no frequency ", 849 print "specified via the command line." 850 print "Using fake 1ghz clock" 851 return (oneghz); |
1325 | 852 |
1326 def callout_stop(self, cpu, timestamp): 1327 timestamp = self.checkstamp(cpu, timestamp) 1328 if (timestamp == 0): 1329 return 1330 wheel = self.findwheel(cpu) 1331 CalloutIdle(wheel, cpu, timestamp) | 853 def fixup(self): 854 for source in sources: 855 e = PadEvent(source, -1, self.timestamp_l) 856 source.addevent(e) 857 e = PadEvent(source, -1, self.timestamp_f, last=1) 858 source.addlastevent(e) 859 source.fixup() 860 sources.sort() |
1332 | 861 |
1333 def lock_try(self, cpu, timestamp, op, name, result, file, line): 1334 timestamp = self.checkstamp(cpu, timestamp) 1335 if (timestamp == 0): 1336 return 1337 lock = self.findlock(name) 1338 if (int(result) == 0): 1339 LockFailedTry(lock, cpu, timestamp, file, line) 1340 else: 1341 LockAcquire(lock, cpu, timestamp, file, line) | 862class SchedNames(Canvas): 863 def __init__(self, master, display): 864 self.display = display 865 self.parent = master 866 self.bdheight = master.bdheight 867 self.items = {} 868 self.ysize = 0 869 self.lines = [] 870 Canvas.__init__(self, master, width=120, 871 height=display["height"], bg='grey', 872 scrollregion=(0, 0, 50, 100)) |
1342 | 873 |
1343 def lock_acquire(self, cpu, timestamp, op, name, recurse, file, line): 1344 if (int(recurse) != 0): | 874 def moveline(self, cur_y, y): 875 for line in self.lines: 876 (x0, y0, x1, y1) = self.coords(line) 877 if (cur_y != y0): 878 continue 879 self.move(line, 0, y) |
1345 return | 880 return |
1346 timestamp = self.checkstamp(cpu, timestamp) 1347 if (timestamp == 0): 1348 return 1349 lock = self.findlock(name) 1350 LockAcquire(lock, cpu, timestamp, file, line) 1351 1352 def lock_release(self, cpu, timestamp, op, name, recurse, file, line): 1353 if (int(recurse) != 0): 1354 return 1355 timestamp = self.checkstamp(cpu, timestamp) 1356 if (timestamp == 0): 1357 return 1358 lock = self.findlock(name) 1359 LockRelease(lock, cpu, timestamp, file, line) | |
1360 | 881 |
1361 def lock_contest(self, cpu, timestamp, name, file, line): 1362 timestamp = self.checkstamp(cpu, timestamp) 1363 if (timestamp == 0): 1364 return 1365 lock = self.findlock(name) 1366 LockContest(lock, cpu, timestamp, file, line) | 882 def draw(self): 883 status.startup("Drawing names") 884 ypos = 0 885 self.configure(scrollregion=(0, 0, 886 self["width"], self.display.ysize())) 887 for source in sources: 888 l = self.create_line(0, ypos, self["width"], ypos, 889 width=1, fill="black", tags=("all","sources")) 890 self.lines.append(l) 891 ypos += self.bdheight 892 ypos += source.ysize() 893 t = source.drawname(self, ypos) 894 self.items[t] = source 895 ypos += self.bdheight 896 self.ysize = ypos 897 self.create_line(0, ypos, self["width"], ypos, 898 width=1, fill="black", tags=("all",)) 899 self.bind("<Button-1>", self.master.mousepress); 900 self.bind("<ButtonRelease-1>", self.master.mouserelease); 901 self.bind("<B1-Motion>", self.master.mousemotion); |
1367 | 902 |
1368 def findlock(self, name): 1369 try: 1370 lock = self.locks[name] 1371 except: 1372 lock = Lock(name) 1373 self.locks[name] = lock 1374 self.sources.append(lock) 1375 return (lock) | |
1376 | 903 |
1377 def findwheel(self, cpu): 1378 cpu = int(cpu) 1379 try: 1380 wheel = self.callwheels[cpu] 1381 except: 1382 wheel = Callwheel(cpu) 1383 self.callwheels[cpu] = wheel 1384 self.sources.append(wheel) 1385 return (wheel) 1386 1387 def findtd(self, td, pcomm): 1388 for thread in self.threads: 1389 if (thread.str == td and thread.name == pcomm): 1390 return thread 1391 thread = Thread(td, pcomm) 1392 self.threads.append(thread) 1393 self.sources.append(thread) 1394 return (thread) 1395 1396 def fixup(self): 1397 for source in self.sources: 1398 Padevent(source, -1, self.timestamp_l) 1399 Padevent(source, -1, self.timestamp_f, last=1) 1400 source.fixup() 1401 self.sources.sort() 1402 | |
1403class SchedDisplay(Canvas): 1404 def __init__(self, master): 1405 self.ratio = 1 | 904class SchedDisplay(Canvas): 905 def __init__(self, master): 906 self.ratio = 1 |
1406 self.ktrfile = None 1407 self.sources = None | |
1408 self.parent = master | 907 self.parent = master |
1409 self.bdheight = 10 1410 self.events = {} 1411 | 908 self.bdheight = master.bdheight 909 self.items = {} 910 self.lines = [] |
1412 Canvas.__init__(self, master, width=800, height=500, bg='grey', 1413 scrollregion=(0, 0, 800, 500)) 1414 | 911 Canvas.__init__(self, master, width=800, height=500, bg='grey', 912 scrollregion=(0, 0, 800, 500)) 913 |
1415 def setfile(self, ktrfile): 1416 self.ktrfile = ktrfile 1417 self.sources = ktrfile.sources 1418 | 914 def prepare(self): 915 # |
1419 # Compute a ratio to ensure that the file's timespan fits into 1420 # 2^31. Although python may handle larger values for X 1421 # values, the Tk internals do not. | 916 # Compute a ratio to ensure that the file's timespan fits into 917 # 2^31. Although python may handle larger values for X 918 # values, the Tk internals do not. |
919 # |
|
1422 self.ratio = (ktrfile.timespan() - 1) / 2**31 + 1 1423 1424 def draw(self): 1425 ypos = 0 1426 xsize = self.xsize() | 920 self.ratio = (ktrfile.timespan() - 1) / 2**31 + 1 921 922 def draw(self): 923 ypos = 0 924 xsize = self.xsize() |
1427 for source in self.sources: | 925 for source in sources: |
1428 status.startup("Drawing " + source.name) | 926 status.startup("Drawing " + source.name) |
1429 self.create_line(0, ypos, xsize, ypos, | 927 l = self.create_line(0, ypos, xsize, ypos, |
1430 width=1, fill="black", tags=("all",)) | 928 width=1, fill="black", tags=("all",)) |
929 self.lines.append(l) |
|
1431 ypos += self.bdheight 1432 ypos += source.ysize() 1433 source.draw(self, ypos) 1434 ypos += self.bdheight 1435 try: 1436 self.tag_raise("point", "state") 1437 self.tag_lower("cpuinfo", "all") 1438 except: 1439 pass 1440 self.create_line(0, ypos, xsize, ypos, 1441 width=1, fill="black", tags=("all",)) 1442 self.tag_bind("event", "<Enter>", self.mouseenter) 1443 self.tag_bind("event", "<Leave>", self.mouseexit) | 930 ypos += self.bdheight 931 ypos += source.ysize() 932 source.draw(self, ypos) 933 ypos += self.bdheight 934 try: 935 self.tag_raise("point", "state") 936 self.tag_lower("cpuinfo", "all") 937 except: 938 pass 939 self.create_line(0, ypos, xsize, ypos, 940 width=1, fill="black", tags=("all",)) 941 self.tag_bind("event", "<Enter>", self.mouseenter) 942 self.tag_bind("event", "<Leave>", self.mouseexit) |
1444 self.tag_bind("event", "<Button-1>", self.mousepress) | 943 self.bind("<Button-1>", self.mousepress) |
1445 self.bind("<Button-4>", self.wheelup) 1446 self.bind("<Button-5>", self.wheeldown) | 944 self.bind("<Button-4>", self.wheelup) 945 self.bind("<Button-5>", self.wheeldown) |
946 self.bind("<ButtonRelease-1>", self.master.mouserelease); 947 self.bind("<B1-Motion>", self.master.mousemotion); |
|
1447 | 948 |
949 def moveline(self, cur_y, y): 950 for line in self.lines: 951 (x0, y0, x1, y1) = self.coords(line) 952 if (cur_y != y0): 953 continue 954 self.move(line, 0, y) 955 return 956 |
|
1448 def mouseenter(self, event): 1449 item, = self.find_withtag(CURRENT) | 957 def mouseenter(self, event): 958 item, = self.find_withtag(CURRENT) |
1450 event = self.events[item] 1451 event.mouseenter(self, item) | 959 self.items[item].mouseenter(self) |
1452 1453 def mouseexit(self, event): 1454 item, = self.find_withtag(CURRENT) | 960 961 def mouseexit(self, event): 962 item, = self.find_withtag(CURRENT) |
1455 event = self.events[item] 1456 event.mouseexit(self, item) | 963 self.items[item].mouseexit(self) |
1457 1458 def mousepress(self, event): | 964 965 def mousepress(self, event): |
1459 item, = self.find_withtag(CURRENT) 1460 event = self.events[item] 1461 event.mousepress(self, item) | 966 # Find out what's beneath us 967 items = self.find_withtag(CURRENT) 968 if (len(items) == 0): 969 self.master.mousepress(event) 970 return 971 # Only grab mouse presses for things with event tags. 972 item = items[0] 973 tags = self.gettags(item) 974 for tag in tags: 975 if (tag == "event"): 976 self.items[item].mousepress(self) 977 return 978 # Leave the rest to the master window 979 self.master.mousepress(event) |
1462 1463 def wheeldown(self, event): 1464 self.parent.display_yview("scroll", 1, "units") 1465 1466 def wheelup(self, event): 1467 self.parent.display_yview("scroll", -1, "units") 1468 | 980 981 def wheeldown(self, event): 982 self.parent.display_yview("scroll", 1, "units") 983 984 def wheelup(self, event): 985 self.parent.display_yview("scroll", -1, "units") 986 |
1469 def drawnames(self, canvas): 1470 status.startup("Drawing names") 1471 ypos = 0 1472 canvas.configure(scrollregion=(0, 0, 1473 canvas["width"], self.ysize())) 1474 for source in self.sources: 1475 canvas.create_line(0, ypos, canvas["width"], ypos, 1476 width=1, fill="black", tags=("all",)) 1477 ypos += self.bdheight 1478 ypos += source.ysize() 1479 source.drawname(canvas, ypos) 1480 ypos += self.bdheight 1481 canvas.create_line(0, ypos, canvas["width"], ypos, 1482 width=1, fill="black", tags=("all",)) 1483 | |
1484 def xsize(self): | 987 def xsize(self): |
1485 return ((self.ktrfile.timespan() / self.ratio) + 20) | 988 return ((ktrfile.timespan() / self.ratio) + 20) |
1486 1487 def ysize(self): 1488 ysize = 0 | 989 990 def ysize(self): 991 ysize = 0 |
1489 for source in self.sources: | 992 for source in sources: |
1490 ysize += source.ysize() + (self.bdheight * 2) | 993 ysize += source.ysize() + (self.bdheight * 2) |
1491 return (ysize) | 994 return ysize |
1492 1493 def scaleset(self, ratio): | 995 996 def scaleset(self, ratio): |
1494 if (self.ktrfile == None): | 997 if (ktrfile == None): |
1495 return 1496 oldratio = self.ratio | 998 return 999 oldratio = self.ratio |
1497 xstart, ystart = self.xview() 1498 length = (float(self["width"]) / self.xsize()) 1499 middle = xstart + (length / 2) | 1000 xstart, xend = self.xview() 1001 midpoint = xstart + ((xend - xstart) / 2) |
1500 1501 self.ratio = ratio 1502 self.configure(scrollregion=(0, 0, self.xsize(), self.ysize())) 1503 self.scale("all", 0, 0, float(oldratio) / ratio, 1) 1504 | 1002 1003 self.ratio = ratio 1004 self.configure(scrollregion=(0, 0, self.xsize(), self.ysize())) 1005 self.scale("all", 0, 0, float(oldratio) / ratio, 1) 1006 |
1505 length = (float(self["width"]) / self.xsize()) 1506 xstart = middle - (length / 2) 1507 self.xview_moveto(xstart) | 1007 xstart, xend = self.xview() 1008 xsize = (xend - xstart) / 2 1009 self.xview_moveto(midpoint - xsize) |
1508 1509 def scaleget(self): 1510 return self.ratio 1511 | 1010 1011 def scaleget(self): 1012 return self.ratio 1013 |
1014 def getcolor(self, tag): 1015 return self.itemcget(tag, "fill") 1016 1017 def getstate(self, tag): 1018 return self.itemcget(tag, "state") 1019 |
|
1512 def setcolor(self, tag, color): 1513 self.itemconfigure(tag, state="normal", fill=color) 1514 1515 def hide(self, tag): 1516 self.itemconfigure(tag, state="hidden") 1517 1518class GraphMenu(Frame): 1519 def __init__(self, master): 1520 Frame.__init__(self, master, bd=2, relief=RAISED) 1521 self.view = Menubutton(self, text="Configure") 1522 self.viewmenu = Menu(self.view, tearoff=0) | 1020 def setcolor(self, tag, color): 1021 self.itemconfigure(tag, state="normal", fill=color) 1022 1023 def hide(self, tag): 1024 self.itemconfigure(tag, state="hidden") 1025 1026class GraphMenu(Frame): 1027 def __init__(self, master): 1028 Frame.__init__(self, master, bd=2, relief=RAISED) 1029 self.view = Menubutton(self, text="Configure") 1030 self.viewmenu = Menu(self.view, tearoff=0) |
1523 self.viewmenu.add_command(label="Events", | 1031 self.viewmenu.add_command(label="Event Colors", |
1524 command=self.econf) | 1032 command=self.econf) |
1033 self.viewmenu.add_command(label="CPU Colors", 1034 command=self.cconf) |
|
1525 self.view["menu"] = self.viewmenu 1526 self.view.pack(side=LEFT) 1527 1528 def econf(self): | 1035 self.view["menu"] = self.viewmenu 1036 self.view.pack(side=LEFT) 1037 1038 def econf(self): |
1529 EventConfigure() | 1039 ColorConfigure(eventcolors, "Event Display Configuration") |
1530 | 1040 |
1041 def cconf(self): 1042 ColorConfigure(cpucolors, "CPU Background Colors") |
|
1531 | 1043 |
1044 |
|
1532class SchedGraph(Frame): 1533 def __init__(self, master): 1534 Frame.__init__(self, master) 1535 self.menu = None 1536 self.names = None 1537 self.display = None 1538 self.scale = None 1539 self.status = None | 1045class SchedGraph(Frame): 1046 def __init__(self, master): 1047 Frame.__init__(self, master) 1048 self.menu = None 1049 self.names = None 1050 self.display = None 1051 self.scale = None 1052 self.status = None |
1053 self.bdheight = 10 1054 self.clicksource = None 1055 self.lastsource = None |
|
1540 self.pack(expand=1, fill="both") 1541 self.buildwidgets() 1542 self.layout() | 1056 self.pack(expand=1, fill="both") 1057 self.buildwidgets() 1058 self.layout() |
1543 self.draw(sys.argv[1]) | |
1544 1545 def buildwidgets(self): 1546 global status 1547 self.menu = GraphMenu(self) 1548 self.display = SchedDisplay(self) | 1059 1060 def buildwidgets(self): 1061 global status 1062 self.menu = GraphMenu(self) 1063 self.display = SchedDisplay(self) |
1549 self.names = Canvas(self, 1550 width=120, height=self.display["height"], 1551 bg='grey', scrollregion=(0, 0, 50, 100)) | 1064 self.names = SchedNames(self, self.display) |
1552 self.scale = Scaler(self, self.display) 1553 status = self.status = Status(self) 1554 self.scrollY = Scrollbar(self, orient="vertical", 1555 command=self.display_yview) 1556 self.display.scrollX = Scrollbar(self, orient="horizontal", 1557 command=self.display.xview) 1558 self.display["xscrollcommand"] = self.display.scrollX.set 1559 self.display["yscrollcommand"] = self.scrollY.set --- 6 unchanged lines hidden (view full) --- 1566 self.names.grid(row=1, column=0, sticky=N+S) 1567 self.display.grid(row=1, column=1, sticky=W+E+N+S) 1568 self.scrollY.grid(row=1, column=2, sticky=N+S) 1569 self.display.scrollX.grid(row=2, column=0, columnspan=2, 1570 sticky=E+W) 1571 self.scale.grid(row=3, column=0, columnspan=3, sticky=E+W) 1572 self.status.grid(row=4, column=0, columnspan=3, sticky=E+W) 1573 | 1065 self.scale = Scaler(self, self.display) 1066 status = self.status = Status(self) 1067 self.scrollY = Scrollbar(self, orient="vertical", 1068 command=self.display_yview) 1069 self.display.scrollX = Scrollbar(self, orient="horizontal", 1070 command=self.display.xview) 1071 self.display["xscrollcommand"] = self.display.scrollX.set 1072 self.display["yscrollcommand"] = self.scrollY.set --- 6 unchanged lines hidden (view full) --- 1079 self.names.grid(row=1, column=0, sticky=N+S) 1080 self.display.grid(row=1, column=1, sticky=W+E+N+S) 1081 self.scrollY.grid(row=1, column=2, sticky=N+S) 1082 self.display.scrollX.grid(row=2, column=0, columnspan=2, 1083 sticky=E+W) 1084 self.scale.grid(row=3, column=0, columnspan=3, sticky=E+W) 1085 self.status.grid(row=4, column=0, columnspan=3, sticky=E+W) 1086 |
1574 def draw(self, file): | 1087 def draw(self): |
1575 self.master.update() | 1088 self.master.update() |
1576 ktrfile = KTRFile(file) 1577 self.display.setfile(ktrfile) 1578 self.display.drawnames(self.names) | 1089 self.display.prepare() 1090 self.names.draw() |
1579 self.display.draw() | 1091 self.display.draw() |
1092 self.status.startup("") |
|
1580 self.scale.set(250000) 1581 self.display.xview_moveto(0) 1582 | 1093 self.scale.set(250000) 1094 self.display.xview_moveto(0) 1095 |
1096 def mousepress(self, event): 1097 self.clicksource = self.sourceat(event.y) 1098 1099 def mouserelease(self, event): 1100 if (self.clicksource == None): 1101 return 1102 newsource = self.sourceat(event.y) 1103 if (self.clicksource != newsource): 1104 self.sourceswap(self.clicksource, newsource) 1105 self.clicksource = None 1106 self.lastsource = None 1107 1108 def mousemotion(self, event): 1109 if (self.clicksource == None): 1110 return 1111 newsource = self.sourceat(event.y) 1112 # 1113 # If we get a None source they moved off the page. 1114 # swapsource() can't handle moving multiple items so just 1115 # pretend we never clicked on anything to begin with so the 1116 # user can't mouseover a non-contiguous area. 1117 # 1118 if (newsource == None): 1119 self.clicksource = None 1120 self.lastsource = None 1121 return 1122 if (newsource == self.lastsource): 1123 return; 1124 self.lastsource = newsource 1125 if (newsource != self.clicksource): 1126 self.sourceswap(self.clicksource, newsource) 1127 1128 # These are here because this object controls layout 1129 def sourcestart(self, source): 1130 return source.y - self.bdheight - source.ysize() 1131 1132 def sourceend(self, source): 1133 return source.y + self.bdheight 1134 1135 def sourcesize(self, source): 1136 return (self.bdheight * 2) + source.ysize() 1137 1138 def sourceswap(self, source1, source2): 1139 # Sort so we always know which one is on top. 1140 if (source2.y < source1.y): 1141 swap = source1 1142 source1 = source2 1143 source2 = swap 1144 # Only swap adjacent sources 1145 if (self.sourceend(source1) != self.sourcestart(source2)): 1146 return 1147 # Compute start coordinates and target coordinates 1148 y1 = self.sourcestart(source1) 1149 y2 = self.sourcestart(source2) 1150 y1targ = y1 + self.sourcesize(source2) 1151 y2targ = y1 1152 # 1153 # If the sizes are not equal, adjust the start of the lower 1154 # source to account for the lost/gained space. 1155 # 1156 if (source1.ysize() != source2.ysize()): 1157 diff = source2.ysize() - source1.ysize() 1158 self.names.moveline(y2, diff); 1159 self.display.moveline(y2, diff) 1160 source1.move(self.display, 0, y1targ - y1) 1161 source2.move(self.display, 0, y2targ - y2) 1162 source1.movename(self.names, 0, y1targ - y1) 1163 source2.movename(self.names, 0, y2targ - y2) 1164 1165 def sourceat(self, ypos): 1166 (start, end) = self.names.yview() 1167 starty = start * float(self.names.ysize) 1168 ypos += starty 1169 for source in sources: 1170 yend = self.sourceend(source) 1171 ystart = self.sourcestart(source) 1172 if (ypos >= ystart and ypos <= yend): 1173 return source 1174 return None 1175 |
|
1583 def display_yview(self, *args): 1584 self.names.yview(*args) 1585 self.display.yview(*args) 1586 1587 def setcolor(self, tag, color): 1588 self.display.setcolor(tag, color) 1589 1590 def hide(self, tag): 1591 self.display.hide(tag) 1592 | 1176 def display_yview(self, *args): 1177 self.names.yview(*args) 1178 self.display.yview(*args) 1179 1180 def setcolor(self, tag, color): 1181 self.display.setcolor(tag, color) 1182 1183 def hide(self, tag): 1184 self.display.hide(tag) 1185 |
1593if (len(sys.argv) != 2): 1594 print "usage:", sys.argv[0], "<ktr file>" | 1186 def getcolor(self, tag): 1187 return self.display.getcolor(tag) 1188 1189 def getstate(self, tag): 1190 return self.display.getstate(tag) 1191 1192if (len(sys.argv) != 2 and len(sys.argv) != 3): 1193 print "usage:", sys.argv[0], "<ktr file> [clock freq in ghz]" |
1595 sys.exit(1) 1596 | 1194 sys.exit(1) 1195 |
1196if (len(sys.argv) > 2): 1197 clockfreq = float(sys.argv[2]) 1198 |
|
1597root = Tk() 1598root.title("Scheduler Graph") | 1199root = Tk() 1200root.title("Scheduler Graph") |
1201colormap = Colormap(eventcolors) 1202cpucolormap = Colormap(cpucolors) |
|
1599graph = SchedGraph(root) | 1203graph = SchedGraph(root) |
1204ktrfile = KTRFile(sys.argv[1]) 1205graph.draw() |
|
1600root.mainloop() | 1206root.mainloop() |