diff options
Diffstat (limited to 'tools/perf/scripts/python')
16 files changed, 619 insertions, 0 deletions
| diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c new file mode 100644 index 000000000000..957085dd5d8d --- /dev/null +++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c @@ -0,0 +1,88 @@ +/* + * Context.c.  Python interfaces for perf trace. + * + * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ + +#include <Python.h> +#include "../../../perf.h" +#include "../../../util/trace-event.h" + +PyMODINIT_FUNC initperf_trace_context(void); + +static PyObject *perf_trace_context_common_pc(PyObject *self, PyObject *args) +{ +	static struct scripting_context *scripting_context; +	PyObject *context; +	int retval; + +	if (!PyArg_ParseTuple(args, "O", &context)) +		return NULL; + +	scripting_context = PyCObject_AsVoidPtr(context); +	retval = common_pc(scripting_context); + +	return Py_BuildValue("i", retval); +} + +static PyObject *perf_trace_context_common_flags(PyObject *self, +						 PyObject *args) +{ +	static struct scripting_context *scripting_context; +	PyObject *context; +	int retval; + +	if (!PyArg_ParseTuple(args, "O", &context)) +		return NULL; + +	scripting_context = PyCObject_AsVoidPtr(context); +	retval = common_flags(scripting_context); + +	return Py_BuildValue("i", retval); +} + +static PyObject *perf_trace_context_common_lock_depth(PyObject *self, +						      PyObject *args) +{ +	static struct scripting_context *scripting_context; +	PyObject *context; +	int retval; + +	if (!PyArg_ParseTuple(args, "O", &context)) +		return NULL; + +	scripting_context = PyCObject_AsVoidPtr(context); +	retval = common_lock_depth(scripting_context); + +	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."}, +	{ "common_flags", perf_trace_context_common_flags, METH_VARARGS, +	  "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."}, +	{ NULL, NULL, 0, NULL} +}; + +PyMODINIT_FUNC initperf_trace_context(void) +{ +	(void) Py_InitModule("perf_trace_context", ContextMethods); +} diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py new file mode 100644 index 000000000000..1dc464ee2ca8 --- /dev/null +++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py @@ -0,0 +1,91 @@ +# Core.py - Python extension for perf trace, core functions +# +# Copyright (C) 2010 by Tom Zanussi <tzanussi@gmail.com> +# +# This software may be distributed under the terms of the GNU General +# Public License ("GPL") version 2 as published by the Free Software +# Foundation. + +from collections import defaultdict + +def autodict(): +    return defaultdict(autodict) + +flag_fields = autodict() +symbolic_fields = autodict() + +def define_flag_field(event_name, field_name, delim): +    flag_fields[event_name][field_name]['delim'] = delim + +def define_flag_value(event_name, field_name, value, field_str): +    flag_fields[event_name][field_name]['values'][value] = field_str + +def define_symbolic_field(event_name, field_name): +    # nothing to do, really +    pass + +def define_symbolic_value(event_name, field_name, value, field_str): +    symbolic_fields[event_name][field_name]['values'][value] = field_str + +def flag_str(event_name, field_name, value): +    string = "" + +    if flag_fields[event_name][field_name]: +	print_delim = 0 +        keys = flag_fields[event_name][field_name]['values'].keys() +        keys.sort() +        for idx in keys: +            if not value and not idx: +                string += flag_fields[event_name][field_name]['values'][idx] +                break +            if idx and (value & idx) == idx: +                if print_delim and flag_fields[event_name][field_name]['delim']: +                    string += " " + flag_fields[event_name][field_name]['delim'] + " " +                string += flag_fields[event_name][field_name]['values'][idx] +                print_delim = 1 +                value &= ~idx + +    return string + +def symbol_str(event_name, field_name, value): +    string = "" + +    if symbolic_fields[event_name][field_name]: +        keys = symbolic_fields[event_name][field_name]['values'].keys() +        keys.sort() +        for idx in keys: +            if not value and not idx: +		string = symbolic_fields[event_name][field_name]['values'][idx] +                break +	    if (value == idx): +		string = symbolic_fields[event_name][field_name]['values'][idx] +                break + +    return string + +trace_flags = { 0x00: "NONE", \ +                    0x01: "IRQS_OFF", \ +                    0x02: "IRQS_NOSUPPORT", \ +                    0x04: "NEED_RESCHED", \ +                    0x08: "HARDIRQ", \ +                    0x10: "SOFTIRQ" } + +def trace_flag_str(value): +    string = "" +    print_delim = 0 + +    keys = trace_flags.keys() + +    for idx in keys: +	if not value and not idx: +	    string += "NONE" +	    break + +	if idx and (value & idx) == idx: +	    if print_delim: +		string += " | "; +	    string += trace_flags[idx] +	    print_delim = 1 +	    value &= ~idx + +    return string diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py new file mode 100644 index 000000000000..9689bc0acd9f --- /dev/null +++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py @@ -0,0 +1,28 @@ +# Util.py - Python extension for perf trace, miscellaneous utility code +# +# Copyright (C) 2010 by Tom Zanussi <tzanussi@gmail.com> +# +# This software may be distributed under the terms of the GNU General +# Public License ("GPL") version 2 as published by the Free Software +# Foundation. + +NSECS_PER_SEC    = 1000000000 + +def avg(total, n): +    return total / n + +def nsecs(secs, nsecs): +    return secs * NSECS_PER_SEC + nsecs + +def nsecs_secs(nsecs): +    return nsecs / NSECS_PER_SEC + +def nsecs_nsecs(nsecs): +    return nsecs % NSECS_PER_SEC + +def nsecs_str(nsecs): +    str = "%5u.%09u" % (nsecs_secs(nsecs), nsecs_nsecs(nsecs)), +    return str + +def clear_term(): +    print("\x1b[H\x1b[2J") diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record new file mode 100644 index 000000000000..eb5846bcb565 --- /dev/null +++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record @@ -0,0 +1,2 @@ +#!/bin/bash +perf record -a -e raw_syscalls:sys_exit $@ diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report new file mode 100644 index 000000000000..30293545fcc2 --- /dev/null +++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report @@ -0,0 +1,10 @@ +#!/bin/bash +# description: system-wide failed syscalls, by pid +# args: [comm] +if [ $# -gt 0 ] ; then +    if ! expr match "$1" "-" > /dev/null ; then +	comm=$1 +	shift +    fi +fi +perf trace $@ -s ~/libexec/perf-core/scripts/python/failed-syscalls-by-pid.py $comm diff --git a/tools/perf/scripts/python/bin/sctop-record b/tools/perf/scripts/python/bin/sctop-record new file mode 100644 index 000000000000..1fc5998b721d --- /dev/null +++ b/tools/perf/scripts/python/bin/sctop-record @@ -0,0 +1,2 @@ +#!/bin/bash +perf record -a -e raw_syscalls:sys_enter $@ diff --git a/tools/perf/scripts/python/bin/sctop-report b/tools/perf/scripts/python/bin/sctop-report new file mode 100644 index 000000000000..b01c842ae7b4 --- /dev/null +++ b/tools/perf/scripts/python/bin/sctop-report @@ -0,0 +1,24 @@ +#!/bin/bash +# description: syscall top +# args: [comm] [interval] +n_args=0 +for i in "$@" +do +    if expr match "$i" "-" > /dev/null ; then +	break +    fi +    n_args=$(( $n_args + 1 )) +done +if [ "$n_args" -gt 2 ] ; then +    echo "usage: sctop-report [comm] [interval]" +    exit +fi +if [ "$n_args" -gt 1 ] ; then +    comm=$1 +    interval=$2 +    shift 2 +elif [ "$n_args" -gt 0 ] ; then +    interval=$1 +    shift +fi +perf trace $@ -s ~/libexec/perf-core/scripts/python/sctop.py $comm $interval diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record new file mode 100644 index 000000000000..1fc5998b721d --- /dev/null +++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record @@ -0,0 +1,2 @@ +#!/bin/bash +perf record -a -e raw_syscalls:sys_enter $@ diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-report b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report new file mode 100644 index 000000000000..9e9d8ddd72ce --- /dev/null +++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report @@ -0,0 +1,10 @@ +#!/bin/bash +# description: system-wide syscall counts, by pid +# args: [comm] +if [ $# -gt 0 ] ; then +    if ! expr match "$1" "-" > /dev/null ; then +	comm=$1 +	shift +    fi +fi +perf trace $@ -s ~/libexec/perf-core/scripts/python/syscall-counts-by-pid.py $comm diff --git a/tools/perf/scripts/python/bin/syscall-counts-record b/tools/perf/scripts/python/bin/syscall-counts-record new file mode 100644 index 000000000000..1fc5998b721d --- /dev/null +++ b/tools/perf/scripts/python/bin/syscall-counts-record @@ -0,0 +1,2 @@ +#!/bin/bash +perf record -a -e raw_syscalls:sys_enter $@ diff --git a/tools/perf/scripts/python/bin/syscall-counts-report b/tools/perf/scripts/python/bin/syscall-counts-report new file mode 100644 index 000000000000..dc076b618796 --- /dev/null +++ b/tools/perf/scripts/python/bin/syscall-counts-report @@ -0,0 +1,10 @@ +#!/bin/bash +# description: system-wide syscall counts +# args: [comm] +if [ $# -gt 0 ] ; then +    if ! expr match "$1" "-" > /dev/null ; then +	comm=$1 +	shift +    fi +fi +perf trace $@ -s ~/libexec/perf-core/scripts/python/syscall-counts.py $comm diff --git a/tools/perf/scripts/python/check-perf-trace.py b/tools/perf/scripts/python/check-perf-trace.py new file mode 100644 index 000000000000..d9f7893e315c --- /dev/null +++ b/tools/perf/scripts/python/check-perf-trace.py @@ -0,0 +1,82 @@ +# perf trace event handlers, generated by perf trace -g python +# (c) 2010, Tom Zanussi <tzanussi@gmail.com> +# Licensed under the terms of the GNU GPL License version 2 +# +# This script tests basic functionality such as flag and symbol +# strings, common_xxx() calls back into perf, begin, end, unhandled +# events, etc.  Basically, if this script runs successfully and +# displays expected results, Python scripting support should be ok. + +import os +import sys + +sys.path.append(os.environ['PERF_EXEC_PATH'] + \ +	'/scripts/python/Perf-Trace-Util/lib/Perf/Trace') + +from Core import * +from perf_trace_context import * + +unhandled = autodict() + +def trace_begin(): +	print "trace_begin" +	pass + +def trace_end(): +        print_unhandled() + +def irq__softirq_entry(event_name, context, common_cpu, +	common_secs, common_nsecs, common_pid, common_comm, +	vec): +		print_header(event_name, common_cpu, common_secs, common_nsecs, +			common_pid, common_comm) + +                print_uncommon(context) + +		print "vec=%s\n" % \ +		(symbol_str("irq__softirq_entry", "vec", vec)), + +def kmem__kmalloc(event_name, context, common_cpu, +	common_secs, common_nsecs, common_pid, common_comm, +	call_site, ptr, bytes_req, bytes_alloc, +	gfp_flags): +		print_header(event_name, common_cpu, common_secs, common_nsecs, +			common_pid, common_comm) + +                print_uncommon(context) + +		print "call_site=%u, ptr=%u, bytes_req=%u, " \ +		"bytes_alloc=%u, gfp_flags=%s\n" % \ +		(call_site, ptr, bytes_req, bytes_alloc, + +		flag_str("kmem__kmalloc", "gfp_flags", gfp_flags)), + +def trace_unhandled(event_name, context, event_fields_dict): +    try: +        unhandled[event_name] += 1 +    except TypeError: +        unhandled[event_name] = 1 + +def print_header(event_name, cpu, secs, nsecs, pid, comm): +	print "%-20s %5u %05u.%09u %8u %-20s " % \ +	(event_name, cpu, secs, nsecs, pid, comm), + +# print trace fields not included in handler args +def print_uncommon(context): +    print "common_preempt_count=%d, common_flags=%s, common_lock_depth=%d, " \ +        % (common_pc(context), trace_flag_str(common_flags(context)), \ +               common_lock_depth(context)) + +def print_unhandled(): +    keys = unhandled.keys() +    if not keys: +        return + +    print "\nunhandled events:\n\n", + +    print "%-40s  %10s\n" % ("event", "count"), +    print "%-40s  %10s\n" % ("----------------------------------------", \ +                                 "-----------"), + +    for event_name in keys: +	print "%-40s  %10d\n" % (event_name, unhandled[event_name]) diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py new file mode 100644 index 000000000000..0ca02278fe69 --- /dev/null +++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py @@ -0,0 +1,68 @@ +# failed system call counts, by pid +# (c) 2010, Tom Zanussi <tzanussi@gmail.com> +# Licensed under the terms of the GNU GPL License version 2 +# +# Displays system-wide failed system call totals, broken down by pid. +# If a [comm] arg is specified, only syscalls called by [comm] are displayed. + +import os +import sys + +sys.path.append(os.environ['PERF_EXEC_PATH'] + \ +	'/scripts/python/Perf-Trace-Util/lib/Perf/Trace') + +from perf_trace_context import * +from Core import * + +usage = "perf trace -s syscall-counts-by-pid.py [comm]\n"; + +for_comm = None + +if len(sys.argv) > 2: +	sys.exit(usage) + +if len(sys.argv) > 1: +	for_comm = sys.argv[1] + +syscalls = autodict() + +def trace_begin(): +	pass + +def trace_end(): +	print_error_totals() + +def raw_syscalls__sys_exit(event_name, context, common_cpu, +	common_secs, common_nsecs, common_pid, common_comm, +	id, ret): +	if for_comm is not None: +		if common_comm != for_comm: +			return + +	if ret < 0: +		try: +			syscalls[common_comm][common_pid][id][ret] += 1 +		except TypeError: +			syscalls[common_comm][common_pid][id][ret] = 1 + +def print_error_totals(): +    if for_comm is not None: +	    print "\nsyscall errors for %s:\n\n" % (for_comm), +    else: +	    print "\nsyscall errors:\n\n", + +    print "%-30s  %10s\n" % ("comm [pid]", "count"), +    print "%-30s  %10s\n" % ("------------------------------", \ +                                 "----------"), + +    comm_keys = syscalls.keys() +    for comm in comm_keys: +	    pid_keys = syscalls[comm].keys() +	    for pid in pid_keys: +		    print "\n%s [%d]\n" % (comm, pid), +		    id_keys = syscalls[comm][pid].keys() +		    for id in id_keys: +			    print "  syscall: %-16d\n" % (id), +			    ret_keys = syscalls[comm][pid][id].keys() +			    for ret, val in sorted(syscalls[comm][pid][id].iteritems(), key = lambda(k, v): (v, k),  reverse = True): +				    print "    err = %-20d  %10d\n" % (ret, val), diff --git a/tools/perf/scripts/python/sctop.py b/tools/perf/scripts/python/sctop.py new file mode 100644 index 000000000000..6cafad40c296 --- /dev/null +++ b/tools/perf/scripts/python/sctop.py @@ -0,0 +1,78 @@ +# system call top +# (c) 2010, Tom Zanussi <tzanussi@gmail.com> +# Licensed under the terms of the GNU GPL License version 2 +# +# Periodically displays system-wide system call totals, broken down by +# syscall.  If a [comm] arg is specified, only syscalls called by +# [comm] are displayed. If an [interval] arg is specified, the display +# will be refreshed every [interval] seconds.  The default interval is +# 3 seconds. + +import thread +import time +import os +import sys + +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 * + +usage = "perf trace -s syscall-counts.py [comm] [interval]\n"; + +for_comm = None +default_interval = 3 +interval = default_interval + +if len(sys.argv) > 3: +	sys.exit(usage) + +if len(sys.argv) > 2: +	for_comm = sys.argv[1] +	interval = int(sys.argv[2]) +elif len(sys.argv) > 1: +	try: +		interval = int(sys.argv[1]) +	except ValueError: +		for_comm = sys.argv[1] +		interval = default_interval + +syscalls = autodict() + +def trace_begin(): +	thread.start_new_thread(print_syscall_totals, (interval,)) +	pass + +def raw_syscalls__sys_enter(event_name, context, common_cpu, +	common_secs, common_nsecs, common_pid, common_comm, +	id, args): +	if for_comm is not None: +		if common_comm != for_comm: +			return +	try: +		syscalls[id] += 1 +	except TypeError: +		syscalls[id] = 1 + +def print_syscall_totals(interval): +	while 1: +		clear_term() +		if for_comm is not None: +			print "\nsyscall events for %s:\n\n" % (for_comm), +		else: +			print "\nsyscall events:\n\n", + +		print "%-40s  %10s\n" % ("event", "count"), +		print "%-40s  %10s\n" % ("----------------------------------------", \ +						 "----------"), + +		for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \ +					      reverse = True): +			try: +				print "%-40d  %10d\n" % (id, val), +			except TypeError: +				pass +		syscalls.clear() +		time.sleep(interval) diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py new file mode 100644 index 000000000000..af722d6a4b3f --- /dev/null +++ b/tools/perf/scripts/python/syscall-counts-by-pid.py @@ -0,0 +1,64 @@ +# system call counts, by pid +# (c) 2010, Tom Zanussi <tzanussi@gmail.com> +# Licensed under the terms of the GNU GPL License version 2 +# +# Displays system-wide system call totals, broken down by syscall. +# If a [comm] arg is specified, only syscalls called by [comm] are displayed. + +import os +import sys + +sys.path.append(os.environ['PERF_EXEC_PATH'] + \ +	'/scripts/python/Perf-Trace-Util/lib/Perf/Trace') + +from perf_trace_context import * +from Core import * + +usage = "perf trace -s syscall-counts-by-pid.py [comm]\n"; + +for_comm = None + +if len(sys.argv) > 2: +	sys.exit(usage) + +if len(sys.argv) > 1: +	for_comm = sys.argv[1] + +syscalls = autodict() + +def trace_begin(): +	pass + +def trace_end(): +	print_syscall_totals() + +def raw_syscalls__sys_enter(event_name, context, common_cpu, +	common_secs, common_nsecs, common_pid, common_comm, +	id, args): +	if for_comm is not None: +		if common_comm != for_comm: +			return +	try: +		syscalls[common_comm][common_pid][id] += 1 +	except TypeError: +		syscalls[common_comm][common_pid][id] = 1 + +def print_syscall_totals(): +    if for_comm is not None: +	    print "\nsyscall events for %s:\n\n" % (for_comm), +    else: +	    print "\nsyscall events by comm/pid:\n\n", + +    print "%-40s  %10s\n" % ("comm [pid]/syscalls", "count"), +    print "%-40s  %10s\n" % ("----------------------------------------", \ +                                 "----------"), + +    comm_keys = syscalls.keys() +    for comm in comm_keys: +	    pid_keys = syscalls[comm].keys() +	    for pid in pid_keys: +		    print "\n%s [%d]\n" % (comm, pid), +		    id_keys = syscalls[comm][pid].keys() +		    for id, val in sorted(syscalls[comm][pid].iteritems(), \ +				  key = lambda(k, v): (v, k),  reverse = True): +			    print "  %-38d  %10d\n" % (id, val), diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py new file mode 100644 index 000000000000..f977e85ff049 --- /dev/null +++ b/tools/perf/scripts/python/syscall-counts.py @@ -0,0 +1,58 @@ +# system call counts +# (c) 2010, Tom Zanussi <tzanussi@gmail.com> +# Licensed under the terms of the GNU GPL License version 2 +# +# Displays system-wide system call totals, broken down by syscall. +# If a [comm] arg is specified, only syscalls called by [comm] are displayed. + +import os +import sys + +sys.path.append(os.environ['PERF_EXEC_PATH'] + \ +	'/scripts/python/Perf-Trace-Util/lib/Perf/Trace') + +from perf_trace_context import * +from Core import * + +usage = "perf trace -s syscall-counts.py [comm]\n"; + +for_comm = None + +if len(sys.argv) > 2: +	sys.exit(usage) + +if len(sys.argv) > 1: +	for_comm = sys.argv[1] + +syscalls = autodict() + +def trace_begin(): +	pass + +def trace_end(): +	print_syscall_totals() + +def raw_syscalls__sys_enter(event_name, context, common_cpu, +	common_secs, common_nsecs, common_pid, common_comm, +	id, args): +	if for_comm is not None: +		if common_comm != for_comm: +			return +	try: +		syscalls[id] += 1 +	except TypeError: +		syscalls[id] = 1 + +def print_syscall_totals(): +    if for_comm is not None: +	    print "\nsyscall events for %s:\n\n" % (for_comm), +    else: +	    print "\nsyscall events:\n\n", + +    print "%-40s  %10s\n" % ("event", "count"), +    print "%-40s  %10s\n" % ("----------------------------------------", \ +                                 "-----------"), + +    for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \ +				  reverse = True): +	    print "%-40d  %10d\n" % (id, val), | 
