• 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':
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_profile_packet(self, ts):
281    packet = self.add_packet()
282    packet.timestamp = ts
283    return packet.profile_packet
284
285  def add_clock_snapshot(self, clocks, seq_id=None):
286    packet = self.add_packet()
287    if seq_id is not None:
288      packet.trusted_packet_sequence_id = seq_id
289    snap = self.packet.clock_snapshot
290    for k, v in clocks.items():
291      clock = snap.clocks.add()
292      clock.clock_id = k
293      clock.timestamp = v
294
295  def add_gpu_counter_spec(self,
296                           ts,
297                           counter_id,
298                           name,
299                           description=None,
300                           unit_numerators=[],
301                           unit_denominators=[]):
302    packet = self.add_packet()
303    packet.timestamp = ts
304    gpu_counters = packet.gpu_counter_event
305    counter_desc = gpu_counters.counter_descriptor
306    spec = counter_desc.specs.add()
307    spec.counter_id = counter_id
308    spec.name = name
309    if description is not None:
310      spec.description = description
311    spec.numerator_units.extend(unit_numerators)
312    spec.denominator_units.extend(unit_denominators)
313
314  def add_gpu_counter(self, ts, counter_id, value, clock_id=None, seq_id=None):
315    packet = self.add_packet()
316    packet.timestamp = ts
317    if clock_id is not None:
318      packet.timestamp_clock_id = clock_id
319    if seq_id is not None:
320      packet.trusted_packet_sequence_id = seq_id
321    gpu_counters = self.packet.gpu_counter_event
322    gpu_counter = gpu_counters.counters.add()
323    gpu_counter.counter_id = counter_id
324    gpu_counter.int_value = value
325
326  def add_gpu_render_stages_hw_queue_spec(self, specs=[]):
327    packet = self.add_packet()
328    spec = self.packet.gpu_render_stage_event.specifications
329    for s in specs:
330      hw_queue = spec.hw_queue.add()
331      hw_queue.name = s.get('name', '')
332      if 'description' in s:
333        hw_queue.description = s['description']
334
335  def add_gpu_render_stages_stage_spec(self, specs=[]):
336    packet = self.add_packet()
337    spec = self.packet.gpu_render_stage_event.specifications
338    for s in specs:
339      stage = spec.stage.add()
340      stage.name = s.get('name', '')
341      if 'description' in s:
342        stage.description = s['description']
343
344  def add_gpu_render_stages(self,
345                            ts,
346                            event_id,
347                            duration,
348                            hw_queue_id,
349                            stage_id,
350                            context,
351                            render_target_handle=None,
352                            render_pass_handle=None,
353                            render_subpass_index_mask=None,
354                            command_buffer_handle=None,
355                            submission_id=None,
356                            extra_data={}):
357    packet = self.add_packet()
358    packet.timestamp = ts
359    render_stage = self.packet.gpu_render_stage_event
360    render_stage.event_id = event_id
361    render_stage.duration = duration
362    render_stage.hw_queue_id = hw_queue_id
363    render_stage.stage_id = stage_id
364    render_stage.context = context
365    if render_target_handle is not None:
366      render_stage.render_target_handle = render_target_handle
367    if render_pass_handle is not None:
368      render_stage.render_pass_handle = render_pass_handle
369    if render_subpass_index_mask is not None:
370      for mask in render_subpass_index_mask:
371        render_stage.render_subpass_index_mask.append(mask)
372    if command_buffer_handle is not None:
373      render_stage.command_buffer_handle = command_buffer_handle
374    if submission_id is not None:
375      render_stage.submission_id = submission_id
376    for key, value in extra_data.items():
377      data = render_stage.extra_data.add()
378      data.name = key
379      if value is not None:
380        data.value = value
381
382  def add_vk_debug_marker(self, ts, pid, vk_device, obj_type, obj, obj_name):
383    packet = self.add_packet()
384    packet.timestamp = ts
385    debug_marker = (self.packet.vulkan_api_event.vk_debug_utils_object_name)
386    debug_marker.pid = pid
387    debug_marker.vk_device = vk_device
388    debug_marker.object_type = obj_type
389    debug_marker.object = obj
390    debug_marker.object_name = obj_name
391
392  def add_vk_queue_submit(self, ts, dur, pid, tid, vk_queue, vk_command_buffers,
393                          submission_id):
394    packet = self.add_packet()
395    packet.timestamp = ts
396    submit = (self.packet.vulkan_api_event.vk_queue_submit)
397    submit.duration_ns = dur
398    submit.pid = pid
399    submit.tid = tid
400    for cmd in vk_command_buffers:
401      submit.vk_command_buffers.append(cmd)
402    submit.submission_id = submission_id
403
404  def add_gpu_log(self, ts, severity, tag, message):
405    packet = self.add_packet()
406    packet.timestamp = ts
407    gpu_log = self.packet.gpu_log
408    gpu_log.severity = severity
409    gpu_log.tag = tag
410    gpu_log.log_message = message
411
412  def add_buffer_event_packet(self, ts, buffer_id, layer_name, frame_number,
413                              event_type, duration):
414    packet = self.add_packet()
415    packet.timestamp = ts
416    buffer_event = packet.graphics_frame_event.buffer_event
417    if buffer_id >= 0:
418      buffer_event.buffer_id = buffer_id
419    buffer_event.layer_name = layer_name
420    buffer_event.frame_number = frame_number
421    if event_type >= 0:
422      buffer_event.type = event_type
423    buffer_event.duration_ns = duration
424
425  def add_cpu(self, freqs):
426    cpu = self.packet.cpu_info.cpus.add()
427    for freq in freqs:
428      cpu.frequencies.append(freq)
429
430  def add_process_stats(self, pid, freqs):
431    process = self.packet.process_stats.processes.add()
432    process.pid = pid
433    thread = process.threads.add()
434    thread.tid = pid * 10
435    for index in freqs:
436      thread.cpu_freq_indices.append(index)
437      thread.cpu_freq_ticks.append(freqs[index])
438
439  def add_gpu_mem_total_ftrace_event(self, ftrace_pid, pid, ts, size):
440    ftrace = self.__add_ftrace_event(ts, ftrace_pid)
441    gpu_mem_total_ftrace_event = ftrace.gpu_mem_total
442    gpu_mem_total_ftrace_event.pid = pid
443    gpu_mem_total_ftrace_event.size = size
444
445  def add_gpu_mem_total_event(self, pid, ts, size):
446    packet = self.add_packet()
447    packet.timestamp = ts
448    gpu_mem_total_event = packet.gpu_mem_total_event
449    gpu_mem_total_event.pid = pid
450    gpu_mem_total_event.size = size
451
452  def add_sched_blocked_reason(self, ts, pid, io_wait, unblock_pid):
453    ftrace = self.__add_ftrace_event(ts, unblock_pid)
454    sched_blocked_reason = ftrace.sched_blocked_reason
455    sched_blocked_reason.pid = pid
456    sched_blocked_reason.io_wait = io_wait
457
458  def add_track_event(self,
459                      name=None,
460                      ts=None,
461                      track=None,
462                      trusted_sequence_id=0,
463                      cpu_time=None):
464    packet = self.add_packet(ts=ts)
465    if name is not None:
466      packet.track_event.name = name
467    if track is not None:
468      packet.track_event.track_uuid = track
469    packet.trusted_packet_sequence_id = trusted_sequence_id
470    if cpu_time is not None:
471      packet.track_event.extra_counter_values.append(cpu_time)
472    return packet
473
474  def add_track_descriptor(self, uuid, parent=None):
475    packet = self.add_packet()
476    track_descriptor = packet.track_descriptor
477    if uuid is not None:
478      track_descriptor.uuid = uuid
479    if parent is not None:
480      track_descriptor.parent_uuid = parent
481    return packet
482
483  def add_process_track_descriptor(self, process_track, pid=None):
484    packet = self.add_track_descriptor(process_track)
485    packet.track_descriptor.process.pid = pid
486    return packet
487
488  def add_chrome_process_track_descriptor(
489      self,
490      process_track,
491      pid=None,
492      process_type=None,
493      host_app_package_name="org.chromium.chrome"):
494    if process_type is None:
495      process_type = self.prototypes.ChromeProcessDescriptor \
496        .ProcessType \
497        .PROCESS_RENDERER
498
499    packet = self.add_process_track_descriptor(process_track, pid=pid)
500    chrome_process = packet.track_descriptor.chrome_process
501    chrome_process.process_type = process_type
502    chrome_process.host_app_package_name = host_app_package_name
503    return packet
504
505  def add_thread_track_descriptor(self,
506                                  process_track,
507                                  thread_track,
508                                  trusted_packet_sequence_id=None,
509                                  pid=None,
510                                  tid=None):
511    packet = self.add_track_descriptor(thread_track, parent=process_track)
512    packet.trusted_packet_sequence_id = trusted_packet_sequence_id
513    packet.track_descriptor.thread.pid = pid
514    packet.track_descriptor.thread.tid = tid
515    return packet
516
517  def add_chrome_thread_track_descriptor(self,
518                                         process_track,
519                                         thread_track,
520                                         trusted_packet_sequence_id=None,
521                                         pid=None,
522                                         tid=None,
523                                         thread_type=None):
524    if thread_type is None:
525      thread_type = self.prototypes.ThreadDescriptor \
526        .ChromeThreadType \
527        .CHROME_THREAD_TYPE_UNSPECIFIED
528
529    packet = self.add_thread_track_descriptor(
530        process_track,
531        thread_track,
532        trusted_packet_sequence_id=trusted_packet_sequence_id,
533        pid=pid,
534        tid=tid)
535    packet.track_descriptor.thread.chrome_thread_type = thread_type
536    return packet
537
538  def add_trace_packet_defaults(self,
539                                trusted_packet_sequence_id=None,
540                                thread_track=None,
541                                counter_track=None):
542    packet = self.add_track_descriptor(None)
543    packet.trusted_packet_sequence_id = trusted_packet_sequence_id
544    track_event_defaults = packet.trace_packet_defaults.track_event_defaults
545    track_event_defaults.track_uuid = thread_track
546    track_event_defaults.extra_counter_track_uuids.append(counter_track)
547    return packet
548
549  def add_counter_track_descriptor(self,
550                                   trusted_packet_sequence_id=None,
551                                   thread_track=None,
552                                   counter_track=None):
553    packet = self.add_track_descriptor(counter_track, parent=thread_track)
554    packet.trusted_packet_sequence_id = trusted_packet_sequence_id
555    packet.track_descriptor.counter.type = self.prototypes.CounterDescriptor \
556      .BuiltinCounterType \
557      .COUNTER_THREAD_TIME_NS
558    return packet
559
560  def add_chrome_thread_with_cpu_counter(self,
561                                         process_track,
562                                         thread_track,
563                                         trusted_packet_sequence_id=None,
564                                         counter_track=None,
565                                         pid=None,
566                                         tid=None,
567                                         thread_type=None):
568    self.add_chrome_thread_track_descriptor(
569        process_track,
570        thread_track,
571        trusted_packet_sequence_id=trusted_packet_sequence_id,
572        pid=pid,
573        tid=tid,
574        thread_type=thread_type)
575    self.add_trace_packet_defaults(
576        trusted_packet_sequence_id=trusted_packet_sequence_id,
577        counter_track=counter_track,
578        thread_track=thread_track)
579
580    self.add_counter_track_descriptor(
581        trusted_packet_sequence_id=trusted_packet_sequence_id,
582        counter_track=counter_track,
583        thread_track=thread_track)
584
585  def add_track_event_slice_begin(self,
586                                  name,
587                                  ts,
588                                  track=None,
589                                  trusted_sequence_id=0,
590                                  cpu_time=None):
591    packet = self.add_track_event(
592        name,
593        ts=ts,
594        track=track,
595        trusted_sequence_id=trusted_sequence_id,
596        cpu_time=cpu_time)
597    packet.track_event.type = self.prototypes.TrackEvent.Type.TYPE_SLICE_BEGIN
598    return packet
599
600  def add_track_event_slice_end(self,
601                                ts,
602                                track=None,
603                                trusted_sequence_id=0,
604                                cpu_time=None):
605    packet = self.add_track_event(
606        ts=ts,
607        track=track,
608        trusted_sequence_id=trusted_sequence_id,
609        cpu_time=cpu_time)
610    packet.track_event.type = self.prototypes.TrackEvent.Type.TYPE_SLICE_END
611    return packet
612
613  # Returns the start slice packet.
614  def add_track_event_slice(self,
615                            name,
616                            ts,
617                            dur,
618                            track=None,
619                            trusted_sequence_id=0,
620                            cpu_start=None,
621                            cpu_delta=None):
622
623    packet = self.add_track_event_slice_begin(
624        name,
625        ts,
626        track=track,
627        trusted_sequence_id=trusted_sequence_id,
628        cpu_time=cpu_start)
629
630    if dur >= 0:
631      cpu_end = cpu_start + cpu_delta if cpu_start is not None else None
632      self.add_track_event_slice_end(
633          ts + dur,
634          track=track,
635          trusted_sequence_id=trusted_sequence_id,
636          cpu_time=cpu_end)
637
638    return packet
639
640  def add_rail_mode_slice(self, ts, dur, track, mode):
641    packet = self.add_track_event_slice(
642        "Scheduler.RAILMode", ts=ts, dur=dur, track=track)
643    packet.track_event.chrome_renderer_scheduler_state.rail_mode = mode
644
645  def add_latency_info_flow(self,
646                            ts,
647                            dur,
648                            track=None,
649                            trusted_sequence_id=None,
650                            trace_id=None,
651                            step=None,
652                            flow_ids=[],
653                            terminating_flow_ids=[]):
654    packet = self.add_track_event_slice(
655        "LatencyInfo.Flow",
656        ts,
657        dur,
658        track=track,
659        trusted_sequence_id=trusted_sequence_id)
660    if trace_id is not None:
661      packet.track_event.chrome_latency_info.trace_id = trace_id
662    if step is not None:
663      packet.track_event.chrome_latency_info.step = step
664    for flow_id in flow_ids:
665      packet.track_event.flow_ids.append(flow_id)
666    for flow_id in terminating_flow_ids:
667      packet.track_event.terminating_flow_ids.append(flow_id)
668    return packet
669
670  def add_input_latency_event_slice(self,
671                                    name,
672                                    ts,
673                                    dur,
674                                    track=None,
675                                    trace_id=None,
676                                    gesture_scroll_id=None,
677                                    touch_id=None,
678                                    is_coalesced=None,
679                                    gets_to_gpu=True):
680    packet = self.add_track_event_slice(
681        "InputLatency::" + name, ts=ts, dur=dur, track=track)
682    latency_info = packet.track_event.chrome_latency_info
683    latency_info.trace_id = trace_id
684    if gesture_scroll_id is not None:
685      latency_info.gesture_scroll_id = gesture_scroll_id
686    if touch_id is not None:
687      latency_info.touch_id = touch_id
688    if gets_to_gpu:
689      component = latency_info.component_info.add()
690      component.component_type = self.prototypes \
691          .ChromeLatencyInfo.ComponentType \
692          .COMPONENT_INPUT_EVENT_GPU_SWAP_BUFFER
693    if is_coalesced is not None:
694      latency_info.is_coalesced = is_coalesced
695    return packet
696
697  def add_chrome_metadata(self, os_name=None):
698    metadata = self.add_packet().chrome_events.metadata.add()
699    if os_name is not None:
700      metadata.name = "os-name"
701      metadata.string_value = os_name
702
703    return metadata
704
705  def add_expected_display_frame_start_event(self, ts, cookie, token, pid):
706    packet = self.add_packet()
707    packet.timestamp = ts
708    event = packet.frame_timeline_event.expected_display_frame_start
709    if token != -1:
710      event.cookie = cookie
711      event.token = token
712      event.pid = pid
713
714  def add_actual_display_frame_start_event(self, ts, cookie, token, pid,
715                                           present_type, on_time_finish,
716                                           gpu_composition, jank_type,
717                                           prediction_type):
718    packet = self.add_packet()
719    packet.timestamp = ts
720    event = packet.frame_timeline_event.actual_display_frame_start
721    if token != -1:
722      event.cookie = cookie
723      event.token = token
724      event.pid = pid
725      event.present_type = present_type
726      event.on_time_finish = on_time_finish
727      event.gpu_composition = gpu_composition
728      event.jank_type = jank_type
729      event.prediction_type = prediction_type
730
731  def add_expected_surface_frame_start_event(self, ts, cookie, token,
732                                             display_frame_token, pid,
733                                             layer_name):
734    packet = self.add_packet()
735    packet.timestamp = ts
736    event = packet.frame_timeline_event.expected_surface_frame_start
737    if token != -1 and display_frame_token != -1:
738      event.cookie = cookie
739      event.token = token
740      event.display_frame_token = display_frame_token
741      event.pid = pid
742      event.layer_name = layer_name
743
744  def add_actual_surface_frame_start_event(self, ts, cookie, token,
745                                           display_frame_token, pid, layer_name,
746                                           present_type, on_time_finish,
747                                           gpu_composition, jank_type,
748                                           prediction_type):
749    packet = self.add_packet()
750    packet.timestamp = ts
751    event = packet.frame_timeline_event.actual_surface_frame_start
752    if token != -1 and display_frame_token != -1:
753      event.cookie = cookie
754      event.token = token
755      event.display_frame_token = display_frame_token
756      event.pid = pid
757      event.layer_name = layer_name
758      event.present_type = present_type
759      event.on_time_finish = on_time_finish
760      event.gpu_composition = gpu_composition
761      event.jank_type = jank_type
762      event.prediction_type = prediction_type
763
764  def add_frame_end_event(self, ts, cookie):
765    packet = self.add_packet()
766    packet.timestamp = ts
767    event = packet.frame_timeline_event.frame_end
768    event.cookie = cookie
769
770
771def read_descriptor(file_name):
772  with open(file_name, 'rb') as f:
773    contents = f.read()
774
775  descriptor = descriptor_pb2.FileDescriptorSet()
776  descriptor.MergeFromString(contents)
777
778  return descriptor
779
780
781def create_pool(args):
782  trace_descriptor = read_descriptor(args.trace_descriptor)
783
784  pool = descriptor_pool.DescriptorPool()
785  for file in trace_descriptor.file:
786    pool.Add(file)
787
788  return pool
789
790
791def create_trace():
792  parser = argparse.ArgumentParser()
793  parser.add_argument(
794      'trace_descriptor', type=str, help='location of trace descriptor')
795  args = parser.parse_args()
796
797  pool = create_pool(args)
798  factory = message_factory.MessageFactory(pool)
799  ProtoTrace = factory.GetPrototype(
800      pool.FindMessageTypeByName('perfetto.protos.Trace'))
801
802  class EnumPrototype(object):
803
804    def from_descriptor(desc):
805      res = EnumPrototype()
806      for desc in desc.values:
807        setattr(res, desc.name, desc.number)
808      return res
809
810  ChromeLatencyInfo = namedtuple('ChromeLatencyInfo', [
811      'ComponentType',
812      'Step',
813  ])
814
815  Prototypes = namedtuple('Prototypes', [
816      'TrackEvent',
817      'ChromeRAILMode',
818      'ChromeLatencyInfo',
819      'ChromeProcessDescriptor',
820      'CounterDescriptor',
821      'ThreadDescriptor',
822  ])
823
824  chrome_latency_info_prototypes = ChromeLatencyInfo(
825      ComponentType=EnumPrototype.from_descriptor(
826          pool.FindEnumTypeByName(
827              'perfetto.protos.ChromeLatencyInfo.LatencyComponentType')),
828      Step=EnumPrototype.from_descriptor(
829          pool.FindEnumTypeByName('perfetto.protos.ChromeLatencyInfo.Step')),
830  )
831
832  prototypes = Prototypes(
833      TrackEvent=factory.GetPrototype(
834          pool.FindMessageTypeByName('perfetto.protos.TrackEvent')),
835      ChromeRAILMode=EnumPrototype.from_descriptor(
836          pool.FindEnumTypeByName('perfetto.protos.ChromeRAILMode')),
837      ChromeLatencyInfo=chrome_latency_info_prototypes,
838      ChromeProcessDescriptor=factory.GetPrototype(
839          pool.FindMessageTypeByName(
840              'perfetto.protos.ChromeProcessDescriptor')),
841      CounterDescriptor=factory.GetPrototype(
842          pool.FindMessageTypeByName('perfetto.protos.CounterDescriptor')),
843      ThreadDescriptor=factory.GetPrototype(
844          pool.FindMessageTypeByName('perfetto.protos.ThreadDescriptor')),
845  )
846  return Trace(ProtoTrace(), prototypes)
847