1e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng# SchedGui.py - Python extension for perf script, basic GUI code for
2e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#		traces drawing and overview.
3e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#
4e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng# Copyright (C) 2010 by Frederic Weisbecker <fweisbec@gmail.com>
5e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng#
6e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng# This software is distributed under the terms of the GNU General
7e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng# Public License ("GPL") version 2 as published by the Free Software
8e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng# Foundation.
9e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
10e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
11e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengtry:
12e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	import wx
13e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengexcept ImportError:
14e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	raise ImportError, "You need to install the wxpython lib for this script"
15e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
16e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
17e6817ec1d8ab31fc7b01906e305f848542df6413Ben Chengclass RootFrame(wx.Frame):
18e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	Y_OFFSET = 100
19e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	RECT_HEIGHT = 100
20e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	RECT_SPACE = 50
21e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	EVENT_MARKING_WIDTH = 5
22e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
23e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def __init__(self, sched_tracer, title, parent = None, id = -1):
24e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		wx.Frame.__init__(self, parent, id, title)
25e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
26e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		(self.screen_width, self.screen_height) = wx.GetDisplaySize()
27e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.screen_width -= 10
28e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.screen_height -= 10
29e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.zoom = 0.5
30e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll_scale = 20
31e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.sched_tracer = sched_tracer
32e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.sched_tracer.set_root_win(self)
33e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		(self.ts_start, self.ts_end) = sched_tracer.interval()
34e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.update_width_virtual()
35e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.nr_rects = sched_tracer.nr_rectangles() + 1
36e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.height_virtual = RootFrame.Y_OFFSET + (self.nr_rects * (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE))
37e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
38e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		# whole window panel
39e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.panel = wx.Panel(self, size=(self.screen_width, self.screen_height))
40e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
41e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		# scrollable container
42e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll = wx.ScrolledWindow(self.panel)
43e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll.SetScrollbars(self.scroll_scale, self.scroll_scale, self.width_virtual / self.scroll_scale, self.height_virtual / self.scroll_scale)
44e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll.EnableScrolling(True, True)
45e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll.SetFocus()
46e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
47e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		# scrollable drawing area
48e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll_panel = wx.Panel(self.scroll, size=(self.screen_width - 15, self.screen_height / 2))
49e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll_panel.Bind(wx.EVT_PAINT, self.on_paint)
50e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll_panel.Bind(wx.EVT_KEY_DOWN, self.on_key_press)
51e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll_panel.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down)
52e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll.Bind(wx.EVT_PAINT, self.on_paint)
53e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll.Bind(wx.EVT_KEY_DOWN, self.on_key_press)
54e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down)
55e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
56e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll.Fit()
57e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.Fit()
58e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
59e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll_panel.SetDimensions(-1, -1, self.width_virtual, self.height_virtual, wx.SIZE_USE_EXISTING)
60e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
61e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.txt = None
62e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
63e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.Show(True)
64e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
65e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def us_to_px(self, val):
66e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return val / (10 ** 3) * self.zoom
67e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
68e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def px_to_us(self, val):
69e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return (val / self.zoom) * (10 ** 3)
70e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
71e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def scroll_start(self):
72e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		(x, y) = self.scroll.GetViewStart()
73e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return (x * self.scroll_scale, y * self.scroll_scale)
74e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
75e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def scroll_start_us(self):
76e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		(x, y) = self.scroll_start()
77e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return self.px_to_us(x)
78e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
79e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def paint_rectangle_zone(self, nr, color, top_color, start, end):
80e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		offset_px = self.us_to_px(start - self.ts_start)
81e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		width_px = self.us_to_px(end - self.ts_start)
82e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
83e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		offset_py = RootFrame.Y_OFFSET + (nr * (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE))
84e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		width_py = RootFrame.RECT_HEIGHT
85e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
86e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		dc = self.dc
87e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
88e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if top_color is not None:
89e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			(r, g, b) = top_color
90e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			top_color = wx.Colour(r, g, b)
91e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			brush = wx.Brush(top_color, wx.SOLID)
92e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			dc.SetBrush(brush)
93e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			dc.DrawRectangle(offset_px, offset_py, width_px, RootFrame.EVENT_MARKING_WIDTH)
94e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			width_py -= RootFrame.EVENT_MARKING_WIDTH
95e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			offset_py += RootFrame.EVENT_MARKING_WIDTH
96e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
97e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		(r ,g, b) = color
98e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		color = wx.Colour(r, g, b)
99e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		brush = wx.Brush(color, wx.SOLID)
100e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		dc.SetBrush(brush)
101e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		dc.DrawRectangle(offset_px, offset_py, width_px, width_py)
102e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
103e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def update_rectangles(self, dc, start, end):
104e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		start += self.ts_start
105e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		end += self.ts_start
106e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.sched_tracer.fill_zone(start, end)
107e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
108e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def on_paint(self, event):
109e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		dc = wx.PaintDC(self.scroll_panel)
110e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.dc = dc
111e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
112e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		width = min(self.width_virtual, self.screen_width)
113e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		(x, y) = self.scroll_start()
114e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		start = self.px_to_us(x)
115e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		end = self.px_to_us(x + width)
116e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.update_rectangles(dc, start, end)
117e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
118e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def rect_from_ypixel(self, y):
119e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		y -= RootFrame.Y_OFFSET
120e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		rect = y / (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE)
121e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		height = y % (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE)
122e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
123e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if rect < 0 or rect > self.nr_rects - 1 or height > RootFrame.RECT_HEIGHT:
124e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			return -1
125e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
126e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		return rect
127e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
128e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def update_summary(self, txt):
129e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if self.txt:
130e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			self.txt.Destroy()
131e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.txt = wx.StaticText(self.panel, -1, txt, (0, (self.screen_height / 2) + 50))
132e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
133e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
134e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def on_mouse_down(self, event):
135e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		(x, y) = event.GetPositionTuple()
136e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		rect = self.rect_from_ypixel(y)
137e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if rect == -1:
138e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			return
139e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
140e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		t = self.px_to_us(x) + self.ts_start
141e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
142e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.sched_tracer.mouse_down(rect, t)
143e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
144e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
145e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def update_width_virtual(self):
146e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.width_virtual = self.us_to_px(self.ts_end - self.ts_start)
147e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
148e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def __zoom(self, x):
149e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.update_width_virtual()
150e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		(xpos, ypos) = self.scroll.GetViewStart()
151e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		xpos = self.us_to_px(x) / self.scroll_scale
152e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.scroll.SetScrollbars(self.scroll_scale, self.scroll_scale, self.width_virtual / self.scroll_scale, self.height_virtual / self.scroll_scale, xpos, ypos)
153e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.Refresh()
154e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
155e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def zoom_in(self):
156e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		x = self.scroll_start_us()
157e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.zoom *= 2
158e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.__zoom(x)
159e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
160e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def zoom_out(self):
161e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		x = self.scroll_start_us()
162e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.zoom /= 2
163e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		self.__zoom(x)
164e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
165e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
166e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng	def on_key_press(self, event):
167e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		key = event.GetRawKeyCode()
168e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if key == ord("+"):
169e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			self.zoom_in()
170e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			return
171e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if key == ord("-"):
172e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			self.zoom_out()
173e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			return
174e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng
175e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		key = event.GetKeyCode()
176e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		(x, y) = self.scroll.GetViewStart()
177e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		if key == wx.WXK_RIGHT:
178e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			self.scroll.Scroll(x + 1, y)
179e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		elif key == wx.WXK_LEFT:
180e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			self.scroll.Scroll(x - 1, y)
181e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		elif key == wx.WXK_DOWN:
182e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			self.scroll.Scroll(x, y + 1)
183e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng		elif key == wx.WXK_UP:
184e6817ec1d8ab31fc7b01906e305f848542df6413Ben Cheng			self.scroll.Scroll(x, y - 1)
185