|
@@ -28,11 +28,11 @@ from Core import *
|
|
|
|
|
|
class RootFrame(wx.Frame):
|
|
class RootFrame(wx.Frame):
|
|
Y_OFFSET = 100
|
|
Y_OFFSET = 100
|
|
- CPU_HEIGHT = 100
|
|
|
|
- CPU_SPACE = 50
|
|
|
|
|
|
+ RECT_HEIGHT = 100
|
|
|
|
+ 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.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.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
|
|
# 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):
|
|
|
|
- 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_py = RootFrame.Y_OFFSET + (nr * (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE))
|
|
|
|
+ width_py = RootFrame.RECT_HEIGHT
|
|
|
|
|
|
- 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()
|
|
|
|
|
|
+ dc = self.dc
|
|
|
|
|
|
- if width_px == 0:
|
|
|
|
- return
|
|
|
|
|
|
+ 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
|
|
|
|
|
|
- offset_py = RootFrame.Y_OFFSET + (cpu * (RootFrame.CPU_HEIGHT + RootFrame.CPU_SPACE))
|
|
|
|
- width_py = RootFrame.CPU_HEIGHT
|
|
|
|
-
|
|
|
|
- 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)
|
|
|
|
- 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)
|
|
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:
|
|
|
|
- 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):
|
|
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)
|
|
|
|
- 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 -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:
|
|
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)
|
|
|
|
- if cpu == -1:
|
|
|
|
|
|
+ rect = self.rect_from_ypixel(y)
|
|
|
|
+ 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,
|