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