| #!/usr/bin/python |
| # Copyright (C) 2018 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import argparse |
| |
| from google.protobuf import descriptor, descriptor_pb2, message_factory, reflection |
| from google.protobuf.pyext import _message |
| |
| CLONE_THREAD = 0x00010000 |
| |
| |
| class Trace(object): |
| def __init__(self, trace): |
| self.trace = trace |
| self.proc_map = {} |
| self.proc_map[0] = "idle_thread" |
| |
| def add_system_info(self, arch=None): |
| self.packet = self.trace.packet.add() |
| self.packet.system_info.utsname.machine = arch |
| |
| def add_ftrace_packet(self, cpu): |
| self.packet = self.trace.packet.add() |
| self.packet.ftrace_events.cpu = cpu |
| |
| def __add_ftrace_event(self, ts, tid): |
| ftrace = self.packet.ftrace_events.event.add() |
| ftrace.timestamp = ts |
| ftrace.pid = tid |
| return ftrace |
| |
| def add_rss_stat(self, ts, tid, member, size): |
| ftrace = self.__add_ftrace_event(ts, tid) |
| rss_stat = ftrace.rss_stat |
| rss_stat.member = member |
| rss_stat.size = size |
| |
| def add_oom_score_update(self, ts, oom_score_adj, pid): |
| ftrace = self.__add_ftrace_event(ts, pid) |
| oom_score = ftrace.oom_score_adj_update |
| oom_score.comm = self.proc_map[pid] |
| oom_score.oom_score_adj = oom_score_adj |
| oom_score.pid = pid |
| |
| def add_sched(self, ts, prev_pid, next_pid, prev_comm=None, next_comm=None): |
| ftrace = self.__add_ftrace_event(ts, 0) |
| ss = ftrace.sched_switch |
| ss.prev_comm = prev_comm or self.proc_map[prev_pid] |
| ss.prev_pid = prev_pid |
| ss.next_pid = next_pid |
| ss.next_comm = next_comm or self.proc_map[next_pid] |
| |
| def add_cpufreq(self, ts, freq, cpu): |
| ftrace = self.__add_ftrace_event(ts, 0) |
| cpufreq = ftrace.cpu_frequency |
| cpufreq.state = freq |
| cpufreq.cpu_id = cpu |
| |
| def add_kernel_lmk(self, ts, tid): |
| ftrace = self.__add_ftrace_event(ts, tid) |
| lowmemory_kill = ftrace.lowmemory_kill |
| lowmemory_kill.pid = tid |
| |
| def add_sys_enter(self, ts, tid, id): |
| ftrace = self.__add_ftrace_event(ts, tid) |
| sys_enter = ftrace.sys_enter |
| sys_enter.id = id |
| |
| def add_sys_exit(self, ts, tid, id, ret): |
| ftrace = self.__add_ftrace_event(ts, tid) |
| sys_exit = ftrace.sys_exit |
| sys_exit.id = id |
| sys_exit.ret = ret |
| |
| def add_newtask(self, ts, tid, new_tid, new_comm, flags): |
| ftrace = self.__add_ftrace_event(ts, tid) |
| newtask = ftrace.task_newtask |
| newtask.pid = new_tid |
| newtask.comm = new_comm |
| newtask.clone_flags = flags |
| |
| def add_process_tree_packet(self, ts=None): |
| self.packet = self.trace.packet.add() |
| if ts is not None: |
| self.packet.timestamp = ts |
| |
| def add_process(self, pid, ppid, cmdline): |
| process = self.packet.process_tree.processes.add() |
| process.pid = pid |
| process.ppid = ppid |
| process.cmdline.append(cmdline) |
| self.proc_map[pid] = cmdline |
| |
| def add_thread(self, tid, tgid, cmdline): |
| thread = self.packet.process_tree.threads.add() |
| thread.tid = tid |
| thread.tgid = tgid |
| self.proc_map[tid] = cmdline |
| |
| |
| def create_trace(): |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| 'trace_descriptor', type=str, help='location of trace descriptor') |
| args = parser.parse_args() |
| |
| with open(args.trace_descriptor, "rb") as t: |
| fileContent = t.read() |
| |
| file_desc_set_pb2 = descriptor_pb2.FileDescriptorSet() |
| file_desc_set_pb2.MergeFromString(fileContent) |
| |
| desc_by_path = {} |
| for f_desc_pb2 in file_desc_set_pb2.file: |
| f_desc_pb2_encode = f_desc_pb2.SerializeToString() |
| f_desc = descriptor.FileDescriptor( |
| name=f_desc_pb2.name, |
| package=f_desc_pb2.package, |
| serialized_pb=f_desc_pb2_encode) |
| |
| for desc in f_desc.message_types_by_name.values(): |
| desc_by_path[desc.full_name] = desc |
| |
| trace = message_factory.MessageFactory().GetPrototype( |
| desc_by_path["perfetto.protos.Trace"])() |
| return Trace(trace) |