cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sched-migration.py (12095B)


      1# Cpu task migration overview toy
      2#
      3# Copyright (C) 2010 Frederic Weisbecker <fweisbec@gmail.com>
      4#
      5# perf script event handlers have been generated by perf script -g python
      6#
      7# This software is distributed under the terms of the GNU General
      8# Public License ("GPL") version 2 as published by the Free Software
      9# Foundation.
     10from __future__ import print_function
     11
     12import os
     13import sys
     14
     15from collections import defaultdict
     16try:
     17	from UserList import UserList
     18except ImportError:
     19	# Python 3: UserList moved to the collections package
     20	from collections import UserList
     21
     22sys.path.append(os.environ['PERF_EXEC_PATH'] + \
     23	'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
     24sys.path.append('scripts/python/Perf-Trace-Util/lib/Perf/Trace')
     25
     26from perf_trace_context import *
     27from Core import *
     28from SchedGui import *
     29
     30
     31threads = { 0 : "idle"}
     32
     33def thread_name(pid):
     34	return "%s:%d" % (threads[pid], pid)
     35
     36class RunqueueEventUnknown:
     37	@staticmethod
     38	def color():
     39		return None
     40
     41	def __repr__(self):
     42		return "unknown"
     43
     44class RunqueueEventSleep:
     45	@staticmethod
     46	def color():
     47		return (0, 0, 0xff)
     48
     49	def __init__(self, sleeper):
     50		self.sleeper = sleeper
     51
     52	def __repr__(self):
     53		return "%s gone to sleep" % thread_name(self.sleeper)
     54
     55class RunqueueEventWakeup:
     56	@staticmethod
     57	def color():
     58		return (0xff, 0xff, 0)
     59
     60	def __init__(self, wakee):
     61		self.wakee = wakee
     62
     63	def __repr__(self):
     64		return "%s woke up" % thread_name(self.wakee)
     65
     66class RunqueueEventFork:
     67	@staticmethod
     68	def color():
     69		return (0, 0xff, 0)
     70
     71	def __init__(self, child):
     72		self.child = child
     73
     74	def __repr__(self):
     75		return "new forked task %s" % thread_name(self.child)
     76
     77class RunqueueMigrateIn:
     78	@staticmethod
     79	def color():
     80		return (0, 0xf0, 0xff)
     81
     82	def __init__(self, new):
     83		self.new = new
     84
     85	def __repr__(self):
     86		return "task migrated in %s" % thread_name(self.new)
     87
     88class RunqueueMigrateOut:
     89	@staticmethod
     90	def color():
     91		return (0xff, 0, 0xff)
     92
     93	def __init__(self, old):
     94		self.old = old
     95
     96	def __repr__(self):
     97		return "task migrated out %s" % thread_name(self.old)
     98
     99class RunqueueSnapshot:
    100	def __init__(self, tasks = [0], event = RunqueueEventUnknown()):
    101		self.tasks = tuple(tasks)
    102		self.event = event
    103
    104	def sched_switch(self, prev, prev_state, next):
    105		event = RunqueueEventUnknown()
    106
    107		if taskState(prev_state) == "R" and next in self.tasks \
    108			and prev in self.tasks:
    109			return self
    110
    111		if taskState(prev_state) != "R":
    112			event = RunqueueEventSleep(prev)
    113
    114		next_tasks = list(self.tasks[:])
    115		if prev in self.tasks:
    116			if taskState(prev_state) != "R":
    117				next_tasks.remove(prev)
    118		elif taskState(prev_state) == "R":
    119			next_tasks.append(prev)
    120
    121		if next not in next_tasks:
    122			next_tasks.append(next)
    123
    124		return RunqueueSnapshot(next_tasks, event)
    125
    126	def migrate_out(self, old):
    127		if old not in self.tasks:
    128			return self
    129		next_tasks = [task for task in self.tasks if task != old]
    130
    131		return RunqueueSnapshot(next_tasks, RunqueueMigrateOut(old))
    132
    133	def __migrate_in(self, new, event):
    134		if new in self.tasks:
    135			self.event = event
    136			return self
    137		next_tasks = self.tasks[:] + tuple([new])
    138
    139		return RunqueueSnapshot(next_tasks, event)
    140
    141	def migrate_in(self, new):
    142		return self.__migrate_in(new, RunqueueMigrateIn(new))
    143
    144	def wake_up(self, new):
    145		return self.__migrate_in(new, RunqueueEventWakeup(new))
    146
    147	def wake_up_new(self, new):
    148		return self.__migrate_in(new, RunqueueEventFork(new))
    149
    150	def load(self):
    151		""" Provide the number of tasks on the runqueue.
    152		    Don't count idle"""
    153		return len(self.tasks) - 1
    154
    155	def __repr__(self):
    156		ret = self.tasks.__repr__()
    157		ret += self.origin_tostring()
    158
    159		return ret
    160
    161class TimeSlice:
    162	def __init__(self, start, prev):
    163		self.start = start
    164		self.prev = prev
    165		self.end = start
    166		# cpus that triggered the event
    167		self.event_cpus = []
    168		if prev is not None:
    169			self.total_load = prev.total_load
    170			self.rqs = prev.rqs.copy()
    171		else:
    172			self.rqs = defaultdict(RunqueueSnapshot)
    173			self.total_load = 0
    174
    175	def __update_total_load(self, old_rq, new_rq):
    176		diff = new_rq.load() - old_rq.load()
    177		self.total_load += diff
    178
    179	def sched_switch(self, ts_list, prev, prev_state, next, cpu):
    180		old_rq = self.prev.rqs[cpu]
    181		new_rq = old_rq.sched_switch(prev, prev_state, next)
    182
    183		if old_rq is new_rq:
    184			return
    185
    186		self.rqs[cpu] = new_rq
    187		self.__update_total_load(old_rq, new_rq)
    188		ts_list.append(self)
    189		self.event_cpus = [cpu]
    190
    191	def migrate(self, ts_list, new, old_cpu, new_cpu):
    192		if old_cpu == new_cpu:
    193			return
    194		old_rq = self.prev.rqs[old_cpu]
    195		out_rq = old_rq.migrate_out(new)
    196		self.rqs[old_cpu] = out_rq
    197		self.__update_total_load(old_rq, out_rq)
    198
    199		new_rq = self.prev.rqs[new_cpu]
    200		in_rq = new_rq.migrate_in(new)
    201		self.rqs[new_cpu] = in_rq
    202		self.__update_total_load(new_rq, in_rq)
    203
    204		ts_list.append(self)
    205
    206		if old_rq is not out_rq:
    207			self.event_cpus.append(old_cpu)
    208		self.event_cpus.append(new_cpu)
    209
    210	def wake_up(self, ts_list, pid, cpu, fork):
    211		old_rq = self.prev.rqs[cpu]
    212		if fork:
    213			new_rq = old_rq.wake_up_new(pid)
    214		else:
    215			new_rq = old_rq.wake_up(pid)
    216
    217		if new_rq is old_rq:
    218			return
    219		self.rqs[cpu] = new_rq
    220		self.__update_total_load(old_rq, new_rq)
    221		ts_list.append(self)
    222		self.event_cpus = [cpu]
    223
    224	def next(self, t):
    225		self.end = t
    226		return TimeSlice(t, self)
    227
    228class TimeSliceList(UserList):
    229	def __init__(self, arg = []):
    230		self.data = arg
    231
    232	def get_time_slice(self, ts):
    233		if len(self.data) == 0:
    234			slice = TimeSlice(ts, TimeSlice(-1, None))
    235		else:
    236			slice = self.data[-1].next(ts)
    237		return slice
    238
    239	def find_time_slice(self, ts):
    240		start = 0
    241		end = len(self.data)
    242		found = -1
    243		searching = True
    244		while searching:
    245			if start == end or start == end - 1:
    246				searching = False
    247
    248			i = (end + start) / 2
    249			if self.data[i].start <= ts and self.data[i].end >= ts:
    250				found = i
    251				end = i
    252				continue
    253
    254			if self.data[i].end < ts:
    255				start = i
    256
    257			elif self.data[i].start > ts:
    258				end = i
    259
    260		return found
    261
    262	def set_root_win(self, win):
    263		self.root_win = win
    264
    265	def mouse_down(self, cpu, t):
    266		idx = self.find_time_slice(t)
    267		if idx == -1:
    268			return
    269
    270		ts = self[idx]
    271		rq = ts.rqs[cpu]
    272		raw = "CPU: %d\n" % cpu
    273		raw += "Last event : %s\n" % rq.event.__repr__()
    274		raw += "Timestamp : %d.%06d\n" % (ts.start / (10 ** 9), (ts.start % (10 ** 9)) / 1000)
    275		raw += "Duration : %6d us\n" % ((ts.end - ts.start) / (10 ** 6))
    276		raw += "Load = %d\n" % rq.load()
    277		for t in rq.tasks:
    278			raw += "%s \n" % thread_name(t)
    279
    280		self.root_win.update_summary(raw)
    281
    282	def update_rectangle_cpu(self, slice, cpu):
    283		rq = slice.rqs[cpu]
    284
    285		if slice.total_load != 0:
    286			load_rate = rq.load() / float(slice.total_load)
    287		else:
    288			load_rate = 0
    289
    290		red_power = int(0xff - (0xff * load_rate))
    291		color = (0xff, red_power, red_power)
    292
    293		top_color = None
    294
    295		if cpu in slice.event_cpus:
    296			top_color = rq.event.color()
    297
    298		self.root_win.paint_rectangle_zone(cpu, color, top_color, slice.start, slice.end)
    299
    300	def fill_zone(self, start, end):
    301		i = self.find_time_slice(start)
    302		if i == -1:
    303			return
    304
    305		for i in range(i, len(self.data)):
    306			timeslice = self.data[i]
    307			if timeslice.start > end:
    308				return
    309
    310			for cpu in timeslice.rqs:
    311				self.update_rectangle_cpu(timeslice, cpu)
    312
    313	def interval(self):
    314		if len(self.data) == 0:
    315			return (0, 0)
    316
    317		return (self.data[0].start, self.data[-1].end)
    318
    319	def nr_rectangles(self):
    320		last_ts = self.data[-1]
    321		max_cpu = 0
    322		for cpu in last_ts.rqs:
    323			if cpu > max_cpu:
    324				max_cpu = cpu
    325		return max_cpu
    326
    327
    328class SchedEventProxy:
    329	def __init__(self):
    330		self.current_tsk = defaultdict(lambda : -1)
    331		self.timeslices = TimeSliceList()
    332
    333	def sched_switch(self, headers, prev_comm, prev_pid, prev_prio, prev_state,
    334			 next_comm, next_pid, next_prio):
    335		""" Ensure the task we sched out this cpu is really the one
    336		    we logged. Otherwise we may have missed traces """
    337
    338		on_cpu_task = self.current_tsk[headers.cpu]
    339
    340		if on_cpu_task != -1 and on_cpu_task != prev_pid:
    341			print("Sched switch event rejected ts: %s cpu: %d prev: %s(%d) next: %s(%d)" % \
    342				headers.ts_format(), headers.cpu, prev_comm, prev_pid, next_comm, next_pid)
    343
    344		threads[prev_pid] = prev_comm
    345		threads[next_pid] = next_comm
    346		self.current_tsk[headers.cpu] = next_pid
    347
    348		ts = self.timeslices.get_time_slice(headers.ts())
    349		ts.sched_switch(self.timeslices, prev_pid, prev_state, next_pid, headers.cpu)
    350
    351	def migrate(self, headers, pid, prio, orig_cpu, dest_cpu):
    352		ts = self.timeslices.get_time_slice(headers.ts())
    353		ts.migrate(self.timeslices, pid, orig_cpu, dest_cpu)
    354
    355	def wake_up(self, headers, comm, pid, success, target_cpu, fork):
    356		if success == 0:
    357			return
    358		ts = self.timeslices.get_time_slice(headers.ts())
    359		ts.wake_up(self.timeslices, pid, target_cpu, fork)
    360
    361
    362def trace_begin():
    363	global parser
    364	parser = SchedEventProxy()
    365
    366def trace_end():
    367	app = wx.App(False)
    368	timeslices = parser.timeslices
    369	frame = RootFrame(timeslices, "Migration")
    370	app.MainLoop()
    371
    372def sched__sched_stat_runtime(event_name, context, common_cpu,
    373	common_secs, common_nsecs, common_pid, common_comm,
    374	common_callchain, comm, pid, runtime, vruntime):
    375	pass
    376
    377def sched__sched_stat_iowait(event_name, context, common_cpu,
    378	common_secs, common_nsecs, common_pid, common_comm,
    379	common_callchain, comm, pid, delay):
    380	pass
    381
    382def sched__sched_stat_sleep(event_name, context, common_cpu,
    383	common_secs, common_nsecs, common_pid, common_comm,
    384	common_callchain, comm, pid, delay):
    385	pass
    386
    387def sched__sched_stat_wait(event_name, context, common_cpu,
    388	common_secs, common_nsecs, common_pid, common_comm,
    389	common_callchain, comm, pid, delay):
    390	pass
    391
    392def sched__sched_process_fork(event_name, context, common_cpu,
    393	common_secs, common_nsecs, common_pid, common_comm,
    394	common_callchain, parent_comm, parent_pid, child_comm, child_pid):
    395	pass
    396
    397def sched__sched_process_wait(event_name, context, common_cpu,
    398	common_secs, common_nsecs, common_pid, common_comm,
    399	common_callchain, comm, pid, prio):
    400	pass
    401
    402def sched__sched_process_exit(event_name, context, common_cpu,
    403	common_secs, common_nsecs, common_pid, common_comm,
    404	common_callchain, comm, pid, prio):
    405	pass
    406
    407def sched__sched_process_free(event_name, context, common_cpu,
    408	common_secs, common_nsecs, common_pid, common_comm,
    409	common_callchain, comm, pid, prio):
    410	pass
    411
    412def sched__sched_migrate_task(event_name, context, common_cpu,
    413	common_secs, common_nsecs, common_pid, common_comm,
    414	common_callchain, comm, pid, prio, orig_cpu,
    415	dest_cpu):
    416	headers = EventHeaders(common_cpu, common_secs, common_nsecs,
    417				common_pid, common_comm, common_callchain)
    418	parser.migrate(headers, pid, prio, orig_cpu, dest_cpu)
    419
    420def sched__sched_switch(event_name, context, common_cpu,
    421	common_secs, common_nsecs, common_pid, common_comm, common_callchain,
    422	prev_comm, prev_pid, prev_prio, prev_state,
    423	next_comm, next_pid, next_prio):
    424
    425	headers = EventHeaders(common_cpu, common_secs, common_nsecs,
    426				common_pid, common_comm, common_callchain)
    427	parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state,
    428			 next_comm, next_pid, next_prio)
    429
    430def sched__sched_wakeup_new(event_name, context, common_cpu,
    431	common_secs, common_nsecs, common_pid, common_comm,
    432	common_callchain, comm, pid, prio, success,
    433	target_cpu):
    434	headers = EventHeaders(common_cpu, common_secs, common_nsecs,
    435				common_pid, common_comm, common_callchain)
    436	parser.wake_up(headers, comm, pid, success, target_cpu, 1)
    437
    438def sched__sched_wakeup(event_name, context, common_cpu,
    439	common_secs, common_nsecs, common_pid, common_comm,
    440	common_callchain, comm, pid, prio, success,
    441	target_cpu):
    442	headers = EventHeaders(common_cpu, common_secs, common_nsecs,
    443				common_pid, common_comm, common_callchain)
    444	parser.wake_up(headers, comm, pid, success, target_cpu, 0)
    445
    446def sched__sched_wait_task(event_name, context, common_cpu,
    447	common_secs, common_nsecs, common_pid, common_comm,
    448	common_callchain, comm, pid, prio):
    449	pass
    450
    451def sched__sched_kthread_stop_ret(event_name, context, common_cpu,
    452	common_secs, common_nsecs, common_pid, common_comm,
    453	common_callchain, ret):
    454	pass
    455
    456def sched__sched_kthread_stop(event_name, context, common_cpu,
    457	common_secs, common_nsecs, common_pid, common_comm,
    458	common_callchain, comm, pid):
    459	pass
    460
    461def trace_unhandled(event_name, context, event_fields_dict):
    462	pass