From a6172059758ba1b496ae024cece7d5bdc8d017db Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 21 May 2021 12:20:51 +0300 Subject: perf scripts python: exported-sql-viewer.py: Fix copy to clipboard from Top Calls by elapsed Time report Provide missing argument to prevent following error when copying a selection to the clipboard: Traceback (most recent call last): File "tools/perf/scripts/python/exported-sql-viewer.py", line 4041, in menu.addAction(CreateAction("&Copy selection", "Copy to clipboard", lambda: CopyCellsToClipboardHdr(self.view), self.view)) File "tools/perf/scripts/python/exported-sql-viewer.py", line 4021, in CopyCellsToClipboardHdr CopyCellsToClipboard(view, False, True) File "tools/perf/scripts/python/exported-sql-viewer.py", line 4018, in CopyCellsToClipboard view.CopyCellsToClipboard(view, as_csv, with_hdr) File "tools/perf/scripts/python/exported-sql-viewer.py", line 3871, in CopyTableCellsToClipboard val = model.headerData(col, Qt.Horizontal) TypeError: headerData() missing 1 required positional argument: 'role' Fixes: 96c43b9a7ab3b ("perf scripts python: exported-sql-viewer.py: Add copy to clipboard") Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: stable@vger.kernel.org Link: http://lore.kernel.org/lkml/20210521092053.25683-2-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/exported-sql-viewer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/scripts/python') diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index 7daa8bb70a5a..b5078d65704e 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py @@ -3868,7 +3868,7 @@ def CopyTableCellsToClipboard(view, as_csv=False, with_hdr=False): if with_hdr: model = indexes[0].model() for col in range(min_col, max_col + 1): - val = model.headerData(col, Qt.Horizontal) + val = model.headerData(col, Qt.Horizontal, Qt.DisplayRole) if as_csv: text += sep + ToCSValue(val) sep = "," -- cgit v1.2.3 From fd931b2e234a7cc451a7bbb1965d6ce623189158 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 21 May 2021 12:20:52 +0300 Subject: perf scripts python: exported-sql-viewer.py: Fix Array TypeError The 'Array' class is present in more than one python standard library. In some versions of Python 3, the following error occurs: Traceback (most recent call last): File "tools/perf/scripts/python/exported-sql-viewer.py", line 4702, in reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda a=None,x=dbid: self.NewBranchView(x), self)) File "tools/perf/scripts/python/exported-sql-viewer.py", line 4727, in NewBranchView BranchWindow(self.glb, event_id, ReportVars(), self) File "tools/perf/scripts/python/exported-sql-viewer.py", line 3208, in __init__ self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, report_vars.where_clause)) File "tools/perf/scripts/python/exported-sql-viewer.py", line 343, in LookupCreateModel model = create_fn() File "tools/perf/scripts/python/exported-sql-viewer.py", line 3208, in self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, report_vars.where_clause)) File "tools/perf/scripts/python/exported-sql-viewer.py", line 3124, in __init__ self.fetcher = SQLFetcher(glb, sql, prep, self.AddSample) File "tools/perf/scripts/python/exported-sql-viewer.py", line 2658, in __init__ self.buffer = Array(c_char, self.buffer_size, lock=False) TypeError: abstract class This apparently happens because Python can be inconsistent about which class of the name 'Array' gets imported. Fix by importing explicitly by name so that only the desired 'Array' gets imported. Fixes: 8392b74b575c3 ("perf scripts python: exported-sql-viewer.py: Add ability to display all the database tables") Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: stable@vger.kernel.org Link: http://lore.kernel.org/lkml/20210521092053.25683-3-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/exported-sql-viewer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tools/perf/scripts/python') diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index b5078d65704e..4a63843f623c 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py @@ -125,8 +125,9 @@ if pyside_version_1: from PySide.QtGui import * from PySide.QtSql import * -from decimal import * -from ctypes import * +from decimal import Decimal, ROUND_HALF_UP +from ctypes import CDLL, Structure, create_string_buffer, addressof, sizeof, \ + c_void_p, c_bool, c_byte, c_char, c_int, c_uint, c_longlong, c_ulonglong from multiprocessing import Process, Array, Value, Event # xrange is range in Python3 -- cgit v1.2.3 From f56299a9c998e0bfbd4ab07cafe9eb8444512448 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 21 May 2021 12:20:53 +0300 Subject: perf scripts python: exported-sql-viewer.py: Fix warning display Deprecation warnings are useful only for the developer, not an end user. Display warnings only when requested using the python -W option. This stops the display of warnings like: tools/perf/scripts/python/exported-sql-viewer.py:5102: DeprecationWarning: an integer is required (got type PySide2.QtCore.Qt.AlignmentFlag). Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python. err = app.exec_() Since the warning can be fixed only in PySide2, we must wait for it to be finally fixed there. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: stable@vger.kernel.org # v5.3+ Link: http://lore.kernel.org/lkml/20210521092053.25683-4-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/exported-sql-viewer.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tools/perf/scripts/python') diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index 4a63843f623c..711d4f9f5645 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py @@ -91,6 +91,11 @@ from __future__ import print_function import sys +# Only change warnings if the python -W option was not used +if not sys.warnoptions: + import warnings + # PySide2 causes deprecation warnings, ignore them. + warnings.filterwarnings("ignore", category=DeprecationWarning) import argparse import weakref import threading -- cgit v1.2.3 From a92bf335fd82eeee0e95705bfd25014ee0c8262e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 25 May 2021 12:51:12 +0300 Subject: perf scripts python: intel-pt-events.py: Add branches to script As an example, add branch information to intel-pt-events.py script. This shows how a simple python script can be used to customize perf script output for Intel PT branch traces or power event traces. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Link: https://lore.kernel.org/r/20210525095112.1399-11-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/scripts/python/bin/intel-pt-events-record | 4 +- .../perf/scripts/python/bin/intel-pt-events-report | 4 +- tools/perf/scripts/python/intel-pt-events.py | 143 ++++++++++++++++----- 3 files changed, 116 insertions(+), 35 deletions(-) (limited to 'tools/perf/scripts/python') diff --git a/tools/perf/scripts/python/bin/intel-pt-events-record b/tools/perf/scripts/python/bin/intel-pt-events-record index 10fe2b6977d4..6b9877cfe23e 100644 --- a/tools/perf/scripts/python/bin/intel-pt-events-record +++ b/tools/perf/scripts/python/bin/intel-pt-events-record @@ -1,8 +1,8 @@ #!/bin/bash # -# print Intel PT Power Events and PTWRITE. The intel_pt PMU event needs -# to be specified with appropriate config terms. +# print Intel PT Events including Power Events and PTWRITE. The intel_pt PMU +# event needs to be specified with appropriate config terms. # if ! echo "$@" | grep -q intel_pt ; then echo "Options must include the Intel PT event e.g. -e intel_pt/pwr_evt,ptw/" diff --git a/tools/perf/scripts/python/bin/intel-pt-events-report b/tools/perf/scripts/python/bin/intel-pt-events-report index 9a9c92fcd026..beeac3fde9db 100644 --- a/tools/perf/scripts/python/bin/intel-pt-events-report +++ b/tools/perf/scripts/python/bin/intel-pt-events-report @@ -1,3 +1,3 @@ #!/bin/bash -# description: print Intel PT Power Events and PTWRITE -perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/intel-pt-events.py \ No newline at end of file +# description: print Intel PT Events including Power Events and PTWRITE +perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/intel-pt-events.py diff --git a/tools/perf/scripts/python/intel-pt-events.py b/tools/perf/scripts/python/intel-pt-events.py index a73847c8f548..fcfae1de731b 100644 --- a/tools/perf/scripts/python/intel-pt-events.py +++ b/tools/perf/scripts/python/intel-pt-events.py @@ -1,5 +1,6 @@ -# intel-pt-events.py: Print Intel PT Power Events and PTWRITE -# Copyright (c) 2017, Intel Corporation. +# SPDX-License-Identifier: GPL-2.0 +# intel-pt-events.py: Print Intel PT Events including Power Events and PTWRITE +# Copyright (c) 2017-2021, Intel Corporation. # # This program is free software; you can redistribute it and/or modify it # under the terms and conditions of the GNU General Public License, @@ -23,8 +24,36 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \ #from perf_trace_context import * #from Core import * +try: + broken_pipe_exception = BrokenPipeError +except: + broken_pipe_exception = IOError + +glb_switch_str = None +glb_switch_printed = True + +def get_optional_null(perf_dict, field): + if field in perf_dict: + return perf_dict[field] + return "" + +def get_optional_zero(perf_dict, field): + if field in perf_dict: + return perf_dict[field] + return 0 + +def get_optional(perf_dict, field): + if field in perf_dict: + return perf_dict[field] + return "[unknown]" + +def get_offset(perf_dict, field): + if field in perf_dict: + return "+%#x" % perf_dict[field] + return "" + def trace_begin(): - print("Intel PT Power Events and PTWRITE") + print("Intel PT Branch Trace, Power Events and PTWRITE") def trace_end(): print("End") @@ -77,58 +106,110 @@ def print_pwrx(raw_buf): print("deepest cstate: %u last cstate: %u wake reason: %#x" % (deepest_cstate, last_cstate, wake_reason), end=' ') +def print_psb(raw_buf): + data = struct.unpack_from(" %x %s%s (%s)" % (addr, symbol, offs, dso)) + else: + print() -def process_event(param_dict): +def do_process_event(param_dict): + global glb_switch_printed + if not glb_switch_printed: + print(glb_switch_str) + glb_switch_printed = True event_attr = param_dict["attr"] - sample = param_dict["sample"] - raw_buf = param_dict["raw_buf"] + sample = param_dict["sample"] + raw_buf = param_dict["raw_buf"] comm = param_dict["comm"] name = param_dict["ev_name"] + # Unused fields: + # callchain = param_dict["callchain"] + # brstack = param_dict["brstack"] + # brstacksym = param_dict["brstacksym"] # Symbol and dso info are not always resolved - if "dso" in param_dict: - dso = param_dict["dso"] - else: - dso = "[unknown]" + dso = get_optional(param_dict, "dso") + symbol = get_optional(param_dict, "symbol") - if "symbol" in param_dict: - symbol = param_dict["symbol"] - else: - symbol = "[unknown]" + print_common_start(comm, sample, name) if name == "ptwrite": - print_common_start(comm, sample, name) print_ptwrite(raw_buf) - print_common_ip(sample, symbol, dso) elif name == "cbr": - print_common_start(comm, sample, name) print_cbr(raw_buf) - print_common_ip(sample, symbol, dso) elif name == "mwait": - print_common_start(comm, sample, name) print_mwait(raw_buf) - print_common_ip(sample, symbol, dso) elif name == "pwre": - print_common_start(comm, sample, name) print_pwre(raw_buf) - print_common_ip(sample, symbol, dso) elif name == "exstop": - print_common_start(comm, sample, name) print_exstop(raw_buf) - print_common_ip(sample, symbol, dso) elif name == "pwrx": - print_common_start(comm, sample, name) print_pwrx(raw_buf) - print_common_ip(sample, symbol, dso) + elif name == "psb": + print_psb(raw_buf) + + print_common_ip(param_dict, sample, symbol, dso) + +def process_event(param_dict): + try: + do_process_event(param_dict) + except broken_pipe_exception: + # Stop python printing broken pipe errors and traceback + sys.stdout = open(os.devnull, 'w') + sys.exit(1) + +def auxtrace_error(typ, code, cpu, pid, tid, ip, ts, msg, cpumode, *x): + try: + print("%16s %5u/%-5u [%03u] %9u.%09u error type %u code %u: %s ip 0x%16x" % + ("Trace error", pid, tid, cpu, ts / 1000000000, ts %1000000000, typ, code, msg, ip)) + except broken_pipe_exception: + # Stop python printing broken pipe errors and traceback + sys.stdout = open(os.devnull, 'w') + sys.exit(1) + +def context_switch(ts, cpu, pid, tid, np_pid, np_tid, machine_pid, out, out_preempt, *x): + global glb_switch_printed + global glb_switch_str + if out: + out_str = "Switch out " + else: + out_str = "Switch In " + if out_preempt: + preempt_str = "preempt" + else: + preempt_str = "" + if machine_pid == -1: + machine_str = "" + else: + machine_str = "machine PID %d" % machine_pid + glb_switch_str = "%16s %5d/%-5d [%03u] %9u.%09u %5d/%-5d %s %s" % \ + (out_str, pid, tid, cpu, ts / 1000000000, ts %1000000000, np_pid, np_tid, machine_str, preempt_str) + glb_switch_printed = False -- cgit v1.2.3 From 4c62244e035e99a9e43d25a017cbe98f7562b21f Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 30 May 2021 22:22:56 +0300 Subject: perf scripting python: Remove unnecessary 'static' The variables are always assigned before use, making the 'static' storage class unnecessary. Signed-off-by: Adrian Hunter Cc: Arnaldo Carvalho de Melo Cc: Andi Kleen Cc: Jiri Olsa Link: https://lore.kernel.org/r/20210530192308.7382-2-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/Perf-Trace-Util/Context.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tools/perf/scripts/python') diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c index 0b7096847991..fdf692d1e8f3 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c @@ -22,7 +22,7 @@ PyMODINIT_FUNC PyInit_perf_trace_context(void); static PyObject *perf_trace_context_common_pc(PyObject *obj, PyObject *args) { - static struct scripting_context *scripting_context; + struct scripting_context *scripting_context; PyObject *context; int retval; @@ -38,7 +38,7 @@ static PyObject *perf_trace_context_common_pc(PyObject *obj, PyObject *args) static PyObject *perf_trace_context_common_flags(PyObject *obj, PyObject *args) { - static struct scripting_context *scripting_context; + struct scripting_context *scripting_context; PyObject *context; int retval; @@ -54,7 +54,7 @@ static PyObject *perf_trace_context_common_flags(PyObject *obj, static PyObject *perf_trace_context_common_lock_depth(PyObject *obj, PyObject *args) { - static struct scripting_context *scripting_context; + struct scripting_context *scripting_context; PyObject *context; int retval; -- cgit v1.2.3 From 6337bd0c91f66527741e61ecb73b9cff0d7f48f8 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 30 May 2021 22:22:57 +0300 Subject: perf scripting python: Simplify perf-trace-context module functions Simplify perf-trace-context module functions by factoring out some common code. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Link: https://lore.kernel.org/r/20210530192308.7382-3-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/scripts/python/Perf-Trace-Util/Context.c | 39 ++++++++++------------ 1 file changed, 17 insertions(+), 22 deletions(-) (limited to 'tools/perf/scripts/python') diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c index fdf692d1e8f3..7cef02d75bc7 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c @@ -20,51 +20,46 @@ PyMODINIT_FUNC initperf_trace_context(void); PyMODINIT_FUNC PyInit_perf_trace_context(void); #endif -static PyObject *perf_trace_context_common_pc(PyObject *obj, PyObject *args) +static struct scripting_context *get_scripting_context(PyObject *args) { - struct scripting_context *scripting_context; PyObject *context; - int retval; if (!PyArg_ParseTuple(args, "O", &context)) return NULL; - scripting_context = _PyCapsule_GetPointer(context, NULL); - retval = common_pc(scripting_context); + return _PyCapsule_GetPointer(context, NULL); +} + +static PyObject *perf_trace_context_common_pc(PyObject *obj, PyObject *args) +{ + struct scripting_context *c = get_scripting_context(args); + + if (!c) + return NULL; - return Py_BuildValue("i", retval); + return Py_BuildValue("i", common_pc(c)); } static PyObject *perf_trace_context_common_flags(PyObject *obj, PyObject *args) { - struct scripting_context *scripting_context; - PyObject *context; - int retval; + struct scripting_context *c = get_scripting_context(args); - if (!PyArg_ParseTuple(args, "O", &context)) + if (!c) return NULL; - scripting_context = _PyCapsule_GetPointer(context, NULL); - retval = common_flags(scripting_context); - - return Py_BuildValue("i", retval); + return Py_BuildValue("i", common_flags(c)); } static PyObject *perf_trace_context_common_lock_depth(PyObject *obj, PyObject *args) { - struct scripting_context *scripting_context; - PyObject *context; - int retval; + struct scripting_context *c = get_scripting_context(args); - if (!PyArg_ParseTuple(args, "O", &context)) + if (!c) return NULL; - scripting_context = _PyCapsule_GetPointer(context, NULL); - retval = common_lock_depth(scripting_context); - - return Py_BuildValue("i", retval); + return Py_BuildValue("i", common_lock_depth(c)); } static PyMethodDef ContextMethods[] = { -- cgit v1.2.3 From cf9bfa6c150f038328f8059a69a6f1598d6702b2 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 30 May 2021 22:23:00 +0300 Subject: perf scripting python: Assign perf_script_context The scripting_context pointer itself does not change and nor does it need to. Put it directly into the script as a variable at the start so it does not have to be passed on each call into the script. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Link: https://lore.kernel.org/r/20210530192308.7382-6-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/scripts/python/Perf-Trace-Util/Context.c | 8 ++++++- .../util/scripting-engines/trace-event-python.c | 28 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) (limited to 'tools/perf/scripts/python') diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c index 7cef02d75bc7..26a45ae78be4 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c @@ -91,6 +91,12 @@ PyMODINIT_FUNC PyInit_perf_trace_context(void) NULL, /* m_clear */ NULL, /* m_free */ }; - return PyModule_Create(&moduledef); + PyObject *mod; + + mod = PyModule_Create(&moduledef); + /* Add perf_script_context to the module so it can be imported */ + PyObject_SetAttrString(mod, "perf_script_context", Py_None); + + return mod; } #endif diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 02d134b6ba8d..164d2f45028c 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -1599,6 +1599,31 @@ static void python_process_stat_interval(u64 tstamp) Py_DECREF(t); } +static int perf_script_context_init(void) +{ + PyObject *perf_script_context; + PyObject *perf_trace_context; + PyObject *dict; + int ret; + + perf_trace_context = PyImport_AddModule("perf_trace_context"); + if (!perf_trace_context) + return -1; + dict = PyModule_GetDict(perf_trace_context); + if (!dict) + return -1; + + perf_script_context = _PyCapsule_New(scripting_context, NULL, NULL); + if (!perf_script_context) + return -1; + + ret = PyDict_SetItemString(dict, "perf_script_context", perf_script_context); + if (!ret) + ret = PyDict_SetItemString(main_dict, "perf_script_context", perf_script_context); + Py_DECREF(perf_script_context); + return ret; +} + static int run_start_sub(void) { main_module = PyImport_AddModule("__main__"); @@ -1611,6 +1636,9 @@ static int run_start_sub(void) goto error; Py_INCREF(main_dict); + if (perf_script_context_init()) + goto error; + try_call_object("trace_begin", NULL); return 0; -- cgit v1.2.3 From 13c71b92327aaacc7a3c3ca5f003f3f66ba5af65 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 30 May 2021 22:23:02 +0300 Subject: perf scripting python: Add perf_sample_insn() Add perf_sample_insn() to the perf_trace_context module so that a script can get the instruction bytes. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Link: https://lore.kernel.org/r/20210530192308.7382-8-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/scripts/python/Perf-Trace-Util/Context.c | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'tools/perf/scripts/python') diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c index 26a45ae78be4..d7f044259f9b 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c @@ -7,15 +7,23 @@ #include #include "../../../util/trace-event.h" +#include "../../../util/event.h" +#include "../../../util/symbol.h" +#include "../../../util/thread.h" +#include "../../../util/maps.h" #if PY_MAJOR_VERSION < 3 #define _PyCapsule_GetPointer(arg1, arg2) \ PyCObject_AsVoidPtr(arg1) +#define _PyBytes_FromStringAndSize(arg1, arg2) \ + PyString_FromStringAndSize((arg1), (arg2)) PyMODINIT_FUNC initperf_trace_context(void); #else #define _PyCapsule_GetPointer(arg1, arg2) \ PyCapsule_GetPointer((arg1), (arg2)) +#define _PyBytes_FromStringAndSize(arg1, arg2) \ + PyBytes_FromStringAndSize((arg1), (arg2)) PyMODINIT_FUNC PyInit_perf_trace_context(void); #endif @@ -62,6 +70,23 @@ static PyObject *perf_trace_context_common_lock_depth(PyObject *obj, return Py_BuildValue("i", common_lock_depth(c)); } +static PyObject *perf_sample_insn(PyObject *obj, PyObject *args) +{ + struct scripting_context *c = get_scripting_context(args); + + if (!c) + return NULL; + + if (c->sample->ip && !c->sample->insn_len && + c->al->thread->maps && c->al->thread->maps->machine) + script_fetch_insn(c->sample, c->al->thread, c->al->thread->maps->machine); + + if (!c->sample->insn_len) + Py_RETURN_NONE; /* N.B. This is a return statement */ + + return _PyBytes_FromStringAndSize(c->sample->insn, c->sample->insn_len); +} + static PyMethodDef ContextMethods[] = { { "common_pc", perf_trace_context_common_pc, METH_VARARGS, "Get the common preempt count event field value."}, @@ -69,6 +94,8 @@ static PyMethodDef ContextMethods[] = { "Get the common flags event field value."}, { "common_lock_depth", perf_trace_context_common_lock_depth, METH_VARARGS, "Get the common lock depth event field value."}, + { "perf_sample_insn", perf_sample_insn, + METH_VARARGS, "Get the machine code instruction."}, { NULL, NULL, 0, NULL} }; -- cgit v1.2.3 From 7d00540d7deb6802cde23b132b0c50347f27cc90 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 30 May 2021 22:23:04 +0300 Subject: perf scripting python: Add perf_set_itrace_options() Add perf_set_itrace_options() to the perf_trace_context module so that a script can set the itrace options for a session if they have not been set already. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Link: https://lore.kernel.org/r/20210530192308.7382-10-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/scripts/python/Perf-Trace-Util/Context.c | 44 +++++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) (limited to 'tools/perf/scripts/python') diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c index d7f044259f9b..3c9bc12a1332 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c @@ -11,12 +11,16 @@ #include "../../../util/symbol.h" #include "../../../util/thread.h" #include "../../../util/maps.h" +#include "../../../util/auxtrace.h" +#include "../../../util/session.h" #if PY_MAJOR_VERSION < 3 #define _PyCapsule_GetPointer(arg1, arg2) \ PyCObject_AsVoidPtr(arg1) #define _PyBytes_FromStringAndSize(arg1, arg2) \ PyString_FromStringAndSize((arg1), (arg2)) +#define _PyUnicode_AsUTF8(arg) \ + PyString_AsString(arg) PyMODINIT_FUNC initperf_trace_context(void); #else @@ -24,20 +28,28 @@ PyMODINIT_FUNC initperf_trace_context(void); PyCapsule_GetPointer((arg1), (arg2)) #define _PyBytes_FromStringAndSize(arg1, arg2) \ PyBytes_FromStringAndSize((arg1), (arg2)) +#define _PyUnicode_AsUTF8(arg) \ + PyUnicode_AsUTF8(arg) PyMODINIT_FUNC PyInit_perf_trace_context(void); #endif -static struct scripting_context *get_scripting_context(PyObject *args) +static struct scripting_context *get_args(PyObject *args, const char *name, PyObject **arg2) { + int cnt = 1 + !!arg2; PyObject *context; - if (!PyArg_ParseTuple(args, "O", &context)) + if (!PyArg_UnpackTuple(args, name, 1, cnt, &context, arg2)) return NULL; return _PyCapsule_GetPointer(context, NULL); } +static struct scripting_context *get_scripting_context(PyObject *args) +{ + return get_args(args, "context", NULL); +} + static PyObject *perf_trace_context_common_pc(PyObject *obj, PyObject *args) { struct scripting_context *c = get_scripting_context(args); @@ -87,6 +99,32 @@ static PyObject *perf_sample_insn(PyObject *obj, PyObject *args) return _PyBytes_FromStringAndSize(c->sample->insn, c->sample->insn_len); } +static PyObject *perf_set_itrace_options(PyObject *obj, PyObject *args) +{ + struct scripting_context *c; + const char *itrace_options; + int retval = -1; + PyObject *str; + + c = get_args(args, "itrace_options", &str); + if (!c) + return NULL; + + if (!c->session || !c->session->itrace_synth_opts) + goto out; + + if (c->session->itrace_synth_opts->set) { + retval = 1; + goto out; + } + + itrace_options = _PyUnicode_AsUTF8(str); + + retval = itrace_do_parse_synth_opts(c->session->itrace_synth_opts, itrace_options, 0); +out: + return Py_BuildValue("i", retval); +} + static PyMethodDef ContextMethods[] = { { "common_pc", perf_trace_context_common_pc, METH_VARARGS, "Get the common preempt count event field value."}, @@ -96,6 +134,8 @@ static PyMethodDef ContextMethods[] = { METH_VARARGS, "Get the common lock depth event field value."}, { "perf_sample_insn", perf_sample_insn, METH_VARARGS, "Get the machine code instruction."}, + { "perf_set_itrace_options", perf_set_itrace_options, + METH_VARARGS, "Set --itrace options."}, { NULL, NULL, 0, NULL} }; -- cgit v1.2.3 From e79457a526105c94930a5babbecaeeb794593723 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 30 May 2021 22:23:05 +0300 Subject: perf scripting python: Add perf_sample_srcline() and perf_sample_srccode() Add perf_sample_srcline() and perf_sample_srccode() to the perf_trace_context module so that a script can get the srcline or srccode information. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Link: https://lore.kernel.org/r/20210530192308.7382-11-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/scripts/python/Perf-Trace-Util/Context.c | 56 ++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'tools/perf/scripts/python') diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c index 3c9bc12a1332..895f5fc23965 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c @@ -5,14 +5,23 @@ * Copyright (C) 2010 Tom Zanussi */ +/* + * Use Py_ssize_t for '#' formats to avoid DeprecationWarning: PY_SSIZE_T_CLEAN + * will be required for '#' formats. + */ +#define PY_SSIZE_T_CLEAN + #include #include "../../../util/trace-event.h" #include "../../../util/event.h" #include "../../../util/symbol.h" #include "../../../util/thread.h" +#include "../../../util/map.h" #include "../../../util/maps.h" #include "../../../util/auxtrace.h" #include "../../../util/session.h" +#include "../../../util/srcline.h" +#include "../../../util/srccode.h" #if PY_MAJOR_VERSION < 3 #define _PyCapsule_GetPointer(arg1, arg2) \ @@ -125,6 +134,49 @@ out: return Py_BuildValue("i", retval); } +static PyObject *perf_sample_src(PyObject *obj, PyObject *args, bool get_srccode) +{ + struct scripting_context *c = get_scripting_context(args); + unsigned int line = 0; + char *srcfile = NULL; + char *srccode = NULL; + PyObject *result; + struct map *map; + int len = 0; + u64 addr; + + if (!c) + return NULL; + + map = c->al->map; + addr = c->al->addr; + + if (map && map->dso) + srcfile = get_srcline_split(map->dso, map__rip_2objdump(map, addr), &line); + + if (get_srccode) { + if (srcfile) + srccode = find_sourceline(srcfile, line, &len); + result = Py_BuildValue("(sIs#)", srcfile, line, srccode, (Py_ssize_t)len); + } else { + result = Py_BuildValue("(sI)", srcfile, line); + } + + free(srcfile); + + return result; +} + +static PyObject *perf_sample_srcline(PyObject *obj, PyObject *args) +{ + return perf_sample_src(obj, args, false); +} + +static PyObject *perf_sample_srccode(PyObject *obj, PyObject *args) +{ + return perf_sample_src(obj, args, true); +} + static PyMethodDef ContextMethods[] = { { "common_pc", perf_trace_context_common_pc, METH_VARARGS, "Get the common preempt count event field value."}, @@ -136,6 +188,10 @@ static PyMethodDef ContextMethods[] = { METH_VARARGS, "Get the machine code instruction."}, { "perf_set_itrace_options", perf_set_itrace_options, METH_VARARGS, "Set --itrace options."}, + { "perf_sample_srcline", perf_sample_srcline, + METH_VARARGS, "Get source file name and line number."}, + { "perf_sample_srccode", perf_sample_srccode, + METH_VARARGS, "Get source file name, line number and line."}, { NULL, NULL, 0, NULL} }; -- cgit v1.2.3 From 2b87386c7a1c0488bf2a27d7f4ac80aa84e22fb5 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 30 May 2021 22:23:07 +0300 Subject: perf scripting python: exported-sql-viewer.py: Factor out libxed.py Factor out libxed.py so it can be reused. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Link: https://lore.kernel.org/r/20210530192308.7382-13-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/exported-sql-viewer.py | 89 +------------------ tools/perf/scripts/python/libxed.py | 107 +++++++++++++++++++++++ 2 files changed, 108 insertions(+), 88 deletions(-) create mode 100644 tools/perf/scripts/python/libxed.py (limited to 'tools/perf/scripts/python') diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index 711d4f9f5645..13f2d8a81610 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py @@ -113,6 +113,7 @@ import os import random import copy import math +from libxed import LibXED pyside_version_1 = True if not "--pyside-version-1" in sys.argv: @@ -4747,94 +4748,6 @@ class MainWindow(QMainWindow): dialog = AboutDialog(self.glb, self) dialog.exec_() -# XED Disassembler - -class xed_state_t(Structure): - - _fields_ = [ - ("mode", c_int), - ("width", c_int) - ] - -class XEDInstruction(): - - def __init__(self, libxed): - # Current xed_decoded_inst_t structure is 192 bytes. Use 512 to allow for future expansion - xedd_t = c_byte * 512 - self.xedd = xedd_t() - self.xedp = addressof(self.xedd) - libxed.xed_decoded_inst_zero(self.xedp) - self.state = xed_state_t() - self.statep = addressof(self.state) - # Buffer for disassembled instruction text - self.buffer = create_string_buffer(256) - self.bufferp = addressof(self.buffer) - -class LibXED(): - - def __init__(self): - try: - self.libxed = CDLL("libxed.so") - except: - self.libxed = None - if not self.libxed: - self.libxed = CDLL("/usr/local/lib/libxed.so") - - self.xed_tables_init = self.libxed.xed_tables_init - self.xed_tables_init.restype = None - self.xed_tables_init.argtypes = [] - - self.xed_decoded_inst_zero = self.libxed.xed_decoded_inst_zero - self.xed_decoded_inst_zero.restype = None - self.xed_decoded_inst_zero.argtypes = [ c_void_p ] - - self.xed_operand_values_set_mode = self.libxed.xed_operand_values_set_mode - self.xed_operand_values_set_mode.restype = None - self.xed_operand_values_set_mode.argtypes = [ c_void_p, c_void_p ] - - self.xed_decoded_inst_zero_keep_mode = self.libxed.xed_decoded_inst_zero_keep_mode - self.xed_decoded_inst_zero_keep_mode.restype = None - self.xed_decoded_inst_zero_keep_mode.argtypes = [ c_void_p ] - - self.xed_decode = self.libxed.xed_decode - self.xed_decode.restype = c_int - self.xed_decode.argtypes = [ c_void_p, c_void_p, c_uint ] - - self.xed_format_context = self.libxed.xed_format_context - self.xed_format_context.restype = c_uint - self.xed_format_context.argtypes = [ c_int, c_void_p, c_void_p, c_int, c_ulonglong, c_void_p, c_void_p ] - - self.xed_tables_init() - - def Instruction(self): - return XEDInstruction(self) - - def SetMode(self, inst, mode): - if mode: - inst.state.mode = 4 # 32-bit - inst.state.width = 4 # 4 bytes - else: - inst.state.mode = 1 # 64-bit - inst.state.width = 8 # 8 bytes - self.xed_operand_values_set_mode(inst.xedp, inst.statep) - - def DisassembleOne(self, inst, bytes_ptr, bytes_cnt, ip): - self.xed_decoded_inst_zero_keep_mode(inst.xedp) - err = self.xed_decode(inst.xedp, bytes_ptr, bytes_cnt) - if err: - return 0, "" - # Use AT&T mode (2), alternative is Intel (3) - ok = self.xed_format_context(2, inst.xedp, inst.bufferp, sizeof(inst.buffer), ip, 0, 0) - if not ok: - return 0, "" - if sys.version_info[0] == 2: - result = inst.buffer.value - else: - result = inst.buffer.value.decode() - # Return instruction length and the disassembled instruction text - # For now, assume the length is in byte 166 - return inst.xedd[166], result - def TryOpen(file_name): try: return open(file_name, "rb") diff --git a/tools/perf/scripts/python/libxed.py b/tools/perf/scripts/python/libxed.py new file mode 100644 index 000000000000..2c70a5a7eb9c --- /dev/null +++ b/tools/perf/scripts/python/libxed.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: GPL-2.0 +# libxed.py: Python wrapper for libxed.so +# Copyright (c) 2014-2021, Intel Corporation. + +# To use Intel XED, libxed.so must be present. To build and install +# libxed.so: +# git clone https://github.com/intelxed/mbuild.git mbuild +# git clone https://github.com/intelxed/xed +# cd xed +# ./mfile.py --share +# sudo ./mfile.py --prefix=/usr/local install +# sudo ldconfig +# + +import sys + +from ctypes import CDLL, Structure, create_string_buffer, addressof, sizeof, \ + c_void_p, c_bool, c_byte, c_char, c_int, c_uint, c_longlong, c_ulonglong + +# XED Disassembler + +class xed_state_t(Structure): + + _fields_ = [ + ("mode", c_int), + ("width", c_int) + ] + +class XEDInstruction(): + + def __init__(self, libxed): + # Current xed_decoded_inst_t structure is 192 bytes. Use 512 to allow for future expansion + xedd_t = c_byte * 512 + self.xedd = xedd_t() + self.xedp = addressof(self.xedd) + libxed.xed_decoded_inst_zero(self.xedp) + self.state = xed_state_t() + self.statep = addressof(self.state) + # Buffer for disassembled instruction text + self.buffer = create_string_buffer(256) + self.bufferp = addressof(self.buffer) + +class LibXED(): + + def __init__(self): + try: + self.libxed = CDLL("libxed.so") + except: + self.libxed = None + if not self.libxed: + self.libxed = CDLL("/usr/local/lib/libxed.so") + + self.xed_tables_init = self.libxed.xed_tables_init + self.xed_tables_init.restype = None + self.xed_tables_init.argtypes = [] + + self.xed_decoded_inst_zero = self.libxed.xed_decoded_inst_zero + self.xed_decoded_inst_zero.restype = None + self.xed_decoded_inst_zero.argtypes = [ c_void_p ] + + self.xed_operand_values_set_mode = self.libxed.xed_operand_values_set_mode + self.xed_operand_values_set_mode.restype = None + self.xed_operand_values_set_mode.argtypes = [ c_void_p, c_void_p ] + + self.xed_decoded_inst_zero_keep_mode = self.libxed.xed_decoded_inst_zero_keep_mode + self.xed_decoded_inst_zero_keep_mode.restype = None + self.xed_decoded_inst_zero_keep_mode.argtypes = [ c_void_p ] + + self.xed_decode = self.libxed.xed_decode + self.xed_decode.restype = c_int + self.xed_decode.argtypes = [ c_void_p, c_void_p, c_uint ] + + self.xed_format_context = self.libxed.xed_format_context + self.xed_format_context.restype = c_uint + self.xed_format_context.argtypes = [ c_int, c_void_p, c_void_p, c_int, c_ulonglong, c_void_p, c_void_p ] + + self.xed_tables_init() + + def Instruction(self): + return XEDInstruction(self) + + def SetMode(self, inst, mode): + if mode: + inst.state.mode = 4 # 32-bit + inst.state.width = 4 # 4 bytes + else: + inst.state.mode = 1 # 64-bit + inst.state.width = 8 # 8 bytes + self.xed_operand_values_set_mode(inst.xedp, inst.statep) + + def DisassembleOne(self, inst, bytes_ptr, bytes_cnt, ip): + self.xed_decoded_inst_zero_keep_mode(inst.xedp) + err = self.xed_decode(inst.xedp, bytes_ptr, bytes_cnt) + if err: + return 0, "" + # Use AT&T mode (2), alternative is Intel (3) + ok = self.xed_format_context(2, inst.xedp, inst.bufferp, sizeof(inst.buffer), ip, 0, 0) + if not ok: + return 0, "" + if sys.version_info[0] == 2: + result = inst.buffer.value + else: + result = inst.buffer.value.decode() + # Return instruction length and the disassembled instruction text + # For now, assume the length is in byte 166 + return inst.xedd[166], result -- cgit v1.2.3 From a483e64c0b62e93a772cbc96f32bad885586fad7 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 30 May 2021 22:23:08 +0300 Subject: perf scripting python: intel-pt-events.py: Add --insn-trace and --src-trace Add an instruction trace and a source trace to the intel-pt-events.py script. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Link: https://lore.kernel.org/r/20210530192308.7382-14-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-intel-pt.txt | 6 +- tools/perf/scripts/python/intel-pt-events.py | 176 ++++++++++++++++++++++++--- 2 files changed, 163 insertions(+), 19 deletions(-) (limited to 'tools/perf/scripts/python') diff --git a/tools/perf/Documentation/perf-intel-pt.txt b/tools/perf/Documentation/perf-intel-pt.txt index e382dbd4ff0a..184ba62420f0 100644 --- a/tools/perf/Documentation/perf-intel-pt.txt +++ b/tools/perf/Documentation/perf-intel-pt.txt @@ -174,7 +174,11 @@ Refer to script export-to-sqlite.py or export-to-postgresql.py for more details, and to script exported-sql-viewer.py for an example of using the database. There is also script intel-pt-events.py which provides an example of how to -unpack the raw data for power events and PTWRITE. +unpack the raw data for power events and PTWRITE. The script also displays +branches, and supports 2 additional modes selected by option: + + --insn-trace - instruction trace + --src-trace - source trace As mentioned above, it is easy to capture too much data. One way to limit the data captured is to use 'snapshot' mode which is explained further below. diff --git a/tools/perf/scripts/python/intel-pt-events.py b/tools/perf/scripts/python/intel-pt-events.py index fcfae1de731b..1d3a189a9a54 100644 --- a/tools/perf/scripts/python/intel-pt-events.py +++ b/tools/perf/scripts/python/intel-pt-events.py @@ -16,21 +16,30 @@ from __future__ import print_function import os import sys import struct +import argparse + +from libxed import LibXED +from ctypes import create_string_buffer, addressof sys.path.append(os.environ['PERF_EXEC_PATH'] + \ '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') -# These perf imports are not used at present -#from perf_trace_context import * -#from Core import * +from perf_trace_context import perf_set_itrace_options, \ + perf_sample_insn, perf_sample_srccode try: broken_pipe_exception = BrokenPipeError except: broken_pipe_exception = IOError -glb_switch_str = None -glb_switch_printed = True +glb_switch_str = None +glb_switch_printed = True +glb_insn = False +glb_disassembler = None +glb_src = False +glb_source_file_name = None +glb_line_number = None +glb_dso = None def get_optional_null(perf_dict, field): if field in perf_dict: @@ -42,6 +51,11 @@ def get_optional_zero(perf_dict, field): return perf_dict[field] return 0 +def get_optional_bytes(perf_dict, field): + if field in perf_dict: + return perf_dict[field] + return bytes() + def get_optional(perf_dict, field): if field in perf_dict: return perf_dict[field] @@ -53,7 +67,31 @@ def get_offset(perf_dict, field): return "" def trace_begin(): - print("Intel PT Branch Trace, Power Events and PTWRITE") + ap = argparse.ArgumentParser(usage = "", add_help = False) + ap.add_argument("--insn-trace", action='store_true') + ap.add_argument("--src-trace", action='store_true') + global glb_args + global glb_insn + global glb_src + glb_args = ap.parse_args() + if glb_args.insn_trace: + print("Intel PT Instruction Trace") + itrace = "i0nsepwx" + glb_insn = True + elif glb_args.src_trace: + print("Intel PT Source Trace") + itrace = "i0nsepwx" + glb_insn = True + glb_src = True + else: + print("Intel PT Branch Trace, Power Events and PTWRITE") + itrace = "bepwx" + global glb_disassembler + try: + glb_disassembler = LibXED() + except: + glb_disassembler = None + perf_set_itrace_options(perf_script_context, itrace) def trace_end(): print("End") @@ -111,11 +149,14 @@ def print_psb(raw_buf): offset = data[1] print("offset: %#x" % (offset), end=' ') -def print_common_start(comm, sample, name): +def common_start_str(comm, sample): ts = sample["time"] cpu = sample["cpu"] pid = sample["pid"] tid = sample["tid"] + return "%16s %5u/%-5u [%03u] %9u.%09u " % (comm, pid, tid, cpu, ts / 1000000000, ts %1000000000) + +def print_common_start(comm, sample, name): flags_disp = get_optional_null(sample, "flags_disp") # Unused fields: # period = sample["period"] @@ -123,22 +164,96 @@ def print_common_start(comm, sample, name): # weight = sample["weight"] # transaction = sample["transaction"] # cpumode = get_optional_zero(sample, "cpumode") - print("%16s %5u/%-5u [%03u] %9u.%09u %7s %19s" % - (comm, pid, tid, cpu, ts / 1000000000, ts %1000000000, name, flags_disp), - end=' ') + print(common_start_str(comm, sample) + "%7s %19s" % (name, flags_disp), end=' ') + +def print_instructions_start(comm, sample): + if "x" in get_optional_null(sample, "flags"): + print(common_start_str(comm, sample) + "x", end=' ') + else: + print(common_start_str(comm, sample), end=' ') + +def disassem(insn, ip): + inst = glb_disassembler.Instruction() + glb_disassembler.SetMode(inst, 0) # Assume 64-bit + buf = create_string_buffer(64) + buf.value = insn + return glb_disassembler.DisassembleOne(inst, addressof(buf), len(insn), ip) def print_common_ip(param_dict, sample, symbol, dso): ip = sample["ip"] offs = get_offset(param_dict, "symoff") - print("%16x %s%s (%s)" % (ip, symbol, offs, dso), end=' ') + if "cyc_cnt" in sample: + cyc_cnt = sample["cyc_cnt"] + insn_cnt = get_optional_zero(sample, "insn_cnt") + ipc_str = " IPC: %#.2f (%u/%u)" % (insn_cnt / cyc_cnt, insn_cnt, cyc_cnt) + else: + ipc_str = "" + if glb_insn and glb_disassembler is not None: + insn = perf_sample_insn(perf_script_context) + if insn and len(insn): + cnt, text = disassem(insn, ip) + byte_str = ("%x" % ip).rjust(16) + if sys.version_info.major >= 3: + for k in range(cnt): + byte_str += " %02x" % insn[k] + else: + for k in xrange(cnt): + byte_str += " %02x" % ord(insn[k]) + print("%-40s %-30s" % (byte_str, text), end=' ') + print("%s%s (%s)" % (symbol, offs, dso), end=' ') + else: + print("%16x %s%s (%s)" % (ip, symbol, offs, dso), end=' ') if "addr_correlates_sym" in sample: addr = sample["addr"] dso = get_optional(sample, "addr_dso") symbol = get_optional(sample, "addr_symbol") offs = get_offset(sample, "addr_symoff") - print("=> %x %s%s (%s)" % (addr, symbol, offs, dso)) + print("=> %x %s%s (%s)%s" % (addr, symbol, offs, dso, ipc_str)) + else: + print(ipc_str) + +def print_srccode(comm, param_dict, sample, symbol, dso, with_insn): + ip = sample["ip"] + if symbol == "[unknown]": + start_str = common_start_str(comm, sample) + ("%x" % ip).rjust(16).ljust(40) else: - print() + offs = get_offset(param_dict, "symoff") + start_str = common_start_str(comm, sample) + (symbol + offs).ljust(40) + + if with_insn and glb_insn and glb_disassembler is not None: + insn = perf_sample_insn(perf_script_context) + if insn and len(insn): + cnt, text = disassem(insn, ip) + start_str += text.ljust(30) + + global glb_source_file_name + global glb_line_number + global glb_dso + + source_file_name, line_number, source_line = perf_sample_srccode(perf_script_context) + if source_file_name: + if glb_line_number == line_number and glb_source_file_name == source_file_name: + src_str = "" + else: + if len(source_file_name) > 40: + src_file = ("..." + source_file_name[-37:]) + " " + else: + src_file = source_file_name.ljust(41) + if source_line is None: + src_str = src_file + str(line_number).rjust(4) + " " + else: + src_str = src_file + str(line_number).rjust(4) + " " + source_line + glb_dso = None + elif dso == glb_dso: + src_str = "" + else: + src_str = dso + glb_dso = dso + + glb_line_number = line_number + glb_source_file_name = source_file_name + + print(start_str, src_str) def do_process_event(param_dict): global glb_switch_printed @@ -159,24 +274,49 @@ def do_process_event(param_dict): dso = get_optional(param_dict, "dso") symbol = get_optional(param_dict, "symbol") - print_common_start(comm, sample, name) - - if name == "ptwrite": + if name[0:12] == "instructions": + if glb_src: + print_srccode(comm, param_dict, sample, symbol, dso, True) + else: + print_instructions_start(comm, sample) + print_common_ip(param_dict, sample, symbol, dso) + elif name[0:8] == "branches": + if glb_src: + print_srccode(comm, param_dict, sample, symbol, dso, False) + else: + print_common_start(comm, sample, name) + print_common_ip(param_dict, sample, symbol, dso) + elif name == "ptwrite": + print_common_start(comm, sample, name) print_ptwrite(raw_buf) + print_common_ip(param_dict, sample, symbol, dso) elif name == "cbr": + print_common_start(comm, sample, name) print_cbr(raw_buf) + print_common_ip(param_dict, sample, symbol, dso) elif name == "mwait": + print_common_start(comm, sample, name) print_mwait(raw_buf) + print_common_ip(param_dict, sample, symbol, dso) elif name == "pwre": + print_common_start(comm, sample, name) print_pwre(raw_buf) + print_common_ip(param_dict, sample, symbol, dso) elif name == "exstop": + print_common_start(comm, sample, name) print_exstop(raw_buf) + print_common_ip(param_dict, sample, symbol, dso) elif name == "pwrx": + print_common_start(comm, sample, name) print_pwrx(raw_buf) + print_common_ip(param_dict, sample, symbol, dso) elif name == "psb": + print_common_start(comm, sample, name) print_psb(raw_buf) - - print_common_ip(param_dict, sample, symbol, dso) + print_common_ip(param_dict, sample, symbol, dso) + else: + print_common_start(comm, sample, name) + print_common_ip(param_dict, sample, symbol, dso) def process_event(param_dict): try: -- cgit v1.2.3