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# $FreeBSD$ 28dcee3bd3SJeff Roberson 29749f65e3SCraig Rodriguesfrom __future__ import print_function 30dcee3bd3SJeff Robersonimport sys 31dcee3bd3SJeff Robersonimport re 32ec5cae07SJeff Robersonimport random 33*7e8ed296SAndriy Gaponfrom operator import attrgetter, itemgetter 34*7e8ed296SAndriy Gaponfrom functools import total_ordering 35*7e8ed296SAndriy Gaponfrom tkinter import * 36dcee3bd3SJeff Roberson 37698e6141SAndrew R. Reiter# To use: 3866835de4SSam Leffler# - Install the ports/x11-toolkits/py-tkinter package; e.g. 39*7e8ed296SAndriy Gapon# pkg install x11-toolkits/py-tkinter 4066835de4SSam Leffler# - Add KTR_SCHED to KTR_COMPILE and KTR_MASK in your KERNCONF; e.g. 4166835de4SSam Leffler# options KTR 4266835de4SSam Leffler# options KTR_ENTRIES=32768 4366835de4SSam Leffler# options KTR_COMPILE=(KTR_SCHED) 4466835de4SSam Leffler# options KTR_MASK=(KTR_SCHED) 4566835de4SSam Leffler# - It is encouraged to increase KTR_ENTRIES size to gather enough 4666835de4SSam Leffler# information for analysis; e.g. 4766835de4SSam Leffler# options KTR_ENTRIES=262144 48e73e7730SKris Kennaway# as 32768 entries may only correspond to a second or two of profiling 49e73e7730SKris Kennaway# data depending on your workload. 5070015002SKris Kennaway# - Rebuild kernel with proper changes to KERNCONF and boot new kernel. 5170015002SKris Kennaway# - Run your workload to be profiled. 5270015002SKris Kennaway# - While the workload is continuing (i.e. before it finishes), disable 5370015002SKris Kennaway# KTR tracing by setting 'sysctl debug.ktr.mask=0'. This is necessary 5470015002SKris Kennaway# to avoid a race condition while running ktrdump, i.e. the KTR ring buffer 5570015002SKris Kennaway# will cycle a bit while ktrdump runs, and this confuses schedgraph because 5670015002SKris Kennaway# the timestamps appear to go backwards at some point. Stopping KTR logging 5770015002SKris Kennaway# while the workload is still running is to avoid wasting log entries on 5870015002SKris Kennaway# "idle" time at the end. 59698e6141SAndrew R. Reiter# - Dump the trace to a file: 'ktrdump -ct > ktr.out' 60*7e8ed296SAndriy Gapon# - Alternatively, use schedgraph.d script in this directory for getting 61*7e8ed296SAndriy Gapon# the trace data by means of DTrace. See the script for details. 62ec5cae07SJeff Roberson# - Run the python script: 'python schedgraph.py ktr.out' optionally provide 63ec5cae07SJeff Roberson# your cpu frequency in ghz: 'python schedgraph.py ktr.out 2.4' 64698e6141SAndrew R. Reiter# 65698e6141SAndrew R. Reiter# To do: 66ec5cae07SJeff Roberson# Add a per-source summary display 67ec5cae07SJeff Roberson# "Vertical rule" to help relate data in different rows 68ec5cae07SJeff Roberson# Mouse-over popup of full thread/event/row label (currently truncated) 69ec5cae07SJeff Roberson# More visible anchors for popup event windows 7070015002SKris Kennaway# 7170015002SKris Kennaway# BUGS: 1) Only 8 CPUs are supported, more CPUs require more choices of 7270015002SKris Kennaway# colours to represent them ;-) 73ec5cae07SJeff Roberson 74ec5cae07SJeff Robersoneventcolors = [ 75ec5cae07SJeff Roberson ("count", "red"), 76ec5cae07SJeff Roberson ("running", "green"), 77ec5cae07SJeff Roberson ("idle", "grey"), 782cba8dd3SJohn Baldwin ("spinning", "red"), 79ec5cae07SJeff Roberson ("yielding", "yellow"), 80ec5cae07SJeff Roberson ("swapped", "violet"), 81ec5cae07SJeff Roberson ("suspended", "purple"), 82ec5cae07SJeff Roberson ("iwait", "grey"), 83ec5cae07SJeff Roberson ("sleep", "blue"), 84ec5cae07SJeff Roberson ("blocked", "dark red"), 85ec5cae07SJeff Roberson ("runq add", "yellow"), 86ec5cae07SJeff Roberson ("runq rem", "yellow"), 87ec5cae07SJeff Roberson ("thread exit", "grey"), 88ec5cae07SJeff Roberson ("proc exit", "grey"), 89ec5cae07SJeff Roberson ("lock acquire", "blue"), 90ec5cae07SJeff Roberson ("lock contest", "purple"), 91ec5cae07SJeff Roberson ("failed lock try", "red"), 92ec5cae07SJeff Roberson ("lock release", "grey"), 93932f0fa2SJeff Roberson ("statclock", "black"), 94ec5cae07SJeff Roberson ("prio", "black"), 95ec5cae07SJeff Roberson ("lend prio", "black"), 96ec5cae07SJeff Roberson ("wokeup", "black") 97ec5cae07SJeff Roberson] 98ec5cae07SJeff Roberson 99ec5cae07SJeff Robersoncpucolors = [ 100ec5cae07SJeff Roberson ("CPU 0", "light grey"), 101ec5cae07SJeff Roberson ("CPU 1", "dark grey"), 102ec5cae07SJeff Roberson ("CPU 2", "light blue"), 103ec5cae07SJeff Roberson ("CPU 3", "light pink"), 104ec5cae07SJeff Roberson ("CPU 4", "blanched almond"), 105ec5cae07SJeff Roberson ("CPU 5", "slate grey"), 106ec5cae07SJeff Roberson ("CPU 6", "tan"), 107ec5cae07SJeff Roberson ("CPU 7", "thistle"), 108ec5cae07SJeff Roberson ("CPU 8", "white") 109ec5cae07SJeff Roberson] 110ec5cae07SJeff Roberson 111ec5cae07SJeff Robersoncolors = [ 112ec5cae07SJeff Roberson "white", "thistle", "blanched almond", "tan", "chartreuse", 113ec5cae07SJeff Roberson "dark red", "red", "pale violet red", "pink", "light pink", 114ec5cae07SJeff Roberson "dark orange", "orange", "coral", "light coral", 115ec5cae07SJeff Roberson "goldenrod", "gold", "yellow", "light yellow", 116ec5cae07SJeff Roberson "dark green", "green", "light green", "light sea green", 117ec5cae07SJeff Roberson "dark blue", "blue", "light blue", "steel blue", "light slate blue", 118ec5cae07SJeff Roberson "dark violet", "violet", "purple", "blue violet", 119ec5cae07SJeff Roberson "dark grey", "slate grey", "light grey", 120ec5cae07SJeff Roberson "black", 121ec5cae07SJeff Roberson] 122ec5cae07SJeff Robersoncolors.sort() 123dcee3bd3SJeff Roberson 124dcee3bd3SJeff Robersonticksps = None 125dcee3bd3SJeff Robersonstatus = None 126ec5cae07SJeff Robersoncolormap = None 127ec5cae07SJeff Robersonktrfile = None 128ec5cae07SJeff Robersonclockfreq = None 129ec5cae07SJeff Robersonsources = [] 13066835de4SSam Lefflerlineno = -1 131dcee3bd3SJeff Roberson 132932f0fa2SJeff RobersonY_BORDER = 10 133932f0fa2SJeff RobersonX_BORDER = 10 134932f0fa2SJeff RobersonY_COUNTER = 80 135932f0fa2SJeff RobersonY_EVENTSOURCE = 10 136932f0fa2SJeff RobersonXY_POINT = 4 137932f0fa2SJeff Roberson 138ec5cae07SJeff Robersonclass Colormap: 139ec5cae07SJeff Roberson def __init__(self, table): 140ec5cae07SJeff Roberson self.table = table 141ec5cae07SJeff Roberson self.map = {} 142ec5cae07SJeff Roberson for entry in table: 143ec5cae07SJeff Roberson self.map[entry[0]] = entry[1] 144ec5cae07SJeff Roberson 145ec5cae07SJeff Roberson def lookup(self, name): 146ec5cae07SJeff Roberson try: 147ec5cae07SJeff Roberson color = self.map[name] 148ec5cae07SJeff Roberson except: 149ec5cae07SJeff Roberson color = colors[random.randrange(0, len(colors))] 150749f65e3SCraig Rodrigues print("Picking random color", color, "for", name) 151ec5cae07SJeff Roberson self.map[name] = color 152ec5cae07SJeff Roberson self.table.append((name, color)) 153ec5cae07SJeff Roberson return (color) 154ec5cae07SJeff Roberson 155dcee3bd3SJeff Robersondef ticks2sec(ticks): 156b62baf95SJeff Roberson ticks = float(ticks) 157b62baf95SJeff Roberson ns = float(ticksps) / 1000000000 158b62baf95SJeff Roberson ticks /= ns 159dcee3bd3SJeff Roberson if (ticks < 1000): 160b62baf95SJeff Roberson return ("%.2fns" % ticks) 161dcee3bd3SJeff Roberson ticks /= 1000 162dcee3bd3SJeff Roberson if (ticks < 1000): 163b62baf95SJeff Roberson return ("%.2fus" % ticks) 164dcee3bd3SJeff Roberson ticks /= 1000 165b62baf95SJeff Roberson if (ticks < 1000): 166b62baf95SJeff Roberson return ("%.2fms" % ticks) 167b62baf95SJeff Roberson ticks /= 1000 168b62baf95SJeff Roberson return ("%.2fs" % ticks) 169dcee3bd3SJeff Roberson 170dcee3bd3SJeff Robersonclass Scaler(Frame): 171dcee3bd3SJeff Roberson def __init__(self, master, target): 172dcee3bd3SJeff Roberson Frame.__init__(self, master) 17316ef0f3bSJeff Roberson self.scale = None 17416ef0f3bSJeff Roberson self.target = target 175dcee3bd3SJeff Roberson self.label = Label(self, text="Ticks per pixel") 176dcee3bd3SJeff Roberson self.label.pack(side=LEFT) 17716ef0f3bSJeff Roberson self.resolution = 100 17816ef0f3bSJeff Roberson self.setmax(10000) 179dcee3bd3SJeff Roberson 180dcee3bd3SJeff Roberson def scaleset(self, value): 181dcee3bd3SJeff Roberson self.target.scaleset(int(value)) 182dcee3bd3SJeff Roberson 183dcee3bd3SJeff Roberson def set(self, value): 184dcee3bd3SJeff Roberson self.scale.set(value) 185dcee3bd3SJeff Roberson 18616ef0f3bSJeff Roberson def setmax(self, value): 18716ef0f3bSJeff Roberson # 18816ef0f3bSJeff Roberson # We can't reconfigure the to_ value so we delete the old 18916ef0f3bSJeff Roberson # window and make a new one when we resize. 19016ef0f3bSJeff Roberson # 19116ef0f3bSJeff Roberson if (self.scale != None): 19216ef0f3bSJeff Roberson self.scale.pack_forget() 19316ef0f3bSJeff Roberson self.scale.destroy() 19416ef0f3bSJeff Roberson self.scale = Scale(self, command=self.scaleset, 19516ef0f3bSJeff Roberson from_=100, to_=value, orient=HORIZONTAL, 19616ef0f3bSJeff Roberson resolution=self.resolution) 19716ef0f3bSJeff Roberson self.scale.pack(fill="both", expand=1) 19816ef0f3bSJeff Roberson self.scale.set(self.target.scaleget()) 19916ef0f3bSJeff Roberson 200dcee3bd3SJeff Robersonclass Status(Frame): 201dcee3bd3SJeff Roberson def __init__(self, master): 202dcee3bd3SJeff Roberson Frame.__init__(self, master) 203dcee3bd3SJeff Roberson self.label = Label(self, bd=1, relief=SUNKEN, anchor=W) 204dcee3bd3SJeff Roberson self.label.pack(fill="both", expand=1) 205dcee3bd3SJeff Roberson self.clear() 206dcee3bd3SJeff Roberson 207dcee3bd3SJeff Roberson def set(self, str): 208dcee3bd3SJeff Roberson self.label.config(text=str) 209dcee3bd3SJeff Roberson 210dcee3bd3SJeff Roberson def clear(self): 211dcee3bd3SJeff Roberson self.label.config(text="") 212dcee3bd3SJeff Roberson 213dcee3bd3SJeff Roberson def startup(self, str): 214dcee3bd3SJeff Roberson self.set(str) 215dcee3bd3SJeff Roberson root.update() 216dcee3bd3SJeff Roberson 217ec5cae07SJeff Robersonclass ColorConf(Frame): 218ec5cae07SJeff Roberson def __init__(self, master, name, color): 219dcee3bd3SJeff Roberson Frame.__init__(self, master) 220ec5cae07SJeff Roberson if (graph.getstate(name) == "hidden"): 221ec5cae07SJeff Roberson enabled = 0 222ec5cae07SJeff Roberson else: 223ec5cae07SJeff Roberson enabled = 1 224dcee3bd3SJeff Roberson self.name = name 225dcee3bd3SJeff Roberson self.color = StringVar() 226dcee3bd3SJeff Roberson self.color_default = color 227dcee3bd3SJeff Roberson self.color_current = color 228dcee3bd3SJeff Roberson self.color.set(color) 229dcee3bd3SJeff Roberson self.enabled = IntVar() 230dcee3bd3SJeff Roberson self.enabled_default = enabled 231dcee3bd3SJeff Roberson self.enabled_current = enabled 232dcee3bd3SJeff Roberson self.enabled.set(enabled) 233dcee3bd3SJeff Roberson self.draw() 234dcee3bd3SJeff Roberson 235dcee3bd3SJeff Roberson def draw(self): 236dcee3bd3SJeff Roberson self.label = Label(self, text=self.name, anchor=W) 237dcee3bd3SJeff Roberson self.sample = Canvas(self, width=24, height=24, 238dcee3bd3SJeff Roberson bg='grey') 239dcee3bd3SJeff Roberson self.rect = self.sample.create_rectangle(0, 0, 24, 24, 240dcee3bd3SJeff Roberson fill=self.color.get()) 241ec5cae07SJeff Roberson self.list = OptionMenu(self, self.color, command=self.setcolor, 242ec5cae07SJeff Roberson *colors) 243dcee3bd3SJeff Roberson self.checkbox = Checkbutton(self, text="enabled", 244dcee3bd3SJeff Roberson variable=self.enabled) 245dcee3bd3SJeff Roberson self.label.grid(row=0, column=0, sticky=E+W) 246dcee3bd3SJeff Roberson self.sample.grid(row=0, column=1) 247dcee3bd3SJeff Roberson self.list.grid(row=0, column=2, sticky=E+W) 248dcee3bd3SJeff Roberson self.checkbox.grid(row=0, column=3) 249dcee3bd3SJeff Roberson self.columnconfigure(0, weight=1) 250ec5cae07SJeff Roberson self.columnconfigure(2, minsize=150) 251dcee3bd3SJeff Roberson 252dcee3bd3SJeff Roberson def setcolor(self, color): 253dcee3bd3SJeff Roberson self.color.set(color) 254dcee3bd3SJeff Roberson self.sample.itemconfigure(self.rect, fill=color) 255dcee3bd3SJeff Roberson 256dcee3bd3SJeff Roberson def apply(self): 257dcee3bd3SJeff Roberson cchange = 0 258dcee3bd3SJeff Roberson echange = 0 259dcee3bd3SJeff Roberson if (self.color_current != self.color.get()): 260dcee3bd3SJeff Roberson cchange = 1 261dcee3bd3SJeff Roberson if (self.enabled_current != self.enabled.get()): 262dcee3bd3SJeff Roberson echange = 1 263dcee3bd3SJeff Roberson self.color_current = self.color.get() 264dcee3bd3SJeff Roberson self.enabled_current = self.enabled.get() 265dcee3bd3SJeff Roberson if (echange != 0): 266dcee3bd3SJeff Roberson if (self.enabled_current): 267dcee3bd3SJeff Roberson graph.setcolor(self.name, self.color_current) 268dcee3bd3SJeff Roberson else: 269dcee3bd3SJeff Roberson graph.hide(self.name) 270dcee3bd3SJeff Roberson return 271dcee3bd3SJeff Roberson if (cchange != 0): 272dcee3bd3SJeff Roberson graph.setcolor(self.name, self.color_current) 273dcee3bd3SJeff Roberson 274dcee3bd3SJeff Roberson def revert(self): 275dcee3bd3SJeff Roberson self.setcolor(self.color_default) 276dcee3bd3SJeff Roberson self.enabled.set(self.enabled_default) 277dcee3bd3SJeff Roberson 278ec5cae07SJeff Robersonclass ColorConfigure(Toplevel): 279ec5cae07SJeff Roberson def __init__(self, table, name): 280dcee3bd3SJeff Roberson Toplevel.__init__(self) 281dcee3bd3SJeff Roberson self.resizable(0, 0) 282ec5cae07SJeff Roberson self.title(name) 283ec5cae07SJeff Roberson self.items = LabelFrame(self, text="Item Type") 284dcee3bd3SJeff Roberson self.buttons = Frame(self) 285dcee3bd3SJeff Roberson self.drawbuttons() 286dcee3bd3SJeff Roberson self.items.grid(row=0, column=0, sticky=E+W) 287dcee3bd3SJeff Roberson self.columnconfigure(0, weight=1) 288dcee3bd3SJeff Roberson self.buttons.grid(row=1, column=0, sticky=E+W) 289dcee3bd3SJeff Roberson self.types = [] 290dcee3bd3SJeff Roberson self.irow = 0 291ec5cae07SJeff Roberson for type in table: 292ec5cae07SJeff Roberson color = graph.getcolor(type[0]) 293ec5cae07SJeff Roberson if (color != ""): 294ec5cae07SJeff Roberson self.additem(type[0], color) 2959799411bSJohn Baldwin self.bind("<Control-w>", self.destroycb) 2969799411bSJohn Baldwin 2979799411bSJohn Baldwin def destroycb(self, event): 2989799411bSJohn Baldwin self.destroy() 299dcee3bd3SJeff Roberson 300ec5cae07SJeff Roberson def additem(self, name, color): 301ec5cae07SJeff Roberson item = ColorConf(self.items, name, color) 302dcee3bd3SJeff Roberson self.types.append(item) 303dcee3bd3SJeff Roberson item.grid(row=self.irow, column=0, sticky=E+W) 304dcee3bd3SJeff Roberson self.irow += 1 305dcee3bd3SJeff Roberson 306dcee3bd3SJeff Roberson def drawbuttons(self): 307dcee3bd3SJeff Roberson self.apply = Button(self.buttons, text="Apply", 308dcee3bd3SJeff Roberson command=self.apress) 309ec5cae07SJeff Roberson self.default = Button(self.buttons, text="Revert", 310dcee3bd3SJeff Roberson command=self.rpress) 311dcee3bd3SJeff Roberson self.apply.grid(row=0, column=0, sticky=E+W) 312ec5cae07SJeff Roberson self.default.grid(row=0, column=1, sticky=E+W) 313dcee3bd3SJeff Roberson self.buttons.columnconfigure(0, weight=1) 314dcee3bd3SJeff Roberson self.buttons.columnconfigure(1, weight=1) 315dcee3bd3SJeff Roberson 316dcee3bd3SJeff Roberson def apress(self): 317dcee3bd3SJeff Roberson for item in self.types: 318dcee3bd3SJeff Roberson item.apply() 319dcee3bd3SJeff Roberson 320dcee3bd3SJeff Roberson def rpress(self): 321dcee3bd3SJeff Roberson for item in self.types: 322dcee3bd3SJeff Roberson item.revert() 323dcee3bd3SJeff Roberson 3243d21f0f4SJeff Robersonclass SourceConf(Frame): 3253d21f0f4SJeff Roberson def __init__(self, master, source): 3263d21f0f4SJeff Roberson Frame.__init__(self, master) 3273d21f0f4SJeff Roberson if (source.hidden == 1): 3283d21f0f4SJeff Roberson enabled = 0 3293d21f0f4SJeff Roberson else: 3303d21f0f4SJeff Roberson enabled = 1 3313d21f0f4SJeff Roberson self.source = source 3323d21f0f4SJeff Roberson self.name = source.name 3333d21f0f4SJeff Roberson self.enabled = IntVar() 3343d21f0f4SJeff Roberson self.enabled_default = enabled 3353d21f0f4SJeff Roberson self.enabled_current = enabled 3363d21f0f4SJeff Roberson self.enabled.set(enabled) 3373d21f0f4SJeff Roberson self.draw() 3383d21f0f4SJeff Roberson 3393d21f0f4SJeff Roberson def draw(self): 3403d21f0f4SJeff Roberson self.label = Label(self, text=self.name, anchor=W) 3413d21f0f4SJeff Roberson self.checkbox = Checkbutton(self, text="enabled", 3423d21f0f4SJeff Roberson variable=self.enabled) 3433d21f0f4SJeff Roberson self.label.grid(row=0, column=0, sticky=E+W) 3443d21f0f4SJeff Roberson self.checkbox.grid(row=0, column=1) 3453d21f0f4SJeff Roberson self.columnconfigure(0, weight=1) 3463d21f0f4SJeff Roberson 34750d670daSJeff Roberson def changed(self): 3483d21f0f4SJeff Roberson if (self.enabled_current != self.enabled.get()): 34950d670daSJeff Roberson return 1 35050d670daSJeff Roberson return 0 35150d670daSJeff Roberson 35250d670daSJeff Roberson def apply(self): 3533d21f0f4SJeff Roberson self.enabled_current = self.enabled.get() 3543d21f0f4SJeff Roberson 3553d21f0f4SJeff Roberson def revert(self): 3563d21f0f4SJeff Roberson self.enabled.set(self.enabled_default) 3573d21f0f4SJeff Roberson 3583d21f0f4SJeff Roberson def check(self): 3593d21f0f4SJeff Roberson self.enabled.set(1) 3603d21f0f4SJeff Roberson 3613d21f0f4SJeff Roberson def uncheck(self): 3623d21f0f4SJeff Roberson self.enabled.set(0) 3633d21f0f4SJeff Roberson 3643d21f0f4SJeff Robersonclass SourceConfigure(Toplevel): 3653d21f0f4SJeff Roberson def __init__(self): 3663d21f0f4SJeff Roberson Toplevel.__init__(self) 3673d21f0f4SJeff Roberson self.resizable(0, 0) 3683d21f0f4SJeff Roberson self.title("Source Configuration") 3693d21f0f4SJeff Roberson self.items = [] 3703d21f0f4SJeff Roberson self.iframe = Frame(self) 3713d21f0f4SJeff Roberson self.iframe.grid(row=0, column=0, sticky=E+W) 3723d21f0f4SJeff Roberson f = LabelFrame(self.iframe, bd=4, text="Sources") 3733d21f0f4SJeff Roberson self.items.append(f) 3743d21f0f4SJeff Roberson self.buttons = Frame(self) 3753d21f0f4SJeff Roberson self.items[0].grid(row=0, column=0, sticky=E+W) 3763d21f0f4SJeff Roberson self.columnconfigure(0, weight=1) 3773d21f0f4SJeff Roberson self.sconfig = [] 3783d21f0f4SJeff Roberson self.irow = 0 3793d21f0f4SJeff Roberson self.icol = 0 3803d21f0f4SJeff Roberson for source in sources: 3813d21f0f4SJeff Roberson self.addsource(source) 3823d21f0f4SJeff Roberson self.drawbuttons() 3833d21f0f4SJeff Roberson self.buttons.grid(row=1, column=0, sticky=W) 3849799411bSJohn Baldwin self.bind("<Control-w>", self.destroycb) 3859799411bSJohn Baldwin 3869799411bSJohn Baldwin def destroycb(self, event): 3879799411bSJohn Baldwin self.destroy() 3883d21f0f4SJeff Roberson 3893d21f0f4SJeff Roberson def addsource(self, source): 3903d21f0f4SJeff Roberson if (self.irow > 30): 3913d21f0f4SJeff Roberson self.icol += 1 3923d21f0f4SJeff Roberson self.irow = 0 3933d21f0f4SJeff Roberson c = self.icol 3943d21f0f4SJeff Roberson f = LabelFrame(self.iframe, bd=4, text="Sources") 3953d21f0f4SJeff Roberson f.grid(row=0, column=c, sticky=N+E+W) 3963d21f0f4SJeff Roberson self.items.append(f) 3973d21f0f4SJeff Roberson item = SourceConf(self.items[self.icol], source) 3983d21f0f4SJeff Roberson self.sconfig.append(item) 3993d21f0f4SJeff Roberson item.grid(row=self.irow, column=0, sticky=E+W) 4003d21f0f4SJeff Roberson self.irow += 1 4013d21f0f4SJeff Roberson 4023d21f0f4SJeff Roberson def drawbuttons(self): 4033d21f0f4SJeff Roberson self.apply = Button(self.buttons, text="Apply", 4043d21f0f4SJeff Roberson command=self.apress) 4053d21f0f4SJeff Roberson self.default = Button(self.buttons, text="Revert", 4063d21f0f4SJeff Roberson command=self.rpress) 4073d21f0f4SJeff Roberson self.checkall = Button(self.buttons, text="Check All", 4083d21f0f4SJeff Roberson command=self.cpress) 4093d21f0f4SJeff Roberson self.uncheckall = Button(self.buttons, text="Uncheck All", 4103d21f0f4SJeff Roberson command=self.upress) 4113d21f0f4SJeff Roberson self.checkall.grid(row=0, column=0, sticky=W) 4123d21f0f4SJeff Roberson self.uncheckall.grid(row=0, column=1, sticky=W) 4133d21f0f4SJeff Roberson self.apply.grid(row=0, column=2, sticky=W) 4143d21f0f4SJeff Roberson self.default.grid(row=0, column=3, sticky=W) 4153d21f0f4SJeff Roberson self.buttons.columnconfigure(0, weight=1) 4163d21f0f4SJeff Roberson self.buttons.columnconfigure(1, weight=1) 4173d21f0f4SJeff Roberson self.buttons.columnconfigure(2, weight=1) 4183d21f0f4SJeff Roberson self.buttons.columnconfigure(3, weight=1) 4193d21f0f4SJeff Roberson 4203d21f0f4SJeff Roberson def apress(self): 42150d670daSJeff Roberson disable_sources = [] 42250d670daSJeff Roberson enable_sources = [] 42350d670daSJeff Roberson for item in self.sconfig: 42450d670daSJeff Roberson if (item.changed() == 0): 42550d670daSJeff Roberson continue 42650d670daSJeff Roberson if (item.enabled.get() == 1): 42750d670daSJeff Roberson enable_sources.append(item.source) 42850d670daSJeff Roberson else: 42950d670daSJeff Roberson disable_sources.append(item.source) 43050d670daSJeff Roberson 43150d670daSJeff Roberson if (len(disable_sources)): 43250d670daSJeff Roberson graph.sourcehidelist(disable_sources) 43350d670daSJeff Roberson if (len(enable_sources)): 43450d670daSJeff Roberson graph.sourceshowlist(enable_sources) 43550d670daSJeff Roberson 4363d21f0f4SJeff Roberson for item in self.sconfig: 4373d21f0f4SJeff Roberson item.apply() 4383d21f0f4SJeff Roberson 4393d21f0f4SJeff Roberson def rpress(self): 4403d21f0f4SJeff Roberson for item in self.sconfig: 4413d21f0f4SJeff Roberson item.revert() 4423d21f0f4SJeff Roberson 4433d21f0f4SJeff Roberson def cpress(self): 4443d21f0f4SJeff Roberson for item in self.sconfig: 4453d21f0f4SJeff Roberson item.check() 4463d21f0f4SJeff Roberson 4473d21f0f4SJeff Roberson def upress(self): 4483d21f0f4SJeff Roberson for item in self.sconfig: 4493d21f0f4SJeff Roberson item.uncheck() 4503d21f0f4SJeff Roberson 45150d670daSJeff Robersonclass SourceStats(Toplevel): 45250d670daSJeff Roberson def __init__(self, source): 45350d670daSJeff Roberson self.source = source 45450d670daSJeff Roberson Toplevel.__init__(self) 45550d670daSJeff Roberson self.resizable(0, 0) 45650d670daSJeff Roberson self.title(source.name + " statistics") 45750d670daSJeff Roberson self.evframe = LabelFrame(self, 458b62baf95SJeff Roberson text="Event Count, Duration, Avg Duration") 45950d670daSJeff Roberson self.evframe.grid(row=0, column=0, sticky=E+W) 46050d670daSJeff Roberson eventtypes={} 46150d670daSJeff Roberson for event in self.source.events: 46250d670daSJeff Roberson if (event.type == "pad"): 46350d670daSJeff Roberson continue 46450d670daSJeff Roberson duration = event.duration 465aef675d8SCraig Rodrigues if (event.name in eventtypes): 46650d670daSJeff Roberson (c, d) = eventtypes[event.name] 46750d670daSJeff Roberson c += 1 46850d670daSJeff Roberson d += duration 46950d670daSJeff Roberson eventtypes[event.name] = (c, d) 47050d670daSJeff Roberson else: 47150d670daSJeff Roberson eventtypes[event.name] = (1, duration) 47250d670daSJeff Roberson events = [] 47350d670daSJeff Roberson for k, v in eventtypes.iteritems(): 47450d670daSJeff Roberson (c, d) = v 47550d670daSJeff Roberson events.append((k, c, d)) 476*7e8ed296SAndriy Gapon events.sort(key=itemgetter(1), reverse=True) 47750d670daSJeff Roberson 47850d670daSJeff Roberson ypos = 0 47950d670daSJeff Roberson for event in events: 48050d670daSJeff Roberson (name, c, d) = event 481b62baf95SJeff Roberson Label(self.evframe, text=name, bd=1, 482b62baf95SJeff Roberson relief=SUNKEN, anchor=W, width=30).grid( 483b62baf95SJeff Roberson row=ypos, column=0, sticky=W+E) 484b62baf95SJeff Roberson Label(self.evframe, text=str(c), bd=1, 485b62baf95SJeff Roberson relief=SUNKEN, anchor=W, width=10).grid( 486b62baf95SJeff Roberson row=ypos, column=1, sticky=W+E) 487b62baf95SJeff Roberson Label(self.evframe, text=ticks2sec(d), 488b62baf95SJeff Roberson bd=1, relief=SUNKEN, width=10).grid( 489b62baf95SJeff Roberson row=ypos, column=2, sticky=W+E) 490b62baf95SJeff Roberson if (d and c): 491b62baf95SJeff Roberson d /= c 492b62baf95SJeff Roberson else: 493b62baf95SJeff Roberson d = 0 494b62baf95SJeff Roberson Label(self.evframe, text=ticks2sec(d), 495b62baf95SJeff Roberson bd=1, relief=SUNKEN, width=10).grid( 496b62baf95SJeff Roberson row=ypos, column=3, sticky=W+E) 49750d670daSJeff Roberson ypos += 1 4989799411bSJohn Baldwin self.bind("<Control-w>", self.destroycb) 4999799411bSJohn Baldwin 5009799411bSJohn Baldwin def destroycb(self, event): 5019799411bSJohn Baldwin self.destroy() 50250d670daSJeff Roberson 50350d670daSJeff Roberson 50450d670daSJeff Robersonclass SourceContext(Menu): 50550d670daSJeff Roberson def __init__(self, event, source): 50650d670daSJeff Roberson self.source = source 50750d670daSJeff Roberson Menu.__init__(self, tearoff=0, takefocus=0) 50850d670daSJeff Roberson self.add_command(label="hide", command=self.hide) 50950d670daSJeff Roberson self.add_command(label="hide group", command=self.hidegroup) 51050d670daSJeff Roberson self.add_command(label="stats", command=self.stats) 51150d670daSJeff Roberson self.tk_popup(event.x_root-3, event.y_root+3) 51250d670daSJeff Roberson 51350d670daSJeff Roberson def hide(self): 51450d670daSJeff Roberson graph.sourcehide(self.source) 51550d670daSJeff Roberson 51650d670daSJeff Roberson def hidegroup(self): 51750d670daSJeff Roberson grouplist = [] 51850d670daSJeff Roberson for source in sources: 51950d670daSJeff Roberson if (source.group == self.source.group): 52050d670daSJeff Roberson grouplist.append(source) 52150d670daSJeff Roberson graph.sourcehidelist(grouplist) 52250d670daSJeff Roberson 52350d670daSJeff Roberson def show(self): 52450d670daSJeff Roberson graph.sourceshow(self.source) 52550d670daSJeff Roberson 52650d670daSJeff Roberson def stats(self): 52750d670daSJeff Roberson SourceStats(self.source) 52850d670daSJeff Roberson 529dcee3bd3SJeff Robersonclass EventView(Toplevel): 530dcee3bd3SJeff Roberson def __init__(self, event, canvas): 531dcee3bd3SJeff Roberson Toplevel.__init__(self) 532dcee3bd3SJeff Roberson self.resizable(0, 0) 533dcee3bd3SJeff Roberson self.title("Event") 534dcee3bd3SJeff Roberson self.event = event 535dcee3bd3SJeff Roberson self.buttons = Frame(self) 536ec5cae07SJeff Roberson self.buttons.grid(row=0, column=0, sticky=E+W) 537ec5cae07SJeff Roberson self.frame = Frame(self) 538ec5cae07SJeff Roberson self.frame.grid(row=1, column=0, sticky=N+S+E+W) 539dcee3bd3SJeff Roberson self.canvas = canvas 540dcee3bd3SJeff Roberson self.drawlabels() 541dcee3bd3SJeff Roberson self.drawbuttons() 542dcee3bd3SJeff Roberson event.displayref(canvas) 543dcee3bd3SJeff Roberson self.bind("<Destroy>", self.destroycb) 5449799411bSJohn Baldwin self.bind("<Control-w>", self.destroycb) 545dcee3bd3SJeff Roberson 546dcee3bd3SJeff Roberson def destroycb(self, event): 547dcee3bd3SJeff Roberson self.unbind("<Destroy>") 548dcee3bd3SJeff Roberson if (self.event != None): 549dcee3bd3SJeff Roberson self.event.displayunref(self.canvas) 550dcee3bd3SJeff Roberson self.event = None 551dcee3bd3SJeff Roberson self.destroy() 552dcee3bd3SJeff Roberson 553dcee3bd3SJeff Roberson def clearlabels(self): 554dcee3bd3SJeff Roberson for label in self.frame.grid_slaves(): 555dcee3bd3SJeff Roberson label.grid_remove() 556dcee3bd3SJeff Roberson 557dcee3bd3SJeff Roberson def drawlabels(self): 558dcee3bd3SJeff Roberson ypos = 0 559dcee3bd3SJeff Roberson labels = self.event.labels() 560dcee3bd3SJeff Roberson while (len(labels) < 7): 561ec5cae07SJeff Roberson labels.append(("", "")) 562dcee3bd3SJeff Roberson for label in labels: 563ec5cae07SJeff Roberson name, value = label 564ec5cae07SJeff Roberson linked = 0 565ec5cae07SJeff Roberson if (name == "linkedto"): 566ec5cae07SJeff Roberson linked = 1 567dcee3bd3SJeff Roberson l = Label(self.frame, text=name, bd=1, width=15, 568dcee3bd3SJeff Roberson relief=SUNKEN, anchor=W) 569dcee3bd3SJeff Roberson if (linked): 570dcee3bd3SJeff Roberson fgcolor = "blue" 571dcee3bd3SJeff Roberson else: 572dcee3bd3SJeff Roberson fgcolor = "black" 573dcee3bd3SJeff Roberson r = Label(self.frame, text=value, bd=1, 574dcee3bd3SJeff Roberson relief=SUNKEN, anchor=W, fg=fgcolor) 575dcee3bd3SJeff Roberson l.grid(row=ypos, column=0, sticky=E+W) 576dcee3bd3SJeff Roberson r.grid(row=ypos, column=1, sticky=E+W) 577dcee3bd3SJeff Roberson if (linked): 578dcee3bd3SJeff Roberson r.bind("<Button-1>", self.linkpress) 579dcee3bd3SJeff Roberson ypos += 1 580dcee3bd3SJeff Roberson self.frame.columnconfigure(1, minsize=80) 581dcee3bd3SJeff Roberson 582dcee3bd3SJeff Roberson def drawbuttons(self): 583dcee3bd3SJeff Roberson self.back = Button(self.buttons, text="<", command=self.bpress) 584dcee3bd3SJeff Roberson self.forw = Button(self.buttons, text=">", command=self.fpress) 585dcee3bd3SJeff Roberson self.new = Button(self.buttons, text="new", command=self.npress) 586dcee3bd3SJeff Roberson self.back.grid(row=0, column=0, sticky=E+W) 587dcee3bd3SJeff Roberson self.forw.grid(row=0, column=1, sticky=E+W) 588dcee3bd3SJeff Roberson self.new.grid(row=0, column=2, sticky=E+W) 589dcee3bd3SJeff Roberson self.buttons.columnconfigure(2, weight=1) 590dcee3bd3SJeff Roberson 591dcee3bd3SJeff Roberson def newevent(self, event): 592dcee3bd3SJeff Roberson self.event.displayunref(self.canvas) 593dcee3bd3SJeff Roberson self.clearlabels() 594dcee3bd3SJeff Roberson self.event = event 595dcee3bd3SJeff Roberson self.event.displayref(self.canvas) 596dcee3bd3SJeff Roberson self.drawlabels() 597dcee3bd3SJeff Roberson 598dcee3bd3SJeff Roberson def npress(self): 599dcee3bd3SJeff Roberson EventView(self.event, self.canvas) 600dcee3bd3SJeff Roberson 601dcee3bd3SJeff Roberson def bpress(self): 602dcee3bd3SJeff Roberson prev = self.event.prev() 603dcee3bd3SJeff Roberson if (prev == None): 604dcee3bd3SJeff Roberson return 605ec5cae07SJeff Roberson while (prev.type == "pad"): 606dcee3bd3SJeff Roberson prev = prev.prev() 607dcee3bd3SJeff Roberson if (prev == None): 608dcee3bd3SJeff Roberson return 609dcee3bd3SJeff Roberson self.newevent(prev) 610dcee3bd3SJeff Roberson 611dcee3bd3SJeff Roberson def fpress(self): 612dcee3bd3SJeff Roberson next = self.event.next() 613dcee3bd3SJeff Roberson if (next == None): 614dcee3bd3SJeff Roberson return 615ec5cae07SJeff Roberson while (next.type == "pad"): 616dcee3bd3SJeff Roberson next = next.next() 617dcee3bd3SJeff Roberson if (next == None): 618dcee3bd3SJeff Roberson return 619dcee3bd3SJeff Roberson self.newevent(next) 620dcee3bd3SJeff Roberson 621dcee3bd3SJeff Roberson def linkpress(self, wevent): 622dcee3bd3SJeff Roberson event = self.event.getlinked() 623dcee3bd3SJeff Roberson if (event != None): 624dcee3bd3SJeff Roberson self.newevent(event) 625dcee3bd3SJeff Roberson 626dcee3bd3SJeff Robersonclass Event: 627ec5cae07SJeff Roberson def __init__(self, source, name, cpu, timestamp, attrs): 628dcee3bd3SJeff Roberson self.source = source 629ec5cae07SJeff Roberson self.name = name 630dcee3bd3SJeff Roberson self.cpu = cpu 631dcee3bd3SJeff Roberson self.timestamp = int(timestamp) 632ec5cae07SJeff Roberson self.attrs = attrs 633dcee3bd3SJeff Roberson self.idx = None 634dcee3bd3SJeff Roberson self.item = None 635dcee3bd3SJeff Roberson self.dispcnt = 0 63650d670daSJeff Roberson self.duration = 0 63766835de4SSam Leffler self.recno = lineno 638dcee3bd3SJeff Roberson 639dcee3bd3SJeff Roberson def status(self): 640dcee3bd3SJeff Roberson statstr = self.name + " " + self.source.name 641dcee3bd3SJeff Roberson statstr += " on: cpu" + str(self.cpu) 642dcee3bd3SJeff Roberson statstr += " at: " + str(self.timestamp) 643ec5cae07SJeff Roberson statstr += " attributes: " 644ec5cae07SJeff Roberson for i in range(0, len(self.attrs)): 645ec5cae07SJeff Roberson attr = self.attrs[i] 646ec5cae07SJeff Roberson statstr += attr[0] + ": " + str(attr[1]) 647ec5cae07SJeff Roberson if (i != len(self.attrs) - 1): 648ec5cae07SJeff Roberson statstr += ", " 649dcee3bd3SJeff Roberson status.set(statstr) 650dcee3bd3SJeff Roberson 651dcee3bd3SJeff Roberson def labels(self): 652ec5cae07SJeff Roberson return [("Source", self.source.name), 653ec5cae07SJeff Roberson ("Event", self.name), 654ec5cae07SJeff Roberson ("CPU", self.cpu), 655ec5cae07SJeff Roberson ("Timestamp", self.timestamp), 656ec5cae07SJeff Roberson ("KTR Line ", self.recno) 657ec5cae07SJeff Roberson ] + self.attrs 658ec5cae07SJeff Roberson 659ec5cae07SJeff Roberson def mouseenter(self, canvas): 660dcee3bd3SJeff Roberson self.displayref(canvas) 661dcee3bd3SJeff Roberson self.status() 662dcee3bd3SJeff Roberson 663ec5cae07SJeff Roberson def mouseexit(self, canvas): 664dcee3bd3SJeff Roberson self.displayunref(canvas) 665dcee3bd3SJeff Roberson status.clear() 666dcee3bd3SJeff Roberson 667ec5cae07SJeff Roberson def mousepress(self, canvas): 668dcee3bd3SJeff Roberson EventView(self, canvas) 669dcee3bd3SJeff Roberson 670ec5cae07SJeff Roberson def draw(self, canvas, xpos, ypos, item): 671ec5cae07SJeff Roberson self.item = item 672ec5cae07SJeff Roberson if (item != None): 673ec5cae07SJeff Roberson canvas.items[item] = self 674ec5cae07SJeff Roberson 675ec5cae07SJeff Roberson def move(self, canvas, x, y): 676ec5cae07SJeff Roberson if (self.item == None): 677ec5cae07SJeff Roberson return; 678ec5cae07SJeff Roberson canvas.move(self.item, x, y); 679ec5cae07SJeff Roberson 680dcee3bd3SJeff Roberson def next(self): 681dcee3bd3SJeff Roberson return self.source.eventat(self.idx + 1) 682dcee3bd3SJeff Roberson 683ec5cae07SJeff Roberson def nexttype(self, type): 684ec5cae07SJeff Roberson next = self.next() 685ec5cae07SJeff Roberson while (next != None and next.type != type): 686ec5cae07SJeff Roberson next = next.next() 687ec5cae07SJeff Roberson return (next) 688ec5cae07SJeff Roberson 689dcee3bd3SJeff Roberson def prev(self): 690dcee3bd3SJeff Roberson return self.source.eventat(self.idx - 1) 691dcee3bd3SJeff Roberson 692dcee3bd3SJeff Roberson def displayref(self, canvas): 693dcee3bd3SJeff Roberson if (self.dispcnt == 0): 694dcee3bd3SJeff Roberson canvas.itemconfigure(self.item, width=2) 695dcee3bd3SJeff Roberson self.dispcnt += 1 696dcee3bd3SJeff Roberson 697dcee3bd3SJeff Roberson def displayunref(self, canvas): 698dcee3bd3SJeff Roberson self.dispcnt -= 1 699dcee3bd3SJeff Roberson if (self.dispcnt == 0): 700dcee3bd3SJeff Roberson canvas.itemconfigure(self.item, width=0) 701dcee3bd3SJeff Roberson canvas.tag_raise("point", "state") 702dcee3bd3SJeff Roberson 703dcee3bd3SJeff Roberson def getlinked(self): 704ec5cae07SJeff Roberson for attr in self.attrs: 705ec5cae07SJeff Roberson if (attr[0] != "linkedto"): 706ec5cae07SJeff Roberson continue 707ec5cae07SJeff Roberson source = ktrfile.findid(attr[1]) 708ec5cae07SJeff Roberson return source.findevent(self.timestamp) 709ec5cae07SJeff Roberson return None 710dcee3bd3SJeff Roberson 711dcee3bd3SJeff Robersonclass PointEvent(Event): 712ec5cae07SJeff Roberson type = "point" 713ec5cae07SJeff Roberson def __init__(self, source, name, cpu, timestamp, attrs): 714ec5cae07SJeff Roberson Event.__init__(self, source, name, cpu, timestamp, attrs) 715dcee3bd3SJeff Roberson 716dcee3bd3SJeff Roberson def draw(self, canvas, xpos, ypos): 717ec5cae07SJeff Roberson color = colormap.lookup(self.name) 718932f0fa2SJeff Roberson l = canvas.create_oval(xpos - XY_POINT, ypos, 719932f0fa2SJeff Roberson xpos + XY_POINT, ypos - (XY_POINT * 2), 72050d670daSJeff Roberson fill=color, width=0, 721932f0fa2SJeff Roberson tags=("event", self.type, self.name, self.source.tag)) 722ec5cae07SJeff Roberson Event.draw(self, canvas, xpos, ypos, l) 723dcee3bd3SJeff Roberson 724ec5cae07SJeff Roberson return xpos 725dcee3bd3SJeff Roberson 726dcee3bd3SJeff Robersonclass StateEvent(Event): 727ec5cae07SJeff Roberson type = "state" 728ec5cae07SJeff Roberson def __init__(self, source, name, cpu, timestamp, attrs): 729ec5cae07SJeff Roberson Event.__init__(self, source, name, cpu, timestamp, attrs) 730dcee3bd3SJeff Roberson 731dcee3bd3SJeff Roberson def draw(self, canvas, xpos, ypos): 732ec5cae07SJeff Roberson next = self.nexttype("state") 733dcee3bd3SJeff Roberson if (next == None): 734ec5cae07SJeff Roberson return (xpos) 73550d670daSJeff Roberson self.duration = duration = next.timestamp - self.timestamp 736ec5cae07SJeff Roberson self.attrs.insert(0, ("duration", ticks2sec(duration))) 737ec5cae07SJeff Roberson color = colormap.lookup(self.name) 738ec5cae07SJeff Roberson if (duration < 0): 739ec5cae07SJeff Roberson duration = 0 740749f65e3SCraig Rodrigues print("Unsynchronized timestamp") 741749f65e3SCraig Rodrigues print(self.cpu, self.timestamp) 742749f65e3SCraig Rodrigues print(next.cpu, next.timestamp) 743ec5cae07SJeff Roberson delta = duration / canvas.ratio 744dcee3bd3SJeff Roberson l = canvas.create_rectangle(xpos, ypos, 745ec5cae07SJeff Roberson xpos + delta, ypos - 10, fill=color, width=0, 746932f0fa2SJeff Roberson tags=("event", self.type, self.name, self.source.tag)) 747ec5cae07SJeff Roberson Event.draw(self, canvas, xpos, ypos, l) 748dcee3bd3SJeff Roberson 749dcee3bd3SJeff Roberson return (xpos + delta) 750dcee3bd3SJeff Roberson 751ec5cae07SJeff Robersonclass CountEvent(Event): 752ec5cae07SJeff Roberson type = "count" 753ec5cae07SJeff Roberson def __init__(self, source, count, cpu, timestamp, attrs): 754ec5cae07SJeff Roberson count = int(count) 755ec5cae07SJeff Roberson self.count = count 756ec5cae07SJeff Roberson Event.__init__(self, source, "count", cpu, timestamp, attrs) 757dcee3bd3SJeff Roberson 758dcee3bd3SJeff Roberson def draw(self, canvas, xpos, ypos): 759ec5cae07SJeff Roberson next = self.nexttype("count") 760ec5cae07SJeff Roberson if (next == None): 761ec5cae07SJeff Roberson return (xpos) 762ec5cae07SJeff Roberson color = colormap.lookup("count") 76350d670daSJeff Roberson self.duration = duration = next.timestamp - self.timestamp 76416ef0f3bSJeff Roberson if (duration < 0): 76516ef0f3bSJeff Roberson duration = 0 766749f65e3SCraig Rodrigues print("Unsynchronized timestamp") 767749f65e3SCraig Rodrigues print(self.cpu, self.timestamp) 768749f65e3SCraig Rodrigues print(next.cpu, next.timestamp) 769ec5cae07SJeff Roberson self.attrs.insert(0, ("count", self.count)) 770ec5cae07SJeff Roberson self.attrs.insert(1, ("duration", ticks2sec(duration))) 771ec5cae07SJeff Roberson delta = duration / canvas.ratio 772dcee3bd3SJeff Roberson yhight = self.source.yscale() * self.count 773dcee3bd3SJeff Roberson l = canvas.create_rectangle(xpos, ypos - yhight, 774ec5cae07SJeff Roberson xpos + delta, ypos, fill=color, width=0, 775932f0fa2SJeff Roberson tags=("event", self.type, self.name, self.source.tag)) 776ec5cae07SJeff Roberson Event.draw(self, canvas, xpos, ypos, l) 777dcee3bd3SJeff Roberson return (xpos + delta) 778dcee3bd3SJeff Roberson 779ec5cae07SJeff Robersonclass PadEvent(StateEvent): 780ec5cae07SJeff Roberson type = "pad" 781ec5cae07SJeff Roberson def __init__(self, source, cpu, timestamp, last=0): 782ec5cae07SJeff Roberson if (last): 783ec5cae07SJeff Roberson cpu = source.events[len(source.events) -1].cpu 784ec5cae07SJeff Roberson else: 785ec5cae07SJeff Roberson cpu = source.events[0].cpu 786ec5cae07SJeff Roberson StateEvent.__init__(self, source, "pad", cpu, timestamp, []) 787dcee3bd3SJeff Roberson def draw(self, canvas, xpos, ypos): 788dcee3bd3SJeff Roberson next = self.next() 789dcee3bd3SJeff Roberson if (next == None): 790dcee3bd3SJeff Roberson return (xpos) 791ec5cae07SJeff Roberson duration = next.timestamp - self.timestamp 792ec5cae07SJeff Roberson delta = duration / canvas.ratio 793ec5cae07SJeff Roberson Event.draw(self, canvas, xpos, ypos, None) 794dcee3bd3SJeff Roberson return (xpos + delta) 795dcee3bd3SJeff Roberson 79650d670daSJeff Roberson 797*7e8ed296SAndriy Gapon@total_ordering 798dcee3bd3SJeff Robersonclass EventSource: 799ec5cae07SJeff Roberson def __init__(self, group, id): 800ec5cae07SJeff Roberson self.name = id 801dcee3bd3SJeff Roberson self.events = [] 802ec5cae07SJeff Roberson self.cpuitems = [] 8032977b8f9SJohn Baldwin self.group = group 804ec5cae07SJeff Roberson self.y = 0 805ec5cae07SJeff Roberson self.item = None 8063d21f0f4SJeff Roberson self.hidden = 0 80750d670daSJeff Roberson self.tag = group + id 808dcee3bd3SJeff Roberson 809*7e8ed296SAndriy Gapon def __lt__(self, other): 810*7e8ed296SAndriy Gapon if other is None: 811*7e8ed296SAndriy Gapon return False 812*7e8ed296SAndriy Gapon return (self.group < other.group or 813*7e8ed296SAndriy Gapon self.group == other.group and self.name < other.name) 814*7e8ed296SAndriy Gapon 815*7e8ed296SAndriy Gapon def __eq__(self, other): 816*7e8ed296SAndriy Gapon if other is None: 817*7e8ed296SAndriy Gapon return False 818*7e8ed296SAndriy Gapon return self.group == other.group and self.name == other.name 8192977b8f9SJohn Baldwin 8202977b8f9SJohn Baldwin # It is much faster to append items to a list then to insert them 8212977b8f9SJohn Baldwin # at the beginning. As a result, we add events in reverse order 8222977b8f9SJohn Baldwin # and then swap the list during fixup. 823dcee3bd3SJeff Roberson def fixup(self): 8242977b8f9SJohn Baldwin self.events.reverse() 825dcee3bd3SJeff Roberson 826ec5cae07SJeff Roberson def addevent(self, event): 8272977b8f9SJohn Baldwin self.events.append(event) 828dcee3bd3SJeff Roberson 829ec5cae07SJeff Roberson def addlastevent(self, event): 8302977b8f9SJohn Baldwin self.events.insert(0, event) 831dcee3bd3SJeff Roberson 832dcee3bd3SJeff Roberson def draw(self, canvas, ypos): 833dcee3bd3SJeff Roberson xpos = 10 834ec5cae07SJeff Roberson cpux = 10 835ec5cae07SJeff Roberson cpu = self.events[1].cpu 836dcee3bd3SJeff Roberson for i in range(0, len(self.events)): 837dcee3bd3SJeff Roberson self.events[i].idx = i 838dcee3bd3SJeff Roberson for event in self.events: 839ec5cae07SJeff Roberson if (event.cpu != cpu and event.cpu != -1): 840ec5cae07SJeff Roberson self.drawcpu(canvas, cpu, cpux, xpos, ypos) 841ec5cae07SJeff Roberson cpux = xpos 842ec5cae07SJeff Roberson cpu = event.cpu 843dcee3bd3SJeff Roberson xpos = event.draw(canvas, xpos, ypos) 844ec5cae07SJeff Roberson self.drawcpu(canvas, cpu, cpux, xpos, ypos) 845dcee3bd3SJeff Roberson 846dcee3bd3SJeff Roberson def drawname(self, canvas, ypos): 847ec5cae07SJeff Roberson self.y = ypos 848dcee3bd3SJeff Roberson ypos = ypos - (self.ysize() / 2) 849932f0fa2SJeff Roberson self.item = canvas.create_text(X_BORDER, ypos, anchor="w", 850932f0fa2SJeff Roberson text=self.name) 851ec5cae07SJeff Roberson return (self.item) 852dcee3bd3SJeff Roberson 853ec5cae07SJeff Roberson def drawcpu(self, canvas, cpu, fromx, tox, ypos): 854ec5cae07SJeff Roberson cpu = "CPU " + str(cpu) 855ec5cae07SJeff Roberson color = cpucolormap.lookup(cpu) 856ec5cae07SJeff Roberson # Create the cpu background colors default to hidden 857ec5cae07SJeff Roberson l = canvas.create_rectangle(fromx, 858dcee3bd3SJeff Roberson ypos - self.ysize() - canvas.bdheight, 859ec5cae07SJeff Roberson tox, ypos + canvas.bdheight, fill=color, width=0, 860932f0fa2SJeff Roberson tags=("cpubg", cpu, self.tag), state="hidden") 861ec5cae07SJeff Roberson self.cpuitems.append(l) 862ec5cae07SJeff Roberson 863ec5cae07SJeff Roberson def move(self, canvas, xpos, ypos): 86450d670daSJeff Roberson canvas.move(self.tag, xpos, ypos) 865ec5cae07SJeff Roberson 866ec5cae07SJeff Roberson def movename(self, canvas, xpos, ypos): 867ec5cae07SJeff Roberson self.y += ypos 868ec5cae07SJeff Roberson canvas.move(self.item, xpos, ypos) 869dcee3bd3SJeff Roberson 870dcee3bd3SJeff Roberson def ysize(self): 871932f0fa2SJeff Roberson return (Y_EVENTSOURCE) 872dcee3bd3SJeff Roberson 873dcee3bd3SJeff Roberson def eventat(self, i): 874c3db6aa6SJohn Baldwin if (i >= len(self.events) or i < 0): 875dcee3bd3SJeff Roberson return (None) 876dcee3bd3SJeff Roberson event = self.events[i] 877dcee3bd3SJeff Roberson return (event) 878dcee3bd3SJeff Roberson 879dcee3bd3SJeff Roberson def findevent(self, timestamp): 880dcee3bd3SJeff Roberson for event in self.events: 881ec5cae07SJeff Roberson if (event.timestamp >= timestamp and event.type != "pad"): 882dcee3bd3SJeff Roberson return (event) 883dcee3bd3SJeff Roberson return (None) 884dcee3bd3SJeff Roberson 885dcee3bd3SJeff Robersonclass Counter(EventSource): 886ec5cae07SJeff Roberson # 887ec5cae07SJeff Roberson # Store a hash of counter groups that keeps the max value 888ec5cae07SJeff Roberson # for a counter in this group for scaling purposes. 889ec5cae07SJeff Roberson # 890ec5cae07SJeff Roberson groups = {} 891ec5cae07SJeff Roberson def __init__(self, group, id): 892dcee3bd3SJeff Roberson try: 893ec5cae07SJeff Roberson Counter.cnt = Counter.groups[group] 894dcee3bd3SJeff Roberson except: 895ec5cae07SJeff Roberson Counter.groups[group] = 0 896ec5cae07SJeff Roberson EventSource.__init__(self, group, id) 897ec5cae07SJeff Roberson 898ec5cae07SJeff Roberson def fixup(self): 899ec5cae07SJeff Roberson for event in self.events: 900ec5cae07SJeff Roberson if (event.type != "count"): 901ec5cae07SJeff Roberson continue; 902ec5cae07SJeff Roberson count = int(event.count) 903ec5cae07SJeff Roberson if (count > Counter.groups[self.group]): 904ec5cae07SJeff Roberson Counter.groups[self.group] = count 905ec5cae07SJeff Roberson EventSource.fixup(self) 906dcee3bd3SJeff Roberson 90766835de4SSam Leffler def ymax(self): 908ec5cae07SJeff Roberson return (Counter.groups[self.group]) 90966835de4SSam Leffler 910dcee3bd3SJeff Roberson def ysize(self): 911932f0fa2SJeff Roberson return (Y_COUNTER) 912dcee3bd3SJeff Roberson 913dcee3bd3SJeff Roberson def yscale(self): 914ec5cae07SJeff Roberson return (self.ysize() / self.ymax()) 915dcee3bd3SJeff Roberson 916dcee3bd3SJeff Robersonclass KTRFile: 917dcee3bd3SJeff Roberson def __init__(self, file): 9180482a607SJeff Roberson self.timestamp_f = None 9190482a607SJeff Roberson self.timestamp_l = None 9200199a61dSJohn Baldwin self.locks = {} 921dcee3bd3SJeff Roberson self.ticks = {} 922dcee3bd3SJeff Roberson self.load = {} 92301e7fb47SScott Long self.crit = {} 9240482a607SJeff Roberson self.stathz = 0 925932f0fa2SJeff Roberson self.eventcnt = 0 92616ef0f3bSJeff Roberson self.taghash = {} 927dcee3bd3SJeff Roberson 928dcee3bd3SJeff Roberson self.parse(file) 929dcee3bd3SJeff Roberson self.fixup() 930dcee3bd3SJeff Roberson global ticksps 9310482a607SJeff Roberson ticksps = self.ticksps() 932932f0fa2SJeff Roberson span = self.timespan() 933932f0fa2SJeff Roberson ghz = float(ticksps) / 1000000000.0 934932f0fa2SJeff Roberson # 935932f0fa2SJeff Roberson # Update the title with some stats from the file 936932f0fa2SJeff Roberson # 937932f0fa2SJeff Roberson titlestr = "SchedGraph: " 938932f0fa2SJeff Roberson titlestr += ticks2sec(span) + " at %.3f ghz, " % ghz 939932f0fa2SJeff Roberson titlestr += str(len(sources)) + " event sources, " 940932f0fa2SJeff Roberson titlestr += str(self.eventcnt) + " events" 941932f0fa2SJeff Roberson root.title(titlestr) 942dcee3bd3SJeff Roberson 943dcee3bd3SJeff Roberson def parse(self, file): 944dcee3bd3SJeff Roberson try: 945dcee3bd3SJeff Roberson ifp = open(file) 946dcee3bd3SJeff Roberson except: 947749f65e3SCraig Rodrigues print("Can't open", file) 948dcee3bd3SJeff Roberson sys.exit(1) 949dcee3bd3SJeff Roberson 950ec5cae07SJeff Roberson # quoteexp matches a quoted string, no escaping 951ec5cae07SJeff Roberson quoteexp = "\"([^\"]*)\"" 952dcee3bd3SJeff Roberson 953ec5cae07SJeff Roberson # 954ec5cae07SJeff Roberson # commaexp matches a quoted string OR the string up 955ec5cae07SJeff Roberson # to the first ',' 956ec5cae07SJeff Roberson # 957ec5cae07SJeff Roberson commaexp = "(?:" + quoteexp + "|([^,]+))" 958dcee3bd3SJeff Roberson 959ec5cae07SJeff Roberson # 960ec5cae07SJeff Roberson # colonstr matches a quoted string OR the string up 961ec5cae07SJeff Roberson # to the first ':' 962ec5cae07SJeff Roberson # 963ec5cae07SJeff Roberson colonexp = "(?:" + quoteexp + "|([^:]+))" 964dcee3bd3SJeff Roberson 965ec5cae07SJeff Roberson # 966ec5cae07SJeff Roberson # Match various manditory parts of the KTR string this is 967ec5cae07SJeff Roberson # fairly inflexible until you get to attributes to make 968ec5cae07SJeff Roberson # parsing faster. 969ec5cae07SJeff Roberson # 970ec5cae07SJeff Roberson hdrexp = "\s*(\d+)\s+(\d+)\s+(\d+)\s+" 971ec5cae07SJeff Roberson groupexp = "KTRGRAPH group:" + quoteexp + ", " 972ec5cae07SJeff Roberson idexp = "id:" + quoteexp + ", " 973ec5cae07SJeff Roberson typeexp = "([^:]+):" + commaexp + ", " 974ec5cae07SJeff Roberson attribexp = "attributes: (.*)" 975dcee3bd3SJeff Roberson 976ec5cae07SJeff Roberson # 977ec5cae07SJeff Roberson # Matches optional attributes in the KTR string. This 978ec5cae07SJeff Roberson # tolerates more variance as the users supply these values. 979ec5cae07SJeff Roberson # 980ec5cae07SJeff Roberson attrexp = colonexp + "\s*:\s*(?:" + commaexp + ", (.*)|" 981ec5cae07SJeff Roberson attrexp += quoteexp +"|(.*))" 982dcee3bd3SJeff Roberson 983ec5cae07SJeff Roberson # Precompile regexp 984ec5cae07SJeff Roberson ktrre = re.compile(hdrexp + groupexp + idexp + typeexp + attribexp) 985ec5cae07SJeff Roberson attrre = re.compile(attrexp) 986dcee3bd3SJeff Roberson 98766835de4SSam Leffler global lineno 98866835de4SSam Leffler lineno = 0 989dbad07bfSJeff Roberson for line in ifp.readlines(): 99066835de4SSam Leffler lineno += 1 991ec5cae07SJeff Roberson if ((lineno % 2048) == 0): 99266835de4SSam Leffler status.startup("Parsing line " + str(lineno)) 993ec5cae07SJeff Roberson m = ktrre.match(line); 9942e2e6cc9SJeff Roberson if (m == None): 995749f65e3SCraig Rodrigues print("Can't parse", lineno, line, end=' ') 996ec5cae07SJeff Roberson continue; 997ec5cae07SJeff Roberson (index, cpu, timestamp, group, id, type, dat, dat1, attrstring) = m.groups(); 998ec5cae07SJeff Roberson if (dat == None): 999ec5cae07SJeff Roberson dat = dat1 1000ec5cae07SJeff Roberson if (self.checkstamp(timestamp) == 0): 1001749f65e3SCraig Rodrigues print("Bad timestamp at", lineno, ":", end=' ') 1002749f65e3SCraig Rodrigues print(cpu, timestamp) 1003ec5cae07SJeff Roberson continue 1004ec5cae07SJeff Roberson # 1005ec5cae07SJeff Roberson # Build the table of optional attributes 1006ec5cae07SJeff Roberson # 1007ec5cae07SJeff Roberson attrs = [] 1008ec5cae07SJeff Roberson while (attrstring != None): 1009ec5cae07SJeff Roberson m = attrre.match(attrstring.strip()) 1010ec5cae07SJeff Roberson if (m == None): 1011ec5cae07SJeff Roberson break; 1012ec5cae07SJeff Roberson # 1013ec5cae07SJeff Roberson # Name may or may not be quoted. 1014ec5cae07SJeff Roberson # 1015ec5cae07SJeff Roberson # For val we have four cases: 1016ec5cae07SJeff Roberson # 1) quotes followed by comma and more 1017ec5cae07SJeff Roberson # attributes. 1018ec5cae07SJeff Roberson # 2) no quotes followed by comma and more 1019ec5cae07SJeff Roberson # attributes. 1020ec5cae07SJeff Roberson # 3) no more attributes or comma with quotes. 1021ec5cae07SJeff Roberson # 4) no more attributes or comma without quotes. 1022ec5cae07SJeff Roberson # 1023ec5cae07SJeff Roberson (name, name1, val, val1, attrstring, end, end1) = m.groups(); 1024ec5cae07SJeff Roberson if (name == None): 1025ec5cae07SJeff Roberson name = name1 1026ec5cae07SJeff Roberson if (end == None): 1027ec5cae07SJeff Roberson end = end1 1028ec5cae07SJeff Roberson if (val == None): 1029ec5cae07SJeff Roberson val = val1 1030ec5cae07SJeff Roberson if (val == None): 1031ec5cae07SJeff Roberson val = end 1032ec5cae07SJeff Roberson if (name == "stathz"): 1033ec5cae07SJeff Roberson self.setstathz(val, cpu) 1034ec5cae07SJeff Roberson attrs.append((name, val)) 1035ec5cae07SJeff Roberson args = (dat, cpu, timestamp, attrs) 1036ec5cae07SJeff Roberson e = self.makeevent(group, id, type, args) 1037ec5cae07SJeff Roberson if (e == None): 1038749f65e3SCraig Rodrigues print("Unknown type", type, lineno, line, end=' ') 1039dcee3bd3SJeff Roberson 1040ec5cae07SJeff Roberson def makeevent(self, group, id, type, args): 1041ec5cae07SJeff Roberson e = None 1042ec5cae07SJeff Roberson source = self.makeid(group, id, type) 1043ec5cae07SJeff Roberson if (type == "state"): 1044ec5cae07SJeff Roberson e = StateEvent(source, *args) 1045ec5cae07SJeff Roberson elif (type == "counter"): 1046ec5cae07SJeff Roberson e = CountEvent(source, *args) 1047ec5cae07SJeff Roberson elif (type == "point"): 1048ec5cae07SJeff Roberson e = PointEvent(source, *args) 1049ec5cae07SJeff Roberson if (e != None): 1050932f0fa2SJeff Roberson self.eventcnt += 1 1051ec5cae07SJeff Roberson source.addevent(e); 1052ec5cae07SJeff Roberson return e 1053dcee3bd3SJeff Roberson 1054ec5cae07SJeff Roberson def setstathz(self, val, cpu): 1055ec5cae07SJeff Roberson self.stathz = int(val) 1056dcee3bd3SJeff Roberson cpu = int(cpu) 1057dcee3bd3SJeff Roberson try: 1058dcee3bd3SJeff Roberson ticks = self.ticks[cpu] 1059dcee3bd3SJeff Roberson except: 1060dcee3bd3SJeff Roberson self.ticks[cpu] = 0 1061dcee3bd3SJeff Roberson self.ticks[cpu] += 1 1062dcee3bd3SJeff Roberson 1063ec5cae07SJeff Roberson def checkstamp(self, timestamp): 1064ec5cae07SJeff Roberson timestamp = int(timestamp) 1065ec5cae07SJeff Roberson if (self.timestamp_f == None): 1066ec5cae07SJeff Roberson self.timestamp_f = timestamp; 106716ef0f3bSJeff Roberson if (self.timestamp_l != None and 106816ef0f3bSJeff Roberson timestamp -2048> self.timestamp_l): 1069ec5cae07SJeff Roberson return (0) 1070ec5cae07SJeff Roberson self.timestamp_l = timestamp; 1071ec5cae07SJeff Roberson return (1) 1072dcee3bd3SJeff Roberson 1073ec5cae07SJeff Roberson def makeid(self, group, id, type): 107416ef0f3bSJeff Roberson tag = group + id 1075aef675d8SCraig Rodrigues if (tag in self.taghash): 107616ef0f3bSJeff Roberson return self.taghash[tag] 1077ec5cae07SJeff Roberson if (type == "counter"): 1078ec5cae07SJeff Roberson source = Counter(group, id) 10790199a61dSJohn Baldwin else: 1080ec5cae07SJeff Roberson source = EventSource(group, id) 1081ec5cae07SJeff Roberson sources.append(source) 108216ef0f3bSJeff Roberson self.taghash[tag] = source 1083ec5cae07SJeff Roberson return (source) 10840199a61dSJohn Baldwin 1085ec5cae07SJeff Roberson def findid(self, id): 1086ec5cae07SJeff Roberson for source in sources: 1087ec5cae07SJeff Roberson if (source.name == id): 1088ec5cae07SJeff Roberson return source 1089ec5cae07SJeff Roberson return (None) 10900199a61dSJohn Baldwin 1091ec5cae07SJeff Roberson def timespan(self): 1092ec5cae07SJeff Roberson return (self.timestamp_f - self.timestamp_l); 10930199a61dSJohn Baldwin 1094ec5cae07SJeff Roberson def ticksps(self): 1095ec5cae07SJeff Roberson oneghz = 1000000000 1096ec5cae07SJeff Roberson # Use user supplied clock first 1097ec5cae07SJeff Roberson if (clockfreq != None): 1098ec5cae07SJeff Roberson return int(clockfreq * oneghz) 10990199a61dSJohn Baldwin 1100ec5cae07SJeff Roberson # Check for a discovered clock 110116ef0f3bSJeff Roberson if (self.stathz != 0): 1102ec5cae07SJeff Roberson return (self.timespan() / self.ticks[0]) * int(self.stathz) 1103ec5cae07SJeff Roberson # Pretend we have a 1ns clock 1104749f65e3SCraig Rodrigues print("WARNING: No clock discovered and no frequency ", end=' ') 1105749f65e3SCraig Rodrigues print("specified via the command line.") 1106749f65e3SCraig Rodrigues print("Using fake 1ghz clock") 1107ec5cae07SJeff Roberson return (oneghz); 1108dcee3bd3SJeff Roberson 1109dcee3bd3SJeff Roberson def fixup(self): 1110ec5cae07SJeff Roberson for source in sources: 1111ec5cae07SJeff Roberson e = PadEvent(source, -1, self.timestamp_l) 1112ec5cae07SJeff Roberson source.addevent(e) 1113ec5cae07SJeff Roberson e = PadEvent(source, -1, self.timestamp_f, last=1) 1114ec5cae07SJeff Roberson source.addlastevent(e) 1115dcee3bd3SJeff Roberson source.fixup() 1116ec5cae07SJeff Roberson sources.sort() 1117ec5cae07SJeff Roberson 1118ec5cae07SJeff Robersonclass SchedNames(Canvas): 1119ec5cae07SJeff Roberson def __init__(self, master, display): 1120ec5cae07SJeff Roberson self.display = display 1121ec5cae07SJeff Roberson self.parent = master 1122ec5cae07SJeff Roberson self.bdheight = master.bdheight 1123ec5cae07SJeff Roberson self.items = {} 1124ec5cae07SJeff Roberson self.ysize = 0 1125ec5cae07SJeff Roberson self.lines = [] 1126ec5cae07SJeff Roberson Canvas.__init__(self, master, width=120, 1127ec5cae07SJeff Roberson height=display["height"], bg='grey', 1128ec5cae07SJeff Roberson scrollregion=(0, 0, 50, 100)) 1129ec5cae07SJeff Roberson 1130ec5cae07SJeff Roberson def moveline(self, cur_y, y): 1131ec5cae07SJeff Roberson for line in self.lines: 1132ec5cae07SJeff Roberson (x0, y0, x1, y1) = self.coords(line) 1133ec5cae07SJeff Roberson if (cur_y != y0): 1134ec5cae07SJeff Roberson continue 1135ec5cae07SJeff Roberson self.move(line, 0, y) 1136ec5cae07SJeff Roberson return 1137ec5cae07SJeff Roberson 1138ec5cae07SJeff Roberson def draw(self): 1139ec5cae07SJeff Roberson status.startup("Drawing names") 1140ec5cae07SJeff Roberson ypos = 0 1141ec5cae07SJeff Roberson self.configure(scrollregion=(0, 0, 1142ec5cae07SJeff Roberson self["width"], self.display.ysize())) 1143ec5cae07SJeff Roberson for source in sources: 1144ec5cae07SJeff Roberson l = self.create_line(0, ypos, self["width"], ypos, 1145ec5cae07SJeff Roberson width=1, fill="black", tags=("all","sources")) 1146ec5cae07SJeff Roberson self.lines.append(l) 1147ec5cae07SJeff Roberson ypos += self.bdheight 1148ec5cae07SJeff Roberson ypos += source.ysize() 1149ec5cae07SJeff Roberson t = source.drawname(self, ypos) 1150ec5cae07SJeff Roberson self.items[t] = source 1151ec5cae07SJeff Roberson ypos += self.bdheight 1152ec5cae07SJeff Roberson self.ysize = ypos 1153ec5cae07SJeff Roberson self.create_line(0, ypos, self["width"], ypos, 1154ec5cae07SJeff Roberson width=1, fill="black", tags=("all",)) 1155ec5cae07SJeff Roberson self.bind("<Button-1>", self.master.mousepress); 115650d670daSJeff Roberson self.bind("<Button-3>", self.master.mousepressright); 1157ec5cae07SJeff Roberson self.bind("<ButtonRelease-1>", self.master.mouserelease); 1158ec5cae07SJeff Roberson self.bind("<B1-Motion>", self.master.mousemotion); 1159ec5cae07SJeff Roberson 11603d21f0f4SJeff Roberson def updatescroll(self): 11613d21f0f4SJeff Roberson self.configure(scrollregion=(0, 0, 11623d21f0f4SJeff Roberson self["width"], self.display.ysize())) 11633d21f0f4SJeff Roberson 1164dcee3bd3SJeff Roberson 1165dcee3bd3SJeff Robersonclass SchedDisplay(Canvas): 1166dcee3bd3SJeff Roberson def __init__(self, master): 11672977b8f9SJohn Baldwin self.ratio = 1 11682977b8f9SJohn Baldwin self.parent = master 1169ec5cae07SJeff Roberson self.bdheight = master.bdheight 1170ec5cae07SJeff Roberson self.items = {} 1171ec5cae07SJeff Roberson self.lines = [] 1172dcee3bd3SJeff Roberson Canvas.__init__(self, master, width=800, height=500, bg='grey', 1173dcee3bd3SJeff Roberson scrollregion=(0, 0, 800, 500)) 1174dcee3bd3SJeff Roberson 1175ec5cae07SJeff Roberson def prepare(self): 1176ec5cae07SJeff Roberson # 11772977b8f9SJohn Baldwin # Compute a ratio to ensure that the file's timespan fits into 11782977b8f9SJohn Baldwin # 2^31. Although python may handle larger values for X 11792977b8f9SJohn Baldwin # values, the Tk internals do not. 1180ec5cae07SJeff Roberson # 11812977b8f9SJohn Baldwin self.ratio = (ktrfile.timespan() - 1) / 2**31 + 1 11822977b8f9SJohn Baldwin 1183dcee3bd3SJeff Roberson def draw(self): 1184dcee3bd3SJeff Roberson ypos = 0 1185dcee3bd3SJeff Roberson xsize = self.xsize() 1186ec5cae07SJeff Roberson for source in sources: 1187dcee3bd3SJeff Roberson status.startup("Drawing " + source.name) 1188ec5cae07SJeff Roberson l = self.create_line(0, ypos, xsize, ypos, 1189dcee3bd3SJeff Roberson width=1, fill="black", tags=("all",)) 1190ec5cae07SJeff Roberson self.lines.append(l) 1191dcee3bd3SJeff Roberson ypos += self.bdheight 1192dcee3bd3SJeff Roberson ypos += source.ysize() 1193dcee3bd3SJeff Roberson source.draw(self, ypos) 1194dcee3bd3SJeff Roberson ypos += self.bdheight 1195dcee3bd3SJeff Roberson self.tag_raise("point", "state") 1196932f0fa2SJeff Roberson self.tag_lower("cpubg", ALL) 1197dcee3bd3SJeff Roberson self.create_line(0, ypos, xsize, ypos, 1198932f0fa2SJeff Roberson width=1, fill="black", tags=("lines",)) 1199dcee3bd3SJeff Roberson self.tag_bind("event", "<Enter>", self.mouseenter) 1200dcee3bd3SJeff Roberson self.tag_bind("event", "<Leave>", self.mouseexit) 1201ec5cae07SJeff Roberson self.bind("<Button-1>", self.mousepress) 120250d670daSJeff Roberson self.bind("<Button-3>", self.master.mousepressright); 12032977b8f9SJohn Baldwin self.bind("<Button-4>", self.wheelup) 12042977b8f9SJohn Baldwin self.bind("<Button-5>", self.wheeldown) 1205ec5cae07SJeff Roberson self.bind("<ButtonRelease-1>", self.master.mouserelease); 1206ec5cae07SJeff Roberson self.bind("<B1-Motion>", self.master.mousemotion); 1207ec5cae07SJeff Roberson 1208ec5cae07SJeff Roberson def moveline(self, cur_y, y): 1209ec5cae07SJeff Roberson for line in self.lines: 1210ec5cae07SJeff Roberson (x0, y0, x1, y1) = self.coords(line) 1211ec5cae07SJeff Roberson if (cur_y != y0): 1212ec5cae07SJeff Roberson continue 1213ec5cae07SJeff Roberson self.move(line, 0, y) 1214ec5cae07SJeff Roberson return 1215dcee3bd3SJeff Roberson 1216dcee3bd3SJeff Roberson def mouseenter(self, event): 1217dcee3bd3SJeff Roberson item, = self.find_withtag(CURRENT) 1218ec5cae07SJeff Roberson self.items[item].mouseenter(self) 1219dcee3bd3SJeff Roberson 1220dcee3bd3SJeff Roberson def mouseexit(self, event): 1221dcee3bd3SJeff Roberson item, = self.find_withtag(CURRENT) 1222ec5cae07SJeff Roberson self.items[item].mouseexit(self) 1223dcee3bd3SJeff Roberson 1224dcee3bd3SJeff Roberson def mousepress(self, event): 1225ec5cae07SJeff Roberson # Find out what's beneath us 1226ec5cae07SJeff Roberson items = self.find_withtag(CURRENT) 1227ec5cae07SJeff Roberson if (len(items) == 0): 1228ec5cae07SJeff Roberson self.master.mousepress(event) 1229ec5cae07SJeff Roberson return 1230ec5cae07SJeff Roberson # Only grab mouse presses for things with event tags. 1231ec5cae07SJeff Roberson item = items[0] 1232ec5cae07SJeff Roberson tags = self.gettags(item) 1233ec5cae07SJeff Roberson for tag in tags: 1234ec5cae07SJeff Roberson if (tag == "event"): 1235ec5cae07SJeff Roberson self.items[item].mousepress(self) 1236ec5cae07SJeff Roberson return 1237ec5cae07SJeff Roberson # Leave the rest to the master window 1238ec5cae07SJeff Roberson self.master.mousepress(event) 1239dcee3bd3SJeff Roberson 12402977b8f9SJohn Baldwin def wheeldown(self, event): 12412977b8f9SJohn Baldwin self.parent.display_yview("scroll", 1, "units") 12422977b8f9SJohn Baldwin 12432977b8f9SJohn Baldwin def wheelup(self, event): 12442977b8f9SJohn Baldwin self.parent.display_yview("scroll", -1, "units") 12452977b8f9SJohn Baldwin 1246dcee3bd3SJeff Roberson def xsize(self): 1247932f0fa2SJeff Roberson return ((ktrfile.timespan() / self.ratio) + (X_BORDER * 2)) 1248dcee3bd3SJeff Roberson 1249dcee3bd3SJeff Roberson def ysize(self): 1250dcee3bd3SJeff Roberson ysize = 0 1251ec5cae07SJeff Roberson for source in sources: 12523d21f0f4SJeff Roberson if (source.hidden == 1): 12533d21f0f4SJeff Roberson continue 12543d21f0f4SJeff Roberson ysize += self.parent.sourcesize(source) 1255ec5cae07SJeff Roberson return ysize 1256dcee3bd3SJeff Roberson 1257dcee3bd3SJeff Roberson def scaleset(self, ratio): 1258ec5cae07SJeff Roberson if (ktrfile == None): 1259dcee3bd3SJeff Roberson return 1260dcee3bd3SJeff Roberson oldratio = self.ratio 1261ec5cae07SJeff Roberson xstart, xend = self.xview() 1262ec5cae07SJeff Roberson midpoint = xstart + ((xend - xstart) / 2) 1263dcee3bd3SJeff Roberson 1264dcee3bd3SJeff Roberson self.ratio = ratio 12653d21f0f4SJeff Roberson self.updatescroll() 1266932f0fa2SJeff Roberson self.scale(ALL, 0, 0, float(oldratio) / ratio, 1) 1267dcee3bd3SJeff Roberson 1268ec5cae07SJeff Roberson xstart, xend = self.xview() 1269ec5cae07SJeff Roberson xsize = (xend - xstart) / 2 1270ec5cae07SJeff Roberson self.xview_moveto(midpoint - xsize) 1271dcee3bd3SJeff Roberson 12723d21f0f4SJeff Roberson def updatescroll(self): 12733d21f0f4SJeff Roberson self.configure(scrollregion=(0, 0, self.xsize(), self.ysize())) 12743d21f0f4SJeff Roberson 1275dcee3bd3SJeff Roberson def scaleget(self): 1276dcee3bd3SJeff Roberson return self.ratio 1277dcee3bd3SJeff Roberson 1278ec5cae07SJeff Roberson def getcolor(self, tag): 1279ec5cae07SJeff Roberson return self.itemcget(tag, "fill") 1280ec5cae07SJeff Roberson 1281ec5cae07SJeff Roberson def getstate(self, tag): 1282ec5cae07SJeff Roberson return self.itemcget(tag, "state") 1283ec5cae07SJeff Roberson 1284dcee3bd3SJeff Roberson def setcolor(self, tag, color): 1285dcee3bd3SJeff Roberson self.itemconfigure(tag, state="normal", fill=color) 1286dcee3bd3SJeff Roberson 1287dcee3bd3SJeff Roberson def hide(self, tag): 1288dcee3bd3SJeff Roberson self.itemconfigure(tag, state="hidden") 1289dcee3bd3SJeff Roberson 1290dcee3bd3SJeff Robersonclass GraphMenu(Frame): 1291dcee3bd3SJeff Roberson def __init__(self, master): 1292dcee3bd3SJeff Roberson Frame.__init__(self, master, bd=2, relief=RAISED) 129350d670daSJeff Roberson self.conf = Menubutton(self, text="Configure") 129450d670daSJeff Roberson self.confmenu = Menu(self.conf, tearoff=0) 129550d670daSJeff Roberson self.confmenu.add_command(label="Event Colors", 1296dcee3bd3SJeff Roberson command=self.econf) 129750d670daSJeff Roberson self.confmenu.add_command(label="CPU Colors", 1298ec5cae07SJeff Roberson command=self.cconf) 129950d670daSJeff Roberson self.confmenu.add_command(label="Source Configure", 13003d21f0f4SJeff Roberson command=self.sconf) 130150d670daSJeff Roberson self.conf["menu"] = self.confmenu 130250d670daSJeff Roberson self.conf.pack(side=LEFT) 1303dcee3bd3SJeff Roberson 1304dcee3bd3SJeff Roberson def econf(self): 1305ec5cae07SJeff Roberson ColorConfigure(eventcolors, "Event Display Configuration") 1306ec5cae07SJeff Roberson 1307ec5cae07SJeff Roberson def cconf(self): 1308ec5cae07SJeff Roberson ColorConfigure(cpucolors, "CPU Background Colors") 1309dcee3bd3SJeff Roberson 13103d21f0f4SJeff Roberson def sconf(self): 13113d21f0f4SJeff Roberson SourceConfigure() 13123d21f0f4SJeff Roberson 1313dcee3bd3SJeff Robersonclass SchedGraph(Frame): 1314dcee3bd3SJeff Roberson def __init__(self, master): 1315dcee3bd3SJeff Roberson Frame.__init__(self, master) 1316dcee3bd3SJeff Roberson self.menu = None 1317dcee3bd3SJeff Roberson self.names = None 1318dcee3bd3SJeff Roberson self.display = None 1319dcee3bd3SJeff Roberson self.scale = None 1320dcee3bd3SJeff Roberson self.status = None 1321932f0fa2SJeff Roberson self.bdheight = Y_BORDER 1322ec5cae07SJeff Roberson self.clicksource = None 1323ec5cae07SJeff Roberson self.lastsource = None 1324dcee3bd3SJeff Roberson self.pack(expand=1, fill="both") 1325dcee3bd3SJeff Roberson self.buildwidgets() 1326dcee3bd3SJeff Roberson self.layout() 13279799411bSJohn Baldwin self.bind_all("<Control-q>", self.quitcb) 13289799411bSJohn Baldwin 13299799411bSJohn Baldwin def quitcb(self, event): 13309799411bSJohn Baldwin self.quit() 1331dcee3bd3SJeff Roberson 1332dcee3bd3SJeff Roberson def buildwidgets(self): 1333dcee3bd3SJeff Roberson global status 1334dcee3bd3SJeff Roberson self.menu = GraphMenu(self) 1335dcee3bd3SJeff Roberson self.display = SchedDisplay(self) 1336ec5cae07SJeff Roberson self.names = SchedNames(self, self.display) 1337dcee3bd3SJeff Roberson self.scale = Scaler(self, self.display) 1338dcee3bd3SJeff Roberson status = self.status = Status(self) 1339dcee3bd3SJeff Roberson self.scrollY = Scrollbar(self, orient="vertical", 1340dcee3bd3SJeff Roberson command=self.display_yview) 1341dcee3bd3SJeff Roberson self.display.scrollX = Scrollbar(self, orient="horizontal", 1342dcee3bd3SJeff Roberson command=self.display.xview) 1343dcee3bd3SJeff Roberson self.display["xscrollcommand"] = self.display.scrollX.set 1344dcee3bd3SJeff Roberson self.display["yscrollcommand"] = self.scrollY.set 1345dcee3bd3SJeff Roberson self.names["yscrollcommand"] = self.scrollY.set 1346dcee3bd3SJeff Roberson 1347dcee3bd3SJeff Roberson def layout(self): 1348dcee3bd3SJeff Roberson self.columnconfigure(1, weight=1) 1349dcee3bd3SJeff Roberson self.rowconfigure(1, weight=1) 1350dcee3bd3SJeff Roberson self.menu.grid(row=0, column=0, columnspan=3, sticky=E+W) 1351dcee3bd3SJeff Roberson self.names.grid(row=1, column=0, sticky=N+S) 1352dcee3bd3SJeff Roberson self.display.grid(row=1, column=1, sticky=W+E+N+S) 1353dcee3bd3SJeff Roberson self.scrollY.grid(row=1, column=2, sticky=N+S) 1354dcee3bd3SJeff Roberson self.display.scrollX.grid(row=2, column=0, columnspan=2, 1355dcee3bd3SJeff Roberson sticky=E+W) 1356dcee3bd3SJeff Roberson self.scale.grid(row=3, column=0, columnspan=3, sticky=E+W) 1357dcee3bd3SJeff Roberson self.status.grid(row=4, column=0, columnspan=3, sticky=E+W) 1358dcee3bd3SJeff Roberson 1359ec5cae07SJeff Roberson def draw(self): 1360dcee3bd3SJeff Roberson self.master.update() 1361ec5cae07SJeff Roberson self.display.prepare() 1362ec5cae07SJeff Roberson self.names.draw() 1363dcee3bd3SJeff Roberson self.display.draw() 1364ec5cae07SJeff Roberson self.status.startup("") 136516ef0f3bSJeff Roberson # 136616ef0f3bSJeff Roberson # Configure scale related values 136716ef0f3bSJeff Roberson # 136816ef0f3bSJeff Roberson scalemax = ktrfile.timespan() / int(self.display["width"]) 136916ef0f3bSJeff Roberson width = int(root.geometry().split('x')[0]) 137016ef0f3bSJeff Roberson self.constwidth = width - int(self.display["width"]) 137116ef0f3bSJeff Roberson self.scale.setmax(scalemax) 137216ef0f3bSJeff Roberson self.scale.set(scalemax) 1373dcee3bd3SJeff Roberson self.display.xview_moveto(0) 137416ef0f3bSJeff Roberson self.bind("<Configure>", self.resize) 1375dcee3bd3SJeff Roberson 1376ec5cae07SJeff Roberson def mousepress(self, event): 1377ec5cae07SJeff Roberson self.clicksource = self.sourceat(event.y) 1378ec5cae07SJeff Roberson 137950d670daSJeff Roberson def mousepressright(self, event): 138050d670daSJeff Roberson source = self.sourceat(event.y) 138150d670daSJeff Roberson if (source == None): 138250d670daSJeff Roberson return 138350d670daSJeff Roberson SourceContext(event, source) 138450d670daSJeff Roberson 1385ec5cae07SJeff Roberson def mouserelease(self, event): 1386ec5cae07SJeff Roberson if (self.clicksource == None): 1387ec5cae07SJeff Roberson return 1388ec5cae07SJeff Roberson newsource = self.sourceat(event.y) 1389ec5cae07SJeff Roberson if (self.clicksource != newsource): 1390ec5cae07SJeff Roberson self.sourceswap(self.clicksource, newsource) 1391ec5cae07SJeff Roberson self.clicksource = None 1392ec5cae07SJeff Roberson self.lastsource = None 1393ec5cae07SJeff Roberson 1394ec5cae07SJeff Roberson def mousemotion(self, event): 1395ec5cae07SJeff Roberson if (self.clicksource == None): 1396ec5cae07SJeff Roberson return 1397ec5cae07SJeff Roberson newsource = self.sourceat(event.y) 1398ec5cae07SJeff Roberson # 1399ec5cae07SJeff Roberson # If we get a None source they moved off the page. 1400ec5cae07SJeff Roberson # swapsource() can't handle moving multiple items so just 1401ec5cae07SJeff Roberson # pretend we never clicked on anything to begin with so the 1402ec5cae07SJeff Roberson # user can't mouseover a non-contiguous area. 1403ec5cae07SJeff Roberson # 1404ec5cae07SJeff Roberson if (newsource == None): 1405ec5cae07SJeff Roberson self.clicksource = None 1406ec5cae07SJeff Roberson self.lastsource = None 1407ec5cae07SJeff Roberson return 1408ec5cae07SJeff Roberson if (newsource == self.lastsource): 1409ec5cae07SJeff Roberson return; 1410ec5cae07SJeff Roberson self.lastsource = newsource 1411ec5cae07SJeff Roberson if (newsource != self.clicksource): 1412ec5cae07SJeff Roberson self.sourceswap(self.clicksource, newsource) 1413ec5cae07SJeff Roberson 1414ec5cae07SJeff Roberson # These are here because this object controls layout 1415ec5cae07SJeff Roberson def sourcestart(self, source): 1416ec5cae07SJeff Roberson return source.y - self.bdheight - source.ysize() 1417ec5cae07SJeff Roberson 1418ec5cae07SJeff Roberson def sourceend(self, source): 1419ec5cae07SJeff Roberson return source.y + self.bdheight 1420ec5cae07SJeff Roberson 1421ec5cae07SJeff Roberson def sourcesize(self, source): 1422ec5cae07SJeff Roberson return (self.bdheight * 2) + source.ysize() 1423ec5cae07SJeff Roberson 1424ec5cae07SJeff Roberson def sourceswap(self, source1, source2): 1425ec5cae07SJeff Roberson # Sort so we always know which one is on top. 1426ec5cae07SJeff Roberson if (source2.y < source1.y): 1427ec5cae07SJeff Roberson swap = source1 1428ec5cae07SJeff Roberson source1 = source2 1429ec5cae07SJeff Roberson source2 = swap 1430ec5cae07SJeff Roberson # Only swap adjacent sources 1431ec5cae07SJeff Roberson if (self.sourceend(source1) != self.sourcestart(source2)): 1432ec5cae07SJeff Roberson return 1433ec5cae07SJeff Roberson # Compute start coordinates and target coordinates 1434ec5cae07SJeff Roberson y1 = self.sourcestart(source1) 1435ec5cae07SJeff Roberson y2 = self.sourcestart(source2) 1436ec5cae07SJeff Roberson y1targ = y1 + self.sourcesize(source2) 1437ec5cae07SJeff Roberson y2targ = y1 1438ec5cae07SJeff Roberson # 1439ec5cae07SJeff Roberson # If the sizes are not equal, adjust the start of the lower 1440ec5cae07SJeff Roberson # source to account for the lost/gained space. 1441ec5cae07SJeff Roberson # 1442ec5cae07SJeff Roberson if (source1.ysize() != source2.ysize()): 1443ec5cae07SJeff Roberson diff = source2.ysize() - source1.ysize() 1444ec5cae07SJeff Roberson self.names.moveline(y2, diff); 1445ec5cae07SJeff Roberson self.display.moveline(y2, diff) 1446ec5cae07SJeff Roberson source1.move(self.display, 0, y1targ - y1) 1447ec5cae07SJeff Roberson source2.move(self.display, 0, y2targ - y2) 1448ec5cae07SJeff Roberson source1.movename(self.names, 0, y1targ - y1) 1449ec5cae07SJeff Roberson source2.movename(self.names, 0, y2targ - y2) 1450ec5cae07SJeff Roberson 145150d670daSJeff Roberson def sourcepicky(self, source): 14523d21f0f4SJeff Roberson if (source.hidden == 0): 145350d670daSJeff Roberson return self.sourcestart(source) 145450d670daSJeff Roberson # Revert to group based sort 145550d670daSJeff Roberson sources.sort() 14563d21f0f4SJeff Roberson prev = None 14573d21f0f4SJeff Roberson for s in sources: 14583d21f0f4SJeff Roberson if (s == source): 14593d21f0f4SJeff Roberson break 14603d21f0f4SJeff Roberson if (s.hidden == 0): 14613d21f0f4SJeff Roberson prev = s 14623d21f0f4SJeff Roberson if (prev == None): 14633d21f0f4SJeff Roberson newy = 0 14643d21f0f4SJeff Roberson else: 14653d21f0f4SJeff Roberson newy = self.sourcestart(prev) + self.sourcesize(prev) 146650d670daSJeff Roberson return newy 146750d670daSJeff Roberson 146850d670daSJeff Roberson def sourceshow(self, source): 146950d670daSJeff Roberson if (source.hidden == 0): 147050d670daSJeff Roberson return; 147150d670daSJeff Roberson newy = self.sourcepicky(source) 14723d21f0f4SJeff Roberson off = newy - self.sourcestart(source) 147350d670daSJeff Roberson self.sourceshiftall(newy-1, self.sourcesize(source)) 14743d21f0f4SJeff Roberson self.sourceshift(source, off) 14753d21f0f4SJeff Roberson source.hidden = 0 14763d21f0f4SJeff Roberson 147750d670daSJeff Roberson # 147850d670daSJeff Roberson # Optimized source show of multiple entries that only moves each 147950d670daSJeff Roberson # existing entry once. Doing sourceshow() iteratively is too 148050d670daSJeff Roberson # expensive due to python's canvas.move(). 148150d670daSJeff Roberson # 148250d670daSJeff Roberson def sourceshowlist(self, srclist): 1483*7e8ed296SAndriy Gapon srclist.sort(key=attrgetter('y')) 148450d670daSJeff Roberson startsize = [] 148550d670daSJeff Roberson for source in srclist: 148650d670daSJeff Roberson if (source.hidden == 0): 148750d670daSJeff Roberson srclist.remove(source) 148850d670daSJeff Roberson startsize.append((self.sourcepicky(source), 148950d670daSJeff Roberson self.sourcesize(source))) 149050d670daSJeff Roberson 1491*7e8ed296SAndriy Gapon sources.sort(key=attrgetter('y'), reverse=True) 149250d670daSJeff Roberson self.status.startup("Updating display..."); 149350d670daSJeff Roberson for source in sources: 149450d670daSJeff Roberson if (source.hidden == 1): 149550d670daSJeff Roberson continue 149650d670daSJeff Roberson nstart = self.sourcestart(source) 149750d670daSJeff Roberson size = 0 149850d670daSJeff Roberson for hidden in startsize: 149950d670daSJeff Roberson (start, sz) = hidden 150050d670daSJeff Roberson if (start <= nstart or start+sz <= nstart): 150150d670daSJeff Roberson size += sz 150250d670daSJeff Roberson self.sourceshift(source, size) 150350d670daSJeff Roberson idx = 0 150450d670daSJeff Roberson size = 0 150550d670daSJeff Roberson for source in srclist: 150650d670daSJeff Roberson (newy, sz) = startsize[idx] 150750d670daSJeff Roberson off = (newy + size) - self.sourcestart(source) 150850d670daSJeff Roberson self.sourceshift(source, off) 150950d670daSJeff Roberson source.hidden = 0 151050d670daSJeff Roberson size += sz 151150d670daSJeff Roberson idx += 1 151216ef0f3bSJeff Roberson self.updatescroll() 151350d670daSJeff Roberson self.status.set("") 151450d670daSJeff Roberson 151550d670daSJeff Roberson # 151650d670daSJeff Roberson # Optimized source hide of multiple entries that only moves each 151750d670daSJeff Roberson # remaining entry once. Doing sourcehide() iteratively is too 151850d670daSJeff Roberson # expensive due to python's canvas.move(). 151950d670daSJeff Roberson # 152050d670daSJeff Roberson def sourcehidelist(self, srclist): 1521*7e8ed296SAndriy Gapon srclist.sort(key=attrgetter('y')) 1522*7e8ed296SAndriy Gapon sources.sort(key=attrgetter('y')) 152350d670daSJeff Roberson startsize = [] 152450d670daSJeff Roberson off = len(sources) * 100 152550d670daSJeff Roberson self.status.startup("Updating display..."); 152650d670daSJeff Roberson for source in srclist: 152750d670daSJeff Roberson if (source.hidden == 1): 152850d670daSJeff Roberson srclist.remove(source) 152950d670daSJeff Roberson # 153050d670daSJeff Roberson # Remember our old position so we can sort things 153150d670daSJeff Roberson # below us when we're done. 153250d670daSJeff Roberson # 153350d670daSJeff Roberson startsize.append((self.sourcestart(source), 153450d670daSJeff Roberson self.sourcesize(source))) 153550d670daSJeff Roberson self.sourceshift(source, off) 153650d670daSJeff Roberson source.hidden = 1 153750d670daSJeff Roberson 153850d670daSJeff Roberson idx = 0 153950d670daSJeff Roberson size = 0 154050d670daSJeff Roberson for hidden in startsize: 154150d670daSJeff Roberson (start, sz) = hidden 154250d670daSJeff Roberson size += sz 154350d670daSJeff Roberson if (idx + 1 < len(startsize)): 154450d670daSJeff Roberson (stop, sz) = startsize[idx+1] 154550d670daSJeff Roberson else: 154650d670daSJeff Roberson stop = self.display.ysize() 154750d670daSJeff Roberson idx += 1 154850d670daSJeff Roberson for source in sources: 154950d670daSJeff Roberson nstart = self.sourcestart(source) 155050d670daSJeff Roberson if (nstart < start or source.hidden == 1): 155150d670daSJeff Roberson continue 155250d670daSJeff Roberson if (nstart >= stop): 155350d670daSJeff Roberson break; 155450d670daSJeff Roberson self.sourceshift(source, -size) 155516ef0f3bSJeff Roberson self.updatescroll() 155650d670daSJeff Roberson self.status.set("") 155750d670daSJeff Roberson 15583d21f0f4SJeff Roberson def sourcehide(self, source): 155950d670daSJeff Roberson if (source.hidden == 1): 156050d670daSJeff Roberson return; 15613d21f0f4SJeff Roberson # Move it out of the visible area 15623d21f0f4SJeff Roberson off = len(sources) * 100 15633d21f0f4SJeff Roberson start = self.sourcestart(source) 15643d21f0f4SJeff Roberson self.sourceshift(source, off) 15653d21f0f4SJeff Roberson self.sourceshiftall(start, -self.sourcesize(source)) 15663d21f0f4SJeff Roberson source.hidden = 1 15673d21f0f4SJeff Roberson 15683d21f0f4SJeff Roberson def sourceshift(self, source, off): 15693d21f0f4SJeff Roberson start = self.sourcestart(source) 15703d21f0f4SJeff Roberson source.move(self.display, 0, off) 15713d21f0f4SJeff Roberson source.movename(self.names, 0, off) 15723d21f0f4SJeff Roberson self.names.moveline(start, off); 15733d21f0f4SJeff Roberson self.display.moveline(start, off) 157450d670daSJeff Roberson # 157550d670daSJeff Roberson # We update the idle tasks to shrink the dirtied area so 157650d670daSJeff Roberson # it does not always include the entire screen. 157750d670daSJeff Roberson # 157850d670daSJeff Roberson self.names.update_idletasks() 157950d670daSJeff Roberson self.display.update_idletasks() 15803d21f0f4SJeff Roberson 15813d21f0f4SJeff Roberson def sourceshiftall(self, start, off): 158250d670daSJeff Roberson self.status.startup("Updating display..."); 15833d21f0f4SJeff Roberson for source in sources: 15843d21f0f4SJeff Roberson nstart = self.sourcestart(source) 15853d21f0f4SJeff Roberson if (nstart < start): 15863d21f0f4SJeff Roberson continue; 15873d21f0f4SJeff Roberson self.sourceshift(source, off) 158816ef0f3bSJeff Roberson self.updatescroll() 158950d670daSJeff Roberson self.status.set("") 15903d21f0f4SJeff Roberson 1591ec5cae07SJeff Roberson def sourceat(self, ypos): 1592ec5cae07SJeff Roberson (start, end) = self.names.yview() 1593ec5cae07SJeff Roberson starty = start * float(self.names.ysize) 1594ec5cae07SJeff Roberson ypos += starty 1595ec5cae07SJeff Roberson for source in sources: 15963d21f0f4SJeff Roberson if (source.hidden == 1): 15973d21f0f4SJeff Roberson continue; 1598ec5cae07SJeff Roberson yend = self.sourceend(source) 1599ec5cae07SJeff Roberson ystart = self.sourcestart(source) 1600ec5cae07SJeff Roberson if (ypos >= ystart and ypos <= yend): 1601ec5cae07SJeff Roberson return source 1602ec5cae07SJeff Roberson return None 1603ec5cae07SJeff Roberson 1604dcee3bd3SJeff Roberson def display_yview(self, *args): 1605dcee3bd3SJeff Roberson self.names.yview(*args) 1606dcee3bd3SJeff Roberson self.display.yview(*args) 1607dcee3bd3SJeff Roberson 160816ef0f3bSJeff Roberson def resize(self, *args): 160916ef0f3bSJeff Roberson width = int(root.geometry().split('x')[0]) 161016ef0f3bSJeff Roberson scalemax = ktrfile.timespan() / (width - self.constwidth) 161116ef0f3bSJeff Roberson self.scale.setmax(scalemax) 161216ef0f3bSJeff Roberson 161316ef0f3bSJeff Roberson def updatescroll(self): 161416ef0f3bSJeff Roberson self.names.updatescroll() 161516ef0f3bSJeff Roberson self.display.updatescroll() 161616ef0f3bSJeff Roberson 1617dcee3bd3SJeff Roberson def setcolor(self, tag, color): 1618dcee3bd3SJeff Roberson self.display.setcolor(tag, color) 1619dcee3bd3SJeff Roberson 1620dcee3bd3SJeff Roberson def hide(self, tag): 1621dcee3bd3SJeff Roberson self.display.hide(tag) 1622dcee3bd3SJeff Roberson 1623ec5cae07SJeff Roberson def getcolor(self, tag): 1624ec5cae07SJeff Roberson return self.display.getcolor(tag) 1625ec5cae07SJeff Roberson 1626ec5cae07SJeff Roberson def getstate(self, tag): 1627ec5cae07SJeff Roberson return self.display.getstate(tag) 1628ec5cae07SJeff Roberson 1629ec5cae07SJeff Robersonif (len(sys.argv) != 2 and len(sys.argv) != 3): 1630749f65e3SCraig Rodrigues print("usage:", sys.argv[0], "<ktr file> [clock freq in ghz]") 1631dcee3bd3SJeff Roberson sys.exit(1) 1632dcee3bd3SJeff Roberson 1633ec5cae07SJeff Robersonif (len(sys.argv) > 2): 1634ec5cae07SJeff Roberson clockfreq = float(sys.argv[2]) 1635ec5cae07SJeff Roberson 1636dcee3bd3SJeff Robersonroot = Tk() 1637932f0fa2SJeff Robersonroot.title("SchedGraph") 1638ec5cae07SJeff Robersoncolormap = Colormap(eventcolors) 1639ec5cae07SJeff Robersoncpucolormap = Colormap(cpucolors) 1640dcee3bd3SJeff Robersongraph = SchedGraph(root) 1641ec5cae07SJeff Robersonktrfile = KTRFile(sys.argv[1]) 1642ec5cae07SJeff Robersongraph.draw() 1643dcee3bd3SJeff Robersonroot.mainloop() 1644