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 Original line Diff line number Diff line
@@ -28,11 +28,11 @@ from Core import *


class RootFrame(wx.Frame):
class RootFrame(wx.Frame):
	Y_OFFSET = 100
	Y_OFFSET = 100
	CPU_HEIGHT = 100
	RECT_HEIGHT = 100
	CPU_SPACE = 50
	RECT_SPACE = 50
	EVENT_MARKING_WIDTH = 5
	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)
		wx.Frame.__init__(self, parent, id, title)


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


		# whole window panel
		# whole window panel
		self.panel = wx.Panel(self, size=(self.screen_width, self.screen_height))
		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()
		(x, y) = self.scroll_start()
		return self.px_to_us(x)
		return self.px_to_us(x)


	def update_rectangle_cpu(self, dc, slice, cpu, offset_time):
	def paint_rectangle_zone(self, nr, color, top_color, start, end):
		rq = slice.rqs[cpu]
		offset_px = self.us_to_px(start - self.ts_start)

		width_px = self.us_to_px(end - self.ts_start)
		if slice.total_load != 0:
			load_rate = rq.load() / float(slice.total_load)
		else:
			load_rate = 0



		offset_px = self.us_to_px(slice.start - offset_time)
		offset_py = RootFrame.Y_OFFSET + (nr * (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE))
		width_px = self.us_to_px(slice.end - slice.start)
		width_py = RootFrame.RECT_HEIGHT
		(x, y) = self.scroll_start()

		if width_px == 0:
			return


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


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


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


	def update_rectangles(self, dc, start, end):
	def update_rectangles(self, dc, start, end):
		if len(self.timeslices) == 0:
		start += self.ts_start
			return
		end += self.ts_start
		start += self.timeslices[0].start
		self.sched_tracer.fill_zone(start, end)
		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)


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


		width = min(self.width_virtual, self.screen_width)
		width = min(self.width_virtual, self.screen_width)
		(x, y) = self.scroll_start()
		(x, y) = self.scroll_start()
@@ -157,45 +127,31 @@ class RootFrame(wx.Frame):
		end = self.px_to_us(x + width)
		end = self.px_to_us(x + width)
		self.update_rectangles(dc, start, end)
		self.update_rectangles(dc, start, end)


	def cpu_from_ypixel(self, y):
	def rect_from_ypixel(self, y):
		y -= RootFrame.Y_OFFSET
		y -= RootFrame.Y_OFFSET
		cpu = y / (RootFrame.CPU_HEIGHT + RootFrame.CPU_SPACE)
		rect = y / (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE)
		height = y % (RootFrame.CPU_HEIGHT + RootFrame.CPU_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 -1


		return cpu
		return rect

	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)


	def update_summary(self, txt):
		if self.txt:
		if self.txt:
			self.txt.Destroy()
			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):
	def on_mouse_down(self, event):
		(x, y) = event.GetPositionTuple()
		(x, y) = event.GetPositionTuple()
		cpu = self.cpu_from_ypixel(y)
		rect = self.rect_from_ypixel(y)
		if cpu == -1:
		if rect == -1:
			return
			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):
	def update_width_virtual(self):
@@ -501,13 +457,64 @@ class TimeSliceList(UserList):


		return found
		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):
	def interval(self):
		if len(self.data) == 0:
		if len(self.data) == 0:
			return (0, 0)
			return (0, 0)


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


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


def sched__sched_stat_runtime(event_name, context, common_cpu,
def sched__sched_stat_runtime(event_name, context, common_cpu,