1139313Sjeff#!/usr/local/bin/python 2139313Sjeff 3187580Sjeff# Copyright (c) 2002-2003, 2009, Jeffrey Roberson <jeff@freebsd.org> 4139313Sjeff# All rights reserved. 5139313Sjeff# 6139313Sjeff# Redistribution and use in source and binary forms, with or without 7139313Sjeff# modification, are permitted provided that the following conditions 8139313Sjeff# are met: 9139313Sjeff# 1. Redistributions of source code must retain the above copyright 10139313Sjeff# notice unmodified, this list of conditions, and the following 11139313Sjeff# disclaimer. 12139313Sjeff# 2. Redistributions in binary form must reproduce the above copyright 13139313Sjeff# notice, this list of conditions and the following disclaimer in the 14139313Sjeff# documentation and/or other materials provided with the distribution. 15139313Sjeff# 16139313Sjeff# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17139313Sjeff# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18139313Sjeff# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19139313Sjeff# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20139313Sjeff# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21139313Sjeff# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22139313Sjeff# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23139313Sjeff# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24139313Sjeff# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25139313Sjeff# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26139313Sjeff# 27139313Sjeff# $FreeBSD$ 28139313Sjeff 29139313Sjeffimport sys 30139313Sjeffimport re 31187358Sjeffimport random 32139313Sjefffrom Tkinter import * 33139313Sjeff 34139366Sarr# To use: 35173743Ssam# - Install the ports/x11-toolkits/py-tkinter package; e.g. 36173743Ssam# portinstall x11-toolkits/py-tkinter package 37173743Ssam# - Add KTR_SCHED to KTR_COMPILE and KTR_MASK in your KERNCONF; e.g. 38173743Ssam# options KTR 39173743Ssam# options KTR_ENTRIES=32768 40173743Ssam# options KTR_COMPILE=(KTR_SCHED) 41173743Ssam# options KTR_MASK=(KTR_SCHED) 42173743Ssam# - It is encouraged to increase KTR_ENTRIES size to gather enough 43173743Ssam# information for analysis; e.g. 44173743Ssam# options KTR_ENTRIES=262144 45175306Skris# as 32768 entries may only correspond to a second or two of profiling 46175306Skris# data depending on your workload. 47168940Skris# - Rebuild kernel with proper changes to KERNCONF and boot new kernel. 48168940Skris# - Run your workload to be profiled. 49168940Skris# - While the workload is continuing (i.e. before it finishes), disable 50168940Skris# KTR tracing by setting 'sysctl debug.ktr.mask=0'. This is necessary 51168940Skris# to avoid a race condition while running ktrdump, i.e. the KTR ring buffer 52168940Skris# will cycle a bit while ktrdump runs, and this confuses schedgraph because 53168940Skris# the timestamps appear to go backwards at some point. Stopping KTR logging 54168940Skris# while the workload is still running is to avoid wasting log entries on 55168940Skris# "idle" time at the end. 56139366Sarr# - Dump the trace to a file: 'ktrdump -ct > ktr.out' 57187358Sjeff# - Run the python script: 'python schedgraph.py ktr.out' optionally provide 58187358Sjeff# your cpu frequency in ghz: 'python schedgraph.py ktr.out 2.4' 59139366Sarr# 60139366Sarr# To do: 61187358Sjeff# Add a per-source summary display 62187358Sjeff# "Vertical rule" to help relate data in different rows 63187358Sjeff# Mouse-over popup of full thread/event/row label (currently truncated) 64187358Sjeff# More visible anchors for popup event windows 65168940Skris# 66168940Skris# BUGS: 1) Only 8 CPUs are supported, more CPUs require more choices of 67168940Skris# colours to represent them ;-) 68139313Sjeff 69187358Sjeffeventcolors = [ 70187358Sjeff ("count", "red"), 71187358Sjeff ("running", "green"), 72187358Sjeff ("idle", "grey"), 73187358Sjeff ("yielding", "yellow"), 74187358Sjeff ("swapped", "violet"), 75187358Sjeff ("suspended", "purple"), 76187358Sjeff ("iwait", "grey"), 77187358Sjeff ("sleep", "blue"), 78187358Sjeff ("blocked", "dark red"), 79187358Sjeff ("runq add", "yellow"), 80187358Sjeff ("runq rem", "yellow"), 81187358Sjeff ("thread exit", "grey"), 82187358Sjeff ("proc exit", "grey"), 83187358Sjeff ("callwheel idle", "grey"), 84187358Sjeff ("callout running", "green"), 85187358Sjeff ("lock acquire", "blue"), 86187358Sjeff ("lock contest", "purple"), 87187358Sjeff ("failed lock try", "red"), 88187358Sjeff ("lock release", "grey"), 89187379Sjeff ("statclock", "black"), 90187358Sjeff ("prio", "black"), 91187358Sjeff ("lend prio", "black"), 92187358Sjeff ("wokeup", "black") 93187358Sjeff] 94187358Sjeff 95187358Sjeffcpucolors = [ 96187358Sjeff ("CPU 0", "light grey"), 97187358Sjeff ("CPU 1", "dark grey"), 98187358Sjeff ("CPU 2", "light blue"), 99187358Sjeff ("CPU 3", "light pink"), 100187358Sjeff ("CPU 4", "blanched almond"), 101187358Sjeff ("CPU 5", "slate grey"), 102187358Sjeff ("CPU 6", "tan"), 103187358Sjeff ("CPU 7", "thistle"), 104187358Sjeff ("CPU 8", "white") 105187358Sjeff] 106187358Sjeff 107187358Sjeffcolors = [ 108187358Sjeff "white", "thistle", "blanched almond", "tan", "chartreuse", 109187358Sjeff "dark red", "red", "pale violet red", "pink", "light pink", 110187358Sjeff "dark orange", "orange", "coral", "light coral", 111187358Sjeff "goldenrod", "gold", "yellow", "light yellow", 112187358Sjeff "dark green", "green", "light green", "light sea green", 113187358Sjeff "dark blue", "blue", "light blue", "steel blue", "light slate blue", 114187358Sjeff "dark violet", "violet", "purple", "blue violet", 115187358Sjeff "dark grey", "slate grey", "light grey", 116187358Sjeff "black", 117187358Sjeff] 118187358Sjeffcolors.sort() 119187358Sjeff 120139313Sjeffticksps = None 121139313Sjeffstatus = None 122187358Sjeffcolormap = None 123187358Sjeffktrfile = None 124187358Sjeffclockfreq = None 125187358Sjeffsources = [] 126173743Ssamlineno = -1 127139313Sjeff 128187379SjeffY_BORDER = 10 129187379SjeffX_BORDER = 10 130187379SjeffY_COUNTER = 80 131187379SjeffY_EVENTSOURCE = 10 132187379SjeffXY_POINT = 4 133187379Sjeff 134187358Sjeffclass Colormap: 135187358Sjeff def __init__(self, table): 136187358Sjeff self.table = table 137187358Sjeff self.map = {} 138187358Sjeff for entry in table: 139187358Sjeff self.map[entry[0]] = entry[1] 140187358Sjeff 141187358Sjeff def lookup(self, name): 142187358Sjeff try: 143187358Sjeff color = self.map[name] 144187358Sjeff except: 145187358Sjeff color = colors[random.randrange(0, len(colors))] 146187358Sjeff print "Picking random color", color, "for", name 147187358Sjeff self.map[name] = color 148187358Sjeff self.table.append((name, color)) 149187358Sjeff return (color) 150187358Sjeff 151139313Sjeffdef ticks2sec(ticks): 152187580Sjeff ticks = float(ticks) 153187580Sjeff ns = float(ticksps) / 1000000000 154187580Sjeff ticks /= ns 155139313Sjeff if (ticks < 1000): 156187580Sjeff return ("%.2fns" % ticks) 157139313Sjeff ticks /= 1000 158139313Sjeff if (ticks < 1000): 159187580Sjeff return ("%.2fus" % ticks) 160139313Sjeff ticks /= 1000 161187580Sjeff if (ticks < 1000): 162187580Sjeff return ("%.2fms" % ticks) 163187580Sjeff ticks /= 1000 164187580Sjeff return ("%.2fs" % ticks) 165139313Sjeff 166139313Sjeffclass Scaler(Frame): 167139313Sjeff def __init__(self, master, target): 168139313Sjeff Frame.__init__(self, master) 169187471Sjeff self.scale = None 170187471Sjeff self.target = target 171139313Sjeff self.label = Label(self, text="Ticks per pixel") 172139313Sjeff self.label.pack(side=LEFT) 173187471Sjeff self.resolution = 100 174187471Sjeff self.setmax(10000) 175139313Sjeff 176139313Sjeff def scaleset(self, value): 177139313Sjeff self.target.scaleset(int(value)) 178139313Sjeff 179139313Sjeff def set(self, value): 180139313Sjeff self.scale.set(value) 181139313Sjeff 182187471Sjeff def setmax(self, value): 183187471Sjeff # 184187471Sjeff # We can't reconfigure the to_ value so we delete the old 185187471Sjeff # window and make a new one when we resize. 186187471Sjeff # 187187471Sjeff if (self.scale != None): 188187471Sjeff self.scale.pack_forget() 189187471Sjeff self.scale.destroy() 190187471Sjeff self.scale = Scale(self, command=self.scaleset, 191187471Sjeff from_=100, to_=value, orient=HORIZONTAL, 192187471Sjeff resolution=self.resolution) 193187471Sjeff self.scale.pack(fill="both", expand=1) 194187471Sjeff self.scale.set(self.target.scaleget()) 195187471Sjeff 196139313Sjeffclass Status(Frame): 197139313Sjeff def __init__(self, master): 198139313Sjeff Frame.__init__(self, master) 199139313Sjeff self.label = Label(self, bd=1, relief=SUNKEN, anchor=W) 200139313Sjeff self.label.pack(fill="both", expand=1) 201139313Sjeff self.clear() 202139313Sjeff 203139313Sjeff def set(self, str): 204139313Sjeff self.label.config(text=str) 205139313Sjeff 206139313Sjeff def clear(self): 207139313Sjeff self.label.config(text="") 208139313Sjeff 209139313Sjeff def startup(self, str): 210139313Sjeff self.set(str) 211139313Sjeff root.update() 212139313Sjeff 213187358Sjeffclass ColorConf(Frame): 214187358Sjeff def __init__(self, master, name, color): 215139313Sjeff Frame.__init__(self, master) 216187358Sjeff if (graph.getstate(name) == "hidden"): 217187358Sjeff enabled = 0 218187358Sjeff else: 219187358Sjeff enabled = 1 220139313Sjeff self.name = name 221139313Sjeff self.color = StringVar() 222139313Sjeff self.color_default = color 223139313Sjeff self.color_current = color 224139313Sjeff self.color.set(color) 225139313Sjeff self.enabled = IntVar() 226139313Sjeff self.enabled_default = enabled 227139313Sjeff self.enabled_current = enabled 228139313Sjeff self.enabled.set(enabled) 229139313Sjeff self.draw() 230139313Sjeff 231139313Sjeff def draw(self): 232139313Sjeff self.label = Label(self, text=self.name, anchor=W) 233139313Sjeff self.sample = Canvas(self, width=24, height=24, 234139313Sjeff bg='grey') 235139313Sjeff self.rect = self.sample.create_rectangle(0, 0, 24, 24, 236139313Sjeff fill=self.color.get()) 237187358Sjeff self.list = OptionMenu(self, self.color, command=self.setcolor, 238187358Sjeff *colors) 239139313Sjeff self.checkbox = Checkbutton(self, text="enabled", 240139313Sjeff variable=self.enabled) 241139313Sjeff self.label.grid(row=0, column=0, sticky=E+W) 242139313Sjeff self.sample.grid(row=0, column=1) 243139313Sjeff self.list.grid(row=0, column=2, sticky=E+W) 244139313Sjeff self.checkbox.grid(row=0, column=3) 245139313Sjeff self.columnconfigure(0, weight=1) 246187358Sjeff self.columnconfigure(2, minsize=150) 247139313Sjeff 248139313Sjeff def setcolor(self, color): 249139313Sjeff self.color.set(color) 250139313Sjeff self.sample.itemconfigure(self.rect, fill=color) 251139313Sjeff 252139313Sjeff def apply(self): 253139313Sjeff cchange = 0 254139313Sjeff echange = 0 255139313Sjeff if (self.color_current != self.color.get()): 256139313Sjeff cchange = 1 257139313Sjeff if (self.enabled_current != self.enabled.get()): 258139313Sjeff echange = 1 259139313Sjeff self.color_current = self.color.get() 260139313Sjeff self.enabled_current = self.enabled.get() 261139313Sjeff if (echange != 0): 262139313Sjeff if (self.enabled_current): 263139313Sjeff graph.setcolor(self.name, self.color_current) 264139313Sjeff else: 265139313Sjeff graph.hide(self.name) 266139313Sjeff return 267139313Sjeff if (cchange != 0): 268139313Sjeff graph.setcolor(self.name, self.color_current) 269139313Sjeff 270139313Sjeff def revert(self): 271139313Sjeff self.setcolor(self.color_default) 272139313Sjeff self.enabled.set(self.enabled_default) 273139313Sjeff 274187358Sjeffclass ColorConfigure(Toplevel): 275187358Sjeff def __init__(self, table, name): 276139313Sjeff Toplevel.__init__(self) 277139313Sjeff self.resizable(0, 0) 278187358Sjeff self.title(name) 279187358Sjeff self.items = LabelFrame(self, text="Item Type") 280139313Sjeff self.buttons = Frame(self) 281139313Sjeff self.drawbuttons() 282139313Sjeff self.items.grid(row=0, column=0, sticky=E+W) 283139313Sjeff self.columnconfigure(0, weight=1) 284139313Sjeff self.buttons.grid(row=1, column=0, sticky=E+W) 285139313Sjeff self.types = [] 286139313Sjeff self.irow = 0 287187358Sjeff for type in table: 288187358Sjeff color = graph.getcolor(type[0]) 289187358Sjeff if (color != ""): 290187358Sjeff self.additem(type[0], color) 291139313Sjeff 292187358Sjeff def additem(self, name, color): 293187358Sjeff item = ColorConf(self.items, name, color) 294139313Sjeff self.types.append(item) 295139313Sjeff item.grid(row=self.irow, column=0, sticky=E+W) 296139313Sjeff self.irow += 1 297139313Sjeff 298139313Sjeff def drawbuttons(self): 299139313Sjeff self.apply = Button(self.buttons, text="Apply", 300139313Sjeff command=self.apress) 301187358Sjeff self.default = Button(self.buttons, text="Revert", 302139313Sjeff command=self.rpress) 303139313Sjeff self.apply.grid(row=0, column=0, sticky=E+W) 304187358Sjeff self.default.grid(row=0, column=1, sticky=E+W) 305139313Sjeff self.buttons.columnconfigure(0, weight=1) 306139313Sjeff self.buttons.columnconfigure(1, weight=1) 307139313Sjeff 308139313Sjeff def apress(self): 309139313Sjeff for item in self.types: 310139313Sjeff item.apply() 311139313Sjeff 312139313Sjeff def rpress(self): 313139313Sjeff for item in self.types: 314139313Sjeff item.revert() 315139313Sjeff 316187359Sjeffclass SourceConf(Frame): 317187359Sjeff def __init__(self, master, source): 318187359Sjeff Frame.__init__(self, master) 319187359Sjeff if (source.hidden == 1): 320187359Sjeff enabled = 0 321187359Sjeff else: 322187359Sjeff enabled = 1 323187359Sjeff self.source = source 324187359Sjeff self.name = source.name 325187359Sjeff self.enabled = IntVar() 326187359Sjeff self.enabled_default = enabled 327187359Sjeff self.enabled_current = enabled 328187359Sjeff self.enabled.set(enabled) 329187359Sjeff self.draw() 330187359Sjeff 331187359Sjeff def draw(self): 332187359Sjeff self.label = Label(self, text=self.name, anchor=W) 333187359Sjeff self.checkbox = Checkbutton(self, text="enabled", 334187359Sjeff variable=self.enabled) 335187359Sjeff self.label.grid(row=0, column=0, sticky=E+W) 336187359Sjeff self.checkbox.grid(row=0, column=1) 337187359Sjeff self.columnconfigure(0, weight=1) 338187359Sjeff 339187376Sjeff def changed(self): 340187376Sjeff if (self.enabled_current != self.enabled.get()): 341187376Sjeff return 1 342187376Sjeff return 0 343187376Sjeff 344187359Sjeff def apply(self): 345187359Sjeff self.enabled_current = self.enabled.get() 346187359Sjeff 347187359Sjeff def revert(self): 348187359Sjeff self.enabled.set(self.enabled_default) 349187359Sjeff 350187359Sjeff def check(self): 351187359Sjeff self.enabled.set(1) 352187359Sjeff 353187359Sjeff def uncheck(self): 354187359Sjeff self.enabled.set(0) 355187359Sjeff 356187359Sjeffclass SourceConfigure(Toplevel): 357187359Sjeff def __init__(self): 358187359Sjeff Toplevel.__init__(self) 359187359Sjeff self.resizable(0, 0) 360187359Sjeff self.title("Source Configuration") 361187359Sjeff self.items = [] 362187359Sjeff self.iframe = Frame(self) 363187359Sjeff self.iframe.grid(row=0, column=0, sticky=E+W) 364187359Sjeff f = LabelFrame(self.iframe, bd=4, text="Sources") 365187359Sjeff self.items.append(f) 366187359Sjeff self.buttons = Frame(self) 367187359Sjeff self.items[0].grid(row=0, column=0, sticky=E+W) 368187359Sjeff self.columnconfigure(0, weight=1) 369187359Sjeff self.sconfig = [] 370187359Sjeff self.irow = 0 371187359Sjeff self.icol = 0 372187359Sjeff for source in sources: 373187359Sjeff self.addsource(source) 374187359Sjeff self.drawbuttons() 375187359Sjeff self.buttons.grid(row=1, column=0, sticky=W) 376187359Sjeff 377187359Sjeff def addsource(self, source): 378187359Sjeff if (self.irow > 30): 379187359Sjeff self.icol += 1 380187359Sjeff self.irow = 0 381187359Sjeff c = self.icol 382187359Sjeff f = LabelFrame(self.iframe, bd=4, text="Sources") 383187359Sjeff f.grid(row=0, column=c, sticky=N+E+W) 384187359Sjeff self.items.append(f) 385187359Sjeff item = SourceConf(self.items[self.icol], source) 386187359Sjeff self.sconfig.append(item) 387187359Sjeff item.grid(row=self.irow, column=0, sticky=E+W) 388187359Sjeff self.irow += 1 389187359Sjeff 390187359Sjeff def drawbuttons(self): 391187359Sjeff self.apply = Button(self.buttons, text="Apply", 392187359Sjeff command=self.apress) 393187359Sjeff self.default = Button(self.buttons, text="Revert", 394187359Sjeff command=self.rpress) 395187359Sjeff self.checkall = Button(self.buttons, text="Check All", 396187359Sjeff command=self.cpress) 397187359Sjeff self.uncheckall = Button(self.buttons, text="Uncheck All", 398187359Sjeff command=self.upress) 399187359Sjeff self.checkall.grid(row=0, column=0, sticky=W) 400187359Sjeff self.uncheckall.grid(row=0, column=1, sticky=W) 401187359Sjeff self.apply.grid(row=0, column=2, sticky=W) 402187359Sjeff self.default.grid(row=0, column=3, sticky=W) 403187359Sjeff self.buttons.columnconfigure(0, weight=1) 404187359Sjeff self.buttons.columnconfigure(1, weight=1) 405187359Sjeff self.buttons.columnconfigure(2, weight=1) 406187359Sjeff self.buttons.columnconfigure(3, weight=1) 407187359Sjeff 408187359Sjeff def apress(self): 409187376Sjeff disable_sources = [] 410187376Sjeff enable_sources = [] 411187359Sjeff for item in self.sconfig: 412187376Sjeff if (item.changed() == 0): 413187376Sjeff continue 414187376Sjeff if (item.enabled.get() == 1): 415187376Sjeff enable_sources.append(item.source) 416187376Sjeff else: 417187376Sjeff disable_sources.append(item.source) 418187376Sjeff 419187376Sjeff if (len(disable_sources)): 420187376Sjeff graph.sourcehidelist(disable_sources) 421187376Sjeff if (len(enable_sources)): 422187376Sjeff graph.sourceshowlist(enable_sources) 423187376Sjeff 424187376Sjeff for item in self.sconfig: 425187359Sjeff item.apply() 426187359Sjeff 427187359Sjeff def rpress(self): 428187359Sjeff for item in self.sconfig: 429187359Sjeff item.revert() 430187359Sjeff 431187359Sjeff def cpress(self): 432187359Sjeff for item in self.sconfig: 433187359Sjeff item.check() 434187359Sjeff 435187359Sjeff def upress(self): 436187359Sjeff for item in self.sconfig: 437187359Sjeff item.uncheck() 438187359Sjeff 439187376Sjeff# Reverse compare of second member of the tuple 440187376Sjeffdef cmp_counts(x, y): 441187376Sjeff return y[1] - x[1] 442187376Sjeff 443187376Sjeffclass SourceStats(Toplevel): 444187376Sjeff def __init__(self, source): 445187376Sjeff self.source = source 446187376Sjeff Toplevel.__init__(self) 447187376Sjeff self.resizable(0, 0) 448187376Sjeff self.title(source.name + " statistics") 449187376Sjeff self.evframe = LabelFrame(self, 450187580Sjeff text="Event Count, Duration, Avg Duration") 451187376Sjeff self.evframe.grid(row=0, column=0, sticky=E+W) 452187376Sjeff eventtypes={} 453187376Sjeff for event in self.source.events: 454187376Sjeff if (event.type == "pad"): 455187376Sjeff continue 456187376Sjeff duration = event.duration 457187376Sjeff if (eventtypes.has_key(event.name)): 458187376Sjeff (c, d) = eventtypes[event.name] 459187376Sjeff c += 1 460187376Sjeff d += duration 461187376Sjeff eventtypes[event.name] = (c, d) 462187376Sjeff else: 463187376Sjeff eventtypes[event.name] = (1, duration) 464187376Sjeff events = [] 465187376Sjeff for k, v in eventtypes.iteritems(): 466187376Sjeff (c, d) = v 467187376Sjeff events.append((k, c, d)) 468187376Sjeff events.sort(cmp=cmp_counts) 469187376Sjeff 470187376Sjeff ypos = 0 471187376Sjeff for event in events: 472187376Sjeff (name, c, d) = event 473187580Sjeff Label(self.evframe, text=name, bd=1, 474187580Sjeff relief=SUNKEN, anchor=W, width=30).grid( 475187580Sjeff row=ypos, column=0, sticky=W+E) 476187580Sjeff Label(self.evframe, text=str(c), bd=1, 477187580Sjeff relief=SUNKEN, anchor=W, width=10).grid( 478187580Sjeff row=ypos, column=1, sticky=W+E) 479187580Sjeff Label(self.evframe, text=ticks2sec(d), 480187580Sjeff bd=1, relief=SUNKEN, width=10).grid( 481187580Sjeff row=ypos, column=2, sticky=W+E) 482187580Sjeff if (d and c): 483187580Sjeff d /= c 484187580Sjeff else: 485187580Sjeff d = 0 486187580Sjeff Label(self.evframe, text=ticks2sec(d), 487187580Sjeff bd=1, relief=SUNKEN, width=10).grid( 488187580Sjeff row=ypos, column=3, sticky=W+E) 489187376Sjeff ypos += 1 490187376Sjeff 491187376Sjeff 492187376Sjeffclass SourceContext(Menu): 493187376Sjeff def __init__(self, event, source): 494187376Sjeff self.source = source 495187376Sjeff Menu.__init__(self, tearoff=0, takefocus=0) 496187376Sjeff self.add_command(label="hide", command=self.hide) 497187376Sjeff self.add_command(label="hide group", command=self.hidegroup) 498187376Sjeff self.add_command(label="stats", command=self.stats) 499187376Sjeff self.tk_popup(event.x_root-3, event.y_root+3) 500187376Sjeff 501187376Sjeff def hide(self): 502187376Sjeff graph.sourcehide(self.source) 503187376Sjeff 504187376Sjeff def hidegroup(self): 505187376Sjeff grouplist = [] 506187376Sjeff for source in sources: 507187376Sjeff if (source.group == self.source.group): 508187376Sjeff grouplist.append(source) 509187376Sjeff graph.sourcehidelist(grouplist) 510187376Sjeff 511187376Sjeff def show(self): 512187376Sjeff graph.sourceshow(self.source) 513187376Sjeff 514187376Sjeff def stats(self): 515187376Sjeff SourceStats(self.source) 516187376Sjeff 517139313Sjeffclass EventView(Toplevel): 518139313Sjeff def __init__(self, event, canvas): 519139313Sjeff Toplevel.__init__(self) 520139313Sjeff self.resizable(0, 0) 521139313Sjeff self.title("Event") 522139313Sjeff self.event = event 523187358Sjeff self.buttons = Frame(self) 524187358Sjeff self.buttons.grid(row=0, column=0, sticky=E+W) 525139313Sjeff self.frame = Frame(self) 526187358Sjeff self.frame.grid(row=1, column=0, sticky=N+S+E+W) 527139313Sjeff self.canvas = canvas 528139313Sjeff self.drawlabels() 529139313Sjeff self.drawbuttons() 530139313Sjeff event.displayref(canvas) 531139313Sjeff self.bind("<Destroy>", self.destroycb) 532139313Sjeff 533139313Sjeff def destroycb(self, event): 534139313Sjeff self.unbind("<Destroy>") 535139313Sjeff if (self.event != None): 536139313Sjeff self.event.displayunref(self.canvas) 537139313Sjeff self.event = None 538139313Sjeff self.destroy() 539139313Sjeff 540139313Sjeff def clearlabels(self): 541139313Sjeff for label in self.frame.grid_slaves(): 542139313Sjeff label.grid_remove() 543139313Sjeff 544139313Sjeff def drawlabels(self): 545139313Sjeff ypos = 0 546139313Sjeff labels = self.event.labels() 547139313Sjeff while (len(labels) < 7): 548187358Sjeff labels.append(("", "")) 549139313Sjeff for label in labels: 550187358Sjeff name, value = label 551187358Sjeff linked = 0 552187358Sjeff if (name == "linkedto"): 553187358Sjeff linked = 1 554139313Sjeff l = Label(self.frame, text=name, bd=1, width=15, 555139313Sjeff relief=SUNKEN, anchor=W) 556139313Sjeff if (linked): 557139313Sjeff fgcolor = "blue" 558139313Sjeff else: 559139313Sjeff fgcolor = "black" 560139313Sjeff r = Label(self.frame, text=value, bd=1, 561139313Sjeff relief=SUNKEN, anchor=W, fg=fgcolor) 562139313Sjeff l.grid(row=ypos, column=0, sticky=E+W) 563139313Sjeff r.grid(row=ypos, column=1, sticky=E+W) 564139313Sjeff if (linked): 565139313Sjeff r.bind("<Button-1>", self.linkpress) 566139313Sjeff ypos += 1 567139313Sjeff self.frame.columnconfigure(1, minsize=80) 568139313Sjeff 569139313Sjeff def drawbuttons(self): 570139313Sjeff self.back = Button(self.buttons, text="<", command=self.bpress) 571139313Sjeff self.forw = Button(self.buttons, text=">", command=self.fpress) 572139313Sjeff self.new = Button(self.buttons, text="new", command=self.npress) 573139313Sjeff self.back.grid(row=0, column=0, sticky=E+W) 574139313Sjeff self.forw.grid(row=0, column=1, sticky=E+W) 575139313Sjeff self.new.grid(row=0, column=2, sticky=E+W) 576139313Sjeff self.buttons.columnconfigure(2, weight=1) 577139313Sjeff 578139313Sjeff def newevent(self, event): 579139313Sjeff self.event.displayunref(self.canvas) 580139313Sjeff self.clearlabels() 581139313Sjeff self.event = event 582139313Sjeff self.event.displayref(self.canvas) 583139313Sjeff self.drawlabels() 584139313Sjeff 585139313Sjeff def npress(self): 586139313Sjeff EventView(self.event, self.canvas) 587139313Sjeff 588139313Sjeff def bpress(self): 589139313Sjeff prev = self.event.prev() 590139313Sjeff if (prev == None): 591139313Sjeff return 592187358Sjeff while (prev.type == "pad"): 593139313Sjeff prev = prev.prev() 594139313Sjeff if (prev == None): 595139313Sjeff return 596139313Sjeff self.newevent(prev) 597139313Sjeff 598139313Sjeff def fpress(self): 599139313Sjeff next = self.event.next() 600139313Sjeff if (next == None): 601139313Sjeff return 602187358Sjeff while (next.type == "pad"): 603139313Sjeff next = next.next() 604139313Sjeff if (next == None): 605139313Sjeff return 606139313Sjeff self.newevent(next) 607139313Sjeff 608139313Sjeff def linkpress(self, wevent): 609139313Sjeff event = self.event.getlinked() 610139313Sjeff if (event != None): 611139313Sjeff self.newevent(event) 612139313Sjeff 613139313Sjeffclass Event: 614187358Sjeff def __init__(self, source, name, cpu, timestamp, attrs): 615139313Sjeff self.source = source 616187358Sjeff self.name = name 617139313Sjeff self.cpu = cpu 618139313Sjeff self.timestamp = int(timestamp) 619187358Sjeff self.attrs = attrs 620139313Sjeff self.idx = None 621139313Sjeff self.item = None 622139313Sjeff self.dispcnt = 0 623187376Sjeff self.duration = 0 624173743Ssam self.recno = lineno 625139313Sjeff 626139313Sjeff def status(self): 627139313Sjeff statstr = self.name + " " + self.source.name 628139313Sjeff statstr += " on: cpu" + str(self.cpu) 629139313Sjeff statstr += " at: " + str(self.timestamp) 630187358Sjeff statstr += " attributes: " 631187358Sjeff for i in range(0, len(self.attrs)): 632187358Sjeff attr = self.attrs[i] 633187358Sjeff statstr += attr[0] + ": " + str(attr[1]) 634187358Sjeff if (i != len(self.attrs) - 1): 635187358Sjeff statstr += ", " 636139313Sjeff status.set(statstr) 637139313Sjeff 638187358Sjeff def labels(self): 639187358Sjeff return [("Source", self.source.name), 640187358Sjeff ("Event", self.name), 641187358Sjeff ("CPU", self.cpu), 642187358Sjeff ("Timestamp", self.timestamp), 643187358Sjeff ("KTR Line ", self.recno) 644187358Sjeff ] + self.attrs 645139313Sjeff 646187358Sjeff def mouseenter(self, canvas): 647139313Sjeff self.displayref(canvas) 648139313Sjeff self.status() 649139313Sjeff 650187358Sjeff def mouseexit(self, canvas): 651139313Sjeff self.displayunref(canvas) 652139313Sjeff status.clear() 653139313Sjeff 654187358Sjeff def mousepress(self, canvas): 655139313Sjeff EventView(self, canvas) 656139313Sjeff 657187358Sjeff def draw(self, canvas, xpos, ypos, item): 658187358Sjeff self.item = item 659187358Sjeff if (item != None): 660187358Sjeff canvas.items[item] = self 661187358Sjeff 662187358Sjeff def move(self, canvas, x, y): 663187358Sjeff if (self.item == None): 664187358Sjeff return; 665187358Sjeff canvas.move(self.item, x, y); 666187358Sjeff 667139313Sjeff def next(self): 668139313Sjeff return self.source.eventat(self.idx + 1) 669139313Sjeff 670187358Sjeff def nexttype(self, type): 671187358Sjeff next = self.next() 672187358Sjeff while (next != None and next.type != type): 673187358Sjeff next = next.next() 674187358Sjeff return (next) 675187358Sjeff 676139313Sjeff def prev(self): 677139313Sjeff return self.source.eventat(self.idx - 1) 678139313Sjeff 679139313Sjeff def displayref(self, canvas): 680139313Sjeff if (self.dispcnt == 0): 681139313Sjeff canvas.itemconfigure(self.item, width=2) 682139313Sjeff self.dispcnt += 1 683139313Sjeff 684139313Sjeff def displayunref(self, canvas): 685139313Sjeff self.dispcnt -= 1 686139313Sjeff if (self.dispcnt == 0): 687139313Sjeff canvas.itemconfigure(self.item, width=0) 688139313Sjeff canvas.tag_raise("point", "state") 689139313Sjeff 690139313Sjeff def getlinked(self): 691187358Sjeff for attr in self.attrs: 692187358Sjeff if (attr[0] != "linkedto"): 693187358Sjeff continue 694187358Sjeff source = ktrfile.findid(attr[1]) 695187358Sjeff return source.findevent(self.timestamp) 696187358Sjeff return None 697139313Sjeff 698139313Sjeffclass PointEvent(Event): 699187358Sjeff type = "point" 700187358Sjeff def __init__(self, source, name, cpu, timestamp, attrs): 701187358Sjeff Event.__init__(self, source, name, cpu, timestamp, attrs) 702139313Sjeff 703139313Sjeff def draw(self, canvas, xpos, ypos): 704187358Sjeff color = colormap.lookup(self.name) 705187379Sjeff l = canvas.create_oval(xpos - XY_POINT, ypos, 706187379Sjeff xpos + XY_POINT, ypos - (XY_POINT * 2), 707187376Sjeff fill=color, width=0, 708187379Sjeff tags=("event", self.type, self.name, self.source.tag)) 709187358Sjeff Event.draw(self, canvas, xpos, ypos, l) 710139313Sjeff 711187358Sjeff return xpos 712139313Sjeff 713139313Sjeffclass StateEvent(Event): 714187358Sjeff type = "state" 715187358Sjeff def __init__(self, source, name, cpu, timestamp, attrs): 716187358Sjeff Event.__init__(self, source, name, cpu, timestamp, attrs) 717139313Sjeff 718139313Sjeff def draw(self, canvas, xpos, ypos): 719187358Sjeff next = self.nexttype("state") 720187358Sjeff if (next == None): 721139313Sjeff return (xpos) 722187376Sjeff self.duration = duration = next.timestamp - self.timestamp 723187358Sjeff self.attrs.insert(0, ("duration", ticks2sec(duration))) 724187358Sjeff color = colormap.lookup(self.name) 725187358Sjeff if (duration < 0): 726187358Sjeff duration = 0 727166209Sjeff print "Unsynchronized timestamp" 728166209Sjeff print self.cpu, self.timestamp 729166209Sjeff print next.cpu, next.timestamp 730187358Sjeff delta = duration / canvas.ratio 731139313Sjeff l = canvas.create_rectangle(xpos, ypos, 732187358Sjeff xpos + delta, ypos - 10, fill=color, width=0, 733187379Sjeff tags=("event", self.type, self.name, self.source.tag)) 734187358Sjeff Event.draw(self, canvas, xpos, ypos, l) 735139313Sjeff 736139313Sjeff return (xpos + delta) 737139313Sjeff 738187358Sjeffclass CountEvent(Event): 739187358Sjeff type = "count" 740187358Sjeff def __init__(self, source, count, cpu, timestamp, attrs): 741187358Sjeff count = int(count) 742187358Sjeff self.count = count 743187358Sjeff Event.__init__(self, source, "count", cpu, timestamp, attrs) 744139313Sjeff 745139313Sjeff def draw(self, canvas, xpos, ypos): 746187358Sjeff next = self.nexttype("count") 747187358Sjeff if (next == None): 748187358Sjeff return (xpos) 749187358Sjeff color = colormap.lookup("count") 750187376Sjeff self.duration = duration = next.timestamp - self.timestamp 751187471Sjeff if (duration < 0): 752187471Sjeff duration = 0 753187471Sjeff print "Unsynchronized timestamp" 754187471Sjeff print self.cpu, self.timestamp 755187471Sjeff print next.cpu, next.timestamp 756187358Sjeff self.attrs.insert(0, ("count", self.count)) 757187358Sjeff self.attrs.insert(1, ("duration", ticks2sec(duration))) 758187358Sjeff delta = duration / canvas.ratio 759139313Sjeff yhight = self.source.yscale() * self.count 760139313Sjeff l = canvas.create_rectangle(xpos, ypos - yhight, 761187358Sjeff xpos + delta, ypos, fill=color, width=0, 762187379Sjeff tags=("event", self.type, self.name, self.source.tag)) 763187358Sjeff Event.draw(self, canvas, xpos, ypos, l) 764139313Sjeff return (xpos + delta) 765139313Sjeff 766187358Sjeffclass PadEvent(StateEvent): 767187358Sjeff type = "pad" 768187358Sjeff def __init__(self, source, cpu, timestamp, last=0): 769187358Sjeff if (last): 770187358Sjeff cpu = source.events[len(source.events) -1].cpu 771187358Sjeff else: 772187358Sjeff cpu = source.events[0].cpu 773187358Sjeff StateEvent.__init__(self, source, "pad", cpu, timestamp, []) 774139313Sjeff def draw(self, canvas, xpos, ypos): 775139313Sjeff next = self.next() 776139313Sjeff if (next == None): 777139313Sjeff return (xpos) 778187358Sjeff duration = next.timestamp - self.timestamp 779187358Sjeff delta = duration / canvas.ratio 780187358Sjeff Event.draw(self, canvas, xpos, ypos, None) 781139313Sjeff return (xpos + delta) 782139313Sjeff 783187376Sjeff# Sort function for start y address 784187376Sjeffdef source_cmp_start(x, y): 785187376Sjeff return x.y - y.y 786187376Sjeff 787139313Sjeffclass EventSource: 788187358Sjeff def __init__(self, group, id): 789187358Sjeff self.name = id 790139313Sjeff self.events = [] 791187358Sjeff self.cpuitems = [] 792187155Sjhb self.group = group 793187358Sjeff self.y = 0 794187358Sjeff self.item = None 795187359Sjeff self.hidden = 0 796187376Sjeff self.tag = group + id 797139313Sjeff 798187155Sjhb def __cmp__(self, other): 799187358Sjeff if (other == None): 800187358Sjeff return -1 801187155Sjhb if (self.group == other.group): 802187358Sjeff return cmp(self.name, other.name) 803187155Sjhb return cmp(self.group, other.group) 804187155Sjhb 805187155Sjhb # It is much faster to append items to a list then to insert them 806187155Sjhb # at the beginning. As a result, we add events in reverse order 807187155Sjhb # and then swap the list during fixup. 808139313Sjeff def fixup(self): 809187155Sjhb self.events.reverse() 810139313Sjeff 811187358Sjeff def addevent(self, event): 812187155Sjhb self.events.append(event) 813139313Sjeff 814187358Sjeff def addlastevent(self, event): 815187155Sjhb self.events.insert(0, event) 816139313Sjeff 817139313Sjeff def draw(self, canvas, ypos): 818139313Sjeff xpos = 10 819187358Sjeff cpux = 10 820187358Sjeff cpu = self.events[1].cpu 821139313Sjeff for i in range(0, len(self.events)): 822139313Sjeff self.events[i].idx = i 823139313Sjeff for event in self.events: 824187358Sjeff if (event.cpu != cpu and event.cpu != -1): 825187358Sjeff self.drawcpu(canvas, cpu, cpux, xpos, ypos) 826187358Sjeff cpux = xpos 827187358Sjeff cpu = event.cpu 828139313Sjeff xpos = event.draw(canvas, xpos, ypos) 829187358Sjeff self.drawcpu(canvas, cpu, cpux, xpos, ypos) 830139313Sjeff 831139313Sjeff def drawname(self, canvas, ypos): 832187358Sjeff self.y = ypos 833139313Sjeff ypos = ypos - (self.ysize() / 2) 834187379Sjeff self.item = canvas.create_text(X_BORDER, ypos, anchor="w", 835187379Sjeff text=self.name) 836187358Sjeff return (self.item) 837139313Sjeff 838187358Sjeff def drawcpu(self, canvas, cpu, fromx, tox, ypos): 839187358Sjeff cpu = "CPU " + str(cpu) 840187358Sjeff color = cpucolormap.lookup(cpu) 841187358Sjeff # Create the cpu background colors default to hidden 842187358Sjeff l = canvas.create_rectangle(fromx, 843139313Sjeff ypos - self.ysize() - canvas.bdheight, 844187358Sjeff tox, ypos + canvas.bdheight, fill=color, width=0, 845187379Sjeff tags=("cpubg", cpu, self.tag), state="hidden") 846187358Sjeff self.cpuitems.append(l) 847139313Sjeff 848187358Sjeff def move(self, canvas, xpos, ypos): 849187376Sjeff canvas.move(self.tag, xpos, ypos) 850187358Sjeff 851187358Sjeff def movename(self, canvas, xpos, ypos): 852187358Sjeff self.y += ypos 853187358Sjeff canvas.move(self.item, xpos, ypos) 854187358Sjeff 855139313Sjeff def ysize(self): 856187379Sjeff return (Y_EVENTSOURCE) 857139313Sjeff 858139313Sjeff def eventat(self, i): 859139313Sjeff if (i >= len(self.events)): 860139313Sjeff return (None) 861139313Sjeff event = self.events[i] 862139313Sjeff return (event) 863139313Sjeff 864139313Sjeff def findevent(self, timestamp): 865139313Sjeff for event in self.events: 866187358Sjeff if (event.timestamp >= timestamp and event.type != "pad"): 867139313Sjeff return (event) 868139313Sjeff return (None) 869139313Sjeff 870187358Sjeffclass Counter(EventSource): 871187358Sjeff # 872187358Sjeff # Store a hash of counter groups that keeps the max value 873187358Sjeff # for a counter in this group for scaling purposes. 874187358Sjeff # 875187358Sjeff groups = {} 876187358Sjeff def __init__(self, group, id): 877139313Sjeff try: 878187358Sjeff Counter.cnt = Counter.groups[group] 879139313Sjeff except: 880187358Sjeff Counter.groups[group] = 0 881187358Sjeff EventSource.__init__(self, group, id) 882139313Sjeff 883139313Sjeff def fixup(self): 884187358Sjeff for event in self.events: 885187358Sjeff if (event.type != "count"): 886187358Sjeff continue; 887187358Sjeff count = int(event.count) 888187358Sjeff if (count > Counter.groups[self.group]): 889187358Sjeff Counter.groups[self.group] = count 890187155Sjhb EventSource.fixup(self) 891139313Sjeff 892173743Ssam def ymax(self): 893187358Sjeff return (Counter.groups[self.group]) 894173743Ssam 895139313Sjeff def ysize(self): 896187379Sjeff return (Y_COUNTER) 897139313Sjeff 898139313Sjeff def yscale(self): 899187358Sjeff return (self.ysize() / self.ymax()) 900139313Sjeff 901139313Sjeffclass KTRFile: 902139313Sjeff def __init__(self, file): 903166209Sjeff self.timestamp_f = None 904166209Sjeff self.timestamp_l = None 905187156Sjhb self.locks = {} 906187156Sjhb self.callwheels = {} 907139313Sjeff self.ticks = {} 908139313Sjeff self.load = {} 909152663Sscottl self.crit = {} 910166209Sjeff self.stathz = 0 911187379Sjeff self.eventcnt = 0 912187471Sjeff self.taghash = {} 913139313Sjeff 914139313Sjeff self.parse(file) 915139313Sjeff self.fixup() 916139313Sjeff global ticksps 917139313Sjeff ticksps = self.ticksps() 918187379Sjeff span = self.timespan() 919187379Sjeff ghz = float(ticksps) / 1000000000.0 920187379Sjeff # 921187379Sjeff # Update the title with some stats from the file 922187379Sjeff # 923187379Sjeff titlestr = "SchedGraph: " 924187379Sjeff titlestr += ticks2sec(span) + " at %.3f ghz, " % ghz 925187379Sjeff titlestr += str(len(sources)) + " event sources, " 926187379Sjeff titlestr += str(self.eventcnt) + " events" 927187379Sjeff root.title(titlestr) 928139313Sjeff 929139313Sjeff def parse(self, file): 930139313Sjeff try: 931139313Sjeff ifp = open(file) 932139313Sjeff except: 933139313Sjeff print "Can't open", file 934139313Sjeff sys.exit(1) 935139313Sjeff 936187358Sjeff # quoteexp matches a quoted string, no escaping 937187358Sjeff quoteexp = "\"([^\"]*)\"" 938139313Sjeff 939187358Sjeff # 940187358Sjeff # commaexp matches a quoted string OR the string up 941187358Sjeff # to the first ',' 942187358Sjeff # 943187358Sjeff commaexp = "(?:" + quoteexp + "|([^,]+))" 944139313Sjeff 945187358Sjeff # 946187358Sjeff # colonstr matches a quoted string OR the string up 947187358Sjeff # to the first ':' 948187358Sjeff # 949187358Sjeff colonexp = "(?:" + quoteexp + "|([^:]+))" 950139313Sjeff 951187358Sjeff # 952187358Sjeff # Match various manditory parts of the KTR string this is 953187358Sjeff # fairly inflexible until you get to attributes to make 954187358Sjeff # parsing faster. 955187358Sjeff # 956187358Sjeff hdrexp = "\s*(\d+)\s+(\d+)\s+(\d+)\s+" 957187358Sjeff groupexp = "KTRGRAPH group:" + quoteexp + ", " 958187358Sjeff idexp = "id:" + quoteexp + ", " 959187358Sjeff typeexp = "([^:]+):" + commaexp + ", " 960187358Sjeff attribexp = "attributes: (.*)" 961139313Sjeff 962187358Sjeff # 963187358Sjeff # Matches optional attributes in the KTR string. This 964187358Sjeff # tolerates more variance as the users supply these values. 965187358Sjeff # 966187358Sjeff attrexp = colonexp + "\s*:\s*(?:" + commaexp + ", (.*)|" 967187358Sjeff attrexp += quoteexp +"|(.*))" 968139313Sjeff 969187358Sjeff # Precompile regexp 970187358Sjeff ktrre = re.compile(hdrexp + groupexp + idexp + typeexp + attribexp) 971187358Sjeff attrre = re.compile(attrexp) 972139313Sjeff 973173743Ssam global lineno 974173743Ssam lineno = 0 975178571Sjeff for line in ifp.readlines(): 976173743Ssam lineno += 1 977187358Sjeff if ((lineno % 2048) == 0): 978173743Ssam status.startup("Parsing line " + str(lineno)) 979187358Sjeff m = ktrre.match(line); 980173568Sjeff if (m == None): 981187358Sjeff print "Can't parse", lineno, line, 982187358Sjeff continue; 983187358Sjeff (index, cpu, timestamp, group, id, type, dat, dat1, attrstring) = m.groups(); 984187358Sjeff if (dat == None): 985187358Sjeff dat = dat1 986187358Sjeff if (self.checkstamp(timestamp) == 0): 987187471Sjeff print "Bad timestamp at", lineno, ":", 988187471Sjeff print cpu, timestamp 989187358Sjeff continue 990187358Sjeff # 991187358Sjeff # Build the table of optional attributes 992187358Sjeff # 993187358Sjeff attrs = [] 994187358Sjeff while (attrstring != None): 995187358Sjeff m = attrre.match(attrstring.strip()) 996187358Sjeff if (m == None): 997187358Sjeff break; 998187358Sjeff # 999187358Sjeff # Name may or may not be quoted. 1000187358Sjeff # 1001187358Sjeff # For val we have four cases: 1002187358Sjeff # 1) quotes followed by comma and more 1003187358Sjeff # attributes. 1004187358Sjeff # 2) no quotes followed by comma and more 1005187358Sjeff # attributes. 1006187358Sjeff # 3) no more attributes or comma with quotes. 1007187358Sjeff # 4) no more attributes or comma without quotes. 1008187358Sjeff # 1009187358Sjeff (name, name1, val, val1, attrstring, end, end1) = m.groups(); 1010187358Sjeff if (name == None): 1011187358Sjeff name = name1 1012187358Sjeff if (end == None): 1013187358Sjeff end = end1 1014187358Sjeff if (val == None): 1015187358Sjeff val = val1 1016187358Sjeff if (val == None): 1017187358Sjeff val = end 1018187358Sjeff if (name == "stathz"): 1019187358Sjeff self.setstathz(val, cpu) 1020187358Sjeff attrs.append((name, val)) 1021187358Sjeff args = (dat, cpu, timestamp, attrs) 1022187358Sjeff e = self.makeevent(group, id, type, args) 1023187358Sjeff if (e == None): 1024187358Sjeff print "Unknown type", type, lineno, line, 1025139313Sjeff 1026187358Sjeff def makeevent(self, group, id, type, args): 1027187358Sjeff e = None 1028187358Sjeff source = self.makeid(group, id, type) 1029187358Sjeff if (type == "state"): 1030187358Sjeff e = StateEvent(source, *args) 1031187358Sjeff elif (type == "counter"): 1032187358Sjeff e = CountEvent(source, *args) 1033187358Sjeff elif (type == "point"): 1034187358Sjeff e = PointEvent(source, *args) 1035187358Sjeff if (e != None): 1036187379Sjeff self.eventcnt += 1 1037187358Sjeff source.addevent(e); 1038187358Sjeff return e 1039139313Sjeff 1040187358Sjeff def setstathz(self, val, cpu): 1041187358Sjeff self.stathz = int(val) 1042139313Sjeff cpu = int(cpu) 1043139313Sjeff try: 1044139313Sjeff ticks = self.ticks[cpu] 1045139313Sjeff except: 1046139313Sjeff self.ticks[cpu] = 0 1047139313Sjeff self.ticks[cpu] += 1 1048139313Sjeff 1049187358Sjeff def checkstamp(self, timestamp): 1050187358Sjeff timestamp = int(timestamp) 1051187358Sjeff if (self.timestamp_f == None): 1052187358Sjeff self.timestamp_f = timestamp; 1053187471Sjeff if (self.timestamp_l != None and 1054187471Sjeff timestamp -2048> self.timestamp_l): 1055187358Sjeff return (0) 1056187358Sjeff self.timestamp_l = timestamp; 1057187358Sjeff return (1) 1058139313Sjeff 1059187358Sjeff def makeid(self, group, id, type): 1060187471Sjeff tag = group + id 1061187471Sjeff if (self.taghash.has_key(tag)): 1062187471Sjeff return self.taghash[tag] 1063187358Sjeff if (type == "counter"): 1064187358Sjeff source = Counter(group, id) 1065187358Sjeff else: 1066187358Sjeff source = EventSource(group, id) 1067187358Sjeff sources.append(source) 1068187471Sjeff self.taghash[tag] = source 1069187358Sjeff return (source) 1070139313Sjeff 1071187358Sjeff def findid(self, id): 1072187358Sjeff for source in sources: 1073187358Sjeff if (source.name == id): 1074187358Sjeff return source 1075187358Sjeff return (None) 1076173568Sjeff 1077187358Sjeff def timespan(self): 1078187358Sjeff return (self.timestamp_f - self.timestamp_l); 1079139313Sjeff 1080187358Sjeff def ticksps(self): 1081187358Sjeff oneghz = 1000000000 1082187358Sjeff # Use user supplied clock first 1083187358Sjeff if (clockfreq != None): 1084187358Sjeff return int(clockfreq * oneghz) 1085152663Sscottl 1086187358Sjeff # Check for a discovered clock 1087187471Sjeff if (self.stathz != 0): 1088187358Sjeff return (self.timespan() / self.ticks[0]) * int(self.stathz) 1089187358Sjeff # Pretend we have a 1ns clock 1090187358Sjeff print "WARNING: No clock discovered and no frequency ", 1091187358Sjeff print "specified via the command line." 1092187358Sjeff print "Using fake 1ghz clock" 1093187358Sjeff return (oneghz); 1094187156Sjhb 1095187358Sjeff def fixup(self): 1096187358Sjeff for source in sources: 1097187358Sjeff e = PadEvent(source, -1, self.timestamp_l) 1098187358Sjeff source.addevent(e) 1099187358Sjeff e = PadEvent(source, -1, self.timestamp_f, last=1) 1100187358Sjeff source.addlastevent(e) 1101187358Sjeff source.fixup() 1102187358Sjeff sources.sort() 1103187156Sjhb 1104187358Sjeffclass SchedNames(Canvas): 1105187358Sjeff def __init__(self, master, display): 1106187358Sjeff self.display = display 1107187358Sjeff self.parent = master 1108187358Sjeff self.bdheight = master.bdheight 1109187358Sjeff self.items = {} 1110187358Sjeff self.ysize = 0 1111187358Sjeff self.lines = [] 1112187358Sjeff Canvas.__init__(self, master, width=120, 1113187358Sjeff height=display["height"], bg='grey', 1114187358Sjeff scrollregion=(0, 0, 50, 100)) 1115187156Sjhb 1116187358Sjeff def moveline(self, cur_y, y): 1117187358Sjeff for line in self.lines: 1118187358Sjeff (x0, y0, x1, y1) = self.coords(line) 1119187358Sjeff if (cur_y != y0): 1120187358Sjeff continue 1121187358Sjeff self.move(line, 0, y) 1122187156Sjhb return 1123187156Sjhb 1124187358Sjeff def draw(self): 1125187358Sjeff status.startup("Drawing names") 1126187358Sjeff ypos = 0 1127187358Sjeff self.configure(scrollregion=(0, 0, 1128187358Sjeff self["width"], self.display.ysize())) 1129187358Sjeff for source in sources: 1130187358Sjeff l = self.create_line(0, ypos, self["width"], ypos, 1131187358Sjeff width=1, fill="black", tags=("all","sources")) 1132187358Sjeff self.lines.append(l) 1133187358Sjeff ypos += self.bdheight 1134187358Sjeff ypos += source.ysize() 1135187358Sjeff t = source.drawname(self, ypos) 1136187358Sjeff self.items[t] = source 1137187358Sjeff ypos += self.bdheight 1138187358Sjeff self.ysize = ypos 1139187358Sjeff self.create_line(0, ypos, self["width"], ypos, 1140187358Sjeff width=1, fill="black", tags=("all",)) 1141187358Sjeff self.bind("<Button-1>", self.master.mousepress); 1142187376Sjeff self.bind("<Button-3>", self.master.mousepressright); 1143187358Sjeff self.bind("<ButtonRelease-1>", self.master.mouserelease); 1144187358Sjeff self.bind("<B1-Motion>", self.master.mousemotion); 1145187156Sjhb 1146187359Sjeff def updatescroll(self): 1147187359Sjeff self.configure(scrollregion=(0, 0, 1148187359Sjeff self["width"], self.display.ysize())) 1149187156Sjhb 1150187359Sjeff 1151139313Sjeffclass SchedDisplay(Canvas): 1152139313Sjeff def __init__(self, master): 1153187155Sjhb self.ratio = 1 1154187155Sjhb self.parent = master 1155187358Sjeff self.bdheight = master.bdheight 1156187358Sjeff self.items = {} 1157187358Sjeff self.lines = [] 1158139313Sjeff Canvas.__init__(self, master, width=800, height=500, bg='grey', 1159139313Sjeff scrollregion=(0, 0, 800, 500)) 1160139313Sjeff 1161187358Sjeff def prepare(self): 1162187358Sjeff # 1163187155Sjhb # Compute a ratio to ensure that the file's timespan fits into 1164187155Sjhb # 2^31. Although python may handle larger values for X 1165187155Sjhb # values, the Tk internals do not. 1166187358Sjeff # 1167187155Sjhb self.ratio = (ktrfile.timespan() - 1) / 2**31 + 1 1168187155Sjhb 1169139313Sjeff def draw(self): 1170139313Sjeff ypos = 0 1171139313Sjeff xsize = self.xsize() 1172187358Sjeff for source in sources: 1173139313Sjeff status.startup("Drawing " + source.name) 1174187358Sjeff l = self.create_line(0, ypos, xsize, ypos, 1175139313Sjeff width=1, fill="black", tags=("all",)) 1176187358Sjeff self.lines.append(l) 1177139313Sjeff ypos += self.bdheight 1178139313Sjeff ypos += source.ysize() 1179139313Sjeff source.draw(self, ypos) 1180139313Sjeff ypos += self.bdheight 1181187379Sjeff self.tag_raise("point", "state") 1182187379Sjeff self.tag_lower("cpubg", ALL) 1183139313Sjeff self.create_line(0, ypos, xsize, ypos, 1184187379Sjeff width=1, fill="black", tags=("lines",)) 1185139313Sjeff self.tag_bind("event", "<Enter>", self.mouseenter) 1186139313Sjeff self.tag_bind("event", "<Leave>", self.mouseexit) 1187187358Sjeff self.bind("<Button-1>", self.mousepress) 1188187376Sjeff self.bind("<Button-3>", self.master.mousepressright); 1189187155Sjhb self.bind("<Button-4>", self.wheelup) 1190187155Sjhb self.bind("<Button-5>", self.wheeldown) 1191187358Sjeff self.bind("<ButtonRelease-1>", self.master.mouserelease); 1192187358Sjeff self.bind("<B1-Motion>", self.master.mousemotion); 1193139313Sjeff 1194187358Sjeff def moveline(self, cur_y, y): 1195187358Sjeff for line in self.lines: 1196187358Sjeff (x0, y0, x1, y1) = self.coords(line) 1197187358Sjeff if (cur_y != y0): 1198187358Sjeff continue 1199187358Sjeff self.move(line, 0, y) 1200187358Sjeff return 1201187358Sjeff 1202139313Sjeff def mouseenter(self, event): 1203139313Sjeff item, = self.find_withtag(CURRENT) 1204187358Sjeff self.items[item].mouseenter(self) 1205139313Sjeff 1206139313Sjeff def mouseexit(self, event): 1207139313Sjeff item, = self.find_withtag(CURRENT) 1208187358Sjeff self.items[item].mouseexit(self) 1209139313Sjeff 1210139313Sjeff def mousepress(self, event): 1211187358Sjeff # Find out what's beneath us 1212187358Sjeff items = self.find_withtag(CURRENT) 1213187358Sjeff if (len(items) == 0): 1214187358Sjeff self.master.mousepress(event) 1215187358Sjeff return 1216187358Sjeff # Only grab mouse presses for things with event tags. 1217187358Sjeff item = items[0] 1218187358Sjeff tags = self.gettags(item) 1219187358Sjeff for tag in tags: 1220187358Sjeff if (tag == "event"): 1221187358Sjeff self.items[item].mousepress(self) 1222187358Sjeff return 1223187358Sjeff # Leave the rest to the master window 1224187358Sjeff self.master.mousepress(event) 1225139313Sjeff 1226187155Sjhb def wheeldown(self, event): 1227187155Sjhb self.parent.display_yview("scroll", 1, "units") 1228187155Sjhb 1229187155Sjhb def wheelup(self, event): 1230187155Sjhb self.parent.display_yview("scroll", -1, "units") 1231187155Sjhb 1232139313Sjeff def xsize(self): 1233187379Sjeff return ((ktrfile.timespan() / self.ratio) + (X_BORDER * 2)) 1234139313Sjeff 1235139313Sjeff def ysize(self): 1236139313Sjeff ysize = 0 1237187358Sjeff for source in sources: 1238187359Sjeff if (source.hidden == 1): 1239187359Sjeff continue 1240187359Sjeff ysize += self.parent.sourcesize(source) 1241187358Sjeff return ysize 1242139313Sjeff 1243139313Sjeff def scaleset(self, ratio): 1244187358Sjeff if (ktrfile == None): 1245139313Sjeff return 1246139313Sjeff oldratio = self.ratio 1247187358Sjeff xstart, xend = self.xview() 1248187358Sjeff midpoint = xstart + ((xend - xstart) / 2) 1249139313Sjeff 1250139313Sjeff self.ratio = ratio 1251187359Sjeff self.updatescroll() 1252187379Sjeff self.scale(ALL, 0, 0, float(oldratio) / ratio, 1) 1253139313Sjeff 1254187358Sjeff xstart, xend = self.xview() 1255187358Sjeff xsize = (xend - xstart) / 2 1256187358Sjeff self.xview_moveto(midpoint - xsize) 1257139313Sjeff 1258187359Sjeff def updatescroll(self): 1259187359Sjeff self.configure(scrollregion=(0, 0, self.xsize(), self.ysize())) 1260187359Sjeff 1261139313Sjeff def scaleget(self): 1262139313Sjeff return self.ratio 1263139313Sjeff 1264187358Sjeff def getcolor(self, tag): 1265187358Sjeff return self.itemcget(tag, "fill") 1266187358Sjeff 1267187358Sjeff def getstate(self, tag): 1268187358Sjeff return self.itemcget(tag, "state") 1269187358Sjeff 1270139313Sjeff def setcolor(self, tag, color): 1271139313Sjeff self.itemconfigure(tag, state="normal", fill=color) 1272139313Sjeff 1273139313Sjeff def hide(self, tag): 1274139313Sjeff self.itemconfigure(tag, state="hidden") 1275139313Sjeff 1276139313Sjeffclass GraphMenu(Frame): 1277139313Sjeff def __init__(self, master): 1278139313Sjeff Frame.__init__(self, master, bd=2, relief=RAISED) 1279187376Sjeff self.conf = Menubutton(self, text="Configure") 1280187376Sjeff self.confmenu = Menu(self.conf, tearoff=0) 1281187376Sjeff self.confmenu.add_command(label="Event Colors", 1282139313Sjeff command=self.econf) 1283187376Sjeff self.confmenu.add_command(label="CPU Colors", 1284187358Sjeff command=self.cconf) 1285187376Sjeff self.confmenu.add_command(label="Source Configure", 1286187359Sjeff command=self.sconf) 1287187376Sjeff self.conf["menu"] = self.confmenu 1288187376Sjeff self.conf.pack(side=LEFT) 1289139313Sjeff 1290139313Sjeff def econf(self): 1291187358Sjeff ColorConfigure(eventcolors, "Event Display Configuration") 1292139313Sjeff 1293187358Sjeff def cconf(self): 1294187358Sjeff ColorConfigure(cpucolors, "CPU Background Colors") 1295139313Sjeff 1296187359Sjeff def sconf(self): 1297187359Sjeff SourceConfigure() 1298187358Sjeff 1299139313Sjeffclass SchedGraph(Frame): 1300139313Sjeff def __init__(self, master): 1301139313Sjeff Frame.__init__(self, master) 1302139313Sjeff self.menu = None 1303139313Sjeff self.names = None 1304139313Sjeff self.display = None 1305139313Sjeff self.scale = None 1306139313Sjeff self.status = None 1307187379Sjeff self.bdheight = Y_BORDER 1308187358Sjeff self.clicksource = None 1309187358Sjeff self.lastsource = None 1310139313Sjeff self.pack(expand=1, fill="both") 1311139313Sjeff self.buildwidgets() 1312139313Sjeff self.layout() 1313139313Sjeff 1314139313Sjeff def buildwidgets(self): 1315139313Sjeff global status 1316139313Sjeff self.menu = GraphMenu(self) 1317139313Sjeff self.display = SchedDisplay(self) 1318187358Sjeff self.names = SchedNames(self, self.display) 1319139313Sjeff self.scale = Scaler(self, self.display) 1320139313Sjeff status = self.status = Status(self) 1321139313Sjeff self.scrollY = Scrollbar(self, orient="vertical", 1322139313Sjeff command=self.display_yview) 1323139313Sjeff self.display.scrollX = Scrollbar(self, orient="horizontal", 1324139313Sjeff command=self.display.xview) 1325139313Sjeff self.display["xscrollcommand"] = self.display.scrollX.set 1326139313Sjeff self.display["yscrollcommand"] = self.scrollY.set 1327139313Sjeff self.names["yscrollcommand"] = self.scrollY.set 1328139313Sjeff 1329139313Sjeff def layout(self): 1330139313Sjeff self.columnconfigure(1, weight=1) 1331139313Sjeff self.rowconfigure(1, weight=1) 1332139313Sjeff self.menu.grid(row=0, column=0, columnspan=3, sticky=E+W) 1333139313Sjeff self.names.grid(row=1, column=0, sticky=N+S) 1334139313Sjeff self.display.grid(row=1, column=1, sticky=W+E+N+S) 1335139313Sjeff self.scrollY.grid(row=1, column=2, sticky=N+S) 1336139313Sjeff self.display.scrollX.grid(row=2, column=0, columnspan=2, 1337139313Sjeff sticky=E+W) 1338139313Sjeff self.scale.grid(row=3, column=0, columnspan=3, sticky=E+W) 1339139313Sjeff self.status.grid(row=4, column=0, columnspan=3, sticky=E+W) 1340139313Sjeff 1341187358Sjeff def draw(self): 1342139313Sjeff self.master.update() 1343187358Sjeff self.display.prepare() 1344187358Sjeff self.names.draw() 1345139313Sjeff self.display.draw() 1346187358Sjeff self.status.startup("") 1347187471Sjeff # 1348187471Sjeff # Configure scale related values 1349187471Sjeff # 1350187471Sjeff scalemax = ktrfile.timespan() / int(self.display["width"]) 1351187471Sjeff width = int(root.geometry().split('x')[0]) 1352187471Sjeff self.constwidth = width - int(self.display["width"]) 1353187471Sjeff self.scale.setmax(scalemax) 1354187471Sjeff self.scale.set(scalemax) 1355139313Sjeff self.display.xview_moveto(0) 1356187471Sjeff self.bind("<Configure>", self.resize) 1357139313Sjeff 1358187358Sjeff def mousepress(self, event): 1359187358Sjeff self.clicksource = self.sourceat(event.y) 1360187358Sjeff 1361187376Sjeff def mousepressright(self, event): 1362187376Sjeff source = self.sourceat(event.y) 1363187376Sjeff if (source == None): 1364187376Sjeff return 1365187376Sjeff SourceContext(event, source) 1366187376Sjeff 1367187358Sjeff def mouserelease(self, event): 1368187358Sjeff if (self.clicksource == None): 1369187358Sjeff return 1370187358Sjeff newsource = self.sourceat(event.y) 1371187358Sjeff if (self.clicksource != newsource): 1372187358Sjeff self.sourceswap(self.clicksource, newsource) 1373187358Sjeff self.clicksource = None 1374187358Sjeff self.lastsource = None 1375187358Sjeff 1376187358Sjeff def mousemotion(self, event): 1377187358Sjeff if (self.clicksource == None): 1378187358Sjeff return 1379187358Sjeff newsource = self.sourceat(event.y) 1380187358Sjeff # 1381187358Sjeff # If we get a None source they moved off the page. 1382187358Sjeff # swapsource() can't handle moving multiple items so just 1383187358Sjeff # pretend we never clicked on anything to begin with so the 1384187358Sjeff # user can't mouseover a non-contiguous area. 1385187358Sjeff # 1386187358Sjeff if (newsource == None): 1387187358Sjeff self.clicksource = None 1388187358Sjeff self.lastsource = None 1389187358Sjeff return 1390187358Sjeff if (newsource == self.lastsource): 1391187358Sjeff return; 1392187358Sjeff self.lastsource = newsource 1393187358Sjeff if (newsource != self.clicksource): 1394187358Sjeff self.sourceswap(self.clicksource, newsource) 1395187358Sjeff 1396187358Sjeff # These are here because this object controls layout 1397187358Sjeff def sourcestart(self, source): 1398187358Sjeff return source.y - self.bdheight - source.ysize() 1399187358Sjeff 1400187358Sjeff def sourceend(self, source): 1401187358Sjeff return source.y + self.bdheight 1402187358Sjeff 1403187358Sjeff def sourcesize(self, source): 1404187358Sjeff return (self.bdheight * 2) + source.ysize() 1405187358Sjeff 1406187358Sjeff def sourceswap(self, source1, source2): 1407187358Sjeff # Sort so we always know which one is on top. 1408187358Sjeff if (source2.y < source1.y): 1409187358Sjeff swap = source1 1410187358Sjeff source1 = source2 1411187358Sjeff source2 = swap 1412187358Sjeff # Only swap adjacent sources 1413187358Sjeff if (self.sourceend(source1) != self.sourcestart(source2)): 1414187358Sjeff return 1415187358Sjeff # Compute start coordinates and target coordinates 1416187358Sjeff y1 = self.sourcestart(source1) 1417187358Sjeff y2 = self.sourcestart(source2) 1418187358Sjeff y1targ = y1 + self.sourcesize(source2) 1419187358Sjeff y2targ = y1 1420187358Sjeff # 1421187358Sjeff # If the sizes are not equal, adjust the start of the lower 1422187358Sjeff # source to account for the lost/gained space. 1423187358Sjeff # 1424187358Sjeff if (source1.ysize() != source2.ysize()): 1425187358Sjeff diff = source2.ysize() - source1.ysize() 1426187358Sjeff self.names.moveline(y2, diff); 1427187358Sjeff self.display.moveline(y2, diff) 1428187358Sjeff source1.move(self.display, 0, y1targ - y1) 1429187358Sjeff source2.move(self.display, 0, y2targ - y2) 1430187358Sjeff source1.movename(self.names, 0, y1targ - y1) 1431187358Sjeff source2.movename(self.names, 0, y2targ - y2) 1432187358Sjeff 1433187376Sjeff def sourcepicky(self, source): 1434187359Sjeff if (source.hidden == 0): 1435187376Sjeff return self.sourcestart(source) 1436187376Sjeff # Revert to group based sort 1437187376Sjeff sources.sort() 1438187359Sjeff prev = None 1439187359Sjeff for s in sources: 1440187359Sjeff if (s == source): 1441187359Sjeff break 1442187359Sjeff if (s.hidden == 0): 1443187359Sjeff prev = s 1444187359Sjeff if (prev == None): 1445187359Sjeff newy = 0 1446187359Sjeff else: 1447187359Sjeff newy = self.sourcestart(prev) + self.sourcesize(prev) 1448187376Sjeff return newy 1449187376Sjeff 1450187376Sjeff def sourceshow(self, source): 1451187376Sjeff if (source.hidden == 0): 1452187376Sjeff return; 1453187376Sjeff newy = self.sourcepicky(source) 1454187376Sjeff off = newy - self.sourcestart(source) 1455187359Sjeff self.sourceshiftall(newy-1, self.sourcesize(source)) 1456187359Sjeff self.sourceshift(source, off) 1457187359Sjeff source.hidden = 0 1458187359Sjeff 1459187376Sjeff # 1460187376Sjeff # Optimized source show of multiple entries that only moves each 1461187376Sjeff # existing entry once. Doing sourceshow() iteratively is too 1462187376Sjeff # expensive due to python's canvas.move(). 1463187376Sjeff # 1464187376Sjeff def sourceshowlist(self, srclist): 1465187376Sjeff srclist.sort(cmp=source_cmp_start) 1466187376Sjeff startsize = [] 1467187376Sjeff for source in srclist: 1468187376Sjeff if (source.hidden == 0): 1469187376Sjeff srclist.remove(source) 1470187376Sjeff startsize.append((self.sourcepicky(source), 1471187376Sjeff self.sourcesize(source))) 1472187376Sjeff 1473187376Sjeff sources.sort(cmp=source_cmp_start, reverse=True) 1474187376Sjeff self.status.startup("Updating display..."); 1475187376Sjeff for source in sources: 1476187376Sjeff if (source.hidden == 1): 1477187376Sjeff continue 1478187376Sjeff nstart = self.sourcestart(source) 1479187376Sjeff size = 0 1480187376Sjeff for hidden in startsize: 1481187376Sjeff (start, sz) = hidden 1482187376Sjeff if (start <= nstart or start+sz <= nstart): 1483187376Sjeff size += sz 1484187376Sjeff self.sourceshift(source, size) 1485187376Sjeff idx = 0 1486187376Sjeff size = 0 1487187376Sjeff for source in srclist: 1488187376Sjeff (newy, sz) = startsize[idx] 1489187376Sjeff off = (newy + size) - self.sourcestart(source) 1490187376Sjeff self.sourceshift(source, off) 1491187376Sjeff source.hidden = 0 1492187376Sjeff size += sz 1493187376Sjeff idx += 1 1494187471Sjeff self.updatescroll() 1495187376Sjeff self.status.set("") 1496187376Sjeff 1497187376Sjeff # 1498187376Sjeff # Optimized source hide of multiple entries that only moves each 1499187376Sjeff # remaining entry once. Doing sourcehide() iteratively is too 1500187376Sjeff # expensive due to python's canvas.move(). 1501187376Sjeff # 1502187376Sjeff def sourcehidelist(self, srclist): 1503187376Sjeff srclist.sort(cmp=source_cmp_start) 1504187376Sjeff sources.sort(cmp=source_cmp_start) 1505187376Sjeff startsize = [] 1506187376Sjeff off = len(sources) * 100 1507187376Sjeff self.status.startup("Updating display..."); 1508187376Sjeff for source in srclist: 1509187376Sjeff if (source.hidden == 1): 1510187376Sjeff srclist.remove(source) 1511187376Sjeff # 1512187376Sjeff # Remember our old position so we can sort things 1513187376Sjeff # below us when we're done. 1514187376Sjeff # 1515187376Sjeff startsize.append((self.sourcestart(source), 1516187376Sjeff self.sourcesize(source))) 1517187376Sjeff self.sourceshift(source, off) 1518187376Sjeff source.hidden = 1 1519187376Sjeff 1520187376Sjeff idx = 0 1521187376Sjeff size = 0 1522187376Sjeff for hidden in startsize: 1523187376Sjeff (start, sz) = hidden 1524187376Sjeff size += sz 1525187376Sjeff if (idx + 1 < len(startsize)): 1526187376Sjeff (stop, sz) = startsize[idx+1] 1527187376Sjeff else: 1528187376Sjeff stop = self.display.ysize() 1529187376Sjeff idx += 1 1530187376Sjeff for source in sources: 1531187376Sjeff nstart = self.sourcestart(source) 1532187376Sjeff if (nstart < start or source.hidden == 1): 1533187376Sjeff continue 1534187376Sjeff if (nstart >= stop): 1535187376Sjeff break; 1536187376Sjeff self.sourceshift(source, -size) 1537187471Sjeff self.updatescroll() 1538187376Sjeff self.status.set("") 1539187376Sjeff 1540187359Sjeff def sourcehide(self, source): 1541187376Sjeff if (source.hidden == 1): 1542187376Sjeff return; 1543187359Sjeff # Move it out of the visible area 1544187359Sjeff off = len(sources) * 100 1545187359Sjeff start = self.sourcestart(source) 1546187359Sjeff self.sourceshift(source, off) 1547187359Sjeff self.sourceshiftall(start, -self.sourcesize(source)) 1548187359Sjeff source.hidden = 1 1549187359Sjeff 1550187359Sjeff def sourceshift(self, source, off): 1551187359Sjeff start = self.sourcestart(source) 1552187359Sjeff source.move(self.display, 0, off) 1553187359Sjeff source.movename(self.names, 0, off) 1554187359Sjeff self.names.moveline(start, off); 1555187359Sjeff self.display.moveline(start, off) 1556187376Sjeff # 1557187376Sjeff # We update the idle tasks to shrink the dirtied area so 1558187376Sjeff # it does not always include the entire screen. 1559187376Sjeff # 1560187376Sjeff self.names.update_idletasks() 1561187376Sjeff self.display.update_idletasks() 1562187359Sjeff 1563187359Sjeff def sourceshiftall(self, start, off): 1564187376Sjeff self.status.startup("Updating display..."); 1565187359Sjeff for source in sources: 1566187359Sjeff nstart = self.sourcestart(source) 1567187359Sjeff if (nstart < start): 1568187359Sjeff continue; 1569187359Sjeff self.sourceshift(source, off) 1570187471Sjeff self.updatescroll() 1571187376Sjeff self.status.set("") 1572187359Sjeff 1573187358Sjeff def sourceat(self, ypos): 1574187358Sjeff (start, end) = self.names.yview() 1575187358Sjeff starty = start * float(self.names.ysize) 1576187358Sjeff ypos += starty 1577187358Sjeff for source in sources: 1578187359Sjeff if (source.hidden == 1): 1579187359Sjeff continue; 1580187358Sjeff yend = self.sourceend(source) 1581187358Sjeff ystart = self.sourcestart(source) 1582187358Sjeff if (ypos >= ystart and ypos <= yend): 1583187358Sjeff return source 1584187358Sjeff return None 1585187358Sjeff 1586139313Sjeff def display_yview(self, *args): 1587139313Sjeff self.names.yview(*args) 1588139313Sjeff self.display.yview(*args) 1589139313Sjeff 1590187471Sjeff def resize(self, *args): 1591187471Sjeff width = int(root.geometry().split('x')[0]) 1592187471Sjeff scalemax = ktrfile.timespan() / (width - self.constwidth) 1593187471Sjeff self.scale.setmax(scalemax) 1594187471Sjeff 1595187471Sjeff def updatescroll(self): 1596187471Sjeff self.names.updatescroll() 1597187471Sjeff self.display.updatescroll() 1598187471Sjeff 1599139313Sjeff def setcolor(self, tag, color): 1600139313Sjeff self.display.setcolor(tag, color) 1601139313Sjeff 1602139313Sjeff def hide(self, tag): 1603139313Sjeff self.display.hide(tag) 1604139313Sjeff 1605187358Sjeff def getcolor(self, tag): 1606187358Sjeff return self.display.getcolor(tag) 1607187358Sjeff 1608187358Sjeff def getstate(self, tag): 1609187358Sjeff return self.display.getstate(tag) 1610187358Sjeff 1611187358Sjeffif (len(sys.argv) != 2 and len(sys.argv) != 3): 1612187358Sjeff print "usage:", sys.argv[0], "<ktr file> [clock freq in ghz]" 1613139313Sjeff sys.exit(1) 1614139313Sjeff 1615187358Sjeffif (len(sys.argv) > 2): 1616187358Sjeff clockfreq = float(sys.argv[2]) 1617187358Sjeff 1618139313Sjeffroot = Tk() 1619187379Sjeffroot.title("SchedGraph") 1620187358Sjeffcolormap = Colormap(eventcolors) 1621187358Sjeffcpucolormap = Colormap(cpucolors) 1622139313Sjeffgraph = SchedGraph(root) 1623187358Sjeffktrfile = KTRFile(sys.argv[1]) 1624187358Sjeffgraph.draw() 1625139313Sjeffroot.mainloop() 1626