1dcee3bd3SJeff Roberson#!/usr/local/bin/python 2dcee3bd3SJeff Roberson 3b62baf95SJeff Roberson# Copyright (c) 2002-2003, 2009, Jeffrey Roberson <jeff@freebsd.org> 4dcee3bd3SJeff Roberson# All rights reserved. 5dcee3bd3SJeff Roberson# 6dcee3bd3SJeff Roberson# Redistribution and use in source and binary forms, with or without 7dcee3bd3SJeff Roberson# modification, are permitted provided that the following conditions 8dcee3bd3SJeff Roberson# are met: 9dcee3bd3SJeff Roberson# 1. Redistributions of source code must retain the above copyright 10dcee3bd3SJeff Roberson# notice unmodified, this list of conditions, and the following 11dcee3bd3SJeff Roberson# disclaimer. 12dcee3bd3SJeff Roberson# 2. Redistributions in binary form must reproduce the above copyright 13dcee3bd3SJeff Roberson# notice, this list of conditions and the following disclaimer in the 14dcee3bd3SJeff Roberson# documentation and/or other materials provided with the distribution. 15dcee3bd3SJeff Roberson# 16dcee3bd3SJeff Roberson# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17dcee3bd3SJeff Roberson# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18dcee3bd3SJeff Roberson# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19dcee3bd3SJeff Roberson# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20dcee3bd3SJeff Roberson# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21dcee3bd3SJeff Roberson# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22dcee3bd3SJeff Roberson# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23dcee3bd3SJeff Roberson# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24dcee3bd3SJeff Roberson# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25dcee3bd3SJeff Roberson# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26dcee3bd3SJeff Roberson# 27dcee3bd3SJeff Roberson 28749f65e3SCraig Rodriguesfrom __future__ import print_function 29dcee3bd3SJeff Robersonimport sys 30dcee3bd3SJeff Robersonimport re 31ec5cae07SJeff Robersonimport random 32*7e8ed296SAndriy Gaponfrom operator import attrgetter, itemgetter 33*7e8ed296SAndriy Gaponfrom functools import total_ordering 34*7e8ed296SAndriy Gaponfrom tkinter import * 35dcee3bd3SJeff Roberson 36698e6141SAndrew R. Reiter# To use: 3766835de4SSam Leffler# - Install the ports/x11-toolkits/py-tkinter package; e.g. 38*7e8ed296SAndriy Gapon# pkg install x11-toolkits/py-tkinter 3966835de4SSam Leffler# - Add KTR_SCHED to KTR_COMPILE and KTR_MASK in your KERNCONF; e.g. 4066835de4SSam Leffler# options KTR 4166835de4SSam Leffler# options KTR_ENTRIES=32768 4266835de4SSam Leffler# options KTR_COMPILE=(KTR_SCHED) 4366835de4SSam Leffler# options KTR_MASK=(KTR_SCHED) 4466835de4SSam Leffler# - It is encouraged to increase KTR_ENTRIES size to gather enough 4566835de4SSam Leffler# information for analysis; e.g. 4666835de4SSam Leffler# options KTR_ENTRIES=262144 47e73e7730SKris Kennaway# as 32768 entries may only correspond to a second or two of profiling 48e73e7730SKris Kennaway# data depending on your workload. 4970015002SKris Kennaway# - Rebuild kernel with proper changes to KERNCONF and boot new kernel. 5070015002SKris Kennaway# - Run your workload to be profiled. 5170015002SKris Kennaway# - While the workload is continuing (i.e. before it finishes), disable 5270015002SKris Kennaway# KTR tracing by setting 'sysctl debug.ktr.mask=0'. This is necessary 5370015002SKris Kennaway# to avoid a race condition while running ktrdump, i.e. the KTR ring buffer 5470015002SKris Kennaway# will cycle a bit while ktrdump runs, and this confuses schedgraph because 5570015002SKris Kennaway# the timestamps appear to go backwards at some point. Stopping KTR logging 5670015002SKris Kennaway# while the workload is still running is to avoid wasting log entries on 5770015002SKris Kennaway# "idle" time at the end. 58698e6141SAndrew R. Reiter# - Dump the trace to a file: 'ktrdump -ct > ktr.out' 59*7e8ed296SAndriy Gapon# - Alternatively, use schedgraph.d script in this directory for getting 60*7e8ed296SAndriy Gapon# the trace data by means of DTrace. See the script for details. 61ec5cae07SJeff Roberson# - Run the python script: 'python schedgraph.py ktr.out' optionally provide 62ec5cae07SJeff Roberson# your cpu frequency in ghz: 'python schedgraph.py ktr.out 2.4' 63698e6141SAndrew R. Reiter# 64698e6141SAndrew R. Reiter# To do: 65ec5cae07SJeff Roberson# Add a per-source summary display 66ec5cae07SJeff Roberson# "Vertical rule" to help relate data in different rows 67ec5cae07SJeff Roberson# Mouse-over popup of full thread/event/row label (currently truncated) 68ec5cae07SJeff Roberson# More visible anchors for popup event windows 6970015002SKris Kennaway# 7070015002SKris Kennaway# BUGS: 1) Only 8 CPUs are supported, more CPUs require more choices of 7170015002SKris Kennaway# colours to represent them ;-) 72ec5cae07SJeff Roberson 73ec5cae07SJeff Robersoneventcolors = [ 74ec5cae07SJeff Roberson ("count", "red"), 75ec5cae07SJeff Roberson ("running", "green"), 76ec5cae07SJeff Roberson ("idle", "grey"), 772cba8dd3SJohn Baldwin ("spinning", "red"), 78ec5cae07SJeff Roberson ("yielding", "yellow"), 79ec5cae07SJeff Roberson ("swapped", "violet"), 80ec5cae07SJeff Roberson ("suspended", "purple"), 81ec5cae07SJeff Roberson ("iwait", "grey"), 82ec5cae07SJeff Roberson ("sleep", "blue"), 83ec5cae07SJeff Roberson ("blocked", "dark red"), 84ec5cae07SJeff Roberson ("runq add", "yellow"), 85ec5cae07SJeff Roberson ("runq rem", "yellow"), 86ec5cae07SJeff Roberson ("thread exit", "grey"), 87ec5cae07SJeff Roberson ("proc exit", "grey"), 88ec5cae07SJeff Roberson ("lock acquire", "blue"), 89ec5cae07SJeff Roberson ("lock contest", "purple"), 90ec5cae07SJeff Roberson ("failed lock try", "red"), 91ec5cae07SJeff Roberson ("lock release", "grey"), 92932f0fa2SJeff Roberson ("statclock", "black"), 93ec5cae07SJeff Roberson ("prio", "black"), 94ec5cae07SJeff Roberson ("lend prio", "black"), 95ec5cae07SJeff Roberson ("wokeup", "black") 96ec5cae07SJeff Roberson] 97ec5cae07SJeff Roberson 98ec5cae07SJeff Robersoncpucolors = [ 99ec5cae07SJeff Roberson ("CPU 0", "light grey"), 100ec5cae07SJeff Roberson ("CPU 1", "dark grey"), 101ec5cae07SJeff Roberson ("CPU 2", "light blue"), 102ec5cae07SJeff Roberson ("CPU 3", "light pink"), 103ec5cae07SJeff Roberson ("CPU 4", "blanched almond"), 104ec5cae07SJeff Roberson ("CPU 5", "slate grey"), 105ec5cae07SJeff Roberson ("CPU 6", "tan"), 106ec5cae07SJeff Roberson ("CPU 7", "thistle"), 107ec5cae07SJeff Roberson ("CPU 8", "white") 108ec5cae07SJeff Roberson] 109ec5cae07SJeff Roberson 110ec5cae07SJeff Robersoncolors = [ 111ec5cae07SJeff Roberson "white", "thistle", "blanched almond", "tan", "chartreuse", 112ec5cae07SJeff Roberson "dark red", "red", "pale violet red", "pink", "light pink", 113ec5cae07SJeff Roberson "dark orange", "orange", "coral", "light coral", 114ec5cae07SJeff Roberson "goldenrod", "gold", "yellow", "light yellow", 115ec5cae07SJeff Roberson "dark green", "green", "light green", "light sea green", 116ec5cae07SJeff Roberson "dark blue", "blue", "light blue", "steel blue", "light slate blue", 117ec5cae07SJeff Roberson "dark violet", "violet", "purple", "blue violet", 118ec5cae07SJeff Roberson "dark grey", "slate grey", "light grey", 119ec5cae07SJeff Roberson "black", 120ec5cae07SJeff Roberson] 121ec5cae07SJeff Robersoncolors.sort() 122dcee3bd3SJeff Roberson 123dcee3bd3SJeff Robersonticksps = None 124dcee3bd3SJeff Robersonstatus = None 125ec5cae07SJeff Robersoncolormap = None 126ec5cae07SJeff Robersonktrfile = None 127ec5cae07SJeff Robersonclockfreq = None 128ec5cae07SJeff Robersonsources = [] 12966835de4SSam Lefflerlineno = -1 130dcee3bd3SJeff Roberson 131932f0fa2SJeff RobersonY_BORDER = 10 132932f0fa2SJeff RobersonX_BORDER = 10 133932f0fa2SJeff RobersonY_COUNTER = 80 134932f0fa2SJeff RobersonY_EVENTSOURCE = 10 135932f0fa2SJeff RobersonXY_POINT = 4 136932f0fa2SJeff Roberson 137ec5cae07SJeff Robersonclass Colormap: 138ec5cae07SJeff Roberson def __init__(self, table): 139ec5cae07SJeff Roberson self.table = table 140ec5cae07SJeff Roberson self.map = {} 141ec5cae07SJeff Roberson for entry in table: 142ec5cae07SJeff Roberson self.map[entry[0]] = entry[1] 143ec5cae07SJeff Roberson 144ec5cae07SJeff Roberson def lookup(self, name): 145ec5cae07SJeff Roberson try: 146ec5cae07SJeff Roberson color = self.map[name] 147ec5cae07SJeff Roberson except: 148ec5cae07SJeff Roberson color = colors[random.randrange(0, len(colors))] 149749f65e3SCraig Rodrigues print("Picking random color", color, "for", name) 150ec5cae07SJeff Roberson self.map[name] = color 151ec5cae07SJeff Roberson self.table.append((name, color)) 152ec5cae07SJeff Roberson return (color) 153ec5cae07SJeff Roberson 154dcee3bd3SJeff Robersondef ticks2sec(ticks): 155b62baf95SJeff Roberson ticks = float(ticks) 156b62baf95SJeff Roberson ns = float(ticksps) / 1000000000 157b62baf95SJeff Roberson ticks /= ns 158dcee3bd3SJeff Roberson if (ticks < 1000): 159b62baf95SJeff Roberson return ("%.2fns" % ticks) 160dcee3bd3SJeff Roberson ticks /= 1000 161dcee3bd3SJeff Roberson if (ticks < 1000): 162b62baf95SJeff Roberson return ("%.2fus" % ticks) 163dcee3bd3SJeff Roberson ticks /= 1000 164b62baf95SJeff Roberson if (ticks < 1000): 165b62baf95SJeff Roberson return ("%.2fms" % ticks) 166b62baf95SJeff Roberson ticks /= 1000 167b62baf95SJeff Roberson return ("%.2fs" % ticks) 168dcee3bd3SJeff Roberson 169dcee3bd3SJeff Robersonclass Scaler(Frame): 170dcee3bd3SJeff Roberson def __init__(self, master, target): 171dcee3bd3SJeff Roberson Frame.__init__(self, master) 17216ef0f3bSJeff Roberson self.scale = None 17316ef0f3bSJeff Roberson self.target = target 174dcee3bd3SJeff Roberson self.label = Label(self, text="Ticks per pixel") 175dcee3bd3SJeff Roberson self.label.pack(side=LEFT) 17616ef0f3bSJeff Roberson self.resolution = 100 17716ef0f3bSJeff Roberson self.setmax(10000) 178dcee3bd3SJeff Roberson 179dcee3bd3SJeff Roberson def scaleset(self, value): 180dcee3bd3SJeff Roberson self.target.scaleset(int(value)) 181dcee3bd3SJeff Roberson 182dcee3bd3SJeff Roberson def set(self, value): 183dcee3bd3SJeff Roberson self.scale.set(value) 184dcee3bd3SJeff Roberson 18516ef0f3bSJeff Roberson def setmax(self, value): 18616ef0f3bSJeff Roberson # 18716ef0f3bSJeff Roberson # We can't reconfigure the to_ value so we delete the old 18816ef0f3bSJeff Roberson # window and make a new one when we resize. 18916ef0f3bSJeff Roberson # 19016ef0f3bSJeff Roberson if (self.scale != None): 19116ef0f3bSJeff Roberson self.scale.pack_forget() 19216ef0f3bSJeff Roberson self.scale.destroy() 19316ef0f3bSJeff Roberson self.scale = Scale(self, command=self.scaleset, 19416ef0f3bSJeff Roberson from_=100, to_=value, orient=HORIZONTAL, 19516ef0f3bSJeff Roberson resolution=self.resolution) 19616ef0f3bSJeff Roberson self.scale.pack(fill="both", expand=1) 19716ef0f3bSJeff Roberson self.scale.set(self.target.scaleget()) 19816ef0f3bSJeff Roberson 199dcee3bd3SJeff Robersonclass Status(Frame): 200dcee3bd3SJeff Roberson def __init__(self, master): 201dcee3bd3SJeff Roberson Frame.__init__(self, master) 202dcee3bd3SJeff Roberson self.label = Label(self, bd=1, relief=SUNKEN, anchor=W) 203dcee3bd3SJeff Roberson self.label.pack(fill="both", expand=1) 204dcee3bd3SJeff Roberson self.clear() 205dcee3bd3SJeff Roberson 206dcee3bd3SJeff Roberson def set(self, str): 207dcee3bd3SJeff Roberson self.label.config(text=str) 208dcee3bd3SJeff Roberson 209dcee3bd3SJeff Roberson def clear(self): 210dcee3bd3SJeff Roberson self.label.config(text="") 211dcee3bd3SJeff Roberson 212dcee3bd3SJeff Roberson def startup(self, str): 213dcee3bd3SJeff Roberson self.set(str) 214dcee3bd3SJeff Roberson root.update() 215dcee3bd3SJeff Roberson 216ec5cae07SJeff Robersonclass ColorConf(Frame): 217ec5cae07SJeff Roberson def __init__(self, master, name, color): 218dcee3bd3SJeff Roberson Frame.__init__(self, master) 219ec5cae07SJeff Roberson if (graph.getstate(name) == "hidden"): 220ec5cae07SJeff Roberson enabled = 0 221ec5cae07SJeff Roberson else: 222ec5cae07SJeff Roberson enabled = 1 223dcee3bd3SJeff Roberson self.name = name 224dcee3bd3SJeff Roberson self.color = StringVar() 225dcee3bd3SJeff Roberson self.color_default = color 226dcee3bd3SJeff Roberson self.color_current = color 227dcee3bd3SJeff Roberson self.color.set(color) 228dcee3bd3SJeff Roberson self.enabled = IntVar() 229dcee3bd3SJeff Roberson self.enabled_default = enabled 230dcee3bd3SJeff Roberson self.enabled_current = enabled 231dcee3bd3SJeff Roberson self.enabled.set(enabled) 232dcee3bd3SJeff Roberson self.draw() 233dcee3bd3SJeff Roberson 234dcee3bd3SJeff Roberson def draw(self): 235dcee3bd3SJeff Roberson self.label = Label(self, text=self.name, anchor=W) 236dcee3bd3SJeff Roberson self.sample = Canvas(self, width=24, height=24, 237dcee3bd3SJeff Roberson bg='grey') 238dcee3bd3SJeff Roberson self.rect = self.sample.create_rectangle(0, 0, 24, 24, 239dcee3bd3SJeff Roberson fill=self.color.get()) 240ec5cae07SJeff Roberson self.list = OptionMenu(self, self.color, command=self.setcolor, 241ec5cae07SJeff Roberson *colors) 242dcee3bd3SJeff Roberson self.checkbox = Checkbutton(self, text="enabled", 243dcee3bd3SJeff Roberson variable=self.enabled) 244dcee3bd3SJeff Roberson self.label.grid(row=0, column=0, sticky=E+W) 245dcee3bd3SJeff Roberson self.sample.grid(row=0, column=1) 246dcee3bd3SJeff Roberson self.list.grid(row=0, column=2, sticky=E+W) 247dcee3bd3SJeff Roberson self.checkbox.grid(row=0, column=3) 248dcee3bd3SJeff Roberson self.columnconfigure(0, weight=1) 249ec5cae07SJeff Roberson self.columnconfigure(2, minsize=150) 250dcee3bd3SJeff Roberson 251dcee3bd3SJeff Roberson def setcolor(self, color): 252dcee3bd3SJeff Roberson self.color.set(color) 253dcee3bd3SJeff Roberson self.sample.itemconfigure(self.rect, fill=color) 254dcee3bd3SJeff Roberson 255dcee3bd3SJeff Roberson def apply(self): 256dcee3bd3SJeff Roberson cchange = 0 257dcee3bd3SJeff Roberson echange = 0 258dcee3bd3SJeff Roberson if (self.color_current != self.color.get()): 259dcee3bd3SJeff Roberson cchange = 1 260dcee3bd3SJeff Roberson if (self.enabled_current != self.enabled.get()): 261dcee3bd3SJeff Roberson echange = 1 262dcee3bd3SJeff Roberson self.color_current = self.color.get() 263dcee3bd3SJeff Roberson self.enabled_current = self.enabled.get() 264dcee3bd3SJeff Roberson if (echange != 0): 265dcee3bd3SJeff Roberson if (self.enabled_current): 266dcee3bd3SJeff Roberson graph.setcolor(self.name, self.color_current) 267dcee3bd3SJeff Roberson else: 268dcee3bd3SJeff Roberson graph.hide(self.name) 269dcee3bd3SJeff Roberson return 270dcee3bd3SJeff Roberson if (cchange != 0): 271dcee3bd3SJeff Roberson graph.setcolor(self.name, self.color_current) 272dcee3bd3SJeff Roberson 273dcee3bd3SJeff Roberson def revert(self): 274dcee3bd3SJeff Roberson self.setcolor(self.color_default) 275dcee3bd3SJeff Roberson self.enabled.set(self.enabled_default) 276dcee3bd3SJeff Roberson 277ec5cae07SJeff Robersonclass ColorConfigure(Toplevel): 278ec5cae07SJeff Roberson def __init__(self, table, name): 279dcee3bd3SJeff Roberson Toplevel.__init__(self) 280dcee3bd3SJeff Roberson self.resizable(0, 0) 281ec5cae07SJeff Roberson self.title(name) 282ec5cae07SJeff Roberson self.items = LabelFrame(self, text="Item Type") 283dcee3bd3SJeff Roberson self.buttons = Frame(self) 284dcee3bd3SJeff Roberson self.drawbuttons() 285dcee3bd3SJeff Roberson self.items.grid(row=0, column=0, sticky=E+W) 286dcee3bd3SJeff Roberson self.columnconfigure(0, weight=1) 287dcee3bd3SJeff Roberson self.buttons.grid(row=1, column=0, sticky=E+W) 288dcee3bd3SJeff Roberson self.types = [] 289dcee3bd3SJeff Roberson self.irow = 0 290ec5cae07SJeff Roberson for type in table: 291ec5cae07SJeff Roberson color = graph.getcolor(type[0]) 292ec5cae07SJeff Roberson if (color != ""): 293ec5cae07SJeff Roberson self.additem(type[0], color) 2949799411bSJohn Baldwin self.bind("<Control-w>", self.destroycb) 2959799411bSJohn Baldwin 2969799411bSJohn Baldwin def destroycb(self, event): 2979799411bSJohn Baldwin self.destroy() 298dcee3bd3SJeff Roberson 299ec5cae07SJeff Roberson def additem(self, name, color): 300ec5cae07SJeff Roberson item = ColorConf(self.items, name, color) 301dcee3bd3SJeff Roberson self.types.append(item) 302dcee3bd3SJeff Roberson item.grid(row=self.irow, column=0, sticky=E+W) 303dcee3bd3SJeff Roberson self.irow += 1 304dcee3bd3SJeff Roberson 305dcee3bd3SJeff Roberson def drawbuttons(self): 306dcee3bd3SJeff Roberson self.apply = Button(self.buttons, text="Apply", 307dcee3bd3SJeff Roberson command=self.apress) 308ec5cae07SJeff Roberson self.default = Button(self.buttons, text="Revert", 309dcee3bd3SJeff Roberson command=self.rpress) 310dcee3bd3SJeff Roberson self.apply.grid(row=0, column=0, sticky=E+W) 311ec5cae07SJeff Roberson self.default.grid(row=0, column=1, sticky=E+W) 312dcee3bd3SJeff Roberson self.buttons.columnconfigure(0, weight=1) 313dcee3bd3SJeff Roberson self.buttons.columnconfigure(1, weight=1) 314dcee3bd3SJeff Roberson 315dcee3bd3SJeff Roberson def apress(self): 316dcee3bd3SJeff Roberson for item in self.types: 317dcee3bd3SJeff Roberson item.apply() 318dcee3bd3SJeff Roberson 319dcee3bd3SJeff Roberson def rpress(self): 320dcee3bd3SJeff Roberson for item in self.types: 321dcee3bd3SJeff Roberson item.revert() 322dcee3bd3SJeff Roberson 3233d21f0f4SJeff Robersonclass SourceConf(Frame): 3243d21f0f4SJeff Roberson def __init__(self, master, source): 3253d21f0f4SJeff Roberson Frame.__init__(self, master) 3263d21f0f4SJeff Roberson if (source.hidden == 1): 3273d21f0f4SJeff Roberson enabled = 0 3283d21f0f4SJeff Roberson else: 3293d21f0f4SJeff Roberson enabled = 1 3303d21f0f4SJeff Roberson self.source = source 3313d21f0f4SJeff Roberson self.name = source.name 3323d21f0f4SJeff Roberson self.enabled = IntVar() 3333d21f0f4SJeff Roberson self.enabled_default = enabled 3343d21f0f4SJeff Roberson self.enabled_current = enabled 3353d21f0f4SJeff Roberson self.enabled.set(enabled) 3363d21f0f4SJeff Roberson self.draw() 3373d21f0f4SJeff Roberson 3383d21f0f4SJeff Roberson def draw(self): 3393d21f0f4SJeff Roberson self.label = Label(self, text=self.name, anchor=W) 3403d21f0f4SJeff Roberson self.checkbox = Checkbutton(self, text="enabled", 3413d21f0f4SJeff Roberson variable=self.enabled) 3423d21f0f4SJeff Roberson self.label.grid(row=0, column=0, sticky=E+W) 3433d21f0f4SJeff Roberson self.checkbox.grid(row=0, column=1) 3443d21f0f4SJeff Roberson self.columnconfigure(0, weight=1) 3453d21f0f4SJeff Roberson 34650d670daSJeff Roberson def changed(self): 3473d21f0f4SJeff Roberson if (self.enabled_current != self.enabled.get()): 34850d670daSJeff Roberson return 1 34950d670daSJeff Roberson return 0 35050d670daSJeff Roberson 35150d670daSJeff Roberson def apply(self): 3523d21f0f4SJeff Roberson self.enabled_current = self.enabled.get() 3533d21f0f4SJeff Roberson 3543d21f0f4SJeff Roberson def revert(self): 3553d21f0f4SJeff Roberson self.enabled.set(self.enabled_default) 3563d21f0f4SJeff Roberson 3573d21f0f4SJeff Roberson def check(self): 3583d21f0f4SJeff Roberson self.enabled.set(1) 3593d21f0f4SJeff Roberson 3603d21f0f4SJeff Roberson def uncheck(self): 3613d21f0f4SJeff Roberson self.enabled.set(0) 3623d21f0f4SJeff Roberson 3633d21f0f4SJeff Robersonclass SourceConfigure(Toplevel): 3643d21f0f4SJeff Roberson def __init__(self): 3653d21f0f4SJeff Roberson Toplevel.__init__(self) 3663d21f0f4SJeff Roberson self.resizable(0, 0) 3673d21f0f4SJeff Roberson self.title("Source Configuration") 3683d21f0f4SJeff Roberson self.items = [] 3693d21f0f4SJeff Roberson self.iframe = Frame(self) 3703d21f0f4SJeff Roberson self.iframe.grid(row=0, column=0, sticky=E+W) 3713d21f0f4SJeff Roberson f = LabelFrame(self.iframe, bd=4, text="Sources") 3723d21f0f4SJeff Roberson self.items.append(f) 3733d21f0f4SJeff Roberson self.buttons = Frame(self) 3743d21f0f4SJeff Roberson self.items[0].grid(row=0, column=0, sticky=E+W) 3753d21f0f4SJeff Roberson self.columnconfigure(0, weight=1) 3763d21f0f4SJeff Roberson self.sconfig = [] 3773d21f0f4SJeff Roberson self.irow = 0 3783d21f0f4SJeff Roberson self.icol = 0 3793d21f0f4SJeff Roberson for source in sources: 3803d21f0f4SJeff Roberson self.addsource(source) 3813d21f0f4SJeff Roberson self.drawbuttons() 3823d21f0f4SJeff Roberson self.buttons.grid(row=1, column=0, sticky=W) 3839799411bSJohn Baldwin self.bind("<Control-w>", self.destroycb) 3849799411bSJohn Baldwin 3859799411bSJohn Baldwin def destroycb(self, event): 3869799411bSJohn Baldwin self.destroy() 3873d21f0f4SJeff Roberson 3883d21f0f4SJeff Roberson def addsource(self, source): 3893d21f0f4SJeff Roberson if (self.irow > 30): 3903d21f0f4SJeff Roberson self.icol += 1 3913d21f0f4SJeff Roberson self.irow = 0 3923d21f0f4SJeff Roberson c = self.icol 3933d21f0f4SJeff Roberson f = LabelFrame(self.iframe, bd=4, text="Sources") 3943d21f0f4SJeff Roberson f.grid(row=0, column=c, sticky=N+E+W) 3953d21f0f4SJeff Roberson self.items.append(f) 3963d21f0f4SJeff Roberson item = SourceConf(self.items[self.icol], source) 3973d21f0f4SJeff Roberson self.sconfig.append(item) 3983d21f0f4SJeff Roberson item.grid(row=self.irow, column=0, sticky=E+W) 3993d21f0f4SJeff Roberson self.irow += 1 4003d21f0f4SJeff Roberson 4013d21f0f4SJeff Roberson def drawbuttons(self): 4023d21f0f4SJeff Roberson self.apply = Button(self.buttons, text="Apply", 4033d21f0f4SJeff Roberson command=self.apress) 4043d21f0f4SJeff Roberson self.default = Button(self.buttons, text="Revert", 4053d21f0f4SJeff Roberson command=self.rpress) 4063d21f0f4SJeff Roberson self.checkall = Button(self.buttons, text="Check All", 4073d21f0f4SJeff Roberson command=self.cpress) 4083d21f0f4SJeff Roberson self.uncheckall = Button(self.buttons, text="Uncheck All", 4093d21f0f4SJeff Roberson command=self.upress) 4103d21f0f4SJeff Roberson self.checkall.grid(row=0, column=0, sticky=W) 4113d21f0f4SJeff Roberson self.uncheckall.grid(row=0, column=1, sticky=W) 4123d21f0f4SJeff Roberson self.apply.grid(row=0, column=2, sticky=W) 4133d21f0f4SJeff Roberson self.default.grid(row=0, column=3, sticky=W) 4143d21f0f4SJeff Roberson self.buttons.columnconfigure(0, weight=1) 4153d21f0f4SJeff Roberson self.buttons.columnconfigure(1, weight=1) 4163d21f0f4SJeff Roberson self.buttons.columnconfigure(2, weight=1) 4173d21f0f4SJeff Roberson self.buttons.columnconfigure(3, weight=1) 4183d21f0f4SJeff Roberson 4193d21f0f4SJeff Roberson def apress(self): 42050d670daSJeff Roberson disable_sources = [] 42150d670daSJeff Roberson enable_sources = [] 42250d670daSJeff Roberson for item in self.sconfig: 42350d670daSJeff Roberson if (item.changed() == 0): 42450d670daSJeff Roberson continue 42550d670daSJeff Roberson if (item.enabled.get() == 1): 42650d670daSJeff Roberson enable_sources.append(item.source) 42750d670daSJeff Roberson else: 42850d670daSJeff Roberson disable_sources.append(item.source) 42950d670daSJeff Roberson 43050d670daSJeff Roberson if (len(disable_sources)): 43150d670daSJeff Roberson graph.sourcehidelist(disable_sources) 43250d670daSJeff Roberson if (len(enable_sources)): 43350d670daSJeff Roberson graph.sourceshowlist(enable_sources) 43450d670daSJeff Roberson 4353d21f0f4SJeff Roberson for item in self.sconfig: 4363d21f0f4SJeff Roberson item.apply() 4373d21f0f4SJeff Roberson 4383d21f0f4SJeff Roberson def rpress(self): 4393d21f0f4SJeff Roberson for item in self.sconfig: 4403d21f0f4SJeff Roberson item.revert() 4413d21f0f4SJeff Roberson 4423d21f0f4SJeff Roberson def cpress(self): 4433d21f0f4SJeff Roberson for item in self.sconfig: 4443d21f0f4SJeff Roberson item.check() 4453d21f0f4SJeff Roberson 4463d21f0f4SJeff Roberson def upress(self): 4473d21f0f4SJeff Roberson for item in self.sconfig: 4483d21f0f4SJeff Roberson item.uncheck() 4493d21f0f4SJeff Roberson 45050d670daSJeff Robersonclass SourceStats(Toplevel): 45150d670daSJeff Roberson def __init__(self, source): 45250d670daSJeff Roberson self.source = source 45350d670daSJeff Roberson Toplevel.__init__(self) 45450d670daSJeff Roberson self.resizable(0, 0) 45550d670daSJeff Roberson self.title(source.name + " statistics") 45650d670daSJeff Roberson self.evframe = LabelFrame(self, 457b62baf95SJeff Roberson text="Event Count, Duration, Avg Duration") 45850d670daSJeff Roberson self.evframe.grid(row=0, column=0, sticky=E+W) 45950d670daSJeff Roberson eventtypes={} 46050d670daSJeff Roberson for event in self.source.events: 46150d670daSJeff Roberson if (event.type == "pad"): 46250d670daSJeff Roberson continue 46350d670daSJeff Roberson duration = event.duration 464aef675d8SCraig Rodrigues if (event.name in eventtypes): 46550d670daSJeff Roberson (c, d) = eventtypes[event.name] 46650d670daSJeff Roberson c += 1 46750d670daSJeff Roberson d += duration 46850d670daSJeff Roberson eventtypes[event.name] = (c, d) 46950d670daSJeff Roberson else: 47050d670daSJeff Roberson eventtypes[event.name] = (1, duration) 47150d670daSJeff Roberson events = [] 47250d670daSJeff Roberson for k, v in eventtypes.iteritems(): 47350d670daSJeff Roberson (c, d) = v 47450d670daSJeff Roberson events.append((k, c, d)) 475*7e8ed296SAndriy Gapon events.sort(key=itemgetter(1), reverse=True) 47650d670daSJeff Roberson 47750d670daSJeff Roberson ypos = 0 47850d670daSJeff Roberson for event in events: 47950d670daSJeff Roberson (name, c, d) = event 480b62baf95SJeff Roberson Label(self.evframe, text=name, bd=1, 481b62baf95SJeff Roberson relief=SUNKEN, anchor=W, width=30).grid( 482b62baf95SJeff Roberson row=ypos, column=0, sticky=W+E) 483b62baf95SJeff Roberson Label(self.evframe, text=str(c), bd=1, 484b62baf95SJeff Roberson relief=SUNKEN, anchor=W, width=10).grid( 485b62baf95SJeff Roberson row=ypos, column=1, sticky=W+E) 486b62baf95SJeff Roberson Label(self.evframe, text=ticks2sec(d), 487b62baf95SJeff Roberson bd=1, relief=SUNKEN, width=10).grid( 488b62baf95SJeff Roberson row=ypos, column=2, sticky=W+E) 489b62baf95SJeff Roberson if (d and c): 490b62baf95SJeff Roberson d /= c 491b62baf95SJeff Roberson else: 492b62baf95SJeff Roberson d = 0 493b62baf95SJeff Roberson Label(self.evframe, text=ticks2sec(d), 494b62baf95SJeff Roberson bd=1, relief=SUNKEN, width=10).grid( 495b62baf95SJeff Roberson row=ypos, column=3, sticky=W+E) 49650d670daSJeff Roberson ypos += 1 4979799411bSJohn Baldwin self.bind("<Control-w>", self.destroycb) 4989799411bSJohn Baldwin 4999799411bSJohn Baldwin def destroycb(self, event): 5009799411bSJohn Baldwin self.destroy() 50150d670daSJeff Roberson 50250d670daSJeff Roberson 50350d670daSJeff Robersonclass SourceContext(Menu): 50450d670daSJeff Roberson def __init__(self, event, source): 50550d670daSJeff Roberson self.source = source 50650d670daSJeff Roberson Menu.__init__(self, tearoff=0, takefocus=0) 50750d670daSJeff Roberson self.add_command(label="hide", command=self.hide) 50850d670daSJeff Roberson self.add_command(label="hide group", command=self.hidegroup) 50950d670daSJeff Roberson self.add_command(label="stats", command=self.stats) 51050d670daSJeff Roberson self.tk_popup(event.x_root-3, event.y_root+3) 51150d670daSJeff Roberson 51250d670daSJeff Roberson def hide(self): 51350d670daSJeff Roberson graph.sourcehide(self.source) 51450d670daSJeff Roberson 51550d670daSJeff Roberson def hidegroup(self): 51650d670daSJeff Roberson grouplist = [] 51750d670daSJeff Roberson for source in sources: 51850d670daSJeff Roberson if (source.group == self.source.group): 51950d670daSJeff Roberson grouplist.append(source) 52050d670daSJeff Roberson graph.sourcehidelist(grouplist) 52150d670daSJeff Roberson 52250d670daSJeff Roberson def show(self): 52350d670daSJeff Roberson graph.sourceshow(self.source) 52450d670daSJeff Roberson 52550d670daSJeff Roberson def stats(self): 52650d670daSJeff Roberson SourceStats(self.source) 52750d670daSJeff Roberson 528dcee3bd3SJeff Robersonclass EventView(Toplevel): 529dcee3bd3SJeff Roberson def __init__(self, event, canvas): 530dcee3bd3SJeff Roberson Toplevel.__init__(self) 531dcee3bd3SJeff Roberson self.resizable(0, 0) 532dcee3bd3SJeff Roberson self.title("Event") 533dcee3bd3SJeff Roberson self.event = event 534dcee3bd3SJeff Roberson self.buttons = Frame(self) 535ec5cae07SJeff Roberson self.buttons.grid(row=0, column=0, sticky=E+W) 536ec5cae07SJeff Roberson self.frame = Frame(self) 537ec5cae07SJeff Roberson self.frame.grid(row=1, column=0, sticky=N+S+E+W) 538dcee3bd3SJeff Roberson self.canvas = canvas 539dcee3bd3SJeff Roberson self.drawlabels() 540dcee3bd3SJeff Roberson self.drawbuttons() 541dcee3bd3SJeff Roberson event.displayref(canvas) 542dcee3bd3SJeff Roberson self.bind("<Destroy>", self.destroycb) 5439799411bSJohn Baldwin self.bind("<Control-w>", self.destroycb) 544dcee3bd3SJeff Roberson 545dcee3bd3SJeff Roberson def destroycb(self, event): 546dcee3bd3SJeff Roberson self.unbind("<Destroy>") 547dcee3bd3SJeff Roberson if (self.event != None): 548dcee3bd3SJeff Roberson self.event.displayunref(self.canvas) 549dcee3bd3SJeff Roberson self.event = None 550dcee3bd3SJeff Roberson self.destroy() 551dcee3bd3SJeff Roberson 552dcee3bd3SJeff Roberson def clearlabels(self): 553dcee3bd3SJeff Roberson for label in self.frame.grid_slaves(): 554dcee3bd3SJeff Roberson label.grid_remove() 555dcee3bd3SJeff Roberson 556dcee3bd3SJeff Roberson def drawlabels(self): 557dcee3bd3SJeff Roberson ypos = 0 558dcee3bd3SJeff Roberson labels = self.event.labels() 559dcee3bd3SJeff Roberson while (len(labels) < 7): 560ec5cae07SJeff Roberson labels.append(("", "")) 561dcee3bd3SJeff Roberson for label in labels: 562ec5cae07SJeff Roberson name, value = label 563ec5cae07SJeff Roberson linked = 0 564ec5cae07SJeff Roberson if (name == "linkedto"): 565ec5cae07SJeff Roberson linked = 1 566dcee3bd3SJeff Roberson l = Label(self.frame, text=name, bd=1, width=15, 567dcee3bd3SJeff Roberson relief=SUNKEN, anchor=W) 568dcee3bd3SJeff Roberson if (linked): 569dcee3bd3SJeff Roberson fgcolor = "blue" 570dcee3bd3SJeff Roberson else: 571dcee3bd3SJeff Roberson fgcolor = "black" 572dcee3bd3SJeff Roberson r = Label(self.frame, text=value, bd=1, 573dcee3bd3SJeff Roberson relief=SUNKEN, anchor=W, fg=fgcolor) 574dcee3bd3SJeff Roberson l.grid(row=ypos, column=0, sticky=E+W) 575dcee3bd3SJeff Roberson r.grid(row=ypos, column=1, sticky=E+W) 576dcee3bd3SJeff Roberson if (linked): 577dcee3bd3SJeff Roberson r.bind("<Button-1>", self.linkpress) 578dcee3bd3SJeff Roberson ypos += 1 579dcee3bd3SJeff Roberson self.frame.columnconfigure(1, minsize=80) 580dcee3bd3SJeff Roberson 581dcee3bd3SJeff Roberson def drawbuttons(self): 582dcee3bd3SJeff Roberson self.back = Button(self.buttons, text="<", command=self.bpress) 583dcee3bd3SJeff Roberson self.forw = Button(self.buttons, text=">", command=self.fpress) 584dcee3bd3SJeff Roberson self.new = Button(self.buttons, text="new", command=self.npress) 585dcee3bd3SJeff Roberson self.back.grid(row=0, column=0, sticky=E+W) 586dcee3bd3SJeff Roberson self.forw.grid(row=0, column=1, sticky=E+W) 587dcee3bd3SJeff Roberson self.new.grid(row=0, column=2, sticky=E+W) 588dcee3bd3SJeff Roberson self.buttons.columnconfigure(2, weight=1) 589dcee3bd3SJeff Roberson 590dcee3bd3SJeff Roberson def newevent(self, event): 591dcee3bd3SJeff Roberson self.event.displayunref(self.canvas) 592dcee3bd3SJeff Roberson self.clearlabels() 593dcee3bd3SJeff Roberson self.event = event 594dcee3bd3SJeff Roberson self.event.displayref(self.canvas) 595dcee3bd3SJeff Roberson self.drawlabels() 596dcee3bd3SJeff Roberson 597dcee3bd3SJeff Roberson def npress(self): 598dcee3bd3SJeff Roberson EventView(self.event, self.canvas) 599dcee3bd3SJeff Roberson 600dcee3bd3SJeff Roberson def bpress(self): 601dcee3bd3SJeff Roberson prev = self.event.prev() 602dcee3bd3SJeff Roberson if (prev == None): 603dcee3bd3SJeff Roberson return 604ec5cae07SJeff Roberson while (prev.type == "pad"): 605dcee3bd3SJeff Roberson prev = prev.prev() 606dcee3bd3SJeff Roberson if (prev == None): 607dcee3bd3SJeff Roberson return 608dcee3bd3SJeff Roberson self.newevent(prev) 609dcee3bd3SJeff Roberson 610dcee3bd3SJeff Roberson def fpress(self): 611dcee3bd3SJeff Roberson next = self.event.next() 612dcee3bd3SJeff Roberson if (next == None): 613dcee3bd3SJeff Roberson return 614ec5cae07SJeff Roberson while (next.type == "pad"): 615dcee3bd3SJeff Roberson next = next.next() 616dcee3bd3SJeff Roberson if (next == None): 617dcee3bd3SJeff Roberson return 618dcee3bd3SJeff Roberson self.newevent(next) 619dcee3bd3SJeff Roberson 620dcee3bd3SJeff Roberson def linkpress(self, wevent): 621dcee3bd3SJeff Roberson event = self.event.getlinked() 622dcee3bd3SJeff Roberson if (event != None): 623dcee3bd3SJeff Roberson self.newevent(event) 624dcee3bd3SJeff Roberson 625dcee3bd3SJeff Robersonclass Event: 626ec5cae07SJeff Roberson def __init__(self, source, name, cpu, timestamp, attrs): 627dcee3bd3SJeff Roberson self.source = source 628ec5cae07SJeff Roberson self.name = name 629dcee3bd3SJeff Roberson self.cpu = cpu 630dcee3bd3SJeff Roberson self.timestamp = int(timestamp) 631ec5cae07SJeff Roberson self.attrs = attrs 632dcee3bd3SJeff Roberson self.idx = None 633dcee3bd3SJeff Roberson self.item = None 634dcee3bd3SJeff Roberson self.dispcnt = 0 63550d670daSJeff Roberson self.duration = 0 63666835de4SSam Leffler self.recno = lineno 637dcee3bd3SJeff Roberson 638dcee3bd3SJeff Roberson def status(self): 639dcee3bd3SJeff Roberson statstr = self.name + " " + self.source.name 640dcee3bd3SJeff Roberson statstr += " on: cpu" + str(self.cpu) 641dcee3bd3SJeff Roberson statstr += " at: " + str(self.timestamp) 642ec5cae07SJeff Roberson statstr += " attributes: " 643ec5cae07SJeff Roberson for i in range(0, len(self.attrs)): 644ec5cae07SJeff Roberson attr = self.attrs[i] 645ec5cae07SJeff Roberson statstr += attr[0] + ": " + str(attr[1]) 646ec5cae07SJeff Roberson if (i != len(self.attrs) - 1): 647ec5cae07SJeff Roberson statstr += ", " 648dcee3bd3SJeff Roberson status.set(statstr) 649dcee3bd3SJeff Roberson 650dcee3bd3SJeff Roberson def labels(self): 651ec5cae07SJeff Roberson return [("Source", self.source.name), 652ec5cae07SJeff Roberson ("Event", self.name), 653ec5cae07SJeff Roberson ("CPU", self.cpu), 654ec5cae07SJeff Roberson ("Timestamp", self.timestamp), 655ec5cae07SJeff Roberson ("KTR Line ", self.recno) 656ec5cae07SJeff Roberson ] + self.attrs 657ec5cae07SJeff Roberson 658ec5cae07SJeff Roberson def mouseenter(self, canvas): 659dcee3bd3SJeff Roberson self.displayref(canvas) 660dcee3bd3SJeff Roberson self.status() 661dcee3bd3SJeff Roberson 662ec5cae07SJeff Roberson def mouseexit(self, canvas): 663dcee3bd3SJeff Roberson self.displayunref(canvas) 664dcee3bd3SJeff Roberson status.clear() 665dcee3bd3SJeff Roberson 666ec5cae07SJeff Roberson def mousepress(self, canvas): 667dcee3bd3SJeff Roberson EventView(self, canvas) 668dcee3bd3SJeff Roberson 669ec5cae07SJeff Roberson def draw(self, canvas, xpos, ypos, item): 670ec5cae07SJeff Roberson self.item = item 671ec5cae07SJeff Roberson if (item != None): 672ec5cae07SJeff Roberson canvas.items[item] = self 673ec5cae07SJeff Roberson 674ec5cae07SJeff Roberson def move(self, canvas, x, y): 675ec5cae07SJeff Roberson if (self.item == None): 676ec5cae07SJeff Roberson return; 677ec5cae07SJeff Roberson canvas.move(self.item, x, y); 678ec5cae07SJeff Roberson 679dcee3bd3SJeff Roberson def next(self): 680dcee3bd3SJeff Roberson return self.source.eventat(self.idx + 1) 681dcee3bd3SJeff Roberson 682ec5cae07SJeff Roberson def nexttype(self, type): 683ec5cae07SJeff Roberson next = self.next() 684ec5cae07SJeff Roberson while (next != None and next.type != type): 685ec5cae07SJeff Roberson next = next.next() 686ec5cae07SJeff Roberson return (next) 687ec5cae07SJeff Roberson 688dcee3bd3SJeff Roberson def prev(self): 689dcee3bd3SJeff Roberson return self.source.eventat(self.idx - 1) 690dcee3bd3SJeff Roberson 691dcee3bd3SJeff Roberson def displayref(self, canvas): 692dcee3bd3SJeff Roberson if (self.dispcnt == 0): 693dcee3bd3SJeff Roberson canvas.itemconfigure(self.item, width=2) 694dcee3bd3SJeff Roberson self.dispcnt += 1 695dcee3bd3SJeff Roberson 696dcee3bd3SJeff Roberson def displayunref(self, canvas): 697dcee3bd3SJeff Roberson self.dispcnt -= 1 698dcee3bd3SJeff Roberson if (self.dispcnt == 0): 699dcee3bd3SJeff Roberson canvas.itemconfigure(self.item, width=0) 700dcee3bd3SJeff Roberson canvas.tag_raise("point", "state") 701dcee3bd3SJeff Roberson 702dcee3bd3SJeff Roberson def getlinked(self): 703ec5cae07SJeff Roberson for attr in self.attrs: 704ec5cae07SJeff Roberson if (attr[0] != "linkedto"): 705ec5cae07SJeff Roberson continue 706ec5cae07SJeff Roberson source = ktrfile.findid(attr[1]) 707ec5cae07SJeff Roberson return source.findevent(self.timestamp) 708ec5cae07SJeff Roberson return None 709dcee3bd3SJeff Roberson 710dcee3bd3SJeff Robersonclass PointEvent(Event): 711ec5cae07SJeff Roberson type = "point" 712ec5cae07SJeff Roberson def __init__(self, source, name, cpu, timestamp, attrs): 713ec5cae07SJeff Roberson Event.__init__(self, source, name, cpu, timestamp, attrs) 714dcee3bd3SJeff Roberson 715dcee3bd3SJeff Roberson def draw(self, canvas, xpos, ypos): 716ec5cae07SJeff Roberson color = colormap.lookup(self.name) 717932f0fa2SJeff Roberson l = canvas.create_oval(xpos - XY_POINT, ypos, 718932f0fa2SJeff Roberson xpos + XY_POINT, ypos - (XY_POINT * 2), 71950d670daSJeff Roberson fill=color, width=0, 720932f0fa2SJeff Roberson tags=("event", self.type, self.name, self.source.tag)) 721ec5cae07SJeff Roberson Event.draw(self, canvas, xpos, ypos, l) 722dcee3bd3SJeff Roberson 723ec5cae07SJeff Roberson return xpos 724dcee3bd3SJeff Roberson 725dcee3bd3SJeff Robersonclass StateEvent(Event): 726ec5cae07SJeff Roberson type = "state" 727ec5cae07SJeff Roberson def __init__(self, source, name, cpu, timestamp, attrs): 728ec5cae07SJeff Roberson Event.__init__(self, source, name, cpu, timestamp, attrs) 729dcee3bd3SJeff Roberson 730dcee3bd3SJeff Roberson def draw(self, canvas, xpos, ypos): 731ec5cae07SJeff Roberson next = self.nexttype("state") 732dcee3bd3SJeff Roberson if (next == None): 733ec5cae07SJeff Roberson return (xpos) 73450d670daSJeff Roberson self.duration = duration = next.timestamp - self.timestamp 735ec5cae07SJeff Roberson self.attrs.insert(0, ("duration", ticks2sec(duration))) 736ec5cae07SJeff Roberson color = colormap.lookup(self.name) 737ec5cae07SJeff Roberson if (duration < 0): 738ec5cae07SJeff Roberson duration = 0 739749f65e3SCraig Rodrigues print("Unsynchronized timestamp") 740749f65e3SCraig Rodrigues print(self.cpu, self.timestamp) 741749f65e3SCraig Rodrigues print(next.cpu, next.timestamp) 742ec5cae07SJeff Roberson delta = duration / canvas.ratio 743dcee3bd3SJeff Roberson l = canvas.create_rectangle(xpos, ypos, 744ec5cae07SJeff Roberson xpos + delta, ypos - 10, fill=color, width=0, 745932f0fa2SJeff Roberson tags=("event", self.type, self.name, self.source.tag)) 746ec5cae07SJeff Roberson Event.draw(self, canvas, xpos, ypos, l) 747dcee3bd3SJeff Roberson 748dcee3bd3SJeff Roberson return (xpos + delta) 749dcee3bd3SJeff Roberson 750ec5cae07SJeff Robersonclass CountEvent(Event): 751ec5cae07SJeff Roberson type = "count" 752ec5cae07SJeff Roberson def __init__(self, source, count, cpu, timestamp, attrs): 753ec5cae07SJeff Roberson count = int(count) 754ec5cae07SJeff Roberson self.count = count 755ec5cae07SJeff Roberson Event.__init__(self, source, "count", cpu, timestamp, attrs) 756dcee3bd3SJeff Roberson 757dcee3bd3SJeff Roberson def draw(self, canvas, xpos, ypos): 758ec5cae07SJeff Roberson next = self.nexttype("count") 759ec5cae07SJeff Roberson if (next == None): 760ec5cae07SJeff Roberson return (xpos) 761ec5cae07SJeff Roberson color = colormap.lookup("count") 76250d670daSJeff Roberson self.duration = duration = next.timestamp - self.timestamp 76316ef0f3bSJeff Roberson if (duration < 0): 76416ef0f3bSJeff Roberson duration = 0 765749f65e3SCraig Rodrigues print("Unsynchronized timestamp") 766749f65e3SCraig Rodrigues print(self.cpu, self.timestamp) 767749f65e3SCraig Rodrigues print(next.cpu, next.timestamp) 768ec5cae07SJeff Roberson self.attrs.insert(0, ("count", self.count)) 769ec5cae07SJeff Roberson self.attrs.insert(1, ("duration", ticks2sec(duration))) 770ec5cae07SJeff Roberson delta = duration / canvas.ratio 771dcee3bd3SJeff Roberson yhight = self.source.yscale() * self.count 772dcee3bd3SJeff Roberson l = canvas.create_rectangle(xpos, ypos - yhight, 773ec5cae07SJeff Roberson xpos + delta, ypos, fill=color, width=0, 774932f0fa2SJeff Roberson tags=("event", self.type, self.name, self.source.tag)) 775ec5cae07SJeff Roberson Event.draw(self, canvas, xpos, ypos, l) 776dcee3bd3SJeff Roberson return (xpos + delta) 777dcee3bd3SJeff Roberson 778ec5cae07SJeff Robersonclass PadEvent(StateEvent): 779ec5cae07SJeff Roberson type = "pad" 780ec5cae07SJeff Roberson def __init__(self, source, cpu, timestamp, last=0): 781ec5cae07SJeff Roberson if (last): 782ec5cae07SJeff Roberson cpu = source.events[len(source.events) -1].cpu 783ec5cae07SJeff Roberson else: 784ec5cae07SJeff Roberson cpu = source.events[0].cpu 785ec5cae07SJeff Roberson StateEvent.__init__(self, source, "pad", cpu, timestamp, []) 786dcee3bd3SJeff Roberson def draw(self, canvas, xpos, ypos): 787dcee3bd3SJeff Roberson next = self.next() 788dcee3bd3SJeff Roberson if (next == None): 789dcee3bd3SJeff Roberson return (xpos) 790ec5cae07SJeff Roberson duration = next.timestamp - self.timestamp 791ec5cae07SJeff Roberson delta = duration / canvas.ratio 792ec5cae07SJeff Roberson Event.draw(self, canvas, xpos, ypos, None) 793dcee3bd3SJeff Roberson return (xpos + delta) 794dcee3bd3SJeff Roberson 79550d670daSJeff Roberson 796*7e8ed296SAndriy Gapon@total_ordering 797dcee3bd3SJeff Robersonclass EventSource: 798ec5cae07SJeff Roberson def __init__(self, group, id): 799ec5cae07SJeff Roberson self.name = id 800dcee3bd3SJeff Roberson self.events = [] 801ec5cae07SJeff Roberson self.cpuitems = [] 8022977b8f9SJohn Baldwin self.group = group 803ec5cae07SJeff Roberson self.y = 0 804ec5cae07SJeff Roberson self.item = None 8053d21f0f4SJeff Roberson self.hidden = 0 80650d670daSJeff Roberson self.tag = group + id 807dcee3bd3SJeff Roberson 808*7e8ed296SAndriy Gapon def __lt__(self, other): 809*7e8ed296SAndriy Gapon if other is None: 810*7e8ed296SAndriy Gapon return False 811*7e8ed296SAndriy Gapon return (self.group < other.group or 812*7e8ed296SAndriy Gapon self.group == other.group and self.name < other.name) 813*7e8ed296SAndriy Gapon 814*7e8ed296SAndriy Gapon def __eq__(self, other): 815*7e8ed296SAndriy Gapon if other is None: 816*7e8ed296SAndriy Gapon return False 817*7e8ed296SAndriy Gapon return self.group == other.group and self.name == other.name 8182977b8f9SJohn Baldwin 8192977b8f9SJohn Baldwin # It is much faster to append items to a list then to insert them 8202977b8f9SJohn Baldwin # at the beginning. As a result, we add events in reverse order 8212977b8f9SJohn Baldwin # and then swap the list during fixup. 822dcee3bd3SJeff Roberson def fixup(self): 8232977b8f9SJohn Baldwin self.events.reverse() 824dcee3bd3SJeff Roberson 825ec5cae07SJeff Roberson def addevent(self, event): 8262977b8f9SJohn Baldwin self.events.append(event) 827dcee3bd3SJeff Roberson 828ec5cae07SJeff Roberson def addlastevent(self, event): 8292977b8f9SJohn Baldwin self.events.insert(0, event) 830dcee3bd3SJeff Roberson 831dcee3bd3SJeff Roberson def draw(self, canvas, ypos): 832dcee3bd3SJeff Roberson xpos = 10 833ec5cae07SJeff Roberson cpux = 10 834ec5cae07SJeff Roberson cpu = self.events[1].cpu 835dcee3bd3SJeff Roberson for i in range(0, len(self.events)): 836dcee3bd3SJeff Roberson self.events[i].idx = i 837dcee3bd3SJeff Roberson for event in self.events: 838ec5cae07SJeff Roberson if (event.cpu != cpu and event.cpu != -1): 839ec5cae07SJeff Roberson self.drawcpu(canvas, cpu, cpux, xpos, ypos) 840ec5cae07SJeff Roberson cpux = xpos 841ec5cae07SJeff Roberson cpu = event.cpu 842dcee3bd3SJeff Roberson xpos = event.draw(canvas, xpos, ypos) 843ec5cae07SJeff Roberson self.drawcpu(canvas, cpu, cpux, xpos, ypos) 844dcee3bd3SJeff Roberson 845dcee3bd3SJeff Roberson def drawname(self, canvas, ypos): 846ec5cae07SJeff Roberson self.y = ypos 847dcee3bd3SJeff Roberson ypos = ypos - (self.ysize() / 2) 848932f0fa2SJeff Roberson self.item = canvas.create_text(X_BORDER, ypos, anchor="w", 849932f0fa2SJeff Roberson text=self.name) 850ec5cae07SJeff Roberson return (self.item) 851dcee3bd3SJeff Roberson 852ec5cae07SJeff Roberson def drawcpu(self, canvas, cpu, fromx, tox, ypos): 853ec5cae07SJeff Roberson cpu = "CPU " + str(cpu) 854ec5cae07SJeff Roberson color = cpucolormap.lookup(cpu) 855ec5cae07SJeff Roberson # Create the cpu background colors default to hidden 856ec5cae07SJeff Roberson l = canvas.create_rectangle(fromx, 857dcee3bd3SJeff Roberson ypos - self.ysize() - canvas.bdheight, 858ec5cae07SJeff Roberson tox, ypos + canvas.bdheight, fill=color, width=0, 859932f0fa2SJeff Roberson tags=("cpubg", cpu, self.tag), state="hidden") 860ec5cae07SJeff Roberson self.cpuitems.append(l) 861ec5cae07SJeff Roberson 862ec5cae07SJeff Roberson def move(self, canvas, xpos, ypos): 86350d670daSJeff Roberson canvas.move(self.tag, xpos, ypos) 864ec5cae07SJeff Roberson 865ec5cae07SJeff Roberson def movename(self, canvas, xpos, ypos): 866ec5cae07SJeff Roberson self.y += ypos 867ec5cae07SJeff Roberson canvas.move(self.item, xpos, ypos) 868dcee3bd3SJeff Roberson 869dcee3bd3SJeff Roberson def ysize(self): 870932f0fa2SJeff Roberson return (Y_EVENTSOURCE) 871dcee3bd3SJeff Roberson 872dcee3bd3SJeff Roberson def eventat(self, i): 873c3db6aa6SJohn Baldwin if (i >= len(self.events) or i < 0): 874dcee3bd3SJeff Roberson return (None) 875dcee3bd3SJeff Roberson event = self.events[i] 876dcee3bd3SJeff Roberson return (event) 877dcee3bd3SJeff Roberson 878dcee3bd3SJeff Roberson def findevent(self, timestamp): 879dcee3bd3SJeff Roberson for event in self.events: 880ec5cae07SJeff Roberson if (event.timestamp >= timestamp and event.type != "pad"): 881dcee3bd3SJeff Roberson return (event) 882dcee3bd3SJeff Roberson return (None) 883dcee3bd3SJeff Roberson 884dcee3bd3SJeff Robersonclass Counter(EventSource): 885ec5cae07SJeff Roberson # 886ec5cae07SJeff Roberson # Store a hash of counter groups that keeps the max value 887ec5cae07SJeff Roberson # for a counter in this group for scaling purposes. 888ec5cae07SJeff Roberson # 889ec5cae07SJeff Roberson groups = {} 890ec5cae07SJeff Roberson def __init__(self, group, id): 891dcee3bd3SJeff Roberson try: 892ec5cae07SJeff Roberson Counter.cnt = Counter.groups[group] 893dcee3bd3SJeff Roberson except: 894ec5cae07SJeff Roberson Counter.groups[group] = 0 895ec5cae07SJeff Roberson EventSource.__init__(self, group, id) 896ec5cae07SJeff Roberson 897ec5cae07SJeff Roberson def fixup(self): 898ec5cae07SJeff Roberson for event in self.events: 899ec5cae07SJeff Roberson if (event.type != "count"): 900ec5cae07SJeff Roberson continue; 901ec5cae07SJeff Roberson count = int(event.count) 902ec5cae07SJeff Roberson if (count > Counter.groups[self.group]): 903ec5cae07SJeff Roberson Counter.groups[self.group] = count 904ec5cae07SJeff Roberson EventSource.fixup(self) 905dcee3bd3SJeff Roberson 90666835de4SSam Leffler def ymax(self): 907ec5cae07SJeff Roberson return (Counter.groups[self.group]) 90866835de4SSam Leffler 909dcee3bd3SJeff Roberson def ysize(self): 910932f0fa2SJeff Roberson return (Y_COUNTER) 911dcee3bd3SJeff Roberson 912dcee3bd3SJeff Roberson def yscale(self): 913ec5cae07SJeff Roberson return (self.ysize() / self.ymax()) 914dcee3bd3SJeff Roberson 915dcee3bd3SJeff Robersonclass KTRFile: 916dcee3bd3SJeff Roberson def __init__(self, file): 9170482a607SJeff Roberson self.timestamp_f = None 9180482a607SJeff Roberson self.timestamp_l = None 9190199a61dSJohn Baldwin self.locks = {} 920dcee3bd3SJeff Roberson self.ticks = {} 921dcee3bd3SJeff Roberson self.load = {} 92201e7fb47SScott Long self.crit = {} 9230482a607SJeff Roberson self.stathz = 0 924932f0fa2SJeff Roberson self.eventcnt = 0 92516ef0f3bSJeff Roberson self.taghash = {} 926dcee3bd3SJeff Roberson 927dcee3bd3SJeff Roberson self.parse(file) 928dcee3bd3SJeff Roberson self.fixup() 929dcee3bd3SJeff Roberson global ticksps 9300482a607SJeff Roberson ticksps = self.ticksps() 931932f0fa2SJeff Roberson span = self.timespan() 932932f0fa2SJeff Roberson ghz = float(ticksps) / 1000000000.0 933932f0fa2SJeff Roberson # 934932f0fa2SJeff Roberson # Update the title with some stats from the file 935932f0fa2SJeff Roberson # 936932f0fa2SJeff Roberson titlestr = "SchedGraph: " 937932f0fa2SJeff Roberson titlestr += ticks2sec(span) + " at %.3f ghz, " % ghz 938932f0fa2SJeff Roberson titlestr += str(len(sources)) + " event sources, " 939932f0fa2SJeff Roberson titlestr += str(self.eventcnt) + " events" 940932f0fa2SJeff Roberson root.title(titlestr) 941dcee3bd3SJeff Roberson 942dcee3bd3SJeff Roberson def parse(self, file): 943dcee3bd3SJeff Roberson try: 944dcee3bd3SJeff Roberson ifp = open(file) 945dcee3bd3SJeff Roberson except: 946749f65e3SCraig Rodrigues print("Can't open", file) 947dcee3bd3SJeff Roberson sys.exit(1) 948dcee3bd3SJeff Roberson 949ec5cae07SJeff Roberson # quoteexp matches a quoted string, no escaping 950ec5cae07SJeff Roberson quoteexp = "\"([^\"]*)\"" 951dcee3bd3SJeff Roberson 952ec5cae07SJeff Roberson # 953ec5cae07SJeff Roberson # commaexp matches a quoted string OR the string up 954ec5cae07SJeff Roberson # to the first ',' 955ec5cae07SJeff Roberson # 956ec5cae07SJeff Roberson commaexp = "(?:" + quoteexp + "|([^,]+))" 957dcee3bd3SJeff Roberson 958ec5cae07SJeff Roberson # 959ec5cae07SJeff Roberson # colonstr matches a quoted string OR the string up 960ec5cae07SJeff Roberson # to the first ':' 961ec5cae07SJeff Roberson # 962ec5cae07SJeff Roberson colonexp = "(?:" + quoteexp + "|([^:]+))" 963dcee3bd3SJeff Roberson 964ec5cae07SJeff Roberson # 965ec5cae07SJeff Roberson # Match various manditory parts of the KTR string this is 966ec5cae07SJeff Roberson # fairly inflexible until you get to attributes to make 967ec5cae07SJeff Roberson # parsing faster. 968ec5cae07SJeff Roberson # 969ec5cae07SJeff Roberson hdrexp = "\s*(\d+)\s+(\d+)\s+(\d+)\s+" 970ec5cae07SJeff Roberson groupexp = "KTRGRAPH group:" + quoteexp + ", " 971ec5cae07SJeff Roberson idexp = "id:" + quoteexp + ", " 972ec5cae07SJeff Roberson typeexp = "([^:]+):" + commaexp + ", " 973ec5cae07SJeff Roberson attribexp = "attributes: (.*)" 974dcee3bd3SJeff Roberson 975ec5cae07SJeff Roberson # 976ec5cae07SJeff Roberson # Matches optional attributes in the KTR string. This 977ec5cae07SJeff Roberson # tolerates more variance as the users supply these values. 978ec5cae07SJeff Roberson # 979ec5cae07SJeff Roberson attrexp = colonexp + "\s*:\s*(?:" + commaexp + ", (.*)|" 980ec5cae07SJeff Roberson attrexp += quoteexp +"|(.*))" 981dcee3bd3SJeff Roberson 982ec5cae07SJeff Roberson # Precompile regexp 983ec5cae07SJeff Roberson ktrre = re.compile(hdrexp + groupexp + idexp + typeexp + attribexp) 984ec5cae07SJeff Roberson attrre = re.compile(attrexp) 985dcee3bd3SJeff Roberson 98666835de4SSam Leffler global lineno 98766835de4SSam Leffler lineno = 0 988dbad07bfSJeff Roberson for line in ifp.readlines(): 98966835de4SSam Leffler lineno += 1 990ec5cae07SJeff Roberson if ((lineno % 2048) == 0): 99166835de4SSam Leffler status.startup("Parsing line " + str(lineno)) 992ec5cae07SJeff Roberson m = ktrre.match(line); 9932e2e6cc9SJeff Roberson if (m == None): 994749f65e3SCraig Rodrigues print("Can't parse", lineno, line, end=' ') 995ec5cae07SJeff Roberson continue; 996ec5cae07SJeff Roberson (index, cpu, timestamp, group, id, type, dat, dat1, attrstring) = m.groups(); 997ec5cae07SJeff Roberson if (dat == None): 998ec5cae07SJeff Roberson dat = dat1 999ec5cae07SJeff Roberson if (self.checkstamp(timestamp) == 0): 1000749f65e3SCraig Rodrigues print("Bad timestamp at", lineno, ":", end=' ') 1001749f65e3SCraig Rodrigues print(cpu, timestamp) 1002ec5cae07SJeff Roberson continue 1003ec5cae07SJeff Roberson # 1004ec5cae07SJeff Roberson # Build the table of optional attributes 1005ec5cae07SJeff Roberson # 1006ec5cae07SJeff Roberson attrs = [] 1007ec5cae07SJeff Roberson while (attrstring != None): 1008ec5cae07SJeff Roberson m = attrre.match(attrstring.strip()) 1009ec5cae07SJeff Roberson if (m == None): 1010ec5cae07SJeff Roberson break; 1011ec5cae07SJeff Roberson # 1012ec5cae07SJeff Roberson # Name may or may not be quoted. 1013ec5cae07SJeff Roberson # 1014ec5cae07SJeff Roberson # For val we have four cases: 1015ec5cae07SJeff Roberson # 1) quotes followed by comma and more 1016ec5cae07SJeff Roberson # attributes. 1017ec5cae07SJeff Roberson # 2) no quotes followed by comma and more 1018ec5cae07SJeff Roberson # attributes. 1019ec5cae07SJeff Roberson # 3) no more attributes or comma with quotes. 1020ec5cae07SJeff Roberson # 4) no more attributes or comma without quotes. 1021ec5cae07SJeff Roberson # 1022ec5cae07SJeff Roberson (name, name1, val, val1, attrstring, end, end1) = m.groups(); 1023ec5cae07SJeff Roberson if (name == None): 1024ec5cae07SJeff Roberson name = name1 1025ec5cae07SJeff Roberson if (end == None): 1026ec5cae07SJeff Roberson end = end1 1027ec5cae07SJeff Roberson if (val == None): 1028ec5cae07SJeff Roberson val = val1 1029ec5cae07SJeff Roberson if (val == None): 1030ec5cae07SJeff Roberson val = end 1031ec5cae07SJeff Roberson if (name == "stathz"): 1032ec5cae07SJeff Roberson self.setstathz(val, cpu) 1033ec5cae07SJeff Roberson attrs.append((name, val)) 1034ec5cae07SJeff Roberson args = (dat, cpu, timestamp, attrs) 1035ec5cae07SJeff Roberson e = self.makeevent(group, id, type, args) 1036ec5cae07SJeff Roberson if (e == None): 1037749f65e3SCraig Rodrigues print("Unknown type", type, lineno, line, end=' ') 1038dcee3bd3SJeff Roberson 1039ec5cae07SJeff Roberson def makeevent(self, group, id, type, args): 1040ec5cae07SJeff Roberson e = None 1041ec5cae07SJeff Roberson source = self.makeid(group, id, type) 1042ec5cae07SJeff Roberson if (type == "state"): 1043ec5cae07SJeff Roberson e = StateEvent(source, *args) 1044ec5cae07SJeff Roberson elif (type == "counter"): 1045ec5cae07SJeff Roberson e = CountEvent(source, *args) 1046ec5cae07SJeff Roberson elif (type == "point"): 1047ec5cae07SJeff Roberson e = PointEvent(source, *args) 1048ec5cae07SJeff Roberson if (e != None): 1049932f0fa2SJeff Roberson self.eventcnt += 1 1050ec5cae07SJeff Roberson source.addevent(e); 1051ec5cae07SJeff Roberson return e 1052dcee3bd3SJeff Roberson 1053ec5cae07SJeff Roberson def setstathz(self, val, cpu): 1054ec5cae07SJeff Roberson self.stathz = int(val) 1055dcee3bd3SJeff Roberson cpu = int(cpu) 1056dcee3bd3SJeff Roberson try: 1057dcee3bd3SJeff Roberson ticks = self.ticks[cpu] 1058dcee3bd3SJeff Roberson except: 1059dcee3bd3SJeff Roberson self.ticks[cpu] = 0 1060dcee3bd3SJeff Roberson self.ticks[cpu] += 1 1061dcee3bd3SJeff Roberson 1062ec5cae07SJeff Roberson def checkstamp(self, timestamp): 1063ec5cae07SJeff Roberson timestamp = int(timestamp) 1064ec5cae07SJeff Roberson if (self.timestamp_f == None): 1065ec5cae07SJeff Roberson self.timestamp_f = timestamp; 106616ef0f3bSJeff Roberson if (self.timestamp_l != None and 106716ef0f3bSJeff Roberson timestamp -2048> self.timestamp_l): 1068ec5cae07SJeff Roberson return (0) 1069ec5cae07SJeff Roberson self.timestamp_l = timestamp; 1070ec5cae07SJeff Roberson return (1) 1071dcee3bd3SJeff Roberson 1072ec5cae07SJeff Roberson def makeid(self, group, id, type): 107316ef0f3bSJeff Roberson tag = group + id 1074aef675d8SCraig Rodrigues if (tag in self.taghash): 107516ef0f3bSJeff Roberson return self.taghash[tag] 1076ec5cae07SJeff Roberson if (type == "counter"): 1077ec5cae07SJeff Roberson source = Counter(group, id) 10780199a61dSJohn Baldwin else: 1079ec5cae07SJeff Roberson source = EventSource(group, id) 1080ec5cae07SJeff Roberson sources.append(source) 108116ef0f3bSJeff Roberson self.taghash[tag] = source 1082ec5cae07SJeff Roberson return (source) 10830199a61dSJohn Baldwin 1084ec5cae07SJeff Roberson def findid(self, id): 1085ec5cae07SJeff Roberson for source in sources: 1086ec5cae07SJeff Roberson if (source.name == id): 1087ec5cae07SJeff Roberson return source 1088ec5cae07SJeff Roberson return (None) 10890199a61dSJohn Baldwin 1090ec5cae07SJeff Roberson def timespan(self): 1091ec5cae07SJeff Roberson return (self.timestamp_f - self.timestamp_l); 10920199a61dSJohn Baldwin 1093ec5cae07SJeff Roberson def ticksps(self): 1094ec5cae07SJeff Roberson oneghz = 1000000000 1095ec5cae07SJeff Roberson # Use user supplied clock first 1096ec5cae07SJeff Roberson if (clockfreq != None): 1097ec5cae07SJeff Roberson return int(clockfreq * oneghz) 10980199a61dSJohn Baldwin 1099ec5cae07SJeff Roberson # Check for a discovered clock 110016ef0f3bSJeff Roberson if (self.stathz != 0): 1101ec5cae07SJeff Roberson return (self.timespan() / self.ticks[0]) * int(self.stathz) 1102ec5cae07SJeff Roberson # Pretend we have a 1ns clock 1103749f65e3SCraig Rodrigues print("WARNING: No clock discovered and no frequency ", end=' ') 1104749f65e3SCraig Rodrigues print("specified via the command line.") 1105749f65e3SCraig Rodrigues print("Using fake 1ghz clock") 1106ec5cae07SJeff Roberson return (oneghz); 1107dcee3bd3SJeff Roberson 1108dcee3bd3SJeff Roberson def fixup(self): 1109ec5cae07SJeff Roberson for source in sources: 1110ec5cae07SJeff Roberson e = PadEvent(source, -1, self.timestamp_l) 1111ec5cae07SJeff Roberson source.addevent(e) 1112ec5cae07SJeff Roberson e = PadEvent(source, -1, self.timestamp_f, last=1) 1113ec5cae07SJeff Roberson source.addlastevent(e) 1114dcee3bd3SJeff Roberson source.fixup() 1115ec5cae07SJeff Roberson sources.sort() 1116ec5cae07SJeff Roberson 1117ec5cae07SJeff Robersonclass SchedNames(Canvas): 1118ec5cae07SJeff Roberson def __init__(self, master, display): 1119ec5cae07SJeff Roberson self.display = display 1120ec5cae07SJeff Roberson self.parent = master 1121ec5cae07SJeff Roberson self.bdheight = master.bdheight 1122ec5cae07SJeff Roberson self.items = {} 1123ec5cae07SJeff Roberson self.ysize = 0 1124ec5cae07SJeff Roberson self.lines = [] 1125ec5cae07SJeff Roberson Canvas.__init__(self, master, width=120, 1126ec5cae07SJeff Roberson height=display["height"], bg='grey', 1127ec5cae07SJeff Roberson scrollregion=(0, 0, 50, 100)) 1128ec5cae07SJeff Roberson 1129ec5cae07SJeff Roberson def moveline(self, cur_y, y): 1130ec5cae07SJeff Roberson for line in self.lines: 1131ec5cae07SJeff Roberson (x0, y0, x1, y1) = self.coords(line) 1132ec5cae07SJeff Roberson if (cur_y != y0): 1133ec5cae07SJeff Roberson continue 1134ec5cae07SJeff Roberson self.move(line, 0, y) 1135ec5cae07SJeff Roberson return 1136ec5cae07SJeff Roberson 1137ec5cae07SJeff Roberson def draw(self): 1138ec5cae07SJeff Roberson status.startup("Drawing names") 1139ec5cae07SJeff Roberson ypos = 0 1140ec5cae07SJeff Roberson self.configure(scrollregion=(0, 0, 1141ec5cae07SJeff Roberson self["width"], self.display.ysize())) 1142ec5cae07SJeff Roberson for source in sources: 1143ec5cae07SJeff Roberson l = self.create_line(0, ypos, self["width"], ypos, 1144ec5cae07SJeff Roberson width=1, fill="black", tags=("all","sources")) 1145ec5cae07SJeff Roberson self.lines.append(l) 1146ec5cae07SJeff Roberson ypos += self.bdheight 1147ec5cae07SJeff Roberson ypos += source.ysize() 1148ec5cae07SJeff Roberson t = source.drawname(self, ypos) 1149ec5cae07SJeff Roberson self.items[t] = source 1150ec5cae07SJeff Roberson ypos += self.bdheight 1151ec5cae07SJeff Roberson self.ysize = ypos 1152ec5cae07SJeff Roberson self.create_line(0, ypos, self["width"], ypos, 1153ec5cae07SJeff Roberson width=1, fill="black", tags=("all",)) 1154ec5cae07SJeff Roberson self.bind("<Button-1>", self.master.mousepress); 115550d670daSJeff Roberson self.bind("<Button-3>", self.master.mousepressright); 1156ec5cae07SJeff Roberson self.bind("<ButtonRelease-1>", self.master.mouserelease); 1157ec5cae07SJeff Roberson self.bind("<B1-Motion>", self.master.mousemotion); 1158ec5cae07SJeff Roberson 11593d21f0f4SJeff Roberson def updatescroll(self): 11603d21f0f4SJeff Roberson self.configure(scrollregion=(0, 0, 11613d21f0f4SJeff Roberson self["width"], self.display.ysize())) 11623d21f0f4SJeff Roberson 1163dcee3bd3SJeff Roberson 1164dcee3bd3SJeff Robersonclass SchedDisplay(Canvas): 1165dcee3bd3SJeff Roberson def __init__(self, master): 11662977b8f9SJohn Baldwin self.ratio = 1 11672977b8f9SJohn Baldwin self.parent = master 1168ec5cae07SJeff Roberson self.bdheight = master.bdheight 1169ec5cae07SJeff Roberson self.items = {} 1170ec5cae07SJeff Roberson self.lines = [] 1171dcee3bd3SJeff Roberson Canvas.__init__(self, master, width=800, height=500, bg='grey', 1172dcee3bd3SJeff Roberson scrollregion=(0, 0, 800, 500)) 1173dcee3bd3SJeff Roberson 1174ec5cae07SJeff Roberson def prepare(self): 1175ec5cae07SJeff Roberson # 11762977b8f9SJohn Baldwin # Compute a ratio to ensure that the file's timespan fits into 11772977b8f9SJohn Baldwin # 2^31. Although python may handle larger values for X 11782977b8f9SJohn Baldwin # values, the Tk internals do not. 1179ec5cae07SJeff Roberson # 11802977b8f9SJohn Baldwin self.ratio = (ktrfile.timespan() - 1) / 2**31 + 1 11812977b8f9SJohn Baldwin 1182dcee3bd3SJeff Roberson def draw(self): 1183dcee3bd3SJeff Roberson ypos = 0 1184dcee3bd3SJeff Roberson xsize = self.xsize() 1185ec5cae07SJeff Roberson for source in sources: 1186dcee3bd3SJeff Roberson status.startup("Drawing " + source.name) 1187ec5cae07SJeff Roberson l = self.create_line(0, ypos, xsize, ypos, 1188dcee3bd3SJeff Roberson width=1, fill="black", tags=("all",)) 1189ec5cae07SJeff Roberson self.lines.append(l) 1190dcee3bd3SJeff Roberson ypos += self.bdheight 1191dcee3bd3SJeff Roberson ypos += source.ysize() 1192dcee3bd3SJeff Roberson source.draw(self, ypos) 1193dcee3bd3SJeff Roberson ypos += self.bdheight 1194dcee3bd3SJeff Roberson self.tag_raise("point", "state") 1195932f0fa2SJeff Roberson self.tag_lower("cpubg", ALL) 1196dcee3bd3SJeff Roberson self.create_line(0, ypos, xsize, ypos, 1197932f0fa2SJeff Roberson width=1, fill="black", tags=("lines",)) 1198dcee3bd3SJeff Roberson self.tag_bind("event", "<Enter>", self.mouseenter) 1199dcee3bd3SJeff Roberson self.tag_bind("event", "<Leave>", self.mouseexit) 1200ec5cae07SJeff Roberson self.bind("<Button-1>", self.mousepress) 120150d670daSJeff Roberson self.bind("<Button-3>", self.master.mousepressright); 12022977b8f9SJohn Baldwin self.bind("<Button-4>", self.wheelup) 12032977b8f9SJohn Baldwin self.bind("<Button-5>", self.wheeldown) 1204ec5cae07SJeff Roberson self.bind("<ButtonRelease-1>", self.master.mouserelease); 1205ec5cae07SJeff Roberson self.bind("<B1-Motion>", self.master.mousemotion); 1206ec5cae07SJeff Roberson 1207ec5cae07SJeff Roberson def moveline(self, cur_y, y): 1208ec5cae07SJeff Roberson for line in self.lines: 1209ec5cae07SJeff Roberson (x0, y0, x1, y1) = self.coords(line) 1210ec5cae07SJeff Roberson if (cur_y != y0): 1211ec5cae07SJeff Roberson continue 1212ec5cae07SJeff Roberson self.move(line, 0, y) 1213ec5cae07SJeff Roberson return 1214dcee3bd3SJeff Roberson 1215dcee3bd3SJeff Roberson def mouseenter(self, event): 1216dcee3bd3SJeff Roberson item, = self.find_withtag(CURRENT) 1217ec5cae07SJeff Roberson self.items[item].mouseenter(self) 1218dcee3bd3SJeff Roberson 1219dcee3bd3SJeff Roberson def mouseexit(self, event): 1220dcee3bd3SJeff Roberson item, = self.find_withtag(CURRENT) 1221ec5cae07SJeff Roberson self.items[item].mouseexit(self) 1222dcee3bd3SJeff Roberson 1223dcee3bd3SJeff Roberson def mousepress(self, event): 1224ec5cae07SJeff Roberson # Find out what's beneath us 1225ec5cae07SJeff Roberson items = self.find_withtag(CURRENT) 1226ec5cae07SJeff Roberson if (len(items) == 0): 1227ec5cae07SJeff Roberson self.master.mousepress(event) 1228ec5cae07SJeff Roberson return 1229ec5cae07SJeff Roberson # Only grab mouse presses for things with event tags. 1230ec5cae07SJeff Roberson item = items[0] 1231ec5cae07SJeff Roberson tags = self.gettags(item) 1232ec5cae07SJeff Roberson for tag in tags: 1233ec5cae07SJeff Roberson if (tag == "event"): 1234ec5cae07SJeff Roberson self.items[item].mousepress(self) 1235ec5cae07SJeff Roberson return 1236ec5cae07SJeff Roberson # Leave the rest to the master window 1237ec5cae07SJeff Roberson self.master.mousepress(event) 1238dcee3bd3SJeff Roberson 12392977b8f9SJohn Baldwin def wheeldown(self, event): 12402977b8f9SJohn Baldwin self.parent.display_yview("scroll", 1, "units") 12412977b8f9SJohn Baldwin 12422977b8f9SJohn Baldwin def wheelup(self, event): 12432977b8f9SJohn Baldwin self.parent.display_yview("scroll", -1, "units") 12442977b8f9SJohn Baldwin 1245dcee3bd3SJeff Roberson def xsize(self): 1246932f0fa2SJeff Roberson return ((ktrfile.timespan() / self.ratio) + (X_BORDER * 2)) 1247dcee3bd3SJeff Roberson 1248dcee3bd3SJeff Roberson def ysize(self): 1249dcee3bd3SJeff Roberson ysize = 0 1250ec5cae07SJeff Roberson for source in sources: 12513d21f0f4SJeff Roberson if (source.hidden == 1): 12523d21f0f4SJeff Roberson continue 12533d21f0f4SJeff Roberson ysize += self.parent.sourcesize(source) 1254ec5cae07SJeff Roberson return ysize 1255dcee3bd3SJeff Roberson 1256dcee3bd3SJeff Roberson def scaleset(self, ratio): 1257ec5cae07SJeff Roberson if (ktrfile == None): 1258dcee3bd3SJeff Roberson return 1259dcee3bd3SJeff Roberson oldratio = self.ratio 1260ec5cae07SJeff Roberson xstart, xend = self.xview() 1261ec5cae07SJeff Roberson midpoint = xstart + ((xend - xstart) / 2) 1262dcee3bd3SJeff Roberson 1263dcee3bd3SJeff Roberson self.ratio = ratio 12643d21f0f4SJeff Roberson self.updatescroll() 1265932f0fa2SJeff Roberson self.scale(ALL, 0, 0, float(oldratio) / ratio, 1) 1266dcee3bd3SJeff Roberson 1267ec5cae07SJeff Roberson xstart, xend = self.xview() 1268ec5cae07SJeff Roberson xsize = (xend - xstart) / 2 1269ec5cae07SJeff Roberson self.xview_moveto(midpoint - xsize) 1270dcee3bd3SJeff Roberson 12713d21f0f4SJeff Roberson def updatescroll(self): 12723d21f0f4SJeff Roberson self.configure(scrollregion=(0, 0, self.xsize(), self.ysize())) 12733d21f0f4SJeff Roberson 1274dcee3bd3SJeff Roberson def scaleget(self): 1275dcee3bd3SJeff Roberson return self.ratio 1276dcee3bd3SJeff Roberson 1277ec5cae07SJeff Roberson def getcolor(self, tag): 1278ec5cae07SJeff Roberson return self.itemcget(tag, "fill") 1279ec5cae07SJeff Roberson 1280ec5cae07SJeff Roberson def getstate(self, tag): 1281ec5cae07SJeff Roberson return self.itemcget(tag, "state") 1282ec5cae07SJeff Roberson 1283dcee3bd3SJeff Roberson def setcolor(self, tag, color): 1284dcee3bd3SJeff Roberson self.itemconfigure(tag, state="normal", fill=color) 1285dcee3bd3SJeff Roberson 1286dcee3bd3SJeff Roberson def hide(self, tag): 1287dcee3bd3SJeff Roberson self.itemconfigure(tag, state="hidden") 1288dcee3bd3SJeff Roberson 1289dcee3bd3SJeff Robersonclass GraphMenu(Frame): 1290dcee3bd3SJeff Roberson def __init__(self, master): 1291dcee3bd3SJeff Roberson Frame.__init__(self, master, bd=2, relief=RAISED) 129250d670daSJeff Roberson self.conf = Menubutton(self, text="Configure") 129350d670daSJeff Roberson self.confmenu = Menu(self.conf, tearoff=0) 129450d670daSJeff Roberson self.confmenu.add_command(label="Event Colors", 1295dcee3bd3SJeff Roberson command=self.econf) 129650d670daSJeff Roberson self.confmenu.add_command(label="CPU Colors", 1297ec5cae07SJeff Roberson command=self.cconf) 129850d670daSJeff Roberson self.confmenu.add_command(label="Source Configure", 12993d21f0f4SJeff Roberson command=self.sconf) 130050d670daSJeff Roberson self.conf["menu"] = self.confmenu 130150d670daSJeff Roberson self.conf.pack(side=LEFT) 1302dcee3bd3SJeff Roberson 1303dcee3bd3SJeff Roberson def econf(self): 1304ec5cae07SJeff Roberson ColorConfigure(eventcolors, "Event Display Configuration") 1305ec5cae07SJeff Roberson 1306ec5cae07SJeff Roberson def cconf(self): 1307ec5cae07SJeff Roberson ColorConfigure(cpucolors, "CPU Background Colors") 1308dcee3bd3SJeff Roberson 13093d21f0f4SJeff Roberson def sconf(self): 13103d21f0f4SJeff Roberson SourceConfigure() 13113d21f0f4SJeff Roberson 1312dcee3bd3SJeff Robersonclass SchedGraph(Frame): 1313dcee3bd3SJeff Roberson def __init__(self, master): 1314dcee3bd3SJeff Roberson Frame.__init__(self, master) 1315dcee3bd3SJeff Roberson self.menu = None 1316dcee3bd3SJeff Roberson self.names = None 1317dcee3bd3SJeff Roberson self.display = None 1318dcee3bd3SJeff Roberson self.scale = None 1319dcee3bd3SJeff Roberson self.status = None 1320932f0fa2SJeff Roberson self.bdheight = Y_BORDER 1321ec5cae07SJeff Roberson self.clicksource = None 1322ec5cae07SJeff Roberson self.lastsource = None 1323dcee3bd3SJeff Roberson self.pack(expand=1, fill="both") 1324dcee3bd3SJeff Roberson self.buildwidgets() 1325dcee3bd3SJeff Roberson self.layout() 13269799411bSJohn Baldwin self.bind_all("<Control-q>", self.quitcb) 13279799411bSJohn Baldwin 13289799411bSJohn Baldwin def quitcb(self, event): 13299799411bSJohn Baldwin self.quit() 1330dcee3bd3SJeff Roberson 1331dcee3bd3SJeff Roberson def buildwidgets(self): 1332dcee3bd3SJeff Roberson global status 1333dcee3bd3SJeff Roberson self.menu = GraphMenu(self) 1334dcee3bd3SJeff Roberson self.display = SchedDisplay(self) 1335ec5cae07SJeff Roberson self.names = SchedNames(self, self.display) 1336dcee3bd3SJeff Roberson self.scale = Scaler(self, self.display) 1337dcee3bd3SJeff Roberson status = self.status = Status(self) 1338dcee3bd3SJeff Roberson self.scrollY = Scrollbar(self, orient="vertical", 1339dcee3bd3SJeff Roberson command=self.display_yview) 1340dcee3bd3SJeff Roberson self.display.scrollX = Scrollbar(self, orient="horizontal", 1341dcee3bd3SJeff Roberson command=self.display.xview) 1342dcee3bd3SJeff Roberson self.display["xscrollcommand"] = self.display.scrollX.set 1343dcee3bd3SJeff Roberson self.display["yscrollcommand"] = self.scrollY.set 1344dcee3bd3SJeff Roberson self.names["yscrollcommand"] = self.scrollY.set 1345dcee3bd3SJeff Roberson 1346dcee3bd3SJeff Roberson def layout(self): 1347dcee3bd3SJeff Roberson self.columnconfigure(1, weight=1) 1348dcee3bd3SJeff Roberson self.rowconfigure(1, weight=1) 1349dcee3bd3SJeff Roberson self.menu.grid(row=0, column=0, columnspan=3, sticky=E+W) 1350dcee3bd3SJeff Roberson self.names.grid(row=1, column=0, sticky=N+S) 1351dcee3bd3SJeff Roberson self.display.grid(row=1, column=1, sticky=W+E+N+S) 1352dcee3bd3SJeff Roberson self.scrollY.grid(row=1, column=2, sticky=N+S) 1353dcee3bd3SJeff Roberson self.display.scrollX.grid(row=2, column=0, columnspan=2, 1354dcee3bd3SJeff Roberson sticky=E+W) 1355dcee3bd3SJeff Roberson self.scale.grid(row=3, column=0, columnspan=3, sticky=E+W) 1356dcee3bd3SJeff Roberson self.status.grid(row=4, column=0, columnspan=3, sticky=E+W) 1357dcee3bd3SJeff Roberson 1358ec5cae07SJeff Roberson def draw(self): 1359dcee3bd3SJeff Roberson self.master.update() 1360ec5cae07SJeff Roberson self.display.prepare() 1361ec5cae07SJeff Roberson self.names.draw() 1362dcee3bd3SJeff Roberson self.display.draw() 1363ec5cae07SJeff Roberson self.status.startup("") 136416ef0f3bSJeff Roberson # 136516ef0f3bSJeff Roberson # Configure scale related values 136616ef0f3bSJeff Roberson # 136716ef0f3bSJeff Roberson scalemax = ktrfile.timespan() / int(self.display["width"]) 136816ef0f3bSJeff Roberson width = int(root.geometry().split('x')[0]) 136916ef0f3bSJeff Roberson self.constwidth = width - int(self.display["width"]) 137016ef0f3bSJeff Roberson self.scale.setmax(scalemax) 137116ef0f3bSJeff Roberson self.scale.set(scalemax) 1372dcee3bd3SJeff Roberson self.display.xview_moveto(0) 137316ef0f3bSJeff Roberson self.bind("<Configure>", self.resize) 1374dcee3bd3SJeff Roberson 1375ec5cae07SJeff Roberson def mousepress(self, event): 1376ec5cae07SJeff Roberson self.clicksource = self.sourceat(event.y) 1377ec5cae07SJeff Roberson 137850d670daSJeff Roberson def mousepressright(self, event): 137950d670daSJeff Roberson source = self.sourceat(event.y) 138050d670daSJeff Roberson if (source == None): 138150d670daSJeff Roberson return 138250d670daSJeff Roberson SourceContext(event, source) 138350d670daSJeff Roberson 1384ec5cae07SJeff Roberson def mouserelease(self, event): 1385ec5cae07SJeff Roberson if (self.clicksource == None): 1386ec5cae07SJeff Roberson return 1387ec5cae07SJeff Roberson newsource = self.sourceat(event.y) 1388ec5cae07SJeff Roberson if (self.clicksource != newsource): 1389ec5cae07SJeff Roberson self.sourceswap(self.clicksource, newsource) 1390ec5cae07SJeff Roberson self.clicksource = None 1391ec5cae07SJeff Roberson self.lastsource = None 1392ec5cae07SJeff Roberson 1393ec5cae07SJeff Roberson def mousemotion(self, event): 1394ec5cae07SJeff Roberson if (self.clicksource == None): 1395ec5cae07SJeff Roberson return 1396ec5cae07SJeff Roberson newsource = self.sourceat(event.y) 1397ec5cae07SJeff Roberson # 1398ec5cae07SJeff Roberson # If we get a None source they moved off the page. 1399ec5cae07SJeff Roberson # swapsource() can't handle moving multiple items so just 1400ec5cae07SJeff Roberson # pretend we never clicked on anything to begin with so the 1401ec5cae07SJeff Roberson # user can't mouseover a non-contiguous area. 1402ec5cae07SJeff Roberson # 1403ec5cae07SJeff Roberson if (newsource == None): 1404ec5cae07SJeff Roberson self.clicksource = None 1405ec5cae07SJeff Roberson self.lastsource = None 1406ec5cae07SJeff Roberson return 1407ec5cae07SJeff Roberson if (newsource == self.lastsource): 1408ec5cae07SJeff Roberson return; 1409ec5cae07SJeff Roberson self.lastsource = newsource 1410ec5cae07SJeff Roberson if (newsource != self.clicksource): 1411ec5cae07SJeff Roberson self.sourceswap(self.clicksource, newsource) 1412ec5cae07SJeff Roberson 1413ec5cae07SJeff Roberson # These are here because this object controls layout 1414ec5cae07SJeff Roberson def sourcestart(self, source): 1415ec5cae07SJeff Roberson return source.y - self.bdheight - source.ysize() 1416ec5cae07SJeff Roberson 1417ec5cae07SJeff Roberson def sourceend(self, source): 1418ec5cae07SJeff Roberson return source.y + self.bdheight 1419ec5cae07SJeff Roberson 1420ec5cae07SJeff Roberson def sourcesize(self, source): 1421ec5cae07SJeff Roberson return (self.bdheight * 2) + source.ysize() 1422ec5cae07SJeff Roberson 1423ec5cae07SJeff Roberson def sourceswap(self, source1, source2): 1424ec5cae07SJeff Roberson # Sort so we always know which one is on top. 1425ec5cae07SJeff Roberson if (source2.y < source1.y): 1426ec5cae07SJeff Roberson swap = source1 1427ec5cae07SJeff Roberson source1 = source2 1428ec5cae07SJeff Roberson source2 = swap 1429ec5cae07SJeff Roberson # Only swap adjacent sources 1430ec5cae07SJeff Roberson if (self.sourceend(source1) != self.sourcestart(source2)): 1431ec5cae07SJeff Roberson return 1432ec5cae07SJeff Roberson # Compute start coordinates and target coordinates 1433ec5cae07SJeff Roberson y1 = self.sourcestart(source1) 1434ec5cae07SJeff Roberson y2 = self.sourcestart(source2) 1435ec5cae07SJeff Roberson y1targ = y1 + self.sourcesize(source2) 1436ec5cae07SJeff Roberson y2targ = y1 1437ec5cae07SJeff Roberson # 1438ec5cae07SJeff Roberson # If the sizes are not equal, adjust the start of the lower 1439ec5cae07SJeff Roberson # source to account for the lost/gained space. 1440ec5cae07SJeff Roberson # 1441ec5cae07SJeff Roberson if (source1.ysize() != source2.ysize()): 1442ec5cae07SJeff Roberson diff = source2.ysize() - source1.ysize() 1443ec5cae07SJeff Roberson self.names.moveline(y2, diff); 1444ec5cae07SJeff Roberson self.display.moveline(y2, diff) 1445ec5cae07SJeff Roberson source1.move(self.display, 0, y1targ - y1) 1446ec5cae07SJeff Roberson source2.move(self.display, 0, y2targ - y2) 1447ec5cae07SJeff Roberson source1.movename(self.names, 0, y1targ - y1) 1448ec5cae07SJeff Roberson source2.movename(self.names, 0, y2targ - y2) 1449ec5cae07SJeff Roberson 145050d670daSJeff Roberson def sourcepicky(self, source): 14513d21f0f4SJeff Roberson if (source.hidden == 0): 145250d670daSJeff Roberson return self.sourcestart(source) 145350d670daSJeff Roberson # Revert to group based sort 145450d670daSJeff Roberson sources.sort() 14553d21f0f4SJeff Roberson prev = None 14563d21f0f4SJeff Roberson for s in sources: 14573d21f0f4SJeff Roberson if (s == source): 14583d21f0f4SJeff Roberson break 14593d21f0f4SJeff Roberson if (s.hidden == 0): 14603d21f0f4SJeff Roberson prev = s 14613d21f0f4SJeff Roberson if (prev == None): 14623d21f0f4SJeff Roberson newy = 0 14633d21f0f4SJeff Roberson else: 14643d21f0f4SJeff Roberson newy = self.sourcestart(prev) + self.sourcesize(prev) 146550d670daSJeff Roberson return newy 146650d670daSJeff Roberson 146750d670daSJeff Roberson def sourceshow(self, source): 146850d670daSJeff Roberson if (source.hidden == 0): 146950d670daSJeff Roberson return; 147050d670daSJeff Roberson newy = self.sourcepicky(source) 14713d21f0f4SJeff Roberson off = newy - self.sourcestart(source) 147250d670daSJeff Roberson self.sourceshiftall(newy-1, self.sourcesize(source)) 14733d21f0f4SJeff Roberson self.sourceshift(source, off) 14743d21f0f4SJeff Roberson source.hidden = 0 14753d21f0f4SJeff Roberson 147650d670daSJeff Roberson # 147750d670daSJeff Roberson # Optimized source show of multiple entries that only moves each 147850d670daSJeff Roberson # existing entry once. Doing sourceshow() iteratively is too 147950d670daSJeff Roberson # expensive due to python's canvas.move(). 148050d670daSJeff Roberson # 148150d670daSJeff Roberson def sourceshowlist(self, srclist): 1482*7e8ed296SAndriy Gapon srclist.sort(key=attrgetter('y')) 148350d670daSJeff Roberson startsize = [] 148450d670daSJeff Roberson for source in srclist: 148550d670daSJeff Roberson if (source.hidden == 0): 148650d670daSJeff Roberson srclist.remove(source) 148750d670daSJeff Roberson startsize.append((self.sourcepicky(source), 148850d670daSJeff Roberson self.sourcesize(source))) 148950d670daSJeff Roberson 1490*7e8ed296SAndriy Gapon sources.sort(key=attrgetter('y'), reverse=True) 149150d670daSJeff Roberson self.status.startup("Updating display..."); 149250d670daSJeff Roberson for source in sources: 149350d670daSJeff Roberson if (source.hidden == 1): 149450d670daSJeff Roberson continue 149550d670daSJeff Roberson nstart = self.sourcestart(source) 149650d670daSJeff Roberson size = 0 149750d670daSJeff Roberson for hidden in startsize: 149850d670daSJeff Roberson (start, sz) = hidden 149950d670daSJeff Roberson if (start <= nstart or start+sz <= nstart): 150050d670daSJeff Roberson size += sz 150150d670daSJeff Roberson self.sourceshift(source, size) 150250d670daSJeff Roberson idx = 0 150350d670daSJeff Roberson size = 0 150450d670daSJeff Roberson for source in srclist: 150550d670daSJeff Roberson (newy, sz) = startsize[idx] 150650d670daSJeff Roberson off = (newy + size) - self.sourcestart(source) 150750d670daSJeff Roberson self.sourceshift(source, off) 150850d670daSJeff Roberson source.hidden = 0 150950d670daSJeff Roberson size += sz 151050d670daSJeff Roberson idx += 1 151116ef0f3bSJeff Roberson self.updatescroll() 151250d670daSJeff Roberson self.status.set("") 151350d670daSJeff Roberson 151450d670daSJeff Roberson # 151550d670daSJeff Roberson # Optimized source hide of multiple entries that only moves each 151650d670daSJeff Roberson # remaining entry once. Doing sourcehide() iteratively is too 151750d670daSJeff Roberson # expensive due to python's canvas.move(). 151850d670daSJeff Roberson # 151950d670daSJeff Roberson def sourcehidelist(self, srclist): 1520*7e8ed296SAndriy Gapon srclist.sort(key=attrgetter('y')) 1521*7e8ed296SAndriy Gapon sources.sort(key=attrgetter('y')) 152250d670daSJeff Roberson startsize = [] 152350d670daSJeff Roberson off = len(sources) * 100 152450d670daSJeff Roberson self.status.startup("Updating display..."); 152550d670daSJeff Roberson for source in srclist: 152650d670daSJeff Roberson if (source.hidden == 1): 152750d670daSJeff Roberson srclist.remove(source) 152850d670daSJeff Roberson # 152950d670daSJeff Roberson # Remember our old position so we can sort things 153050d670daSJeff Roberson # below us when we're done. 153150d670daSJeff Roberson # 153250d670daSJeff Roberson startsize.append((self.sourcestart(source), 153350d670daSJeff Roberson self.sourcesize(source))) 153450d670daSJeff Roberson self.sourceshift(source, off) 153550d670daSJeff Roberson source.hidden = 1 153650d670daSJeff Roberson 153750d670daSJeff Roberson idx = 0 153850d670daSJeff Roberson size = 0 153950d670daSJeff Roberson for hidden in startsize: 154050d670daSJeff Roberson (start, sz) = hidden 154150d670daSJeff Roberson size += sz 154250d670daSJeff Roberson if (idx + 1 < len(startsize)): 154350d670daSJeff Roberson (stop, sz) = startsize[idx+1] 154450d670daSJeff Roberson else: 154550d670daSJeff Roberson stop = self.display.ysize() 154650d670daSJeff Roberson idx += 1 154750d670daSJeff Roberson for source in sources: 154850d670daSJeff Roberson nstart = self.sourcestart(source) 154950d670daSJeff Roberson if (nstart < start or source.hidden == 1): 155050d670daSJeff Roberson continue 155150d670daSJeff Roberson if (nstart >= stop): 155250d670daSJeff Roberson break; 155350d670daSJeff Roberson self.sourceshift(source, -size) 155416ef0f3bSJeff Roberson self.updatescroll() 155550d670daSJeff Roberson self.status.set("") 155650d670daSJeff Roberson 15573d21f0f4SJeff Roberson def sourcehide(self, source): 155850d670daSJeff Roberson if (source.hidden == 1): 155950d670daSJeff Roberson return; 15603d21f0f4SJeff Roberson # Move it out of the visible area 15613d21f0f4SJeff Roberson off = len(sources) * 100 15623d21f0f4SJeff Roberson start = self.sourcestart(source) 15633d21f0f4SJeff Roberson self.sourceshift(source, off) 15643d21f0f4SJeff Roberson self.sourceshiftall(start, -self.sourcesize(source)) 15653d21f0f4SJeff Roberson source.hidden = 1 15663d21f0f4SJeff Roberson 15673d21f0f4SJeff Roberson def sourceshift(self, source, off): 15683d21f0f4SJeff Roberson start = self.sourcestart(source) 15693d21f0f4SJeff Roberson source.move(self.display, 0, off) 15703d21f0f4SJeff Roberson source.movename(self.names, 0, off) 15713d21f0f4SJeff Roberson self.names.moveline(start, off); 15723d21f0f4SJeff Roberson self.display.moveline(start, off) 157350d670daSJeff Roberson # 157450d670daSJeff Roberson # We update the idle tasks to shrink the dirtied area so 157550d670daSJeff Roberson # it does not always include the entire screen. 157650d670daSJeff Roberson # 157750d670daSJeff Roberson self.names.update_idletasks() 157850d670daSJeff Roberson self.display.update_idletasks() 15793d21f0f4SJeff Roberson 15803d21f0f4SJeff Roberson def sourceshiftall(self, start, off): 158150d670daSJeff Roberson self.status.startup("Updating display..."); 15823d21f0f4SJeff Roberson for source in sources: 15833d21f0f4SJeff Roberson nstart = self.sourcestart(source) 15843d21f0f4SJeff Roberson if (nstart < start): 15853d21f0f4SJeff Roberson continue; 15863d21f0f4SJeff Roberson self.sourceshift(source, off) 158716ef0f3bSJeff Roberson self.updatescroll() 158850d670daSJeff Roberson self.status.set("") 15893d21f0f4SJeff Roberson 1590ec5cae07SJeff Roberson def sourceat(self, ypos): 1591ec5cae07SJeff Roberson (start, end) = self.names.yview() 1592ec5cae07SJeff Roberson starty = start * float(self.names.ysize) 1593ec5cae07SJeff Roberson ypos += starty 1594ec5cae07SJeff Roberson for source in sources: 15953d21f0f4SJeff Roberson if (source.hidden == 1): 15963d21f0f4SJeff Roberson continue; 1597ec5cae07SJeff Roberson yend = self.sourceend(source) 1598ec5cae07SJeff Roberson ystart = self.sourcestart(source) 1599ec5cae07SJeff Roberson if (ypos >= ystart and ypos <= yend): 1600ec5cae07SJeff Roberson return source 1601ec5cae07SJeff Roberson return None 1602ec5cae07SJeff Roberson 1603dcee3bd3SJeff Roberson def display_yview(self, *args): 1604dcee3bd3SJeff Roberson self.names.yview(*args) 1605dcee3bd3SJeff Roberson self.display.yview(*args) 1606dcee3bd3SJeff Roberson 160716ef0f3bSJeff Roberson def resize(self, *args): 160816ef0f3bSJeff Roberson width = int(root.geometry().split('x')[0]) 160916ef0f3bSJeff Roberson scalemax = ktrfile.timespan() / (width - self.constwidth) 161016ef0f3bSJeff Roberson self.scale.setmax(scalemax) 161116ef0f3bSJeff Roberson 161216ef0f3bSJeff Roberson def updatescroll(self): 161316ef0f3bSJeff Roberson self.names.updatescroll() 161416ef0f3bSJeff Roberson self.display.updatescroll() 161516ef0f3bSJeff Roberson 1616dcee3bd3SJeff Roberson def setcolor(self, tag, color): 1617dcee3bd3SJeff Roberson self.display.setcolor(tag, color) 1618dcee3bd3SJeff Roberson 1619dcee3bd3SJeff Roberson def hide(self, tag): 1620dcee3bd3SJeff Roberson self.display.hide(tag) 1621dcee3bd3SJeff Roberson 1622ec5cae07SJeff Roberson def getcolor(self, tag): 1623ec5cae07SJeff Roberson return self.display.getcolor(tag) 1624ec5cae07SJeff Roberson 1625ec5cae07SJeff Roberson def getstate(self, tag): 1626ec5cae07SJeff Roberson return self.display.getstate(tag) 1627ec5cae07SJeff Roberson 1628ec5cae07SJeff Robersonif (len(sys.argv) != 2 and len(sys.argv) != 3): 1629749f65e3SCraig Rodrigues print("usage:", sys.argv[0], "<ktr file> [clock freq in ghz]") 1630dcee3bd3SJeff Roberson sys.exit(1) 1631dcee3bd3SJeff Roberson 1632ec5cae07SJeff Robersonif (len(sys.argv) > 2): 1633ec5cae07SJeff Roberson clockfreq = float(sys.argv[2]) 1634ec5cae07SJeff Roberson 1635dcee3bd3SJeff Robersonroot = Tk() 1636932f0fa2SJeff Robersonroot.title("SchedGraph") 1637ec5cae07SJeff Robersoncolormap = Colormap(eventcolors) 1638ec5cae07SJeff Robersoncpucolormap = Colormap(cpucolors) 1639dcee3bd3SJeff Robersongraph = SchedGraph(root) 1640ec5cae07SJeff Robersonktrfile = KTRFile(sys.argv[1]) 1641ec5cae07SJeff Robersongraph.draw() 1642dcee3bd3SJeff Robersonroot.mainloop() 1643