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