Path: blob/master/tools/perf/scripts/python/sched-migration.py
10823 views
#!/usr/bin/python1#2# Cpu task migration overview toy3#4# Copyright (C) 2010 Frederic Weisbecker <[email protected]>5#6# perf script event handlers have been generated by perf script -g python7#8# This software is distributed under the terms of the GNU General9# Public License ("GPL") version 2 as published by the Free Software10# Foundation.111213import os14import sys1516from collections import defaultdict17from UserList import UserList1819sys.path.append(os.environ['PERF_EXEC_PATH'] + \20'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')21sys.path.append('scripts/python/Perf-Trace-Util/lib/Perf/Trace')2223from perf_trace_context import *24from Core import *25from SchedGui import *262728threads = { 0 : "idle"}2930def thread_name(pid):31return "%s:%d" % (threads[pid], pid)3233class RunqueueEventUnknown:34@staticmethod35def color():36return None3738def __repr__(self):39return "unknown"4041class RunqueueEventSleep:42@staticmethod43def color():44return (0, 0, 0xff)4546def __init__(self, sleeper):47self.sleeper = sleeper4849def __repr__(self):50return "%s gone to sleep" % thread_name(self.sleeper)5152class RunqueueEventWakeup:53@staticmethod54def color():55return (0xff, 0xff, 0)5657def __init__(self, wakee):58self.wakee = wakee5960def __repr__(self):61return "%s woke up" % thread_name(self.wakee)6263class RunqueueEventFork:64@staticmethod65def color():66return (0, 0xff, 0)6768def __init__(self, child):69self.child = child7071def __repr__(self):72return "new forked task %s" % thread_name(self.child)7374class RunqueueMigrateIn:75@staticmethod76def color():77return (0, 0xf0, 0xff)7879def __init__(self, new):80self.new = new8182def __repr__(self):83return "task migrated in %s" % thread_name(self.new)8485class RunqueueMigrateOut:86@staticmethod87def color():88return (0xff, 0, 0xff)8990def __init__(self, old):91self.old = old9293def __repr__(self):94return "task migrated out %s" % thread_name(self.old)9596class RunqueueSnapshot:97def __init__(self, tasks = [0], event = RunqueueEventUnknown()):98self.tasks = tuple(tasks)99self.event = event100101def sched_switch(self, prev, prev_state, next):102event = RunqueueEventUnknown()103104if taskState(prev_state) == "R" and next in self.tasks \105and prev in self.tasks:106return self107108if taskState(prev_state) != "R":109event = RunqueueEventSleep(prev)110111next_tasks = list(self.tasks[:])112if prev in self.tasks:113if taskState(prev_state) != "R":114next_tasks.remove(prev)115elif taskState(prev_state) == "R":116next_tasks.append(prev)117118if next not in next_tasks:119next_tasks.append(next)120121return RunqueueSnapshot(next_tasks, event)122123def migrate_out(self, old):124if old not in self.tasks:125return self126next_tasks = [task for task in self.tasks if task != old]127128return RunqueueSnapshot(next_tasks, RunqueueMigrateOut(old))129130def __migrate_in(self, new, event):131if new in self.tasks:132self.event = event133return self134next_tasks = self.tasks[:] + tuple([new])135136return RunqueueSnapshot(next_tasks, event)137138def migrate_in(self, new):139return self.__migrate_in(new, RunqueueMigrateIn(new))140141def wake_up(self, new):142return self.__migrate_in(new, RunqueueEventWakeup(new))143144def wake_up_new(self, new):145return self.__migrate_in(new, RunqueueEventFork(new))146147def load(self):148""" Provide the number of tasks on the runqueue.149Don't count idle"""150return len(self.tasks) - 1151152def __repr__(self):153ret = self.tasks.__repr__()154ret += self.origin_tostring()155156return ret157158class TimeSlice:159def __init__(self, start, prev):160self.start = start161self.prev = prev162self.end = start163# cpus that triggered the event164self.event_cpus = []165if prev is not None:166self.total_load = prev.total_load167self.rqs = prev.rqs.copy()168else:169self.rqs = defaultdict(RunqueueSnapshot)170self.total_load = 0171172def __update_total_load(self, old_rq, new_rq):173diff = new_rq.load() - old_rq.load()174self.total_load += diff175176def sched_switch(self, ts_list, prev, prev_state, next, cpu):177old_rq = self.prev.rqs[cpu]178new_rq = old_rq.sched_switch(prev, prev_state, next)179180if old_rq is new_rq:181return182183self.rqs[cpu] = new_rq184self.__update_total_load(old_rq, new_rq)185ts_list.append(self)186self.event_cpus = [cpu]187188def migrate(self, ts_list, new, old_cpu, new_cpu):189if old_cpu == new_cpu:190return191old_rq = self.prev.rqs[old_cpu]192out_rq = old_rq.migrate_out(new)193self.rqs[old_cpu] = out_rq194self.__update_total_load(old_rq, out_rq)195196new_rq = self.prev.rqs[new_cpu]197in_rq = new_rq.migrate_in(new)198self.rqs[new_cpu] = in_rq199self.__update_total_load(new_rq, in_rq)200201ts_list.append(self)202203if old_rq is not out_rq:204self.event_cpus.append(old_cpu)205self.event_cpus.append(new_cpu)206207def wake_up(self, ts_list, pid, cpu, fork):208old_rq = self.prev.rqs[cpu]209if fork:210new_rq = old_rq.wake_up_new(pid)211else:212new_rq = old_rq.wake_up(pid)213214if new_rq is old_rq:215return216self.rqs[cpu] = new_rq217self.__update_total_load(old_rq, new_rq)218ts_list.append(self)219self.event_cpus = [cpu]220221def next(self, t):222self.end = t223return TimeSlice(t, self)224225class TimeSliceList(UserList):226def __init__(self, arg = []):227self.data = arg228229def get_time_slice(self, ts):230if len(self.data) == 0:231slice = TimeSlice(ts, TimeSlice(-1, None))232else:233slice = self.data[-1].next(ts)234return slice235236def find_time_slice(self, ts):237start = 0238end = len(self.data)239found = -1240searching = True241while searching:242if start == end or start == end - 1:243searching = False244245i = (end + start) / 2246if self.data[i].start <= ts and self.data[i].end >= ts:247found = i248end = i249continue250251if self.data[i].end < ts:252start = i253254elif self.data[i].start > ts:255end = i256257return found258259def set_root_win(self, win):260self.root_win = win261262def mouse_down(self, cpu, t):263idx = self.find_time_slice(t)264if idx == -1:265return266267ts = self[idx]268rq = ts.rqs[cpu]269raw = "CPU: %d\n" % cpu270raw += "Last event : %s\n" % rq.event.__repr__()271raw += "Timestamp : %d.%06d\n" % (ts.start / (10 ** 9), (ts.start % (10 ** 9)) / 1000)272raw += "Duration : %6d us\n" % ((ts.end - ts.start) / (10 ** 6))273raw += "Load = %d\n" % rq.load()274for t in rq.tasks:275raw += "%s \n" % thread_name(t)276277self.root_win.update_summary(raw)278279def update_rectangle_cpu(self, slice, cpu):280rq = slice.rqs[cpu]281282if slice.total_load != 0:283load_rate = rq.load() / float(slice.total_load)284else:285load_rate = 0286287red_power = int(0xff - (0xff * load_rate))288color = (0xff, red_power, red_power)289290top_color = None291292if cpu in slice.event_cpus:293top_color = rq.event.color()294295self.root_win.paint_rectangle_zone(cpu, color, top_color, slice.start, slice.end)296297def fill_zone(self, start, end):298i = self.find_time_slice(start)299if i == -1:300return301302for i in xrange(i, len(self.data)):303timeslice = self.data[i]304if timeslice.start > end:305return306307for cpu in timeslice.rqs:308self.update_rectangle_cpu(timeslice, cpu)309310def interval(self):311if len(self.data) == 0:312return (0, 0)313314return (self.data[0].start, self.data[-1].end)315316def nr_rectangles(self):317last_ts = self.data[-1]318max_cpu = 0319for cpu in last_ts.rqs:320if cpu > max_cpu:321max_cpu = cpu322return max_cpu323324325class SchedEventProxy:326def __init__(self):327self.current_tsk = defaultdict(lambda : -1)328self.timeslices = TimeSliceList()329330def sched_switch(self, headers, prev_comm, prev_pid, prev_prio, prev_state,331next_comm, next_pid, next_prio):332""" Ensure the task we sched out this cpu is really the one333we logged. Otherwise we may have missed traces """334335on_cpu_task = self.current_tsk[headers.cpu]336337if on_cpu_task != -1 and on_cpu_task != prev_pid:338print "Sched switch event rejected ts: %s cpu: %d prev: %s(%d) next: %s(%d)" % \339(headers.ts_format(), headers.cpu, prev_comm, prev_pid, next_comm, next_pid)340341threads[prev_pid] = prev_comm342threads[next_pid] = next_comm343self.current_tsk[headers.cpu] = next_pid344345ts = self.timeslices.get_time_slice(headers.ts())346ts.sched_switch(self.timeslices, prev_pid, prev_state, next_pid, headers.cpu)347348def migrate(self, headers, pid, prio, orig_cpu, dest_cpu):349ts = self.timeslices.get_time_slice(headers.ts())350ts.migrate(self.timeslices, pid, orig_cpu, dest_cpu)351352def wake_up(self, headers, comm, pid, success, target_cpu, fork):353if success == 0:354return355ts = self.timeslices.get_time_slice(headers.ts())356ts.wake_up(self.timeslices, pid, target_cpu, fork)357358359def trace_begin():360global parser361parser = SchedEventProxy()362363def trace_end():364app = wx.App(False)365timeslices = parser.timeslices366frame = RootFrame(timeslices, "Migration")367app.MainLoop()368369def sched__sched_stat_runtime(event_name, context, common_cpu,370common_secs, common_nsecs, common_pid, common_comm,371comm, pid, runtime, vruntime):372pass373374def sched__sched_stat_iowait(event_name, context, common_cpu,375common_secs, common_nsecs, common_pid, common_comm,376comm, pid, delay):377pass378379def sched__sched_stat_sleep(event_name, context, common_cpu,380common_secs, common_nsecs, common_pid, common_comm,381comm, pid, delay):382pass383384def sched__sched_stat_wait(event_name, context, common_cpu,385common_secs, common_nsecs, common_pid, common_comm,386comm, pid, delay):387pass388389def sched__sched_process_fork(event_name, context, common_cpu,390common_secs, common_nsecs, common_pid, common_comm,391parent_comm, parent_pid, child_comm, child_pid):392pass393394def sched__sched_process_wait(event_name, context, common_cpu,395common_secs, common_nsecs, common_pid, common_comm,396comm, pid, prio):397pass398399def sched__sched_process_exit(event_name, context, common_cpu,400common_secs, common_nsecs, common_pid, common_comm,401comm, pid, prio):402pass403404def sched__sched_process_free(event_name, context, common_cpu,405common_secs, common_nsecs, common_pid, common_comm,406comm, pid, prio):407pass408409def sched__sched_migrate_task(event_name, context, common_cpu,410common_secs, common_nsecs, common_pid, common_comm,411comm, pid, prio, orig_cpu,412dest_cpu):413headers = EventHeaders(common_cpu, common_secs, common_nsecs,414common_pid, common_comm)415parser.migrate(headers, pid, prio, orig_cpu, dest_cpu)416417def sched__sched_switch(event_name, context, common_cpu,418common_secs, common_nsecs, common_pid, common_comm,419prev_comm, prev_pid, prev_prio, prev_state,420next_comm, next_pid, next_prio):421422headers = EventHeaders(common_cpu, common_secs, common_nsecs,423common_pid, common_comm)424parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state,425next_comm, next_pid, next_prio)426427def sched__sched_wakeup_new(event_name, context, common_cpu,428common_secs, common_nsecs, common_pid, common_comm,429comm, pid, prio, success,430target_cpu):431headers = EventHeaders(common_cpu, common_secs, common_nsecs,432common_pid, common_comm)433parser.wake_up(headers, comm, pid, success, target_cpu, 1)434435def sched__sched_wakeup(event_name, context, common_cpu,436common_secs, common_nsecs, common_pid, common_comm,437comm, pid, prio, success,438target_cpu):439headers = EventHeaders(common_cpu, common_secs, common_nsecs,440common_pid, common_comm)441parser.wake_up(headers, comm, pid, success, target_cpu, 0)442443def sched__sched_wait_task(event_name, context, common_cpu,444common_secs, common_nsecs, common_pid, common_comm,445comm, pid, prio):446pass447448def sched__sched_kthread_stop_ret(event_name, context, common_cpu,449common_secs, common_nsecs, common_pid, common_comm,450ret):451pass452453def sched__sched_kthread_stop(event_name, context, common_cpu,454common_secs, common_nsecs, common_pid, common_comm,455comm, pid):456pass457458def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs,459common_pid, common_comm):460pass461462463