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@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 11try: 12 import wx 13except ImportError: 14 raise ImportError, "You need to install the wxpython lib for this script" 15 16 17class 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