# perf script event handlers, generated by perf script -g python # Licensed under the terms of the GNU GPL License version 2 # The common_* event handler fields are the most useful fields common to # all events. They don't necessarily correspond to the 'common_*' fields # in the format files. Those fields not available as handler params can # be retrieved using Python functions of the form common_*(context). # See the perf-script-python Documentation for the list of available functions. from __future__ import print_function import os import sys import collections sys.path.append(os.environ['PERF_EXEC_PATH'] + \ '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') from perf_trace_context import * from Core import * from Util import * class QemuTrace: APP_NAME = "qemu-system-x86" # IO ports for different exit points LINUX_EXIT_PORT = 0xf4 FW_EXIT_PORT = 0xf5 # Exit point values EXIT_POINTS = { 1 : 'fw_start', 2 : 'linux_start_fwcfg', 3 : 'linux_start_boot', 4 : 'fw_do_boot', 5 : 'linux_start_kernel', 6 : 'linux_start_user'} def __init__(self): self.start = 0 self.qemu_init_end = 0 self.probes = [] def print(self, div = 1): print(" qemu_init_end: %f" % \ ((self.qemu_init_end - float(self.start))/div)) pre_ep = 0 pre_ts = self.qemu_init_end for ep, ts in self.probes: if ep == pre_ep: continue if ep in QemuTrace.EXIT_POINTS: ep_name = QemuTrace.EXIT_POINTS[ep] else: ep_name = "Exit point " + str(ep) print(" {}: {} (+{})".format(ep_name, (ts - float(self.start))/div, \ (ts - float(pre_ts))/div)) pre_ts = ts pre_ep = ep @staticmethod def stats(pids, traces, div): avgQT = QemuTrace() minQT = QemuTrace() maxQT = QemuTrace() count = 0 for pid in pids: count += 1 print("%d) pid %d" % (count, pid)) traces[pid].print(div) qit = traces[pid].qemu_init_end - traces[pid].start avgQT.qemu_init_end += qit maxQT.qemu_init_end = max(maxQT.qemu_init_end, qit) if (count == 1): minQT.qemu_init_end = qit else: minQT.qemu_init_end = min(minQT.qemu_init_end, qit) i = 0 for ep, ts in traces[pid].probes: rel_ts = ts - traces[pid].start if (count == 1): avgQT.probes.append((ep, rel_ts)) minQT.probes.append((ep, rel_ts)) maxQT.probes.append((ep, 0)) else: avgQT.probes[i] = (ep, avgQT.probes[i][1] + rel_ts) minQT.probes[i] = (ep, min(minQT.probes[i][1], rel_ts)) maxQT.probes[i] = (ep, max(maxQT.probes[i][1], rel_ts)) i+=1 if count > 1: avgQT.qemu_init_end /= count i = 0 for ep, ts in avgQT.probes: avgQT.probes[i] = (ep, avgQT.probes[i][1] / count) i+=1 print("\nAvg") avgQT.print(div) print("\nMin") minQT.print(div) print("\nMax") maxQT.print(div) class Events: def __init__(self, ClassTrace): self.ClassTrace = ClassTrace self.app_name = ClassTrace.APP_NAME self.pids = [] self.traces = autodict() def stats(self, div): self.ClassTrace.stats(self.pids, self.traces, div) events = Events(QemuTrace) def trace_begin(): print("in trace_begin") def trace_end(): print("in trace_end") print("Trace %s" % (events.app_name)) events.stats(1000000) def sched__sched_process_exec(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, filename, pid, old_pid, perf_sample_dict): if (events.app_name != common_comm): return events.traces[pid] = QemuTrace() events.traces[pid].start = perf_sample_dict["sample"]["time"] events.pids.append(pid) print_header(event_name, common_cpu, common_secs, common_nsecs, common_pid, common_comm) print() def kvm__kvm_pio(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, rw, port, size, count, val, perf_sample_dict): if (events.app_name != common_comm): return ts = perf_sample_dict["sample"]["time"] pid = perf_sample_dict["sample"]["pid"] if (port == QemuTrace.FW_EXIT_PORT or port == QemuTrace.LINUX_EXIT_PORT): events.traces[pid].probes.append((val, ts)) else: return print_header(event_name, common_cpu, common_secs, common_nsecs, common_pid, common_comm) print("rw=%u, port=0x%x, size=%u, count=%u, val=%u" % \ (rw, port, size, count, val)) print() def kvm__kvm_entry(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, vcpu_id, perf_sample_dict): if (events.app_name != common_comm): return ts = perf_sample_dict["sample"]["time"] pid = perf_sample_dict["sample"]["pid"] if (events.traces[pid].qemu_init_end != 0): return events.traces[pid].qemu_init_end = ts print_header(event_name, common_cpu, common_secs, common_nsecs, common_pid, common_comm) print() def trace_unhandled(event_name, context, event_fields_dict, perf_sample_dict): pass def print_header(event_name, cpu, secs, nsecs, pid, comm): print("%-20s %5u %05u.%09u %8u %-20s " % \ (event_name, cpu, secs, nsecs, pid, comm), end="") def get_dict_as_string(a_dict, delimiter=' '): return delimiter.join(['%s=%s'%(k,str(v))for k,v in sorted(a_dict.items())])