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