You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
6.9 KiB
154 lines
6.9 KiB
#!/usr/bin/python3
|
|
#
|
|
# Copyright (C) 2020 Collabora Ltd
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
# copy of this software and associated documentation files (the "Software"),
|
|
# to deal in the Software without restriction, including without limitation
|
|
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
# and/or sell copies of the Software, and to permit persons to whom the
|
|
# Software is furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included
|
|
# in all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
# OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
from google import protobuf
|
|
import protos.perfetto.trace.perfetto_trace_pb2
|
|
from protos.perfetto.trace.perfetto_trace_pb2 import BUILTIN_CLOCK_BOOTTIME
|
|
from protos.perfetto.trace.perfetto_trace_pb2 import BUILTIN_CLOCK_REALTIME
|
|
import math
|
|
import sys
|
|
import operator
|
|
import time
|
|
|
|
def add_ftrace_event(out_message, in_packet, in_event, max_host_sequence_id = 0):
|
|
out_packet = out_message.packet.add()
|
|
out_packet.ftrace_events.cpu = in_packet.ftrace_events.cpu
|
|
out_packet.trusted_uid = in_packet.trusted_uid
|
|
out_packet.trusted_packet_sequence_id += max_host_sequence_id
|
|
out_packet.ftrace_events.event.add().CopyFrom(in_event)
|
|
|
|
virtio_gpu_pids = set()
|
|
|
|
print('%d Loading host trace' % time.time())
|
|
|
|
in_message = protos.perfetto.trace.perfetto_trace_pb2.Trace()
|
|
in_message.ParseFromString(open(sys.argv[1], 'rb').read())
|
|
|
|
print('%d Copying host trace' % time.time())
|
|
|
|
out_message = protos.perfetto.trace.perfetto_trace_pb2.Trace()
|
|
max_host_sequence_id = 0
|
|
first_host_virtio_gpu_cmd = math.inf
|
|
host_boot_ts = -1
|
|
for in_packet in in_message.packet:
|
|
max_host_sequence_id = max(max_host_sequence_id,
|
|
in_packet.trusted_packet_sequence_id)
|
|
|
|
if in_packet.HasField('ftrace_events'):
|
|
for event in in_packet.ftrace_events.event:
|
|
if event.HasField('sched_switch'):
|
|
if 'virtio_gpu' == event.sched_switch.prev_comm:
|
|
virtio_gpu_pids.add(event.sched_switch.prev_pid)
|
|
if 'virtio_gpu' == event.sched_switch.next_comm:
|
|
virtio_gpu_pids.add(event.sched_switch.next_pid)
|
|
|
|
if event.sched_switch.prev_pid in virtio_gpu_pids or \
|
|
event.sched_switch.next_pid in virtio_gpu_pids:
|
|
add_ftrace_event(out_message, in_packet, event)
|
|
elif event.HasField('sched_wakeup'):
|
|
if 'virtio_gpu' == event.sched_wakeup.comm:
|
|
virtio_gpu_pids.add(event.sched_wakeup.pid)
|
|
|
|
if event.sched_wakeup.pid in virtio_gpu_pids:
|
|
add_ftrace_event(out_message, in_packet, event)
|
|
elif event.HasField('print'):
|
|
event_type, guest_pid, label, cookie = event.print.buf.split('|')
|
|
|
|
# Replace host PID with the guest PID
|
|
event.pid = int(guest_pid)
|
|
add_ftrace_event(out_message, in_packet, event)
|
|
else:
|
|
if in_packet.HasField('track_descriptor'):
|
|
if in_packet.track_descriptor.HasField('name'):
|
|
in_packet.track_descriptor.name += ' (Host)'
|
|
elif in_packet.HasField('track_event'):
|
|
if in_packet.track_event.type == in_packet.track_event.TYPE_SLICE_BEGIN and \
|
|
in_packet.track_event.name == 'GetCapset':
|
|
first_host_virtio_gpu_cmd = min(first_host_virtio_gpu_cmd, in_packet.timestamp)
|
|
elif host_boot_ts == -1 and in_packet.HasField('clock_snapshot'):
|
|
for clock in in_packet.clock_snapshot.clocks:
|
|
if clock.clock_id == BUILTIN_CLOCK_BOOTTIME:
|
|
host_boottime = clock.timestamp
|
|
elif clock.clock_id == BUILTIN_CLOCK_REALTIME:
|
|
host_realtime = clock.timestamp
|
|
host_boot_ts = host_realtime - host_boottime
|
|
out_packet = out_message.packet.add()
|
|
out_packet.CopyFrom(in_packet)
|
|
|
|
print('%d Loading guest trace' % time.time())
|
|
in_message.ParseFromString(open(sys.argv[2], 'rb').read())
|
|
|
|
#print('%d Writing guest trace txt' % time.time())
|
|
#open('../traces-db/perfetto-guest.txt', 'w').write(str(in_message))
|
|
|
|
first_guest_virtio_gpu_cmd = math.inf
|
|
guest_boot_ts = -1
|
|
for in_packet in in_message.packet:
|
|
if guest_boot_ts == -1 and in_packet.HasField('clock_snapshot'):
|
|
for clock in in_packet.clock_snapshot.clocks:
|
|
if clock.clock_id == BUILTIN_CLOCK_BOOTTIME:
|
|
guest_boottime = clock.timestamp
|
|
elif clock.clock_id == BUILTIN_CLOCK_REALTIME:
|
|
guest_realtime = clock.timestamp
|
|
guest_boot_ts = guest_realtime - guest_boottime
|
|
elif in_packet.HasField('track_event'):
|
|
if in_packet.track_event.type == in_packet.track_event.TYPE_SLICE_BEGIN and \
|
|
in_packet.track_event.name == 'DRM_IOCTL_VIRTGPU_GET_CAPS':
|
|
first_guest_virtio_gpu_cmd = min(first_guest_virtio_gpu_cmd, in_packet.timestamp)
|
|
|
|
delta = guest_boot_ts - host_boot_ts
|
|
cmd_delta = first_host_virtio_gpu_cmd - first_guest_virtio_gpu_cmd - delta
|
|
print("boottime delta %ds." % (delta / 1000 / 1000 / 1000))
|
|
print("cmd delta %dus." % (cmd_delta / 1000))
|
|
|
|
for in_packet in in_message.packet:
|
|
if in_packet.HasField('process_tree') or \
|
|
in_packet.HasField('service_event') or \
|
|
in_packet.HasField('track_event') or \
|
|
in_packet.HasField('trace_packet_defaults') or \
|
|
in_packet.HasField('track_descriptor'):
|
|
out_packet = out_message.packet.add()
|
|
out_packet.CopyFrom(in_packet)
|
|
out_packet.trusted_packet_sequence_id += max_host_sequence_id
|
|
out_packet.timestamp += delta
|
|
if out_packet.HasField('track_descriptor'):
|
|
if out_packet.track_descriptor.HasField('name'):
|
|
out_packet.track_descriptor.name += ' (Guest)'
|
|
elif in_packet.HasField('ftrace_events'):
|
|
for event in in_packet.ftrace_events.event:
|
|
event.timestamp += delta
|
|
add_ftrace_event(out_message, in_packet, event, max_host_sequence_id)
|
|
|
|
def get_timestamp(packet):
|
|
if packet.HasField('timestamp'):
|
|
return packet.timestamp
|
|
elif packet.HasField('ftrace_events') and \
|
|
packet.ftrace_events.event:
|
|
return packet.ftrace_events.event[0].timestamp
|
|
return 0
|
|
|
|
out_message.packet.sort(key=get_timestamp)
|
|
print('%d Writing merged trace' % time.time())
|
|
open(sys.argv[3], 'wb').write(out_message.SerializeToString())
|
|
|
|
#print('%d Writing merged trace txt' % time.time())
|
|
#open('../traces-db/perfetto.txt', 'w').write(str(out_message))
|
|
|