1880d22f2SFrederic Weisbecker#!/usr/bin/python
2880d22f2SFrederic Weisbecker#
3880d22f2SFrederic Weisbecker# Cpu task migration overview toy
4880d22f2SFrederic Weisbecker#
5880d22f2SFrederic Weisbecker# Copyright (C) 2010 Frederic Weisbecker <[email protected]>
6880d22f2SFrederic Weisbecker#
7880d22f2SFrederic Weisbecker# perf trace event handlers have been generated by perf trace -g python
8880d22f2SFrederic Weisbecker#
9880d22f2SFrederic Weisbecker# The whole is licensed under the terms of the GNU GPL License version 2
10880d22f2SFrederic Weisbecker
11880d22f2SFrederic Weisbecker
12880d22f2SFrederic Weisbeckertry:
13880d22f2SFrederic Weisbecker	import wx
14880d22f2SFrederic Weisbeckerexcept ImportError:
15880d22f2SFrederic Weisbecker	raise ImportError, "You need to install the wxpython lib for this script"
16880d22f2SFrederic Weisbecker
17880d22f2SFrederic Weisbeckerimport os
18880d22f2SFrederic Weisbeckerimport sys
19880d22f2SFrederic Weisbecker
20880d22f2SFrederic Weisbeckerfrom collections import defaultdict
21880d22f2SFrederic Weisbeckerfrom UserList import UserList
22880d22f2SFrederic Weisbecker
23880d22f2SFrederic Weisbeckersys.path.append(os.environ['PERF_EXEC_PATH'] + \
24880d22f2SFrederic Weisbecker	'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
25880d22f2SFrederic Weisbecker
26880d22f2SFrederic Weisbeckerfrom perf_trace_context import *
27880d22f2SFrederic Weisbeckerfrom Core import *
28880d22f2SFrederic Weisbecker
29880d22f2SFrederic Weisbeckerclass RootFrame(wx.Frame):
300cddf56aSNikhil Rao	Y_OFFSET = 100
310cddf56aSNikhil Rao	CPU_HEIGHT = 100
320cddf56aSNikhil Rao	CPU_SPACE = 50
330cddf56aSNikhil Rao	EVENT_MARKING_WIDTH = 5
340cddf56aSNikhil Rao
35880d22f2SFrederic Weisbecker	def __init__(self, timeslices, parent = None, id = -1, title = "Migration"):
36880d22f2SFrederic Weisbecker		wx.Frame.__init__(self, parent, id, title)
37880d22f2SFrederic Weisbecker
38880d22f2SFrederic Weisbecker		(self.screen_width, self.screen_height) = wx.GetDisplaySize()
39880d22f2SFrederic Weisbecker		self.screen_width -= 10
40880d22f2SFrederic Weisbecker		self.screen_height -= 10
41880d22f2SFrederic Weisbecker		self.zoom = 0.5
42880d22f2SFrederic Weisbecker		self.scroll_scale = 20
43880d22f2SFrederic Weisbecker		self.timeslices = timeslices
44880d22f2SFrederic Weisbecker		(self.ts_start, self.ts_end) = timeslices.interval()
45880d22f2SFrederic Weisbecker		self.update_width_virtual()
46*70d815a3SFrederic Weisbecker		self.nr_cpus = timeslices.max_cpu() + 1
47*70d815a3SFrederic Weisbecker		self.height_virtual = RootFrame.Y_OFFSET + (self.nr_cpus * (RootFrame.CPU_HEIGHT + RootFrame.CPU_SPACE))
48880d22f2SFrederic Weisbecker
49880d22f2SFrederic Weisbecker		# whole window panel
50880d22f2SFrederic Weisbecker		self.panel = wx.Panel(self, size=(self.screen_width, self.screen_height))
51880d22f2SFrederic Weisbecker
52880d22f2SFrederic Weisbecker		# scrollable container
53880d22f2SFrederic Weisbecker		self.scroll = wx.ScrolledWindow(self.panel)
54*70d815a3SFrederic Weisbecker		self.scroll.SetScrollbars(self.scroll_scale, self.scroll_scale, self.width_virtual / self.scroll_scale, self.height_virtual / self.scroll_scale)
55880d22f2SFrederic Weisbecker		self.scroll.EnableScrolling(True, True)
56880d22f2SFrederic Weisbecker		self.scroll.SetFocus()
57880d22f2SFrederic Weisbecker
58880d22f2SFrederic Weisbecker		# scrollable drawing area
59*70d815a3SFrederic Weisbecker		self.scroll_panel = wx.Panel(self.scroll, size=(self.screen_width - 15, self.screen_height / 2))
60880d22f2SFrederic Weisbecker		self.scroll_panel.Bind(wx.EVT_PAINT, self.on_paint)
61880d22f2SFrederic Weisbecker		self.scroll_panel.Bind(wx.EVT_KEY_DOWN, self.on_key_press)
62880d22f2SFrederic Weisbecker		self.scroll_panel.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down)
63880d22f2SFrederic Weisbecker		self.scroll.Bind(wx.EVT_PAINT, self.on_paint)
64be6d9476SNikhil Rao		self.scroll.Bind(wx.EVT_KEY_DOWN, self.on_key_press)
65be6d9476SNikhil Rao		self.scroll.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down)
66880d22f2SFrederic Weisbecker
67880d22f2SFrederic Weisbecker		self.scroll.Fit()
68880d22f2SFrederic Weisbecker		self.Fit()
69880d22f2SFrederic Weisbecker
70*70d815a3SFrederic Weisbecker		self.scroll_panel.SetDimensions(-1, -1, self.width_virtual, self.height_virtual, wx.SIZE_USE_EXISTING)
71880d22f2SFrederic Weisbecker
72880d22f2SFrederic Weisbecker		self.txt = None
73880d22f2SFrederic Weisbecker
74880d22f2SFrederic Weisbecker		self.Show(True)
75880d22f2SFrederic Weisbecker
76880d22f2SFrederic Weisbecker	def us_to_px(self, val):
77880d22f2SFrederic Weisbecker		return val / (10 ** 3) * self.zoom
78880d22f2SFrederic Weisbecker
79880d22f2SFrederic Weisbecker	def px_to_us(self, val):
80880d22f2SFrederic Weisbecker		return (val / self.zoom) * (10 ** 3)
81880d22f2SFrederic Weisbecker
82880d22f2SFrederic Weisbecker	def scroll_start(self):
83880d22f2SFrederic Weisbecker		(x, y) = self.scroll.GetViewStart()
84880d22f2SFrederic Weisbecker		return (x * self.scroll_scale, y * self.scroll_scale)
85880d22f2SFrederic Weisbecker
86880d22f2SFrederic Weisbecker	def scroll_start_us(self):
87880d22f2SFrederic Weisbecker		(x, y) = self.scroll_start()
88880d22f2SFrederic Weisbecker		return self.px_to_us(x)
89880d22f2SFrederic Weisbecker
90880d22f2SFrederic Weisbecker	def update_rectangle_cpu(self, dc, slice, cpu, offset_time):
91880d22f2SFrederic Weisbecker		rq = slice.rqs[cpu]
92880d22f2SFrederic Weisbecker
93880d22f2SFrederic Weisbecker		if slice.total_load != 0:
94880d22f2SFrederic Weisbecker			load_rate = rq.load() / float(slice.total_load)
95880d22f2SFrederic Weisbecker		else:
96880d22f2SFrederic Weisbecker			load_rate = 0
97880d22f2SFrederic Weisbecker
98880d22f2SFrederic Weisbecker
99880d22f2SFrederic Weisbecker		offset_px = self.us_to_px(slice.start - offset_time)
100880d22f2SFrederic Weisbecker		width_px = self.us_to_px(slice.end - slice.start)
101880d22f2SFrederic Weisbecker		(x, y) = self.scroll_start()
102880d22f2SFrederic Weisbecker
103880d22f2SFrederic Weisbecker		if width_px == 0:
104880d22f2SFrederic Weisbecker			return
105880d22f2SFrederic Weisbecker
1060cddf56aSNikhil Rao		offset_py = RootFrame.Y_OFFSET + (cpu * (RootFrame.CPU_HEIGHT + RootFrame.CPU_SPACE))
1070cddf56aSNikhil Rao		width_py = RootFrame.CPU_HEIGHT
108880d22f2SFrederic Weisbecker
109880d22f2SFrederic Weisbecker		if cpu in slice.event_cpus:
110880d22f2SFrederic Weisbecker			rgb = rq.event.color()
111880d22f2SFrederic Weisbecker			if rgb is not None:
112880d22f2SFrederic Weisbecker				(r, g, b) = rgb
113880d22f2SFrederic Weisbecker				color = wx.Colour(r, g, b)
114880d22f2SFrederic Weisbecker				brush = wx.Brush(color, wx.SOLID)
115880d22f2SFrederic Weisbecker				dc.SetBrush(brush)
1160cddf56aSNikhil Rao				dc.DrawRectangle(offset_px, offset_py, width_px, RootFrame.EVENT_MARKING_WIDTH)
1170cddf56aSNikhil Rao				width_py -= RootFrame.EVENT_MARKING_WIDTH
1180cddf56aSNikhil Rao				offset_py += RootFrame.EVENT_MARKING_WIDTH
119880d22f2SFrederic Weisbecker
120880d22f2SFrederic Weisbecker		red_power = int(0xff - (0xff * load_rate))
121880d22f2SFrederic Weisbecker		color = wx.Colour(0xff, red_power, red_power)
122880d22f2SFrederic Weisbecker		brush = wx.Brush(color, wx.SOLID)
123880d22f2SFrederic Weisbecker		dc.SetBrush(brush)
124880d22f2SFrederic Weisbecker		dc.DrawRectangle(offset_px, offset_py, width_px, width_py)
125880d22f2SFrederic Weisbecker
126880d22f2SFrederic Weisbecker	def update_rectangles(self, dc, start, end):
127880d22f2SFrederic Weisbecker		if len(self.timeslices) == 0:
128880d22f2SFrederic Weisbecker			return
129880d22f2SFrederic Weisbecker		start += self.timeslices[0].start
130880d22f2SFrederic Weisbecker		end += self.timeslices[0].start
131880d22f2SFrederic Weisbecker
132880d22f2SFrederic Weisbecker		color = wx.Colour(0, 0, 0)
133880d22f2SFrederic Weisbecker		brush = wx.Brush(color, wx.SOLID)
134880d22f2SFrederic Weisbecker		dc.SetBrush(brush)
135880d22f2SFrederic Weisbecker
136880d22f2SFrederic Weisbecker		i = self.timeslices.find_time_slice(start)
137880d22f2SFrederic Weisbecker		if i == -1:
138880d22f2SFrederic Weisbecker			return
139880d22f2SFrederic Weisbecker
140880d22f2SFrederic Weisbecker		for i in xrange(i, len(self.timeslices)):
141880d22f2SFrederic Weisbecker			timeslice = self.timeslices[i]
142880d22f2SFrederic Weisbecker			if timeslice.start > end:
143880d22f2SFrederic Weisbecker				return
144880d22f2SFrederic Weisbecker
145880d22f2SFrederic Weisbecker			for cpu in timeslice.rqs:
146880d22f2SFrederic Weisbecker				self.update_rectangle_cpu(dc, timeslice, cpu, self.timeslices[0].start)
147880d22f2SFrederic Weisbecker
148880d22f2SFrederic Weisbecker	def on_paint(self, event):
149880d22f2SFrederic Weisbecker		color = wx.Colour(0xff, 0xff, 0xff)
150880d22f2SFrederic Weisbecker		brush = wx.Brush(color, wx.SOLID)
151880d22f2SFrederic Weisbecker		dc = wx.PaintDC(self.scroll_panel)
152880d22f2SFrederic Weisbecker		dc.SetBrush(brush)
153880d22f2SFrederic Weisbecker
154880d22f2SFrederic Weisbecker		width = min(self.width_virtual, self.screen_width)
155880d22f2SFrederic Weisbecker		(x, y) = self.scroll_start()
156880d22f2SFrederic Weisbecker		start = self.px_to_us(x)
157880d22f2SFrederic Weisbecker		end = self.px_to_us(x + width)
158880d22f2SFrederic Weisbecker		self.update_rectangles(dc, start, end)
159880d22f2SFrederic Weisbecker
160880d22f2SFrederic Weisbecker	def cpu_from_ypixel(self, y):
1610cddf56aSNikhil Rao		y -= RootFrame.Y_OFFSET
1620cddf56aSNikhil Rao		cpu = y / (RootFrame.CPU_HEIGHT + RootFrame.CPU_SPACE)
1630cddf56aSNikhil Rao		height = y % (RootFrame.CPU_HEIGHT + RootFrame.CPU_SPACE)
164880d22f2SFrederic Weisbecker
165*70d815a3SFrederic Weisbecker		if cpu < 0 or cpu > self.nr_cpus - 1 or height > RootFrame.CPU_HEIGHT:
166880d22f2SFrederic Weisbecker			return -1
167880d22f2SFrederic Weisbecker
168880d22f2SFrederic Weisbecker		return cpu
169880d22f2SFrederic Weisbecker
170880d22f2SFrederic Weisbecker	def update_summary(self, cpu, t):
171880d22f2SFrederic Weisbecker		idx = self.timeslices.find_time_slice(t)
172880d22f2SFrederic Weisbecker		if idx == -1:
173880d22f2SFrederic Weisbecker			return
174880d22f2SFrederic Weisbecker
175880d22f2SFrederic Weisbecker		ts = self.timeslices[idx]
176880d22f2SFrederic Weisbecker		rq = ts.rqs[cpu]
177880d22f2SFrederic Weisbecker		raw = "CPU: %d\n" % cpu
178880d22f2SFrederic Weisbecker		raw += "Last event : %s\n" % rq.event.__repr__()
179880d22f2SFrederic Weisbecker		raw += "Timestamp : %d.%06d\n" % (ts.start / (10 ** 9), (ts.start % (10 ** 9)) / 1000)
180880d22f2SFrederic Weisbecker		raw += "Duration : %6d us\n" % ((ts.end - ts.start) / (10 ** 6))
181880d22f2SFrederic Weisbecker		raw += "Load = %d\n" % rq.load()
182880d22f2SFrederic Weisbecker		for t in rq.tasks:
183880d22f2SFrederic Weisbecker			raw += "%s \n" % thread_name(t)
184880d22f2SFrederic Weisbecker
185880d22f2SFrederic Weisbecker		if self.txt:
186880d22f2SFrederic Weisbecker			self.txt.Destroy()
187880d22f2SFrederic Weisbecker		self.txt = wx.StaticText(self.panel, -1, raw, (0, (self.screen_height / 2) + 50))
188880d22f2SFrederic Weisbecker
189880d22f2SFrederic Weisbecker
190880d22f2SFrederic Weisbecker	def on_mouse_down(self, event):
191880d22f2SFrederic Weisbecker		(x, y) = event.GetPositionTuple()
192880d22f2SFrederic Weisbecker		cpu = self.cpu_from_ypixel(y)
193880d22f2SFrederic Weisbecker		if cpu == -1:
194880d22f2SFrederic Weisbecker			return
195880d22f2SFrederic Weisbecker
196880d22f2SFrederic Weisbecker		t = self.px_to_us(x) + self.timeslices[0].start
197880d22f2SFrederic Weisbecker
198880d22f2SFrederic Weisbecker		self.update_summary(cpu, t)
199880d22f2SFrederic Weisbecker
200880d22f2SFrederic Weisbecker
201880d22f2SFrederic Weisbecker	def update_width_virtual(self):
202880d22f2SFrederic Weisbecker		self.width_virtual = self.us_to_px(self.ts_end - self.ts_start)
203880d22f2SFrederic Weisbecker
204880d22f2SFrederic Weisbecker	def __zoom(self, x):
205880d22f2SFrederic Weisbecker		self.update_width_virtual()
206880d22f2SFrederic Weisbecker		(xpos, ypos) = self.scroll.GetViewStart()
207880d22f2SFrederic Weisbecker		xpos = self.us_to_px(x) / self.scroll_scale
208*70d815a3SFrederic Weisbecker		self.scroll.SetScrollbars(self.scroll_scale, self.scroll_scale, self.width_virtual / self.scroll_scale, self.height_virtual / self.scroll_scale, xpos, ypos)
209880d22f2SFrederic Weisbecker		self.Refresh()
210880d22f2SFrederic Weisbecker
211880d22f2SFrederic Weisbecker	def zoom_in(self):
212880d22f2SFrederic Weisbecker		x = self.scroll_start_us()
213880d22f2SFrederic Weisbecker		self.zoom *= 2
214880d22f2SFrederic Weisbecker		self.__zoom(x)
215880d22f2SFrederic Weisbecker
216880d22f2SFrederic Weisbecker	def zoom_out(self):
217880d22f2SFrederic Weisbecker		x = self.scroll_start_us()
218880d22f2SFrederic Weisbecker		self.zoom /= 2
219880d22f2SFrederic Weisbecker		self.__zoom(x)
220880d22f2SFrederic Weisbecker
221880d22f2SFrederic Weisbecker
222880d22f2SFrederic Weisbecker	def on_key_press(self, event):
223880d22f2SFrederic Weisbecker		key = event.GetRawKeyCode()
224880d22f2SFrederic Weisbecker		if key == ord("+"):
225880d22f2SFrederic Weisbecker			self.zoom_in()
226880d22f2SFrederic Weisbecker			return
227880d22f2SFrederic Weisbecker		if key == ord("-"):
228880d22f2SFrederic Weisbecker			self.zoom_out()
229880d22f2SFrederic Weisbecker			return
230880d22f2SFrederic Weisbecker
231880d22f2SFrederic Weisbecker		key = event.GetKeyCode()
232880d22f2SFrederic Weisbecker		(x, y) = self.scroll.GetViewStart()
233880d22f2SFrederic Weisbecker		if key == wx.WXK_RIGHT:
234880d22f2SFrederic Weisbecker			self.scroll.Scroll(x + 1, y)
235880d22f2SFrederic Weisbecker		elif key == wx.WXK_LEFT:
236880d22f2SFrederic Weisbecker			self.scroll.Scroll(x - 1, y)
237*70d815a3SFrederic Weisbecker		elif key == wx.WXK_DOWN:
238*70d815a3SFrederic Weisbecker			self.scroll.Scroll(x, y + 1)
239*70d815a3SFrederic Weisbecker		elif key == wx.WXK_UP:
240*70d815a3SFrederic Weisbecker			self.scroll.Scroll(x, y - 1)
241880d22f2SFrederic Weisbecker
242880d22f2SFrederic Weisbecker
243880d22f2SFrederic Weisbeckerthreads = { 0 : "idle"}
244880d22f2SFrederic Weisbecker
245880d22f2SFrederic Weisbeckerdef thread_name(pid):
246880d22f2SFrederic Weisbecker	return "%s:%d" % (threads[pid], pid)
247880d22f2SFrederic Weisbecker
248880d22f2SFrederic Weisbeckerclass EventHeaders:
249880d22f2SFrederic Weisbecker	def __init__(self, common_cpu, common_secs, common_nsecs,
250880d22f2SFrederic Weisbecker		     common_pid, common_comm):
251880d22f2SFrederic Weisbecker		self.cpu = common_cpu
252880d22f2SFrederic Weisbecker		self.secs = common_secs
253880d22f2SFrederic Weisbecker		self.nsecs = common_nsecs
254880d22f2SFrederic Weisbecker		self.pid = common_pid
255880d22f2SFrederic Weisbecker		self.comm = common_comm
256880d22f2SFrederic Weisbecker
257880d22f2SFrederic Weisbecker	def ts(self):
258880d22f2SFrederic Weisbecker		return (self.secs * (10 ** 9)) + self.nsecs
259880d22f2SFrederic Weisbecker
260880d22f2SFrederic Weisbecker	def ts_format(self):
261880d22f2SFrederic Weisbecker		return "%d.%d" % (self.secs, int(self.nsecs / 1000))
262880d22f2SFrederic Weisbecker
263880d22f2SFrederic Weisbecker
264880d22f2SFrederic Weisbeckerdef taskState(state):
265880d22f2SFrederic Weisbecker	states = {
266880d22f2SFrederic Weisbecker		0 : "R",
267880d22f2SFrederic Weisbecker		1 : "S",
268880d22f2SFrederic Weisbecker		2 : "D",
269880d22f2SFrederic Weisbecker		64: "DEAD"
270880d22f2SFrederic Weisbecker	}
271880d22f2SFrederic Weisbecker
272880d22f2SFrederic Weisbecker	if state not in states:
273207f90fcSFrederic Weisbecker		return "Unknown"
274880d22f2SFrederic Weisbecker
275880d22f2SFrederic Weisbecker	return states[state]
276880d22f2SFrederic Weisbecker
277880d22f2SFrederic Weisbecker
278880d22f2SFrederic Weisbeckerclass RunqueueEventUnknown:
279880d22f2SFrederic Weisbecker	@staticmethod
280880d22f2SFrederic Weisbecker	def color():
281880d22f2SFrederic Weisbecker		return None
282880d22f2SFrederic Weisbecker
283880d22f2SFrederic Weisbecker	def __repr__(self):
284880d22f2SFrederic Weisbecker		return "unknown"
285880d22f2SFrederic Weisbecker
286880d22f2SFrederic Weisbeckerclass RunqueueEventSleep:
287880d22f2SFrederic Weisbecker	@staticmethod
288880d22f2SFrederic Weisbecker	def color():
289880d22f2SFrederic Weisbecker		return (0, 0, 0xff)
290880d22f2SFrederic Weisbecker
291880d22f2SFrederic Weisbecker	def __init__(self, sleeper):
292880d22f2SFrederic Weisbecker		self.sleeper = sleeper
293880d22f2SFrederic Weisbecker
294880d22f2SFrederic Weisbecker	def __repr__(self):
295880d22f2SFrederic Weisbecker		return "%s gone to sleep" % thread_name(self.sleeper)
296880d22f2SFrederic Weisbecker
297880d22f2SFrederic Weisbeckerclass RunqueueEventWakeup:
298880d22f2SFrederic Weisbecker	@staticmethod
299880d22f2SFrederic Weisbecker	def color():
300880d22f2SFrederic Weisbecker		return (0xff, 0xff, 0)
301880d22f2SFrederic Weisbecker
302880d22f2SFrederic Weisbecker	def __init__(self, wakee):
303880d22f2SFrederic Weisbecker		self.wakee = wakee
304880d22f2SFrederic Weisbecker
305880d22f2SFrederic Weisbecker	def __repr__(self):
306880d22f2SFrederic Weisbecker		return "%s woke up" % thread_name(self.wakee)
307880d22f2SFrederic Weisbecker
308880d22f2SFrederic Weisbeckerclass RunqueueEventFork:
309880d22f2SFrederic Weisbecker	@staticmethod
310880d22f2SFrederic Weisbecker	def color():
311880d22f2SFrederic Weisbecker		return (0, 0xff, 0)
312880d22f2SFrederic Weisbecker
313880d22f2SFrederic Weisbecker	def __init__(self, child):
314880d22f2SFrederic Weisbecker		self.child = child
315880d22f2SFrederic Weisbecker
316880d22f2SFrederic Weisbecker	def __repr__(self):
317880d22f2SFrederic Weisbecker		return "new forked task %s" % thread_name(self.child)
318880d22f2SFrederic Weisbecker
319880d22f2SFrederic Weisbeckerclass RunqueueMigrateIn:
320880d22f2SFrederic Weisbecker	@staticmethod
321880d22f2SFrederic Weisbecker	def color():
322880d22f2SFrederic Weisbecker		return (0, 0xf0, 0xff)
323880d22f2SFrederic Weisbecker
324880d22f2SFrederic Weisbecker	def __init__(self, new):
325880d22f2SFrederic Weisbecker		self.new = new
326880d22f2SFrederic Weisbecker
327880d22f2SFrederic Weisbecker	def __repr__(self):
328880d22f2SFrederic Weisbecker		return "task migrated in %s" % thread_name(self.new)
329880d22f2SFrederic Weisbecker
330880d22f2SFrederic Weisbeckerclass RunqueueMigrateOut:
331880d22f2SFrederic Weisbecker	@staticmethod
332880d22f2SFrederic Weisbecker	def color():
333880d22f2SFrederic Weisbecker		return (0xff, 0, 0xff)
334880d22f2SFrederic Weisbecker
335880d22f2SFrederic Weisbecker	def __init__(self, old):
336880d22f2SFrederic Weisbecker		self.old = old
337880d22f2SFrederic Weisbecker
338880d22f2SFrederic Weisbecker	def __repr__(self):
339880d22f2SFrederic Weisbecker		return "task migrated out %s" % thread_name(self.old)
340880d22f2SFrederic Weisbecker
341880d22f2SFrederic Weisbeckerclass RunqueueSnapshot:
342880d22f2SFrederic Weisbecker	def __init__(self, tasks = [0], event = RunqueueEventUnknown()):
343880d22f2SFrederic Weisbecker		self.tasks = tuple(tasks)
344880d22f2SFrederic Weisbecker		self.event = event
345880d22f2SFrederic Weisbecker
346880d22f2SFrederic Weisbecker	def sched_switch(self, prev, prev_state, next):
347880d22f2SFrederic Weisbecker		event = RunqueueEventUnknown()
348880d22f2SFrederic Weisbecker
349880d22f2SFrederic Weisbecker		if taskState(prev_state) == "R" and next in self.tasks \
350880d22f2SFrederic Weisbecker			and prev in self.tasks:
351880d22f2SFrederic Weisbecker			return self
352880d22f2SFrederic Weisbecker
353880d22f2SFrederic Weisbecker		if taskState(prev_state) != "R":
354880d22f2SFrederic Weisbecker			event = RunqueueEventSleep(prev)
355880d22f2SFrederic Weisbecker
356880d22f2SFrederic Weisbecker		next_tasks = list(self.tasks[:])
357880d22f2SFrederic Weisbecker		if prev in self.tasks:
358880d22f2SFrederic Weisbecker			if taskState(prev_state) != "R":
359880d22f2SFrederic Weisbecker				next_tasks.remove(prev)
360880d22f2SFrederic Weisbecker		elif taskState(prev_state) == "R":
361880d22f2SFrederic Weisbecker			next_tasks.append(prev)
362880d22f2SFrederic Weisbecker
363880d22f2SFrederic Weisbecker		if next not in next_tasks:
364880d22f2SFrederic Weisbecker			next_tasks.append(next)
365880d22f2SFrederic Weisbecker
366880d22f2SFrederic Weisbecker		return RunqueueSnapshot(next_tasks, event)
367880d22f2SFrederic Weisbecker
368880d22f2SFrederic Weisbecker	def migrate_out(self, old):
369880d22f2SFrederic Weisbecker		if old not in self.tasks:
370880d22f2SFrederic Weisbecker			return self
371880d22f2SFrederic Weisbecker		next_tasks = [task for task in self.tasks if task != old]
372880d22f2SFrederic Weisbecker
373880d22f2SFrederic Weisbecker		return RunqueueSnapshot(next_tasks, RunqueueMigrateOut(old))
374880d22f2SFrederic Weisbecker
375880d22f2SFrederic Weisbecker	def __migrate_in(self, new, event):
376880d22f2SFrederic Weisbecker		if new in self.tasks:
377880d22f2SFrederic Weisbecker			self.event = event
378880d22f2SFrederic Weisbecker			return self
379880d22f2SFrederic Weisbecker		next_tasks = self.tasks[:] + tuple([new])
380880d22f2SFrederic Weisbecker
381880d22f2SFrederic Weisbecker		return RunqueueSnapshot(next_tasks, event)
382880d22f2SFrederic Weisbecker
383880d22f2SFrederic Weisbecker	def migrate_in(self, new):
384880d22f2SFrederic Weisbecker		return self.__migrate_in(new, RunqueueMigrateIn(new))
385880d22f2SFrederic Weisbecker
386880d22f2SFrederic Weisbecker	def wake_up(self, new):
387880d22f2SFrederic Weisbecker		return self.__migrate_in(new, RunqueueEventWakeup(new))
388880d22f2SFrederic Weisbecker
389880d22f2SFrederic Weisbecker	def wake_up_new(self, new):
390880d22f2SFrederic Weisbecker		return self.__migrate_in(new, RunqueueEventFork(new))
391880d22f2SFrederic Weisbecker
392880d22f2SFrederic Weisbecker	def load(self):
393880d22f2SFrederic Weisbecker		""" Provide the number of tasks on the runqueue.
394880d22f2SFrederic Weisbecker		    Don't count idle"""
395880d22f2SFrederic Weisbecker		return len(self.tasks) - 1
396880d22f2SFrederic Weisbecker
397880d22f2SFrederic Weisbecker	def __repr__(self):
398880d22f2SFrederic Weisbecker		ret = self.tasks.__repr__()
399880d22f2SFrederic Weisbecker		ret += self.origin_tostring()
400880d22f2SFrederic Weisbecker
401880d22f2SFrederic Weisbecker		return ret
402880d22f2SFrederic Weisbecker
403880d22f2SFrederic Weisbeckerclass TimeSlice:
404880d22f2SFrederic Weisbecker	def __init__(self, start, prev):
405880d22f2SFrederic Weisbecker		self.start = start
406880d22f2SFrederic Weisbecker		self.prev = prev
407880d22f2SFrederic Weisbecker		self.end = start
408880d22f2SFrederic Weisbecker		# cpus that triggered the event
409880d22f2SFrederic Weisbecker		self.event_cpus = []
410880d22f2SFrederic Weisbecker		if prev is not None:
411880d22f2SFrederic Weisbecker			self.total_load = prev.total_load
412880d22f2SFrederic Weisbecker			self.rqs = prev.rqs.copy()
413880d22f2SFrederic Weisbecker		else:
414880d22f2SFrederic Weisbecker			self.rqs = defaultdict(RunqueueSnapshot)
415880d22f2SFrederic Weisbecker			self.total_load = 0
416880d22f2SFrederic Weisbecker
417880d22f2SFrederic Weisbecker	def __update_total_load(self, old_rq, new_rq):
418880d22f2SFrederic Weisbecker		diff = new_rq.load() - old_rq.load()
419880d22f2SFrederic Weisbecker		self.total_load += diff
420880d22f2SFrederic Weisbecker
421880d22f2SFrederic Weisbecker	def sched_switch(self, ts_list, prev, prev_state, next, cpu):
422880d22f2SFrederic Weisbecker		old_rq = self.prev.rqs[cpu]
423880d22f2SFrederic Weisbecker		new_rq = old_rq.sched_switch(prev, prev_state, next)
424880d22f2SFrederic Weisbecker
425880d22f2SFrederic Weisbecker		if old_rq is new_rq:
426880d22f2SFrederic Weisbecker			return
427880d22f2SFrederic Weisbecker
428880d22f2SFrederic Weisbecker		self.rqs[cpu] = new_rq
429880d22f2SFrederic Weisbecker		self.__update_total_load(old_rq, new_rq)
430880d22f2SFrederic Weisbecker		ts_list.append(self)
431880d22f2SFrederic Weisbecker		self.event_cpus = [cpu]
432880d22f2SFrederic Weisbecker
433880d22f2SFrederic Weisbecker	def migrate(self, ts_list, new, old_cpu, new_cpu):
434880d22f2SFrederic Weisbecker		if old_cpu == new_cpu:
435880d22f2SFrederic Weisbecker			return
436880d22f2SFrederic Weisbecker		old_rq = self.prev.rqs[old_cpu]
437880d22f2SFrederic Weisbecker		out_rq = old_rq.migrate_out(new)
438880d22f2SFrederic Weisbecker		self.rqs[old_cpu] = out_rq
439880d22f2SFrederic Weisbecker		self.__update_total_load(old_rq, out_rq)
440880d22f2SFrederic Weisbecker
441880d22f2SFrederic Weisbecker		new_rq = self.prev.rqs[new_cpu]
442880d22f2SFrederic Weisbecker		in_rq = new_rq.migrate_in(new)
443880d22f2SFrederic Weisbecker		self.rqs[new_cpu] = in_rq
444880d22f2SFrederic Weisbecker		self.__update_total_load(new_rq, in_rq)
445880d22f2SFrederic Weisbecker
446880d22f2SFrederic Weisbecker		ts_list.append(self)
447749e5074SFrederic Weisbecker
448749e5074SFrederic Weisbecker		if old_rq is not out_rq:
449749e5074SFrederic Weisbecker			self.event_cpus.append(old_cpu)
450749e5074SFrederic Weisbecker		self.event_cpus.append(new_cpu)
451880d22f2SFrederic Weisbecker
452880d22f2SFrederic Weisbecker	def wake_up(self, ts_list, pid, cpu, fork):
453880d22f2SFrederic Weisbecker		old_rq = self.prev.rqs[cpu]
454880d22f2SFrederic Weisbecker		if fork:
455880d22f2SFrederic Weisbecker			new_rq = old_rq.wake_up_new(pid)
456880d22f2SFrederic Weisbecker		else:
457880d22f2SFrederic Weisbecker			new_rq = old_rq.wake_up(pid)
458880d22f2SFrederic Weisbecker
459880d22f2SFrederic Weisbecker		if new_rq is old_rq:
460880d22f2SFrederic Weisbecker			return
461880d22f2SFrederic Weisbecker		self.rqs[cpu] = new_rq
462880d22f2SFrederic Weisbecker		self.__update_total_load(old_rq, new_rq)
463880d22f2SFrederic Weisbecker		ts_list.append(self)
464880d22f2SFrederic Weisbecker		self.event_cpus = [cpu]
465880d22f2SFrederic Weisbecker
466880d22f2SFrederic Weisbecker	def next(self, t):
467880d22f2SFrederic Weisbecker		self.end = t
468880d22f2SFrederic Weisbecker		return TimeSlice(t, self)
469880d22f2SFrederic Weisbecker
470880d22f2SFrederic Weisbeckerclass TimeSliceList(UserList):
471880d22f2SFrederic Weisbecker	def __init__(self, arg = []):
472880d22f2SFrederic Weisbecker		self.data = arg
473880d22f2SFrederic Weisbecker
474880d22f2SFrederic Weisbecker	def get_time_slice(self, ts):
475880d22f2SFrederic Weisbecker		if len(self.data) == 0:
476880d22f2SFrederic Weisbecker			slice = TimeSlice(ts, TimeSlice(-1, None))
477880d22f2SFrederic Weisbecker		else:
478880d22f2SFrederic Weisbecker			slice = self.data[-1].next(ts)
479880d22f2SFrederic Weisbecker		return slice
480880d22f2SFrederic Weisbecker
481880d22f2SFrederic Weisbecker	def find_time_slice(self, ts):
482880d22f2SFrederic Weisbecker		start = 0
483880d22f2SFrederic Weisbecker		end = len(self.data)
484880d22f2SFrederic Weisbecker		found = -1
485880d22f2SFrederic Weisbecker		searching = True
486880d22f2SFrederic Weisbecker		while searching:
487880d22f2SFrederic Weisbecker			if start == end or start == end - 1:
488880d22f2SFrederic Weisbecker				searching = False
489880d22f2SFrederic Weisbecker
490880d22f2SFrederic Weisbecker			i = (end + start) / 2
491880d22f2SFrederic Weisbecker			if self.data[i].start <= ts and self.data[i].end >= ts:
492880d22f2SFrederic Weisbecker				found = i
493880d22f2SFrederic Weisbecker				end = i
494880d22f2SFrederic Weisbecker				continue
495880d22f2SFrederic Weisbecker
496880d22f2SFrederic Weisbecker			if self.data[i].end < ts:
497880d22f2SFrederic Weisbecker				start = i
498880d22f2SFrederic Weisbecker
499880d22f2SFrederic Weisbecker			elif self.data[i].start > ts:
500880d22f2SFrederic Weisbecker				end = i
501880d22f2SFrederic Weisbecker
502880d22f2SFrederic Weisbecker		return found
503880d22f2SFrederic Weisbecker
504880d22f2SFrederic Weisbecker	def interval(self):
505880d22f2SFrederic Weisbecker		if len(self.data) == 0:
506880d22f2SFrederic Weisbecker			return (0, 0)
507880d22f2SFrederic Weisbecker
508880d22f2SFrederic Weisbecker		return (self.data[0].start, self.data[-1].end)
509880d22f2SFrederic Weisbecker
510*70d815a3SFrederic Weisbecker	def max_cpu(self):
511*70d815a3SFrederic Weisbecker		last_ts = self.data[-1]
512*70d815a3SFrederic Weisbecker		max_cpu = 0
513*70d815a3SFrederic Weisbecker		for cpu in last_ts.rqs:
514*70d815a3SFrederic Weisbecker			if cpu > max_cpu:
515*70d815a3SFrederic Weisbecker				max_cpu = cpu
516*70d815a3SFrederic Weisbecker		return max_cpu
517*70d815a3SFrederic Weisbecker
518880d22f2SFrederic Weisbecker
519880d22f2SFrederic Weisbeckerclass SchedEventProxy:
520880d22f2SFrederic Weisbecker	def __init__(self):
521880d22f2SFrederic Weisbecker		self.current_tsk = defaultdict(lambda : -1)
522880d22f2SFrederic Weisbecker		self.timeslices = TimeSliceList()
523880d22f2SFrederic Weisbecker
524880d22f2SFrederic Weisbecker	def sched_switch(self, headers, prev_comm, prev_pid, prev_prio, prev_state,
525880d22f2SFrederic Weisbecker			 next_comm, next_pid, next_prio):
526880d22f2SFrederic Weisbecker		""" Ensure the task we sched out this cpu is really the one
527880d22f2SFrederic Weisbecker		    we logged. Otherwise we may have missed traces """
528880d22f2SFrederic Weisbecker
529880d22f2SFrederic Weisbecker		on_cpu_task = self.current_tsk[headers.cpu]
530880d22f2SFrederic Weisbecker
531880d22f2SFrederic Weisbecker		if on_cpu_task != -1 and on_cpu_task != prev_pid:
532880d22f2SFrederic Weisbecker			print "Sched switch event rejected ts: %s cpu: %d prev: %s(%d) next: %s(%d)" % \
533880d22f2SFrederic Weisbecker				(headers.ts_format(), headers.cpu, prev_comm, prev_pid, next_comm, next_pid)
534880d22f2SFrederic Weisbecker
535880d22f2SFrederic Weisbecker		threads[prev_pid] = prev_comm
536880d22f2SFrederic Weisbecker		threads[next_pid] = next_comm
537880d22f2SFrederic Weisbecker		self.current_tsk[headers.cpu] = next_pid
538880d22f2SFrederic Weisbecker
539880d22f2SFrederic Weisbecker		ts = self.timeslices.get_time_slice(headers.ts())
540880d22f2SFrederic Weisbecker		ts.sched_switch(self.timeslices, prev_pid, prev_state, next_pid, headers.cpu)
541880d22f2SFrederic Weisbecker
542880d22f2SFrederic Weisbecker	def migrate(self, headers, pid, prio, orig_cpu, dest_cpu):
543880d22f2SFrederic Weisbecker		ts = self.timeslices.get_time_slice(headers.ts())
544880d22f2SFrederic Weisbecker		ts.migrate(self.timeslices, pid, orig_cpu, dest_cpu)
545880d22f2SFrederic Weisbecker
546880d22f2SFrederic Weisbecker	def wake_up(self, headers, comm, pid, success, target_cpu, fork):
547880d22f2SFrederic Weisbecker		if success == 0:
548880d22f2SFrederic Weisbecker			return
549880d22f2SFrederic Weisbecker		ts = self.timeslices.get_time_slice(headers.ts())
550880d22f2SFrederic Weisbecker		ts.wake_up(self.timeslices, pid, target_cpu, fork)
551880d22f2SFrederic Weisbecker
552880d22f2SFrederic Weisbecker
553880d22f2SFrederic Weisbeckerdef trace_begin():
554880d22f2SFrederic Weisbecker	global parser
555880d22f2SFrederic Weisbecker	parser = SchedEventProxy()
556880d22f2SFrederic Weisbecker
557880d22f2SFrederic Weisbeckerdef trace_end():
558880d22f2SFrederic Weisbecker	app = wx.App(False)
559880d22f2SFrederic Weisbecker	timeslices = parser.timeslices
560880d22f2SFrederic Weisbecker	frame = RootFrame(timeslices)
561880d22f2SFrederic Weisbecker	app.MainLoop()
562880d22f2SFrederic Weisbecker
563880d22f2SFrederic Weisbeckerdef sched__sched_stat_runtime(event_name, context, common_cpu,
564880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
565880d22f2SFrederic Weisbecker	comm, pid, runtime, vruntime):
566880d22f2SFrederic Weisbecker	pass
567880d22f2SFrederic Weisbecker
568880d22f2SFrederic Weisbeckerdef sched__sched_stat_iowait(event_name, context, common_cpu,
569880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
570880d22f2SFrederic Weisbecker	comm, pid, delay):
571880d22f2SFrederic Weisbecker	pass
572880d22f2SFrederic Weisbecker
573880d22f2SFrederic Weisbeckerdef sched__sched_stat_sleep(event_name, context, common_cpu,
574880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
575880d22f2SFrederic Weisbecker	comm, pid, delay):
576880d22f2SFrederic Weisbecker	pass
577880d22f2SFrederic Weisbecker
578880d22f2SFrederic Weisbeckerdef sched__sched_stat_wait(event_name, context, common_cpu,
579880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
580880d22f2SFrederic Weisbecker	comm, pid, delay):
581880d22f2SFrederic Weisbecker	pass
582880d22f2SFrederic Weisbecker
583880d22f2SFrederic Weisbeckerdef sched__sched_process_fork(event_name, context, common_cpu,
584880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
585880d22f2SFrederic Weisbecker	parent_comm, parent_pid, child_comm, child_pid):
586880d22f2SFrederic Weisbecker	pass
587880d22f2SFrederic Weisbecker
588880d22f2SFrederic Weisbeckerdef sched__sched_process_wait(event_name, context, common_cpu,
589880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
590880d22f2SFrederic Weisbecker	comm, pid, prio):
591880d22f2SFrederic Weisbecker	pass
592880d22f2SFrederic Weisbecker
593880d22f2SFrederic Weisbeckerdef sched__sched_process_exit(event_name, context, common_cpu,
594880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
595880d22f2SFrederic Weisbecker	comm, pid, prio):
596880d22f2SFrederic Weisbecker	pass
597880d22f2SFrederic Weisbecker
598880d22f2SFrederic Weisbeckerdef sched__sched_process_free(event_name, context, common_cpu,
599880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
600880d22f2SFrederic Weisbecker	comm, pid, prio):
601880d22f2SFrederic Weisbecker	pass
602880d22f2SFrederic Weisbecker
603880d22f2SFrederic Weisbeckerdef sched__sched_migrate_task(event_name, context, common_cpu,
604880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
605880d22f2SFrederic Weisbecker	comm, pid, prio, orig_cpu,
606880d22f2SFrederic Weisbecker	dest_cpu):
607880d22f2SFrederic Weisbecker	headers = EventHeaders(common_cpu, common_secs, common_nsecs,
608880d22f2SFrederic Weisbecker				common_pid, common_comm)
609880d22f2SFrederic Weisbecker	parser.migrate(headers, pid, prio, orig_cpu, dest_cpu)
610880d22f2SFrederic Weisbecker
611880d22f2SFrederic Weisbeckerdef sched__sched_switch(event_name, context, common_cpu,
612880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
613880d22f2SFrederic Weisbecker	prev_comm, prev_pid, prev_prio, prev_state,
614880d22f2SFrederic Weisbecker	next_comm, next_pid, next_prio):
615880d22f2SFrederic Weisbecker
616880d22f2SFrederic Weisbecker	headers = EventHeaders(common_cpu, common_secs, common_nsecs,
617880d22f2SFrederic Weisbecker				common_pid, common_comm)
618880d22f2SFrederic Weisbecker	parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state,
619880d22f2SFrederic Weisbecker			 next_comm, next_pid, next_prio)
620880d22f2SFrederic Weisbecker
621880d22f2SFrederic Weisbeckerdef sched__sched_wakeup_new(event_name, context, common_cpu,
622880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
623880d22f2SFrederic Weisbecker	comm, pid, prio, success,
624880d22f2SFrederic Weisbecker	target_cpu):
625880d22f2SFrederic Weisbecker	headers = EventHeaders(common_cpu, common_secs, common_nsecs,
626880d22f2SFrederic Weisbecker				common_pid, common_comm)
627880d22f2SFrederic Weisbecker	parser.wake_up(headers, comm, pid, success, target_cpu, 1)
628880d22f2SFrederic Weisbecker
629880d22f2SFrederic Weisbeckerdef sched__sched_wakeup(event_name, context, common_cpu,
630880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
631880d22f2SFrederic Weisbecker	comm, pid, prio, success,
632880d22f2SFrederic Weisbecker	target_cpu):
633880d22f2SFrederic Weisbecker	headers = EventHeaders(common_cpu, common_secs, common_nsecs,
634880d22f2SFrederic Weisbecker				common_pid, common_comm)
635880d22f2SFrederic Weisbecker	parser.wake_up(headers, comm, pid, success, target_cpu, 0)
636880d22f2SFrederic Weisbecker
637880d22f2SFrederic Weisbeckerdef sched__sched_wait_task(event_name, context, common_cpu,
638880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
639880d22f2SFrederic Weisbecker	comm, pid, prio):
640880d22f2SFrederic Weisbecker	pass
641880d22f2SFrederic Weisbecker
642880d22f2SFrederic Weisbeckerdef sched__sched_kthread_stop_ret(event_name, context, common_cpu,
643880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
644880d22f2SFrederic Weisbecker	ret):
645880d22f2SFrederic Weisbecker	pass
646880d22f2SFrederic Weisbecker
647880d22f2SFrederic Weisbeckerdef sched__sched_kthread_stop(event_name, context, common_cpu,
648880d22f2SFrederic Weisbecker	common_secs, common_nsecs, common_pid, common_comm,
649880d22f2SFrederic Weisbecker	comm, pid):
650880d22f2SFrederic Weisbecker	pass
651880d22f2SFrederic Weisbecker
652880d22f2SFrederic Weisbeckerdef trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs,
653880d22f2SFrederic Weisbecker		common_pid, common_comm):
654880d22f2SFrederic Weisbecker	pass
655