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