Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 699b6d92 authored by Frederic Weisbecker's avatar Frederic Weisbecker
Browse files

perf, sched migration: Make the GUI class client agnostic



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: default avatarFrederic 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>
parent 70d815a3
Loading
Loading
Loading
Loading
+92 −85
Original line number Diff line number Diff line
@@ -28,11 +28,11 @@ from Core import *

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()
@@ -40,11 +40,12 @@ class RootFrame(wx.Frame):
		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))
@@ -87,69 +88,38 @@ class RootFrame(wx.Frame):
		(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_px = self.us_to_px(slice.start - offset_time)
		width_px = self.us_to_px(slice.end - slice.start)
		(x, y) = self.scroll_start()

		if width_px == 0:
			return
		offset_py = RootFrame.Y_OFFSET + (nr * (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE))
		width_py = RootFrame.RECT_HEIGHT

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

		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)
		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

		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()
@@ -157,45 +127,31 @@ class RootFrame(wx.Frame):
		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):
@@ -501,13 +457,64 @@ class TimeSliceList(UserList):

		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:
@@ -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,