• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# Copyright (C) 2018 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import argparse
17
18from collections import namedtuple
19from google.protobuf import descriptor_pb2, message_factory, descriptor_pool
20
21CLONE_THREAD = 0x00010000
22CLONE_VFORK = 0x00004000
23CLONE_VM = 0x00000100
24
25
26# For compatibility with older pb module versions.
27def get_message_class(pool, msg):
28  if hasattr(message_factory, "GetMessageClass"):
29    return message_factory.GetMessageClass(msg)
30  else:
31    return message_factory.MessageFactory(pool).GetPrototype(msg)
32
33
34def ms_to_ns(time_in_ms):
35  return int(time_in_ms * 1000000)
36
37
38def s_to_ns(time_in_s):
39  return int(time_in_s * 1000000000)
40
41
42class Trace(object):
43
44  def __init__(self, trace, prototypes):
45    self.trace = trace
46    self.prototypes = prototypes
47    self.proc_map = {}
48    self.proc_map[0] = 'idle_thread'
49
50  def add_system_info(self, arch="", fingerprint=""):
51    self.packet = self.trace.packet.add()
52    self.packet.system_info.utsname.machine = arch
53    self.packet.system_info.android_build_fingerprint = fingerprint
54
55  def add_ftrace_packet(self, cpu):
56    self.packet = self.trace.packet.add()
57    self.packet.ftrace_events.cpu = cpu
58
59  def add_packet(self, ts=None):
60    self.packet = self.trace.packet.add()
61    if ts is not None:
62      self.packet.timestamp = ts
63    return self.packet
64
65  def __add_ftrace_event(self, ts, tid):
66    ftrace = self.packet.ftrace_events.event.add()
67    ftrace.timestamp = ts
68    ftrace.pid = tid
69    return ftrace
70
71  def add_rss_stat(self, ts, tid, member, size, mm_id=None, curr=None):
72    ftrace = self.__add_ftrace_event(ts, tid)
73    rss_stat = ftrace.rss_stat
74    rss_stat.member = member
75    rss_stat.size = size
76    if mm_id is not None:
77      rss_stat.mm_id = mm_id
78    if curr is not None:
79      rss_stat.curr = curr
80
81  def add_ion_event(self, ts, tid, heap_name, len, size=0):
82    ftrace = self.__add_ftrace_event(ts, tid)
83    ion = ftrace.ion_heap_grow
84    ion.heap_name = heap_name
85    ion.len = len
86    ion.total_allocated = size
87
88  def add_oom_score_update(self, ts, oom_score_adj, pid):
89    ftrace = self.__add_ftrace_event(ts, pid)
90    oom_score = ftrace.oom_score_adj_update
91    oom_score.comm = self.proc_map[pid]
92    oom_score.oom_score_adj = oom_score_adj
93    oom_score.pid = pid
94
95  def add_sched(self,
96                ts,
97                prev_pid,
98                next_pid,
99                prev_comm=None,
100                next_comm=None,
101                prev_state=None):
102    ftrace = self.__add_ftrace_event(ts, 0)
103    ss = ftrace.sched_switch
104    ss.prev_comm = prev_comm or self.proc_map[prev_pid]
105    ss.prev_pid = prev_pid
106    ss.next_pid = next_pid
107    ss.next_comm = next_comm or self.proc_map[next_pid]
108    if prev_state:
109      if prev_state == 'R':
110        ss.prev_state = 0
111      elif prev_state == 'S':
112        ss.prev_state = 1
113      elif prev_state == 'U' or prev_state == 'D':
114        ss.prev_state = 2
115      else:
116        raise Exception('Invalid prev state {}'.format(prev_state))
117
118  def add_cpufreq(self, ts, freq, cpu):
119    ftrace = self.__add_ftrace_event(ts, 0)
120    cpufreq = ftrace.cpu_frequency
121    cpufreq.state = freq
122    cpufreq.cpu_id = cpu
123
124  def add_kernel_lmk(self, ts, tid):
125    ftrace = self.__add_ftrace_event(ts, tid)
126    lowmemory_kill = ftrace.lowmemory_kill
127    lowmemory_kill.pid = tid
128
129  def add_sys_enter(self, ts, tid, id):
130    ftrace = self.__add_ftrace_event(ts, tid)
131    sys_enter = ftrace.sys_enter
132    sys_enter.id = id
133
134  def add_sys_exit(self, ts, tid, id, ret):
135    ftrace = self.__add_ftrace_event(ts, tid)
136    sys_exit = ftrace.sys_exit
137    sys_exit.id = id
138    sys_exit.ret = ret
139
140  def add_newtask(self, ts, tid, new_tid, new_comm, flags):
141    ftrace = self.__add_ftrace_event(ts, tid)
142    newtask = ftrace.task_newtask
143    newtask.pid = new_tid
144    newtask.comm = new_comm
145    newtask.clone_flags = flags
146
147  def add_process_free(self, ts, tid, comm, prio):
148    ftrace = self.__add_ftrace_event(ts, tid)
149    sched_process_free = ftrace.sched_process_free
150    sched_process_free.pid = tid
151    sched_process_free.comm = comm
152    sched_process_free.prio = prio
153
154  def add_rename(self, ts, tid, old_comm, new_comm, oom_score_adj):
155    ftrace = self.__add_ftrace_event(ts, tid)
156    task_rename = ftrace.task_rename
157    task_rename.pid = tid
158    task_rename.oldcomm = old_comm
159    task_rename.newcomm = new_comm
160    task_rename.oom_score_adj = oom_score_adj
161
162  def add_print(self, ts, tid, buf):
163    ftrace = self.__add_ftrace_event(ts, tid)
164    print_event = getattr(ftrace, 'print')
165    print_event.buf = buf
166
167  def add_kmalloc(self, ts, tid, bytes_alloc, bytes_req, call_site, gfp_flags,
168                  ptr):
169    ftrace = self.__add_ftrace_event(ts, tid)
170    kmalloc = ftrace.kmalloc
171    kmalloc.bytes_alloc = bytes_alloc
172    kmalloc.bytes_req = bytes_req
173    kmalloc.call_site = call_site
174    kmalloc.gfp_flags = gfp_flags
175    kmalloc.ptr = ptr
176
177  def add_kfree(self, ts, tid, call_site, ptr):
178    ftrace = self.__add_ftrace_event(ts, tid)
179    kfree = ftrace.kfree
180    kfree.call_site = call_site
181    kfree.ptr = ptr
182
183  def add_atrace_counter(self, ts, pid, tid, buf, cnt):
184    self.add_print(ts, tid, 'C|{}|{}|{}'.format(pid, buf, cnt))
185
186  def add_atrace_begin(self, ts, tid, pid, buf):
187    self.add_print(ts, tid, 'B|{}|{}'.format(pid, buf))
188
189  def add_atrace_end(self, ts, tid, pid):
190    self.add_print(ts, tid, 'E|{}'.format(pid))
191
192  def add_atrace_async_begin(self, ts, tid, pid, buf):
193    self.add_print(ts, tid, 'S|{}|{}|0'.format(pid, buf))
194
195  def add_atrace_async_end(self, ts, tid, pid, buf):
196    self.add_print(ts, tid, 'F|{}|{}|0'.format(pid, buf))
197
198  def add_atrace_instant(self, ts, tid, pid, buf):
199    self.add_print(ts, tid, 'I|{}|{}'.format(pid, buf))
200
201  def add_atrace_instant_for_track(self, ts, tid, pid, track_name, buf):
202        self.add_print(ts, tid, 'N|{}|{}|{}'.format(pid, track_name, buf))
203
204  def add_process(self, pid, ppid, cmdline, uid=None):
205    process = self.packet.process_tree.processes.add()
206    process.pid = pid
207    process.ppid = ppid
208    process.cmdline.append(cmdline)
209    if uid is not None:
210      process.uid = uid
211    self.proc_map[pid] = cmdline
212
213  def add_thread(self, tid, tgid, cmdline, name=None):
214    thread = self.packet.process_tree.threads.add()
215    thread.tid = tid
216    thread.tgid = tgid
217    if name is not None:
218      thread.name = name
219    self.proc_map[tid] = cmdline
220
221  def add_battery_counters(self, ts, charge_uah, cap_prct, curr_ua, curr_avg_ua,
222                           voltage_uv):
223    self.packet = self.trace.packet.add()
224    self.packet.timestamp = ts
225    battery_count = self.packet.battery
226    battery_count.charge_counter_uah = charge_uah
227    battery_count.capacity_percent = cap_prct
228    battery_count.current_ua = curr_ua
229    battery_count.current_avg_ua = curr_avg_ua
230    battery_count.voltage_uv = voltage_uv
231
232  def add_binder_transaction(self, transaction_id, ts_start, ts_end, tid, pid,
233                             reply_id, reply_ts_start, reply_ts_end, reply_tid,
234                             reply_pid):
235    # Binder transaction start.
236    ftrace = self.__add_ftrace_event(ts_start, tid)
237    binder_transaction = ftrace.binder_transaction
238    binder_transaction.debug_id = transaction_id
239    binder_transaction.to_proc = reply_pid
240    binder_transaction.to_thread = reply_tid
241    binder_transaction.reply = False
242
243    # Binder reply start
244    ftrace = self.__add_ftrace_event(reply_ts_start, reply_tid)
245    binder_transaction_received = ftrace.binder_transaction_received
246    binder_transaction_received.debug_id = transaction_id
247
248    # Binder reply finish
249    ftrace = self.__add_ftrace_event(reply_ts_end, reply_tid)
250    reply_binder_transaction = ftrace.binder_transaction
251    reply_binder_transaction.debug_id = reply_id
252    reply_binder_transaction.to_proc = pid
253    reply_binder_transaction.to_thread = tid
254    reply_binder_transaction.reply = True
255
256    # Binder transaction finish
257    ftrace = self.__add_ftrace_event(ts_end, tid)
258    reply_binder_transaction_received = ftrace.binder_transaction_received
259    reply_binder_transaction_received.debug_id = reply_id
260
261  def add_battery_counters_no_curr_ua(self, ts, charge_uah, cap_prct,
262                                      curr_avg_ua, voltage_uv):
263    self.packet = self.trace.packet.add()
264    self.packet.timestamp = ts
265    battery_count = self.packet.battery
266    battery_count.charge_counter_uah = charge_uah
267    battery_count.capacity_percent = cap_prct
268    battery_count.current_avg_ua = curr_avg_ua
269    battery_count.voltage_uv = voltage_uv
270
271  def add_power_rails_desc(self, index_val, name):
272    power_rails = self.packet.power_rails
273    descriptor = power_rails.rail_descriptor.add()
274    descriptor.index = index_val
275    descriptor.rail_name = name
276
277  def add_power_rails_data(self, ts, index_val, value):
278    power_rails = self.packet.power_rails
279    energy_data = power_rails.energy_data.add()
280    energy_data.index = index_val
281    energy_data.timestamp_ms = ts
282    energy_data.energy = value
283
284  def add_package_list(self, ts, name, uid, version_code):
285    packet = self.add_packet()
286    packet.timestamp = ts
287    plist = packet.packages_list
288    pinfo = plist.packages.add()
289    pinfo.name = name
290    pinfo.uid = uid
291    pinfo.version_code = version_code
292
293  def add_debuggable_package_list(self, ts, name, uid, version_code):
294    packet = self.add_packet()
295    packet.timestamp = ts
296    plist = packet.packages_list
297    pinfo = plist.packages.add()
298    pinfo.name = name
299    pinfo.uid = uid
300    pinfo.version_code = version_code
301    pinfo.debuggable = True
302
303  def add_profile_packet(self, ts):
304    packet = self.add_packet()
305    packet.timestamp = ts
306    return packet.profile_packet
307
308  def add_clock_snapshot(self, clocks, seq_id=None):
309    packet = self.add_packet()
310    if seq_id is not None:
311      packet.trusted_packet_sequence_id = seq_id
312    snap = self.packet.clock_snapshot
313    for k, v in clocks.items():
314      clock = snap.clocks.add()
315      clock.clock_id = k
316      clock.timestamp = v
317
318  def add_gpu_counter_spec(self,
319                           ts,
320                           counter_id,
321                           name,
322                           description=None,
323                           unit_numerators=[],
324                           unit_denominators=[]):
325    packet = self.add_packet()
326    packet.timestamp = ts
327    gpu_counters = packet.gpu_counter_event
328    counter_desc = gpu_counters.counter_descriptor
329    spec = counter_desc.specs.add()
330    spec.counter_id = counter_id
331    spec.name = name
332    if description is not None:
333      spec.description = description
334    spec.numerator_units.extend(unit_numerators)
335    spec.denominator_units.extend(unit_denominators)
336
337  def add_gpu_counter(self, ts, counter_id, value, clock_id=None, seq_id=None):
338    packet = self.add_packet()
339    packet.timestamp = ts
340    if clock_id is not None:
341      packet.timestamp_clock_id = clock_id
342    if seq_id is not None:
343      packet.trusted_packet_sequence_id = seq_id
344    gpu_counters = self.packet.gpu_counter_event
345    gpu_counter = gpu_counters.counters.add()
346    gpu_counter.counter_id = counter_id
347    gpu_counter.int_value = value
348
349  def add_gpu_render_stages_hw_queue_spec(self, specs=[]):
350    packet = self.add_packet()
351    spec = self.packet.gpu_render_stage_event.specifications
352    for s in specs:
353      hw_queue = spec.hw_queue.add()
354      hw_queue.name = s.get('name', '')
355      if 'description' in s:
356        hw_queue.description = s['description']
357
358  def add_gpu_render_stages_stage_spec(self, specs=[]):
359    packet = self.add_packet()
360    spec = self.packet.gpu_render_stage_event.specifications
361    for s in specs:
362      stage = spec.stage.add()
363      stage.name = s.get('name', '')
364      if 'description' in s:
365        stage.description = s['description']
366
367  def add_gpu_render_stages(self,
368                            ts,
369                            event_id,
370                            duration,
371                            hw_queue_id,
372                            stage_id,
373                            context,
374                            render_target_handle=None,
375                            render_pass_handle=None,
376                            render_subpass_index_mask=None,
377                            command_buffer_handle=None,
378                            submission_id=None,
379                            extra_data={}):
380    packet = self.add_packet()
381    packet.timestamp = ts
382    render_stage = self.packet.gpu_render_stage_event
383    render_stage.event_id = event_id
384    render_stage.duration = duration
385    render_stage.hw_queue_id = hw_queue_id
386    render_stage.stage_id = stage_id
387    render_stage.context = context
388    if render_target_handle is not None:
389      render_stage.render_target_handle = render_target_handle
390    if render_pass_handle is not None:
391      render_stage.render_pass_handle = render_pass_handle
392    if render_subpass_index_mask is not None:
393      for mask in render_subpass_index_mask:
394        render_stage.render_subpass_index_mask.append(mask)
395    if command_buffer_handle is not None:
396      render_stage.command_buffer_handle = command_buffer_handle
397    if submission_id is not None:
398      render_stage.submission_id = submission_id
399    for key, value in extra_data.items():
400      data = render_stage.extra_data.add()
401      data.name = key
402      if value is not None:
403        data.value = value
404
405  def add_vk_debug_marker(self, ts, pid, vk_device, obj_type, obj, obj_name):
406    packet = self.add_packet()
407    packet.timestamp = ts
408    debug_marker = (self.packet.vulkan_api_event.vk_debug_utils_object_name)
409    debug_marker.pid = pid
410    debug_marker.vk_device = vk_device
411    debug_marker.object_type = obj_type
412    debug_marker.object = obj
413    debug_marker.object_name = obj_name
414
415  def add_vk_queue_submit(self, ts, dur, pid, tid, vk_queue, vk_command_buffers,
416                          submission_id):
417    packet = self.add_packet()
418    packet.timestamp = ts
419    submit = (self.packet.vulkan_api_event.vk_queue_submit)
420    submit.duration_ns = dur
421    submit.pid = pid
422    submit.tid = tid
423    for cmd in vk_command_buffers:
424      submit.vk_command_buffers.append(cmd)
425    submit.submission_id = submission_id
426
427  def add_gpu_log(self, ts, severity, tag, message):
428    packet = self.add_packet()
429    packet.timestamp = ts
430    gpu_log = self.packet.gpu_log
431    gpu_log.severity = severity
432    gpu_log.tag = tag
433    gpu_log.log_message = message
434
435  def add_buffer_event_packet(self, ts, buffer_id, layer_name, frame_number,
436                              event_type, duration):
437    packet = self.add_packet()
438    packet.timestamp = ts
439    buffer_event = packet.graphics_frame_event.buffer_event
440    if buffer_id >= 0:
441      buffer_event.buffer_id = buffer_id
442    buffer_event.layer_name = layer_name
443    buffer_event.frame_number = frame_number
444    if event_type >= 0:
445      buffer_event.type = event_type
446    buffer_event.duration_ns = duration
447
448  def add_cpu(self, freqs):
449    cpu = self.packet.cpu_info.cpus.add()
450    for freq in freqs:
451      cpu.frequencies.append(freq)
452
453  def add_process_stats(self, pid, freqs):
454    process = self.packet.process_stats.processes.add()
455    process.pid = pid
456    thread = process.threads.add()
457    thread.tid = pid * 10
458    for index in freqs:
459      thread.cpu_freq_indices.append(index)
460      thread.cpu_freq_ticks.append(freqs[index])
461
462  def add_gpu_mem_total_ftrace_event(self, ftrace_pid, pid, ts, size):
463    ftrace = self.__add_ftrace_event(ts, ftrace_pid)
464    gpu_mem_total_ftrace_event = ftrace.gpu_mem_total
465    gpu_mem_total_ftrace_event.pid = pid
466    gpu_mem_total_ftrace_event.size = size
467
468  def add_gpu_mem_total_event(self, pid, ts, size):
469    packet = self.add_packet()
470    packet.timestamp = ts
471    gpu_mem_total_event = packet.gpu_mem_total_event
472    gpu_mem_total_event.pid = pid
473    gpu_mem_total_event.size = size
474
475  def add_sched_blocked_reason(self, ts, pid, io_wait, unblock_pid):
476    ftrace = self.__add_ftrace_event(ts, unblock_pid)
477    sched_blocked_reason = ftrace.sched_blocked_reason
478    sched_blocked_reason.pid = pid
479    sched_blocked_reason.io_wait = io_wait
480
481  def add_track_event(self,
482                      name=None,
483                      ts=None,
484                      track=None,
485                      trusted_sequence_id=0,
486                      cpu_time=None):
487    packet = self.add_packet(ts=ts)
488    if name is not None:
489      packet.track_event.name = name
490    if track is not None:
491      packet.track_event.track_uuid = track
492    packet.trusted_packet_sequence_id = trusted_sequence_id
493    if cpu_time is not None:
494      packet.track_event.extra_counter_values.append(cpu_time)
495    return packet
496
497  def add_track_descriptor(self, uuid, parent=None):
498    packet = self.add_packet()
499    track_descriptor = packet.track_descriptor
500    if uuid is not None:
501      track_descriptor.uuid = uuid
502    if parent is not None:
503      track_descriptor.parent_uuid = parent
504    return packet
505
506  def add_process_track_descriptor(self,
507                                   process_track,
508                                   pid=None,
509                                   process_name=None):
510    packet = self.add_track_descriptor(process_track)
511    if pid is not None:
512      packet.track_descriptor.process.pid = pid
513    if process_name is not None:
514      packet.track_descriptor.process.process_name = process_name
515    return packet
516
517  def add_chrome_process_track_descriptor(
518      self,
519      process_track,
520      pid=None,
521      process_type=None,
522      host_app_package_name="org.chromium.chrome"):
523    if process_type is None:
524      process_type = self.prototypes.ChromeProcessDescriptor \
525        .ProcessType \
526        .PROCESS_RENDERER
527
528    packet = self.add_process_track_descriptor(process_track, pid=pid)
529    chrome_process = packet.track_descriptor.chrome_process
530    chrome_process.process_type = process_type
531    chrome_process.host_app_package_name = host_app_package_name
532    return packet
533
534  def add_thread_track_descriptor(self,
535                                  process_track,
536                                  thread_track,
537                                  trusted_packet_sequence_id=None,
538                                  pid=None,
539                                  tid=None,
540                                  thread_name=None):
541    packet = self.add_track_descriptor(thread_track, parent=process_track)
542    if trusted_packet_sequence_id is not None:
543      packet.trusted_packet_sequence_id = trusted_packet_sequence_id
544    if pid is not None:
545      packet.track_descriptor.thread.pid = pid
546    if tid is not None:
547      packet.track_descriptor.thread.tid = tid
548    if thread_name is not None:
549      packet.track_descriptor.thread.thread_name = thread_name
550    return packet
551
552  def add_chrome_thread_track_descriptor(self,
553                                         process_track,
554                                         thread_track,
555                                         trusted_packet_sequence_id=None,
556                                         pid=None,
557                                         tid=None,
558                                         thread_type=None):
559    if thread_type is None:
560      thread_type = self.prototypes.ThreadDescriptor \
561        .ChromeThreadType \
562        .CHROME_THREAD_TYPE_UNSPECIFIED
563
564    packet = self.add_thread_track_descriptor(
565        process_track,
566        thread_track,
567        trusted_packet_sequence_id=trusted_packet_sequence_id,
568        pid=pid,
569        tid=tid)
570    packet.track_descriptor.thread.chrome_thread_type = thread_type
571    return packet
572
573  def add_trace_packet_defaults(self,
574                                trusted_packet_sequence_id=None,
575                                thread_track=None,
576                                counter_track=None):
577    packet = self.add_track_descriptor(None)
578    packet.trusted_packet_sequence_id = trusted_packet_sequence_id
579    track_event_defaults = packet.trace_packet_defaults.track_event_defaults
580    track_event_defaults.track_uuid = thread_track
581    track_event_defaults.extra_counter_track_uuids.append(counter_track)
582    return packet
583
584  def add_counter_track_descriptor(self,
585                                   trusted_packet_sequence_id=None,
586                                   thread_track=None,
587                                   counter_track=None):
588    packet = self.add_track_descriptor(counter_track, parent=thread_track)
589    packet.trusted_packet_sequence_id = trusted_packet_sequence_id
590    packet.track_descriptor.counter.type = self.prototypes.CounterDescriptor \
591      .BuiltinCounterType \
592      .COUNTER_THREAD_TIME_NS
593    return packet
594
595  def add_chrome_thread_with_cpu_counter(self,
596                                         process_track,
597                                         thread_track,
598                                         trusted_packet_sequence_id=None,
599                                         counter_track=None,
600                                         pid=None,
601                                         tid=None,
602                                         thread_type=None):
603    self.add_chrome_thread_track_descriptor(
604        process_track,
605        thread_track,
606        trusted_packet_sequence_id=trusted_packet_sequence_id,
607        pid=pid,
608        tid=tid,
609        thread_type=thread_type)
610    self.add_trace_packet_defaults(
611        trusted_packet_sequence_id=trusted_packet_sequence_id,
612        counter_track=counter_track,
613        thread_track=thread_track)
614
615    self.add_counter_track_descriptor(
616        trusted_packet_sequence_id=trusted_packet_sequence_id,
617        counter_track=counter_track,
618        thread_track=thread_track)
619
620  def add_track_event_slice_begin(self,
621                                  name,
622                                  ts,
623                                  track=None,
624                                  trusted_sequence_id=0,
625                                  cpu_time=None):
626    packet = self.add_track_event(
627        name,
628        ts=ts,
629        track=track,
630        trusted_sequence_id=trusted_sequence_id,
631        cpu_time=cpu_time)
632    packet.track_event.type = self.prototypes.TrackEvent.Type.TYPE_SLICE_BEGIN
633    return packet
634
635  def add_track_event_slice_end(self,
636                                ts,
637                                track=None,
638                                trusted_sequence_id=0,
639                                cpu_time=None):
640    packet = self.add_track_event(
641        ts=ts,
642        track=track,
643        trusted_sequence_id=trusted_sequence_id,
644        cpu_time=cpu_time)
645    packet.track_event.type = self.prototypes.TrackEvent.Type.TYPE_SLICE_END
646    return packet
647
648  # Returns the start slice packet.
649  def add_track_event_slice(self,
650                            name,
651                            ts,
652                            dur,
653                            track=None,
654                            trusted_sequence_id=0,
655                            cpu_start=None,
656                            cpu_delta=None):
657
658    packet = self.add_track_event_slice_begin(
659        name,
660        ts,
661        track=track,
662        trusted_sequence_id=trusted_sequence_id,
663        cpu_time=cpu_start)
664
665    if dur >= 0:
666      cpu_end = cpu_start + cpu_delta if cpu_start is not None else None
667      self.add_track_event_slice_end(
668          ts + dur,
669          track=track,
670          trusted_sequence_id=trusted_sequence_id,
671          cpu_time=cpu_end)
672
673    return packet
674
675  def add_rail_mode_slice(self, ts, dur, track, mode):
676    packet = self.add_track_event_slice(
677        "Scheduler.RAILMode", ts=ts, dur=dur, track=track)
678    packet.track_event.chrome_renderer_scheduler_state.rail_mode = mode
679
680  def add_latency_info_flow(self,
681                            ts,
682                            dur,
683                            track=None,
684                            trusted_sequence_id=None,
685                            trace_id=None,
686                            step=None,
687                            flow_ids=[],
688                            terminating_flow_ids=[]):
689    packet = self.add_track_event_slice(
690        "LatencyInfo.Flow",
691        ts,
692        dur,
693        track=track,
694        trusted_sequence_id=trusted_sequence_id)
695    if trace_id is not None:
696      packet.track_event.chrome_latency_info.trace_id = trace_id
697    if step is not None:
698      packet.track_event.chrome_latency_info.step = step
699    for flow_id in flow_ids:
700      packet.track_event.flow_ids.append(flow_id)
701    for flow_id in terminating_flow_ids:
702      packet.track_event.terminating_flow_ids.append(flow_id)
703    return packet
704
705  def add_input_latency_event_slice(self,
706                                    name,
707                                    ts,
708                                    dur,
709                                    track=None,
710                                    trace_id=None,
711                                    gesture_scroll_id=None,
712                                    touch_id=None,
713                                    is_coalesced=None,
714                                    gets_to_gpu=True):
715    packet = self.add_track_event_slice(
716        "InputLatency::" + name, ts=ts, dur=dur, track=track)
717    latency_info = packet.track_event.chrome_latency_info
718    latency_info.trace_id = trace_id
719    if gesture_scroll_id is not None:
720      latency_info.gesture_scroll_id = gesture_scroll_id
721    if touch_id is not None:
722      latency_info.touch_id = touch_id
723    if gets_to_gpu:
724      component = latency_info.component_info.add()
725      component.component_type = self.prototypes \
726          .ChromeLatencyInfo.ComponentType \
727          .COMPONENT_INPUT_EVENT_GPU_SWAP_BUFFER
728    if is_coalesced is not None:
729      latency_info.is_coalesced = is_coalesced
730    return packet
731
732  def add_chrome_metadata(self, os_name=None):
733    metadata = self.add_packet().chrome_events.metadata.add()
734    if os_name is not None:
735      metadata.name = "os-name"
736      metadata.string_value = os_name
737
738    return metadata
739
740  def add_expected_display_frame_start_event(self, ts, cookie, token, pid):
741    packet = self.add_packet()
742    packet.timestamp = ts
743    event = packet.frame_timeline_event.expected_display_frame_start
744    if token != -1:
745      event.cookie = cookie
746      event.token = token
747      event.pid = pid
748
749  def add_actual_display_frame_start_event(self, ts, cookie, token, pid,
750                                           present_type, on_time_finish,
751                                           gpu_composition, jank_type,
752                                           prediction_type):
753    packet = self.add_packet()
754    packet.timestamp = ts
755    event = packet.frame_timeline_event.actual_display_frame_start
756    if token != -1:
757      event.cookie = cookie
758      event.token = token
759      event.pid = pid
760      event.present_type = present_type
761      event.on_time_finish = on_time_finish
762      event.gpu_composition = gpu_composition
763      event.jank_type = jank_type
764      event.prediction_type = prediction_type
765
766  def add_expected_surface_frame_start_event(self, ts, cookie, token,
767                                             display_frame_token, pid,
768                                             layer_name):
769    packet = self.add_packet()
770    packet.timestamp = ts
771    event = packet.frame_timeline_event.expected_surface_frame_start
772    if token != -1 and display_frame_token != -1:
773      event.cookie = cookie
774      event.token = token
775      event.display_frame_token = display_frame_token
776      event.pid = pid
777      event.layer_name = layer_name
778
779  def add_actual_surface_frame_start_event(self,
780                                           ts,
781                                           cookie,
782                                           token,
783                                           display_frame_token,
784                                           pid,
785                                           layer_name,
786                                           present_type,
787                                           on_time_finish,
788                                           gpu_composition,
789                                           jank_type,
790                                           prediction_type,
791                                           jank_severity_type=None):
792    packet = self.add_packet()
793    packet.timestamp = ts
794    event = packet.frame_timeline_event.actual_surface_frame_start
795    if token != -1 and display_frame_token != -1:
796      event.cookie = cookie
797      event.token = token
798      event.display_frame_token = display_frame_token
799      event.pid = pid
800      event.layer_name = layer_name
801      event.present_type = present_type
802      event.on_time_finish = on_time_finish
803      event.gpu_composition = gpu_composition
804      event.jank_type = jank_type
805      # jank severity type is not available on every trace.
806      # When not set, default to none if no jank; otherwise default to unknown
807      if jank_severity_type is None:
808        event.jank_severity_type = 1 if event.jank_type == 1 else 0
809      else:
810        event.jank_severity_type = jank_severity_type
811      event.prediction_type = prediction_type
812
813  def add_frame_end_event(self, ts, cookie):
814    packet = self.add_packet()
815    packet.timestamp = ts
816    event = packet.frame_timeline_event.frame_end
817    event.cookie = cookie
818
819
820def read_descriptor(file_name):
821  with open(file_name, 'rb') as f:
822    contents = f.read()
823
824  descriptor = descriptor_pb2.FileDescriptorSet()
825  descriptor.MergeFromString(contents)
826
827  return descriptor
828
829
830def create_pool(args):
831  trace_descriptor = read_descriptor(args.trace_descriptor)
832
833  pool = descriptor_pool.DescriptorPool()
834  for file in trace_descriptor.file:
835    pool.Add(file)
836
837  return pool
838
839
840def create_trace():
841  parser = argparse.ArgumentParser()
842  parser.add_argument(
843      'trace_descriptor', type=str, help='location of trace descriptor')
844  args = parser.parse_args()
845
846  pool = create_pool(args)
847  ProtoTrace = get_message_class(
848      pool, pool.FindMessageTypeByName('perfetto.protos.Trace'))
849
850  class EnumPrototype(object):
851
852    def from_descriptor(desc):
853      res = EnumPrototype()
854      for desc in desc.values:
855        setattr(res, desc.name, desc.number)
856      return res
857
858  ChromeLatencyInfo = namedtuple('ChromeLatencyInfo', [
859      'ComponentType',
860      'Step',
861  ])
862
863  Prototypes = namedtuple('Prototypes', [
864      'TrackEvent',
865      'ChromeRAILMode',
866      'ChromeLatencyInfo',
867      'ChromeProcessDescriptor',
868      'CounterDescriptor',
869      'ThreadDescriptor',
870  ])
871
872  chrome_latency_info_prototypes = ChromeLatencyInfo(
873      ComponentType=EnumPrototype.from_descriptor(
874          pool.FindEnumTypeByName(
875              'perfetto.protos.ChromeLatencyInfo.LatencyComponentType')),
876      Step=EnumPrototype.from_descriptor(
877          pool.FindEnumTypeByName('perfetto.protos.ChromeLatencyInfo.Step')),
878  )
879
880  prototypes = Prototypes(
881      TrackEvent=get_message_class(
882          pool, pool.FindMessageTypeByName('perfetto.protos.TrackEvent')),
883      ChromeRAILMode=EnumPrototype.from_descriptor(
884          pool.FindEnumTypeByName('perfetto.protos.ChromeRAILMode')),
885      ChromeLatencyInfo=chrome_latency_info_prototypes,
886      ChromeProcessDescriptor=get_message_class(
887          pool,
888          pool.FindMessageTypeByName(
889              'perfetto.protos.ChromeProcessDescriptor')),
890      CounterDescriptor=get_message_class(
891          pool,
892          pool.FindMessageTypeByName('perfetto.protos.CounterDescriptor')),
893      ThreadDescriptor=get_message_class(
894          pool, pool.FindMessageTypeByName('perfetto.protos.ThreadDescriptor')),
895  )
896  return Trace(ProtoTrace(), prototypes)
897