You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
783 lines
27 KiB
783 lines
27 KiB
#!/usr/bin/env python3
|
|
# 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 collections import namedtuple
|
|
from google.protobuf import descriptor, descriptor_pb2, message_factory, descriptor_pool
|
|
|
|
CLONE_THREAD = 0x00010000
|
|
CLONE_VFORK = 0x00004000
|
|
CLONE_VM = 0x00000100
|
|
|
|
|
|
def ms_to_ns(time_in_ms):
|
|
return int(time_in_ms * 1000000)
|
|
|
|
|
|
def s_to_ns(time_in_s):
|
|
return int(time_in_s * 1000000000)
|
|
|
|
|
|
class Trace(object):
|
|
|
|
def __init__(self, trace, prototypes):
|
|
self.trace = trace
|
|
self.prototypes = prototypes
|
|
self.proc_map = {}
|
|
self.proc_map[0] = 'idle_thread'
|
|
|
|
def add_system_info(self, arch="", fingerprint=""):
|
|
self.packet = self.trace.packet.add()
|
|
self.packet.system_info.utsname.machine = arch
|
|
self.packet.system_info.android_build_fingerprint = fingerprint
|
|
|
|
def add_ftrace_packet(self, cpu):
|
|
self.packet = self.trace.packet.add()
|
|
self.packet.ftrace_events.cpu = cpu
|
|
|
|
def add_packet(self, ts=None):
|
|
self.packet = self.trace.packet.add()
|
|
if ts is not None:
|
|
self.packet.timestamp = ts
|
|
return self.packet
|
|
|
|
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, mm_id=None, curr=None):
|
|
ftrace = self.__add_ftrace_event(ts, tid)
|
|
rss_stat = ftrace.rss_stat
|
|
rss_stat.member = member
|
|
rss_stat.size = size
|
|
if mm_id is not None:
|
|
rss_stat.mm_id = mm_id
|
|
if curr is not None:
|
|
rss_stat.curr = curr
|
|
|
|
def add_ion_event(self, ts, tid, heap_name, len, size=0):
|
|
ftrace = self.__add_ftrace_event(ts, tid)
|
|
ion = ftrace.ion_heap_grow
|
|
ion.heap_name = heap_name
|
|
ion.len = len
|
|
ion.total_allocated = 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,
|
|
prev_state=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]
|
|
if prev_state:
|
|
if prev_state == 'R':
|
|
ss.prev_state = 0
|
|
elif prev_state == 'S':
|
|
ss.prev_state = 1
|
|
elif prev_state == 'U':
|
|
ss.prev_state = 2
|
|
else:
|
|
raise Exception('Invalid prev state {}'.format(prev_state))
|
|
|
|
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_free(self, ts, tid, comm, prio):
|
|
ftrace = self.__add_ftrace_event(ts, tid)
|
|
sched_process_free = ftrace.sched_process_free
|
|
sched_process_free.pid = tid
|
|
sched_process_free.comm = comm
|
|
sched_process_free.prio = prio
|
|
|
|
def add_rename(self, ts, tid, old_comm, new_comm, oom_score_adj):
|
|
ftrace = self.__add_ftrace_event(ts, tid)
|
|
task_rename = ftrace.task_rename
|
|
task_rename.pid = tid
|
|
task_rename.oldcomm = old_comm
|
|
task_rename.newcomm = new_comm
|
|
task_rename.oom_score_adj = oom_score_adj
|
|
|
|
def add_print(self, ts, tid, buf):
|
|
ftrace = self.__add_ftrace_event(ts, tid)
|
|
print_event = getattr(ftrace, 'print')
|
|
print_event.buf = buf
|
|
|
|
def add_kmalloc(self, ts, tid, bytes_alloc, bytes_req, call_site, gfp_flags,
|
|
ptr):
|
|
ftrace = self.__add_ftrace_event(ts, tid)
|
|
kmalloc = ftrace.kmalloc
|
|
kmalloc.bytes_alloc = bytes_alloc
|
|
kmalloc.bytes_req = bytes_req
|
|
kmalloc.call_site = call_site
|
|
kmalloc.gfp_flags = gfp_flags
|
|
kmalloc.ptr = ptr
|
|
|
|
def add_kfree(self, ts, tid, call_site, ptr):
|
|
ftrace = self.__add_ftrace_event(ts, tid)
|
|
kfree = ftrace.kfree
|
|
kfree.call_site = call_site
|
|
kfree.ptr = ptr
|
|
|
|
def add_atrace_counter(self, ts, pid, tid, buf, cnt):
|
|
self.add_print(ts, tid, 'C|{}|{}|{}'.format(pid, buf, cnt))
|
|
|
|
def add_atrace_begin(self, ts, tid, pid, buf):
|
|
self.add_print(ts, tid, 'B|{}|{}'.format(pid, buf))
|
|
|
|
def add_atrace_end(self, ts, tid, pid):
|
|
self.add_print(ts, tid, 'E|{}'.format(pid))
|
|
|
|
def add_atrace_async_begin(self, ts, tid, pid, buf):
|
|
self.add_print(ts, tid, 'S|{}|{}|0'.format(pid, buf))
|
|
|
|
def add_atrace_async_end(self, ts, tid, pid, buf):
|
|
self.add_print(ts, tid, 'F|{}|{}|0'.format(pid, buf))
|
|
|
|
def add_process(self, pid, ppid, cmdline, uid=None):
|
|
process = self.packet.process_tree.processes.add()
|
|
process.pid = pid
|
|
process.ppid = ppid
|
|
process.cmdline.append(cmdline)
|
|
if uid is not None:
|
|
process.uid = uid
|
|
self.proc_map[pid] = cmdline
|
|
|
|
def add_thread(self, tid, tgid, cmdline, name=None):
|
|
thread = self.packet.process_tree.threads.add()
|
|
thread.tid = tid
|
|
thread.tgid = tgid
|
|
if name is not None:
|
|
thread.name = name
|
|
self.proc_map[tid] = cmdline
|
|
|
|
def add_battery_counters(self, ts, charge_uah, cap_prct, curr_ua,
|
|
curr_avg_ua):
|
|
self.packet = self.trace.packet.add()
|
|
self.packet.timestamp = ts
|
|
battery_count = self.packet.battery
|
|
battery_count.charge_counter_uah = charge_uah
|
|
battery_count.capacity_percent = cap_prct
|
|
battery_count.current_ua = curr_ua
|
|
battery_count.current_avg_ua = curr_avg_ua
|
|
|
|
def add_battery_counters_no_curr_ua(self, ts, charge_uah, cap_prct,
|
|
curr_avg_ua):
|
|
self.packet = self.trace.packet.add()
|
|
self.packet.timestamp = ts
|
|
battery_count = self.packet.battery
|
|
battery_count.charge_counter_uah = charge_uah
|
|
battery_count.capacity_percent = cap_prct
|
|
battery_count.current_avg_ua = curr_avg_ua
|
|
|
|
def add_power_rails_desc(self, index_val, name):
|
|
power_rails = self.packet.power_rails
|
|
descriptor = power_rails.rail_descriptor.add()
|
|
descriptor.index = index_val
|
|
descriptor.rail_name = name
|
|
|
|
def add_power_rails_data(self, ts, index_val, value):
|
|
power_rails = self.packet.power_rails
|
|
energy_data = power_rails.energy_data.add()
|
|
energy_data.index = index_val
|
|
energy_data.timestamp_ms = ts
|
|
energy_data.energy = value
|
|
|
|
def add_package_list(self, ts, name, uid, version_code):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
plist = packet.packages_list
|
|
pinfo = plist.packages.add()
|
|
pinfo.name = name
|
|
pinfo.uid = uid
|
|
pinfo.version_code = version_code
|
|
|
|
def add_profile_packet(self, ts):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
return packet.profile_packet
|
|
|
|
def add_clock_snapshot(self, clocks, seq_id=None):
|
|
packet = self.add_packet()
|
|
if seq_id is not None:
|
|
packet.trusted_packet_sequence_id = seq_id
|
|
snap = self.packet.clock_snapshot
|
|
for k, v in clocks.items():
|
|
clock = snap.clocks.add()
|
|
clock.clock_id = k
|
|
clock.timestamp = v
|
|
|
|
def add_gpu_counter_spec(self,
|
|
ts,
|
|
counter_id,
|
|
name,
|
|
description=None,
|
|
unit_numerators=[],
|
|
unit_denominators=[]):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
gpu_counters = packet.gpu_counter_event
|
|
counter_desc = gpu_counters.counter_descriptor
|
|
spec = counter_desc.specs.add()
|
|
spec.counter_id = counter_id
|
|
spec.name = name
|
|
if description is not None:
|
|
spec.description = description
|
|
spec.numerator_units.extend(unit_numerators)
|
|
spec.denominator_units.extend(unit_denominators)
|
|
|
|
def add_gpu_counter(self, ts, counter_id, value, clock_id=None, seq_id=None):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
if clock_id is not None:
|
|
packet.timestamp_clock_id = clock_id
|
|
if seq_id is not None:
|
|
packet.trusted_packet_sequence_id = seq_id
|
|
gpu_counters = self.packet.gpu_counter_event
|
|
gpu_counter = gpu_counters.counters.add()
|
|
gpu_counter.counter_id = counter_id
|
|
gpu_counter.int_value = value
|
|
|
|
def add_gpu_render_stages_hw_queue_spec(self, specs=[]):
|
|
packet = self.add_packet()
|
|
spec = self.packet.gpu_render_stage_event.specifications
|
|
for s in specs:
|
|
hw_queue = spec.hw_queue.add()
|
|
hw_queue.name = s.get('name', '')
|
|
if 'description' in s:
|
|
hw_queue.description = s['description']
|
|
|
|
def add_gpu_render_stages_stage_spec(self, specs=[]):
|
|
packet = self.add_packet()
|
|
spec = self.packet.gpu_render_stage_event.specifications
|
|
for s in specs:
|
|
stage = spec.stage.add()
|
|
stage.name = s.get('name', '')
|
|
if 'description' in s:
|
|
stage.description = s['description']
|
|
|
|
def add_gpu_render_stages(self,
|
|
ts,
|
|
event_id,
|
|
duration,
|
|
hw_queue_id,
|
|
stage_id,
|
|
context,
|
|
render_target_handle=None,
|
|
render_pass_handle=None,
|
|
render_subpass_index_mask=None,
|
|
command_buffer_handle=None,
|
|
submission_id=None,
|
|
extra_data={}):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
render_stage = self.packet.gpu_render_stage_event
|
|
render_stage.event_id = event_id
|
|
render_stage.duration = duration
|
|
render_stage.hw_queue_id = hw_queue_id
|
|
render_stage.stage_id = stage_id
|
|
render_stage.context = context
|
|
if render_target_handle is not None:
|
|
render_stage.render_target_handle = render_target_handle
|
|
if render_pass_handle is not None:
|
|
render_stage.render_pass_handle = render_pass_handle
|
|
if render_subpass_index_mask is not None:
|
|
for mask in render_subpass_index_mask:
|
|
render_stage.render_subpass_index_mask.append(mask)
|
|
if command_buffer_handle is not None:
|
|
render_stage.command_buffer_handle = command_buffer_handle
|
|
if submission_id is not None:
|
|
render_stage.submission_id = submission_id
|
|
for key, value in extra_data.items():
|
|
data = render_stage.extra_data.add()
|
|
data.name = key
|
|
if value is not None:
|
|
data.value = value
|
|
|
|
def add_vk_debug_marker(self, ts, pid, vk_device, obj_type, obj, obj_name):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
debug_marker = (self.packet.vulkan_api_event.vk_debug_utils_object_name)
|
|
debug_marker.pid = pid
|
|
debug_marker.vk_device = vk_device
|
|
debug_marker.object_type = obj_type
|
|
debug_marker.object = obj
|
|
debug_marker.object_name = obj_name
|
|
|
|
def add_vk_queue_submit(self, ts, dur, pid, tid, vk_queue, vk_command_buffers,
|
|
submission_id):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
submit = (self.packet.vulkan_api_event.vk_queue_submit)
|
|
submit.duration_ns = dur
|
|
submit.pid = pid
|
|
submit.tid = tid
|
|
for cmd in vk_command_buffers:
|
|
submit.vk_command_buffers.append(cmd)
|
|
submit.submission_id = submission_id
|
|
|
|
def add_gpu_log(self, ts, severity, tag, message):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
gpu_log = self.packet.gpu_log
|
|
gpu_log.severity = severity
|
|
gpu_log.tag = tag
|
|
gpu_log.log_message = message
|
|
|
|
def add_buffer_event_packet(self, ts, buffer_id, layer_name, frame_number,
|
|
event_type, duration):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
buffer_event = packet.graphics_frame_event.buffer_event
|
|
if buffer_id >= 0:
|
|
buffer_event.buffer_id = buffer_id
|
|
buffer_event.layer_name = layer_name
|
|
buffer_event.frame_number = frame_number
|
|
if event_type >= 0:
|
|
buffer_event.type = event_type
|
|
buffer_event.duration_ns = duration
|
|
|
|
def add_cpu(self, freqs):
|
|
cpu = self.packet.cpu_info.cpus.add()
|
|
for freq in freqs:
|
|
cpu.frequencies.append(freq)
|
|
|
|
def add_process_stats(self, pid, freqs):
|
|
process = self.packet.process_stats.processes.add()
|
|
process.pid = pid
|
|
thread = process.threads.add()
|
|
thread.tid = pid * 10
|
|
for index in freqs:
|
|
thread.cpu_freq_indices.append(index)
|
|
thread.cpu_freq_ticks.append(freqs[index])
|
|
|
|
def add_gpu_mem_total_ftrace_event(self, pid, ts, size):
|
|
ftrace = self.__add_ftrace_event(ts, pid)
|
|
gpu_mem_total_ftrace_event = ftrace.gpu_mem_total
|
|
gpu_mem_total_ftrace_event.pid = pid
|
|
gpu_mem_total_ftrace_event.size = size
|
|
|
|
def add_gpu_mem_total_event(self, pid, ts, size):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
gpu_mem_total_event = packet.gpu_mem_total_event
|
|
gpu_mem_total_event.pid = pid
|
|
gpu_mem_total_event.size = size
|
|
|
|
def add_sched_blocked_reason(self, ts, pid, io_wait, unblock_pid):
|
|
ftrace = self.__add_ftrace_event(ts, unblock_pid)
|
|
sched_blocked_reason = ftrace.sched_blocked_reason
|
|
sched_blocked_reason.pid = pid
|
|
sched_blocked_reason.io_wait = io_wait
|
|
|
|
def add_track_event(self,
|
|
name=None,
|
|
ts=None,
|
|
track=None,
|
|
trusted_sequence_id=0,
|
|
cpu_time=None):
|
|
packet = self.add_packet(ts=ts)
|
|
if name is not None:
|
|
packet.track_event.name = name
|
|
if track is not None:
|
|
packet.track_event.track_uuid = track
|
|
packet.trusted_packet_sequence_id = trusted_sequence_id
|
|
if cpu_time is not None:
|
|
packet.track_event.extra_counter_values.append(cpu_time)
|
|
return packet
|
|
|
|
def add_track_descriptor(self, uuid, parent=None):
|
|
packet = self.add_packet()
|
|
track_descriptor = packet.track_descriptor
|
|
if uuid is not None:
|
|
track_descriptor.uuid = uuid
|
|
if parent is not None:
|
|
track_descriptor.parent_uuid = parent
|
|
return packet
|
|
|
|
def add_process_track_descriptor(self, process_track, pid=None):
|
|
packet = self.add_track_descriptor(process_track)
|
|
packet.track_descriptor.process.pid = pid
|
|
return packet
|
|
|
|
def add_chrome_process_track_descriptor(
|
|
self,
|
|
process_track,
|
|
pid=None,
|
|
process_type=None,
|
|
host_app_package_name="org.chromium.chrome"):
|
|
if process_type is None:
|
|
process_type = self.prototypes.ChromeProcessDescriptor \
|
|
.ProcessType \
|
|
.PROCESS_RENDERER
|
|
|
|
packet = self.add_process_track_descriptor(process_track, pid=pid)
|
|
chrome_process = packet.track_descriptor.chrome_process
|
|
chrome_process.process_type = process_type
|
|
chrome_process.host_app_package_name = host_app_package_name
|
|
return packet
|
|
|
|
def add_thread_track_descriptor(self,
|
|
process_track,
|
|
thread_track,
|
|
trusted_packet_sequence_id=None,
|
|
pid=None,
|
|
tid=None):
|
|
packet = self.add_track_descriptor(thread_track, parent=process_track)
|
|
packet.trusted_packet_sequence_id = trusted_packet_sequence_id
|
|
packet.track_descriptor.thread.pid = pid
|
|
packet.track_descriptor.thread.tid = tid
|
|
return packet
|
|
|
|
def add_chrome_thread_track_descriptor(self,
|
|
process_track,
|
|
thread_track,
|
|
trusted_packet_sequence_id=None,
|
|
pid=None,
|
|
tid=None,
|
|
thread_type=None):
|
|
if thread_type is None:
|
|
thread_type = self.prototypes.ThreadDescriptor \
|
|
.ChromeThreadType \
|
|
.CHROME_THREAD_TYPE_UNSPECIFIED
|
|
|
|
packet = self.add_thread_track_descriptor(
|
|
process_track,
|
|
thread_track,
|
|
trusted_packet_sequence_id=trusted_packet_sequence_id,
|
|
pid=pid,
|
|
tid=tid)
|
|
packet.track_descriptor.thread.chrome_thread_type = thread_type
|
|
return packet
|
|
|
|
def add_trace_packet_defaults(self,
|
|
trusted_packet_sequence_id=None,
|
|
thread_track=None,
|
|
counter_track=None):
|
|
packet = self.add_track_descriptor(None)
|
|
packet.trusted_packet_sequence_id = trusted_packet_sequence_id
|
|
track_event_defaults = packet.trace_packet_defaults.track_event_defaults
|
|
track_event_defaults.track_uuid = thread_track
|
|
track_event_defaults.extra_counter_track_uuids.append(counter_track)
|
|
return packet
|
|
|
|
def add_counter_track_descriptor(self,
|
|
trusted_packet_sequence_id=None,
|
|
thread_track=None,
|
|
counter_track=None):
|
|
packet = self.add_track_descriptor(counter_track, parent=thread_track)
|
|
packet.trusted_packet_sequence_id = trusted_packet_sequence_id
|
|
packet.track_descriptor.counter.type = self.prototypes.CounterDescriptor \
|
|
.BuiltinCounterType \
|
|
.COUNTER_THREAD_TIME_NS
|
|
return packet
|
|
|
|
def add_chrome_thread_with_cpu_counter(self,
|
|
process_track,
|
|
thread_track,
|
|
trusted_packet_sequence_id=None,
|
|
counter_track=None,
|
|
pid=None,
|
|
tid=None,
|
|
thread_type=None):
|
|
self.add_chrome_thread_track_descriptor(
|
|
process_track,
|
|
thread_track,
|
|
trusted_packet_sequence_id=trusted_packet_sequence_id,
|
|
pid=pid,
|
|
tid=tid,
|
|
thread_type=thread_type)
|
|
self.add_trace_packet_defaults(
|
|
trusted_packet_sequence_id=trusted_packet_sequence_id,
|
|
counter_track=counter_track,
|
|
thread_track=thread_track)
|
|
|
|
self.add_counter_track_descriptor(
|
|
trusted_packet_sequence_id=trusted_packet_sequence_id,
|
|
counter_track=counter_track,
|
|
thread_track=thread_track)
|
|
|
|
def add_track_event_slice_begin(self,
|
|
name,
|
|
ts,
|
|
track=None,
|
|
trusted_sequence_id=0,
|
|
cpu_time=None):
|
|
packet = self.add_track_event(
|
|
name,
|
|
ts=ts,
|
|
track=track,
|
|
trusted_sequence_id=trusted_sequence_id,
|
|
cpu_time=cpu_time)
|
|
packet.track_event.type = self.prototypes.TrackEvent.Type.TYPE_SLICE_BEGIN
|
|
return packet
|
|
|
|
def add_track_event_slice_end(self,
|
|
ts,
|
|
track=None,
|
|
trusted_sequence_id=0,
|
|
cpu_time=None):
|
|
packet = self.add_track_event(
|
|
ts=ts,
|
|
track=track,
|
|
trusted_sequence_id=trusted_sequence_id,
|
|
cpu_time=cpu_time)
|
|
packet.track_event.type = self.prototypes.TrackEvent.Type.TYPE_SLICE_END
|
|
return packet
|
|
|
|
# Returns the start slice packet.
|
|
def add_track_event_slice(self,
|
|
name,
|
|
ts,
|
|
dur,
|
|
track=None,
|
|
trusted_sequence_id=0,
|
|
cpu_start=None,
|
|
cpu_delta=None):
|
|
|
|
packet = self.add_track_event_slice_begin(
|
|
name,
|
|
ts,
|
|
track=track,
|
|
trusted_sequence_id=trusted_sequence_id,
|
|
cpu_time=cpu_start)
|
|
|
|
if dur >= 0:
|
|
cpu_end = cpu_start + cpu_delta if cpu_start is not None else None
|
|
self.add_track_event_slice_end(
|
|
ts + dur,
|
|
track=track,
|
|
trusted_sequence_id=trusted_sequence_id,
|
|
cpu_time=cpu_end)
|
|
|
|
return packet
|
|
|
|
def add_rail_mode_slice(self, ts, dur, track, mode):
|
|
packet = self.add_track_event_slice(
|
|
"Scheduler.RAILMode", ts=ts, dur=dur, track=track)
|
|
packet.track_event.chrome_renderer_scheduler_state.rail_mode = mode
|
|
|
|
def add_latency_info_flow(self,
|
|
ts,
|
|
dur,
|
|
track=None,
|
|
trusted_sequence_id=None,
|
|
trace_id=None,
|
|
flow_ids=[],
|
|
terminating_flow_ids=[]):
|
|
packet = self.add_track_event_slice(
|
|
"LatencyInfo.Flow",
|
|
ts,
|
|
dur,
|
|
track=track,
|
|
trusted_sequence_id=trusted_sequence_id)
|
|
if trace_id is not None:
|
|
packet.track_event.chrome_latency_info.trace_id = trace_id
|
|
for flow_id in flow_ids:
|
|
packet.track_event.flow_ids.append(flow_id)
|
|
for flow_id in terminating_flow_ids:
|
|
packet.track_event.terminating_flow_ids.append(flow_id)
|
|
return packet
|
|
|
|
def add_input_latency_event_slice(self,
|
|
name,
|
|
ts,
|
|
dur,
|
|
track=None,
|
|
trace_id=None,
|
|
gesture_scroll_id=None,
|
|
is_coalesced=None):
|
|
packet = self.add_track_event_slice(
|
|
"InputLatency::" + name, ts=ts, dur=dur, track=track)
|
|
packet.track_event.chrome_latency_info.trace_id = trace_id
|
|
packet.track_event.chrome_latency_info.gesture_scroll_id = gesture_scroll_id
|
|
if is_coalesced is not None:
|
|
packet.track_event.chrome_latency_info.is_coalesced = is_coalesced
|
|
return packet
|
|
|
|
def add_chrome_metadata(self, os_name=None):
|
|
metadata = self.add_packet().chrome_events.metadata.add()
|
|
if os_name is not None:
|
|
metadata.name = "os-name"
|
|
metadata.string_value = os_name
|
|
|
|
return metadata
|
|
|
|
def add_expected_display_frame_start_event(self, ts, cookie, token, pid):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
event = packet.frame_timeline_event.expected_display_frame_start
|
|
if token != -1:
|
|
event.cookie = cookie
|
|
event.token = token
|
|
event.pid = pid
|
|
|
|
def add_actual_display_frame_start_event(self, ts, cookie, token, pid,
|
|
present_type, on_time_finish,
|
|
gpu_composition, jank_type, prediction_type):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
event = packet.frame_timeline_event.actual_display_frame_start
|
|
if token != -1:
|
|
event.cookie = cookie
|
|
event.token = token
|
|
event.pid = pid
|
|
event.present_type = present_type
|
|
event.on_time_finish = on_time_finish
|
|
event.gpu_composition = gpu_composition
|
|
event.jank_type = jank_type
|
|
event.prediction_type = prediction_type
|
|
|
|
def add_expected_surface_frame_start_event(self, ts, cookie, token,
|
|
display_frame_token, pid,
|
|
layer_name):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
event = packet.frame_timeline_event.expected_surface_frame_start
|
|
if token != -1 and display_frame_token != -1:
|
|
event.cookie = cookie
|
|
event.token = token
|
|
event.display_frame_token = display_frame_token
|
|
event.pid = pid
|
|
event.layer_name = layer_name
|
|
|
|
def add_actual_surface_frame_start_event(self, ts, cookie, token,
|
|
display_frame_token, pid, layer_name,
|
|
present_type, on_time_finish,
|
|
gpu_composition, jank_type, prediction_type):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
event = packet.frame_timeline_event.actual_surface_frame_start
|
|
if token != -1 and display_frame_token != -1:
|
|
event.cookie = cookie
|
|
event.token = token
|
|
event.display_frame_token = display_frame_token
|
|
event.pid = pid
|
|
event.layer_name = layer_name
|
|
event.present_type = present_type
|
|
event.on_time_finish = on_time_finish
|
|
event.gpu_composition = gpu_composition
|
|
event.jank_type = jank_type
|
|
event.prediction_type = prediction_type
|
|
|
|
def add_frame_end_event(self, ts, cookie):
|
|
packet = self.add_packet()
|
|
packet.timestamp = ts
|
|
event = packet.frame_timeline_event.frame_end
|
|
event.cookie = cookie
|
|
|
|
|
|
def read_descriptor(file_name):
|
|
with open(file_name, 'rb') as f:
|
|
contents = f.read()
|
|
|
|
descriptor = descriptor_pb2.FileDescriptorSet()
|
|
descriptor.MergeFromString(contents)
|
|
|
|
return descriptor
|
|
|
|
|
|
def create_pool(args):
|
|
trace_descriptor = read_descriptor(args.trace_descriptor)
|
|
|
|
pool = descriptor_pool.DescriptorPool()
|
|
for file in trace_descriptor.file:
|
|
pool.Add(file)
|
|
|
|
return pool
|
|
|
|
|
|
def create_trace():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
'trace_descriptor', type=str, help='location of trace descriptor')
|
|
args = parser.parse_args()
|
|
|
|
pool = create_pool(args)
|
|
factory = message_factory.MessageFactory(pool)
|
|
ProtoTrace = factory.GetPrototype(
|
|
pool.FindMessageTypeByName('perfetto.protos.Trace'))
|
|
|
|
class EnumPrototype(object):
|
|
|
|
def from_descriptor(desc):
|
|
res = EnumPrototype()
|
|
for desc in desc.values:
|
|
setattr(res, desc.name, desc.number)
|
|
return res
|
|
|
|
Prototypes = namedtuple('Prototypes', [
|
|
'TrackEvent',
|
|
'ChromeRAILMode',
|
|
'ThreadDescriptor',
|
|
'ChromeProcessDescriptor',
|
|
'CounterDescriptor',
|
|
])
|
|
prototypes = Prototypes(
|
|
TrackEvent=factory.GetPrototype(
|
|
pool.FindMessageTypeByName('perfetto.protos.TrackEvent')),
|
|
ChromeRAILMode=EnumPrototype.from_descriptor(
|
|
pool.FindEnumTypeByName('perfetto.protos.ChromeRAILMode')),
|
|
ThreadDescriptor=factory.GetPrototype(
|
|
pool.FindMessageTypeByName('perfetto.protos.ThreadDescriptor')),
|
|
ChromeProcessDescriptor=factory.GetPrototype(
|
|
pool.FindMessageTypeByName(
|
|
'perfetto.protos.ChromeProcessDescriptor')),
|
|
CounterDescriptor=factory.GetPrototype(
|
|
pool.FindMessageTypeByName('perfetto.protos.CounterDescriptor')),
|
|
)
|
|
return Trace(ProtoTrace(), prototypes)
|