diff --git a/tools/perf/scripts/python/sched-migration.py b/tools/perf/scripts/python/sched-migration.py index 8196e3087c9e08..047925c4f4686c 100644 --- a/tools/perf/scripts/python/sched-migration.py +++ b/tools/perf/scripts/python/sched-migration.py @@ -14,10 +14,10 @@ from collections import defaultdict try: - from UserList import UserList + from UserList import UserList except ImportError: # Python 3: UserList moved to the collections package - from collections import UserList + from collections import UserList sys.path.append(os.environ['PERF_EXEC_PATH'] + \ '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') @@ -31,432 +31,430 @@ threads = { 0 : "idle"} def thread_name(pid): - return "%s:%d" % (threads[pid], pid) + return "%s:%d" % (threads[pid], pid) class RunqueueEventUnknown: - @staticmethod - def color(): - return None + @staticmethod + def color(): + return None - def __repr__(self): - return "unknown" + def __repr__(self): + return "unknown" class RunqueueEventSleep: - @staticmethod - def color(): - return (0, 0, 0xff) + @staticmethod + def color(): + return (0, 0, 0xff) - def __init__(self, sleeper): - self.sleeper = sleeper + def __init__(self, sleeper): + self.sleeper = sleeper - def __repr__(self): - return "%s gone to sleep" % thread_name(self.sleeper) + def __repr__(self): + return "%s gone to sleep" % thread_name(self.sleeper) class RunqueueEventWakeup: - @staticmethod - def color(): - return (0xff, 0xff, 0) + @staticmethod + def color(): + return (0xff, 0xff, 0) - def __init__(self, wakee): - self.wakee = wakee + def __init__(self, wakee): + self.wakee = wakee - def __repr__(self): - return "%s woke up" % thread_name(self.wakee) + def __repr__(self): + return "%s woke up" % thread_name(self.wakee) class RunqueueEventFork: - @staticmethod - def color(): - return (0, 0xff, 0) + @staticmethod + def color(): + return (0, 0xff, 0) - def __init__(self, child): - self.child = child + def __init__(self, child): + self.child = child - def __repr__(self): - return "new forked task %s" % thread_name(self.child) + def __repr__(self): + return "new forked task %s" % thread_name(self.child) class RunqueueMigrateIn: - @staticmethod - def color(): - return (0, 0xf0, 0xff) + @staticmethod + def color(): + return (0, 0xf0, 0xff) - def __init__(self, new): - self.new = new + def __init__(self, new): + self.new = new - def __repr__(self): - return "task migrated in %s" % thread_name(self.new) + def __repr__(self): + return "task migrated in %s" % thread_name(self.new) class RunqueueMigrateOut: - @staticmethod - def color(): - return (0xff, 0, 0xff) + @staticmethod + def color(): + return (0xff, 0, 0xff) - def __init__(self, old): - self.old = old + def __init__(self, old): + self.old = old - def __repr__(self): - return "task migrated out %s" % thread_name(self.old) + def __repr__(self): + return "task migrated out %s" % thread_name(self.old) class RunqueueSnapshot: - def __init__(self, tasks = [0], event = RunqueueEventUnknown()): - self.tasks = tuple(tasks) - self.event = event + def __init__(self, tasks = [0], event = RunqueueEventUnknown()): + self.tasks = tuple(tasks) + self.event = event - def sched_switch(self, prev, prev_state, next): - event = RunqueueEventUnknown() + def sched_switch(self, prev, prev_state, next_one): + event = RunqueueEventUnknown() - if taskState(prev_state) == "R" and next in self.tasks \ - and prev in self.tasks: - return self + if taskState(prev_state) == "R" and next_one in self.tasks \ + and prev in self.tasks: + return self - if taskState(prev_state) != "R": - event = RunqueueEventSleep(prev) + if taskState(prev_state) != "R": + event = RunqueueEventSleep(prev) - next_tasks = list(self.tasks[:]) - if prev in self.tasks: - if taskState(prev_state) != "R": - next_tasks.remove(prev) - elif taskState(prev_state) == "R": - next_tasks.append(prev) + next_tasks = list(self.tasks[:]) + if prev in self.tasks: + if taskState(prev_state) != "R": + next_tasks.remove(prev) + elif taskState(prev_state) == "R": + next_tasks.append(prev) - if next not in next_tasks: - next_tasks.append(next) + if next_one not in next_tasks: + next_tasks.append(next_one) - return RunqueueSnapshot(next_tasks, event) + return RunqueueSnapshot(next_tasks, event) - def migrate_out(self, old): - if old not in self.tasks: - return self - next_tasks = [task for task in self.tasks if task != old] + def migrate_out(self, old): + if old not in self.tasks: + return self + next_tasks = [task for task in self.tasks if task != old] - return RunqueueSnapshot(next_tasks, RunqueueMigrateOut(old)) + return RunqueueSnapshot(next_tasks, RunqueueMigrateOut(old)) - def __migrate_in(self, new, event): - if new in self.tasks: - self.event = event - return self - next_tasks = self.tasks[:] + tuple([new]) + def __migrate_in(self, new, event): + if new in self.tasks: + self.event = event + return self + next_tasks = self.tasks[:] + tuple([new]) - return RunqueueSnapshot(next_tasks, event) + return RunqueueSnapshot(next_tasks, event) - def migrate_in(self, new): - return self.__migrate_in(new, RunqueueMigrateIn(new)) + def migrate_in(self, new): + return self.__migrate_in(new, RunqueueMigrateIn(new)) - def wake_up(self, new): - return self.__migrate_in(new, RunqueueEventWakeup(new)) + def wake_up(self, new): + return self.__migrate_in(new, RunqueueEventWakeup(new)) - def wake_up_new(self, new): - return self.__migrate_in(new, RunqueueEventFork(new)) + def wake_up_new(self, new): + return self.__migrate_in(new, RunqueueEventFork(new)) - def load(self): - """ Provide the number of tasks on the runqueue. + def load(self): + """ Provide the number of tasks on the runqueue. Don't count idle""" - return len(self.tasks) - 1 + return len(self.tasks) - 1 - def __repr__(self): - ret = self.tasks.__repr__() - ret += self.origin_tostring() + def __repr__(self): + ret = self.tasks.__repr__() + ret += self.origin_tostring() - return ret + return ret class TimeSlice: - def __init__(self, start, prev): - self.start = start - self.prev = prev - self.end = start + def __init__(self, start, prev): + self.start = start + self.prev = prev + self.end = start # cpus that triggered the event - self.event_cpus = [] - if prev is not None: - self.total_load = prev.total_load - self.rqs = prev.rqs.copy() - else: - self.rqs = defaultdict(RunqueueSnapshot) - self.total_load = 0 - - def __update_total_load(self, old_rq, new_rq): - diff = new_rq.load() - old_rq.load() - self.total_load += diff - - def sched_switch(self, ts_list, prev, prev_state, next, cpu): - old_rq = self.prev.rqs[cpu] - new_rq = old_rq.sched_switch(prev, prev_state, next) - - if old_rq is new_rq: - return - - self.rqs[cpu] = new_rq - self.__update_total_load(old_rq, new_rq) - ts_list.append(self) - self.event_cpus = [cpu] - - def migrate(self, ts_list, new, old_cpu, new_cpu): - if old_cpu == new_cpu: - return - old_rq = self.prev.rqs[old_cpu] - out_rq = old_rq.migrate_out(new) - self.rqs[old_cpu] = out_rq - self.__update_total_load(old_rq, out_rq) - - new_rq = self.prev.rqs[new_cpu] - in_rq = new_rq.migrate_in(new) - self.rqs[new_cpu] = in_rq - self.__update_total_load(new_rq, in_rq) - - ts_list.append(self) - - if old_rq is not out_rq: - self.event_cpus.append(old_cpu) - self.event_cpus.append(new_cpu) - - def wake_up(self, ts_list, pid, cpu, fork): - old_rq = self.prev.rqs[cpu] - if fork: - new_rq = old_rq.wake_up_new(pid) - else: - new_rq = old_rq.wake_up(pid) - - if new_rq is old_rq: - return - self.rqs[cpu] = new_rq - self.__update_total_load(old_rq, new_rq) - ts_list.append(self) - self.event_cpus = [cpu] - - def next(self, t): - self.end = t - return TimeSlice(t, self) + self.event_cpus = [] + if prev is not None: + self.total_load = prev.total_load + self.rqs = prev.rqs.copy() + else: + self.rqs = defaultdict(RunqueueSnapshot) + self.total_load = 0 + + def __update_total_load(self, old_rq, new_rq): + diff = new_rq.load() - old_rq.load() + self.total_load += diff + + def sched_switch(self, ts_list, prev, prev_state, next_one, cpu): + old_rq = self.prev.rqs[cpu] + new_rq = old_rq.sched_switch(prev, prev_state, next_one) + + if old_rq is new_rq: + return + + self.rqs[cpu] = new_rq + self.__update_total_load(old_rq, new_rq) + ts_list.append(self) + self.event_cpus = [cpu] + + def migrate(self, ts_list, new, old_cpu, new_cpu): + if old_cpu == new_cpu: + return + old_rq = self.prev.rqs[old_cpu] + out_rq = old_rq.migrate_out(new) + self.rqs[old_cpu] = out_rq + self.__update_total_load(old_rq, out_rq) + + new_rq = self.prev.rqs[new_cpu] + in_rq = new_rq.migrate_in(new) + self.rqs[new_cpu] = in_rq + self.__update_total_load(new_rq, in_rq) + + ts_list.append(self) + + if old_rq is not out_rq: + self.event_cpus.append(old_cpu) + self.event_cpus.append(new_cpu) + + def wake_up(self, ts_list, pid, cpu, fork): + old_rq = self.prev.rqs[cpu] + if fork: + new_rq = old_rq.wake_up_new(pid) + else: + new_rq = old_rq.wake_up(pid) + + if new_rq is old_rq: + return + self.rqs[cpu] = new_rq + self.__update_total_load(old_rq, new_rq) + ts_list.append(self) + self.event_cpus = [cpu] + + def next(self, t): + self.end = t + return TimeSlice(t, self) class TimeSliceList(UserList): - def __init__(self, arg = []): - self.data = arg + def __init__(self, arg = []): + self.data = arg - def get_time_slice(self, ts): - if len(self.data) == 0: - slice = TimeSlice(ts, TimeSlice(-1, None)) - else: - slice = self.data[-1].next(ts) - return slice + def get_time_slice(self, ts): + if len(self.data) == 0: + sliced = TimeSlice(ts, TimeSlice(-1, None)) + else: + sliced = self.data[-1].next(ts) + return sliced - def find_time_slice(self, ts): - start = 0 - end = len(self.data) - found = -1 - searching = True - while searching: - if start == end or start == end - 1: - searching = False + def find_time_slice(self, ts): + start = 0 + end = len(self.data) + found = -1 + searching = True + while searching: + if start == end or start == end - 1: + searching = False - i = (end + start) / 2 - if self.data[i].start <= ts and self.data[i].end >= ts: - found = i - end = i - continue + i = (end + start) / 2 + if self.data[i].start <= ts and self.data[i].end >= ts: + found = i + end = i + continue - if self.data[i].end < ts: - start = i + if self.data[i].end < ts: + start = i - elif self.data[i].start > ts: - end = i + elif self.data[i].start > ts: + end = i - return found + return found - def set_root_win(self, win): - self.root_win = win + 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 + 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) + 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) + self.root_win.update_summary(raw) - def update_rectangle_cpu(self, slice, cpu): - rq = slice.rqs[cpu] + def update_rectangle_cpu(self, sliced, cpu): + rq = sliced.rqs[cpu] - if slice.total_load != 0: - load_rate = rq.load() / float(slice.total_load) - else: - load_rate = 0 + if sliced.total_load != 0: + load_rate = rq.load() / float(sliced.total_load) + else: + load_rate = 0 - red_power = int(0xff - (0xff * load_rate)) - color = (0xff, red_power, red_power) + red_power = int(0xff - (0xff * load_rate)) + color = (0xff, red_power, red_power) - top_color = None + top_color = None - if cpu in slice.event_cpus: - top_color = rq.event.color() + if cpu in sliced.event_cpus: + top_color = rq.event.color() - self.root_win.paint_rectangle_zone(cpu, color, top_color, slice.start, slice.end) + self.root_win.paint_rectangle_zone(cpu, color, top_color, sliced.start, sliced.end) - def fill_zone(self, start, end): - i = self.find_time_slice(start) - if i == -1: - return + def fill_zone(self, start, end): + i = self.find_time_slice(start) + if i == -1: + return - for i in range(i, len(self.data)): - timeslice = self.data[i] - if timeslice.start > end: - return + for i in range(i, len(self.data)): + timeslice = self.data[i] + if timeslice.start > end: + return - for cpu in timeslice.rqs: - self.update_rectangle_cpu(timeslice, cpu) + for cpu in timeslice.rqs: + self.update_rectangle_cpu(timeslice, cpu) - def interval(self): - if len(self.data) == 0: - return (0, 0) + def interval(self): + if len(self.data) == 0: + return (0, 0) - return (self.data[0].start, self.data[-1].end) + return (self.data[0].start, self.data[-1].end) - def nr_rectangles(self): - last_ts = self.data[-1] - max_cpu = 0 - for cpu in last_ts.rqs: - if cpu > max_cpu: - max_cpu = cpu - return max_cpu + def nr_rectangles(self): + last_ts = self.data[-1] + max_cpu = 0 + for cpu in last_ts.rqs: + if cpu > max_cpu: + max_cpu = cpu + return max_cpu class SchedEventProxy: - def __init__(self): - self.current_tsk = defaultdict(lambda : -1) - self.timeslices = TimeSliceList() + def __init__(self): + self.current_tsk = defaultdict(lambda : -1) + self.timeslices = TimeSliceList() - def sched_switch(self, headers, prev_comm, prev_pid, prev_prio, prev_state, - next_comm, next_pid, next_prio): - """ Ensure the task we sched out this cpu is really the one + def sched_switch(self, headers, prev_comm, prev_pid, prev_prio, prev_state, + next_comm, next_pid, next_prio): + """ Ensure the task we sched out this cpu is really the one we logged. Otherwise we may have missed traces """ - on_cpu_task = self.current_tsk[headers.cpu] + on_cpu_task = self.current_tsk[headers.cpu] - if on_cpu_task != -1 and on_cpu_task != prev_pid: - print("Sched switch event rejected ts: %s cpu: %d prev: %s(%d) next: %s(%d)" % \ + if on_cpu_task != -1 and on_cpu_task != prev_pid: + print("Sched switch event rejected ts: %s cpu: %d prev: %s(%d) next: %s(%d)" % \ headers.ts_format(), headers.cpu, prev_comm, prev_pid, next_comm, next_pid) - threads[prev_pid] = prev_comm - threads[next_pid] = next_comm - self.current_tsk[headers.cpu] = next_pid + threads[prev_pid] = prev_comm + threads[next_pid] = next_comm + self.current_tsk[headers.cpu] = next_pid - ts = self.timeslices.get_time_slice(headers.ts()) - ts.sched_switch(self.timeslices, prev_pid, prev_state, next_pid, headers.cpu) + ts = self.timeslices.get_time_slice(headers.ts()) + ts.sched_switch(self.timeslices, prev_pid, prev_state, next_pid, headers.cpu) - def migrate(self, headers, pid, prio, orig_cpu, dest_cpu): - ts = self.timeslices.get_time_slice(headers.ts()) - ts.migrate(self.timeslices, pid, orig_cpu, dest_cpu) + def migrate(self, headers, pid, prio, orig_cpu, dest_cpu): + ts = self.timeslices.get_time_slice(headers.ts()) + ts.migrate(self.timeslices, pid, orig_cpu, dest_cpu) - def wake_up(self, headers, comm, pid, success, target_cpu, fork): - if success == 0: - return - ts = self.timeslices.get_time_slice(headers.ts()) - ts.wake_up(self.timeslices, pid, target_cpu, fork) + def wake_up(self, headers, comm, pid, success, target_cpu, fork): + if success == 0: + return + ts = self.timeslices.get_time_slice(headers.ts()) + ts.wake_up(self.timeslices, pid, target_cpu, fork) def trace_begin(): - global parser - parser = SchedEventProxy() + global parser + parser = SchedEventProxy() def trace_end(): - app = wx.App(False) - timeslices = parser.timeslices - frame = RootFrame(timeslices, "Migration") - app.MainLoop() + app = wx.App(False) + app.MainLoop() def sched__sched_stat_runtime(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, comm, pid, runtime, vruntime): - pass + pass def sched__sched_stat_iowait(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, comm, pid, delay): - pass + pass def sched__sched_stat_sleep(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, comm, pid, delay): - pass + pass def sched__sched_stat_wait(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, comm, pid, delay): - pass + pass def sched__sched_process_fork(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, parent_comm, parent_pid, child_comm, child_pid): - pass + pass def sched__sched_process_wait(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, comm, pid, prio): - pass + pass def sched__sched_process_exit(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, comm, pid, prio): - pass + pass def sched__sched_process_free(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, comm, pid, prio): - pass + pass def sched__sched_migrate_task(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, comm, pid, prio, orig_cpu, dest_cpu): - headers = EventHeaders(common_cpu, common_secs, common_nsecs, + headers = EventHeaders(common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain) - parser.migrate(headers, pid, prio, orig_cpu, dest_cpu) + parser.migrate(headers, pid, prio, orig_cpu, dest_cpu) def sched__sched_switch(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, prev_comm, prev_pid, prev_prio, prev_state, next_comm, next_pid, next_prio): - headers = EventHeaders(common_cpu, common_secs, common_nsecs, + headers = EventHeaders(common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain) - parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state, + parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state, next_comm, next_pid, next_prio) def sched__sched_wakeup_new(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, comm, pid, prio, success, target_cpu): - headers = EventHeaders(common_cpu, common_secs, common_nsecs, + headers = EventHeaders(common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain) - parser.wake_up(headers, comm, pid, success, target_cpu, 1) + parser.wake_up(headers, comm, pid, success, target_cpu, 1) def sched__sched_wakeup(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, comm, pid, prio, success, target_cpu): - headers = EventHeaders(common_cpu, common_secs, common_nsecs, + headers = EventHeaders(common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain) - parser.wake_up(headers, comm, pid, success, target_cpu, 0) + parser.wake_up(headers, comm, pid, success, target_cpu, 0) def sched__sched_wait_task(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, comm, pid, prio): - pass + pass def sched__sched_kthread_stop_ret(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, ret): - pass + pass def sched__sched_kthread_stop(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, comm, pid): - pass + pass def trace_unhandled(event_name, context, event_fields_dict): - pass + pass