Skip to content

Commit

Permalink
perf, sched migration: Make the GUI class client agnostic
Browse files Browse the repository at this point in the history
Make the perf migration GUI generic so that it can be reused for
other kinds of trace painting. No more notion of CPUs or runqueue
from the GUI class, it's now used as a library by the trace parser.

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Nikhil Rao <ncrao@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
  • Loading branch information
Frederic Weisbecker committed Aug 1, 2010
1 parent 70d815a commit 699b6d9
Showing 1 changed file with 92 additions and 85 deletions.
177 changes: 92 additions & 85 deletions tools/perf/scripts/python/sched-migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,24 @@

class RootFrame(wx.Frame):
Y_OFFSET = 100
CPU_HEIGHT = 100
CPU_SPACE = 50
RECT_HEIGHT = 100
RECT_SPACE = 50
EVENT_MARKING_WIDTH = 5

def __init__(self, timeslices, parent = None, id = -1, title = "Migration"):
def __init__(self, sched_tracer, title, parent = None, id = -1):
wx.Frame.__init__(self, parent, id, title)

(self.screen_width, self.screen_height) = wx.GetDisplaySize()
self.screen_width -= 10
self.screen_height -= 10
self.zoom = 0.5
self.scroll_scale = 20
self.timeslices = timeslices
(self.ts_start, self.ts_end) = timeslices.interval()
self.sched_tracer = sched_tracer
self.sched_tracer.set_root_win(self)
(self.ts_start, self.ts_end) = sched_tracer.interval()
self.update_width_virtual()
self.nr_cpus = timeslices.max_cpu() + 1
self.height_virtual = RootFrame.Y_OFFSET + (self.nr_cpus * (RootFrame.CPU_HEIGHT + RootFrame.CPU_SPACE))
self.nr_rects = sched_tracer.nr_rectangles() + 1
self.height_virtual = RootFrame.Y_OFFSET + (self.nr_rects * (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE))

# whole window panel
self.panel = wx.Panel(self, size=(self.screen_width, self.screen_height))
Expand Down Expand Up @@ -87,115 +88,70 @@ def scroll_start_us(self):
(x, y) = self.scroll_start()
return self.px_to_us(x)

def update_rectangle_cpu(self, dc, slice, cpu, offset_time):
rq = slice.rqs[cpu]

if slice.total_load != 0:
load_rate = rq.load() / float(slice.total_load)
else:
load_rate = 0
def paint_rectangle_zone(self, nr, color, top_color, start, end):
offset_px = self.us_to_px(start - self.ts_start)
width_px = self.us_to_px(end - self.ts_start)

offset_py = RootFrame.Y_OFFSET + (nr * (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE))
width_py = RootFrame.RECT_HEIGHT

offset_px = self.us_to_px(slice.start - offset_time)
width_px = self.us_to_px(slice.end - slice.start)
(x, y) = self.scroll_start()
dc = self.dc

if width_px == 0:
return
if top_color is not None:
(r, g, b) = top_color
top_color = wx.Colour(r, g, b)
brush = wx.Brush(top_color, wx.SOLID)
dc.SetBrush(brush)
dc.DrawRectangle(offset_px, offset_py, width_px, RootFrame.EVENT_MARKING_WIDTH)
width_py -= RootFrame.EVENT_MARKING_WIDTH
offset_py += RootFrame.EVENT_MARKING_WIDTH

offset_py = RootFrame.Y_OFFSET + (cpu * (RootFrame.CPU_HEIGHT + RootFrame.CPU_SPACE))
width_py = RootFrame.CPU_HEIGHT

if cpu in slice.event_cpus:
rgb = rq.event.color()
if rgb is not None:
(r, g, b) = rgb
color = wx.Colour(r, g, b)
brush = wx.Brush(color, wx.SOLID)
dc.SetBrush(brush)
dc.DrawRectangle(offset_px, offset_py, width_px, RootFrame.EVENT_MARKING_WIDTH)
width_py -= RootFrame.EVENT_MARKING_WIDTH
offset_py += RootFrame.EVENT_MARKING_WIDTH

red_power = int(0xff - (0xff * load_rate))
color = wx.Colour(0xff, red_power, red_power)
(r ,g, b) = color
color = wx.Colour(r, g, b)
brush = wx.Brush(color, wx.SOLID)
dc.SetBrush(brush)
dc.DrawRectangle(offset_px, offset_py, width_px, width_py)

def update_rectangles(self, dc, start, end):
if len(self.timeslices) == 0:
return
start += self.timeslices[0].start
end += self.timeslices[0].start

color = wx.Colour(0, 0, 0)
brush = wx.Brush(color, wx.SOLID)
dc.SetBrush(brush)

i = self.timeslices.find_time_slice(start)
if i == -1:
return

for i in xrange(i, len(self.timeslices)):
timeslice = self.timeslices[i]
if timeslice.start > end:
return

for cpu in timeslice.rqs:
self.update_rectangle_cpu(dc, timeslice, cpu, self.timeslices[0].start)
start += self.ts_start
end += self.ts_start
self.sched_tracer.fill_zone(start, end)

def on_paint(self, event):
color = wx.Colour(0xff, 0xff, 0xff)
brush = wx.Brush(color, wx.SOLID)
dc = wx.PaintDC(self.scroll_panel)
dc.SetBrush(brush)
self.dc = dc

width = min(self.width_virtual, self.screen_width)
(x, y) = self.scroll_start()
start = self.px_to_us(x)
end = self.px_to_us(x + width)
self.update_rectangles(dc, start, end)

def cpu_from_ypixel(self, y):
def rect_from_ypixel(self, y):
y -= RootFrame.Y_OFFSET
cpu = y / (RootFrame.CPU_HEIGHT + RootFrame.CPU_SPACE)
height = y % (RootFrame.CPU_HEIGHT + RootFrame.CPU_SPACE)
rect = y / (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE)
height = y % (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE)

if cpu < 0 or cpu > self.nr_cpus - 1 or height > RootFrame.CPU_HEIGHT:
if rect < 0 or rect > self.nr_rects - 1 or height > RootFrame.RECT_HEIGHT:
return -1

return cpu

def update_summary(self, cpu, t):
idx = self.timeslices.find_time_slice(t)
if idx == -1:
return

ts = self.timeslices[idx]
rq = ts.rqs[cpu]
raw = "CPU: %d\n" % cpu
raw += "Last event : %s\n" % rq.event.__repr__()
raw += "Timestamp : %d.%06d\n" % (ts.start / (10 ** 9), (ts.start % (10 ** 9)) / 1000)
raw += "Duration : %6d us\n" % ((ts.end - ts.start) / (10 ** 6))
raw += "Load = %d\n" % rq.load()
for t in rq.tasks:
raw += "%s \n" % thread_name(t)
return rect

def update_summary(self, txt):
if self.txt:
self.txt.Destroy()
self.txt = wx.StaticText(self.panel, -1, raw, (0, (self.screen_height / 2) + 50))
self.txt = wx.StaticText(self.panel, -1, txt, (0, (self.screen_height / 2) + 50))


def on_mouse_down(self, event):
(x, y) = event.GetPositionTuple()
cpu = self.cpu_from_ypixel(y)
if cpu == -1:
rect = self.rect_from_ypixel(y)
if rect == -1:
return

t = self.px_to_us(x) + self.timeslices[0].start
t = self.px_to_us(x) + self.ts_start

self.update_summary(cpu, t)
self.sched_tracer.mouse_down(rect, t)


def update_width_virtual(self):
Expand Down Expand Up @@ -501,13 +457,64 @@ def find_time_slice(self, ts):

return found

def set_root_win(self, win):
self.root_win = win

def mouse_down(self, cpu, t):
idx = self.find_time_slice(t)
if idx == -1:
return

ts = self[idx]
rq = ts.rqs[cpu]
raw = "CPU: %d\n" % cpu
raw += "Last event : %s\n" % rq.event.__repr__()
raw += "Timestamp : %d.%06d\n" % (ts.start / (10 ** 9), (ts.start % (10 ** 9)) / 1000)
raw += "Duration : %6d us\n" % ((ts.end - ts.start) / (10 ** 6))
raw += "Load = %d\n" % rq.load()
for t in rq.tasks:
raw += "%s \n" % thread_name(t)

self.root_win.update_summary(raw)

def update_rectangle_cpu(self, slice, cpu):
rq = slice.rqs[cpu]

if slice.total_load != 0:
load_rate = rq.load() / float(slice.total_load)
else:
load_rate = 0

red_power = int(0xff - (0xff * load_rate))
color = (0xff, red_power, red_power)

top_color = None

if cpu in slice.event_cpus:
top_color = rq.event.color()

self.root_win.paint_rectangle_zone(cpu, color, top_color, slice.start, slice.end)

def fill_zone(self, start, end):
i = self.find_time_slice(start)
if i == -1:
return

for i in xrange(i, len(self.data)):
timeslice = self.data[i]
if timeslice.start > end:
return

for cpu in timeslice.rqs:
self.update_rectangle_cpu(timeslice, cpu)

def interval(self):
if len(self.data) == 0:
return (0, 0)

return (self.data[0].start, self.data[-1].end)

def max_cpu(self):
def nr_rectangles(self):
last_ts = self.data[-1]
max_cpu = 0
for cpu in last_ts.rqs:
Expand Down Expand Up @@ -557,7 +564,7 @@ def trace_begin():
def trace_end():
app = wx.App(False)
timeslices = parser.timeslices
frame = RootFrame(timeslices)
frame = RootFrame(timeslices, "Migration")
app.MainLoop()

def sched__sched_stat_runtime(event_name, context, common_cpu,
Expand Down

0 comments on commit 699b6d9

Please sign in to comment.