2009-11-25 01:15:48 -06:00
|
|
|
/*
|
2010-11-16 18:45:39 +01:00
|
|
|
* trace-event-perl. Feed perf script events to an embedded Perl interpreter.
|
2009-11-25 01:15:48 -06:00
|
|
|
*
|
|
|
|
* Copyright (C) 2009 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
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2017-04-17 15:23:08 -03:00
|
|
|
#include <inttypes.h>
|
2009-11-25 01:15:48 -06:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
2014-10-26 23:44:04 +01:00
|
|
|
#include <linux/bitmap.h>
|
2016-08-05 15:40:30 -03:00
|
|
|
#include <linux/time64.h>
|
perf build: Use libtraceevent from the system
Remove the LIBTRACEEVENT_DYNAMIC and LIBTRACEFS_DYNAMIC make command
line variables.
If libtraceevent isn't installed or NO_LIBTRACEEVENT=1 is passed to the
build, don't compile in libtraceevent and libtracefs support.
This also disables CONFIG_TRACE that controls "perf trace".
CONFIG_LIBTRACEEVENT is used to control enablement in Build/Makefiles,
HAVE_LIBTRACEEVENT is used in C code.
Without HAVE_LIBTRACEEVENT tracepoints are disabled and as such the
commands kmem, kwork, lock, sched and timechart are removed. The
majority of commands continue to work including "perf test".
Committer notes:
Fixed up a tools/perf/util/Build reject and added:
#include <traceevent/event-parse.h>
to tools/perf/util/scripting-engines/trace-event-perl.c.
Committer testing:
$ rpm -qi libtraceevent-devel
Name : libtraceevent-devel
Version : 1.5.3
Release : 2.fc36
Architecture: x86_64
Install Date: Mon 25 Jul 2022 03:20:19 PM -03
Group : Unspecified
Size : 27728
License : LGPLv2+ and GPLv2+
Signature : RSA/SHA256, Fri 15 Apr 2022 02:11:58 PM -03, Key ID 999f7cbf38ab71f4
Source RPM : libtraceevent-1.5.3-2.fc36.src.rpm
Build Date : Fri 15 Apr 2022 10:57:01 AM -03
Build Host : buildvm-x86-05.iad2.fedoraproject.org
Packager : Fedora Project
Vendor : Fedora Project
URL : https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/
Bug URL : https://bugz.fedoraproject.org/libtraceevent
Summary : Development headers of libtraceevent
Description :
Development headers of libtraceevent-libs
$
Default build:
$ ldd ~/bin/perf | grep tracee
libtraceevent.so.1 => /lib64/libtraceevent.so.1 (0x00007f1dcaf8f000)
$
# perf trace -e sched:* --max-events 10
0.000 migration/0/17 sched:sched_migrate_task(comm: "", pid: 1603763 (perf), prio: 120, dest_cpu: 1)
0.005 migration/0/17 sched:sched_wake_idle_without_ipi(cpu: 1)
0.011 migration/0/17 sched:sched_switch(prev_comm: "", prev_pid: 17 (migration/0), prev_state: 1, next_comm: "", next_prio: 120)
1.173 :0/0 sched:sched_wakeup(comm: "", pid: 3138 (gnome-terminal-), prio: 120)
1.180 :0/0 sched:sched_switch(prev_comm: "", prev_prio: 120, next_comm: "", next_pid: 3138 (gnome-terminal-), next_prio: 120)
0.156 migration/1/21 sched:sched_migrate_task(comm: "", pid: 1603763 (perf), prio: 120, orig_cpu: 1, dest_cpu: 2)
0.160 migration/1/21 sched:sched_wake_idle_without_ipi(cpu: 2)
0.166 migration/1/21 sched:sched_switch(prev_comm: "", prev_pid: 21 (migration/1), prev_state: 1, next_comm: "", next_prio: 120)
1.183 :0/0 sched:sched_wakeup(comm: "", pid: 1602985 (kworker/u16:0-f), prio: 120, target_cpu: 1)
1.186 :0/0 sched:sched_switch(prev_comm: "", prev_prio: 120, next_comm: "", next_pid: 1602985 (kworker/u16:0-f), next_prio: 120)
#
Had to tweak tools/perf/util/setup.py to make sure the python binding
shared object links with libtraceevent if -DHAVE_LIBTRACEEVENT is
present in CFLAGS.
Building with NO_LIBTRACEEVENT=1 uncovered some more build failures:
- Make building of data-convert-bt.c to CONFIG_LIBTRACEEVENT=y
- perf-$(CONFIG_LIBTRACEEVENT) += scripts/
- bpf_kwork.o needs also to be dependent on CONFIG_LIBTRACEEVENT=y
- The python binding needed some fixups and util/trace-event.c can't be
built and linked with the python binding shared object, so remove it
in tools/perf/util/setup.py and exclude it from the list of
dependencies in the python/perf.so Makefile.perf target.
Building without libtraceevent-devel installed uncovered more build
failures:
- The python binding tools/perf/util/python.c was assuming that
traceevent/parse-events.h was always available, which was the case
when we defaulted to using the in-kernel tools/lib/traceevent/ files,
now we need to enclose it under ifdef HAVE_LIBTRACEEVENT, just like
the other parts of it that deal with tracepoints.
- We have to ifdef the rules in the Build files with
CONFIG_LIBTRACEEVENT=y to build builtin-trace.c and
tools/perf/trace/beauty/ as we only ifdef setting CONFIG_TRACE=y when
setting NO_LIBTRACEEVENT=1 in the make command line, not when we don't
detect libtraceevent-devel installed in the system. Simplification here
to avoid these two ways of disabling builtin-trace.c and not having
CONFIG_TRACE=y when libtraceevent-devel isn't installed is the clean
way.
From Athira:
<quote>
tools/perf/arch/powerpc/util/Build
-perf-y += kvm-stat.o
+perf-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
</quote>
Then, ditto for arm64 and s390, detected by container cross build tests.
- s/390 uses test__checkevent_tracepoint() that is now only available if
HAVE_LIBTRACEEVENT is defined, enclose the callsite with ifder HAVE_LIBTRACEEVENT.
Also from Athira:
<quote>
With this change, I could successfully compile in these environment:
- Without libtraceevent-devel installed
- With libtraceevent-devel installed
- With “make NO_LIBTRACEEVENT=1”
</quote>
Then, finally rename CONFIG_TRACEEVENT to CONFIG_LIBTRACEEVENT for
consistency with other libraries detected in tools/perf/.
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: bpf@vger.kernel.org
Link: http://lore.kernel.org/lkml/20221205225940.3079667-3-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2022-12-05 14:59:39 -08:00
|
|
|
#include <traceevent/event-parse.h>
|
2009-11-25 01:15:48 -06:00
|
|
|
|
2017-04-26 15:27:52 -03:00
|
|
|
#include <stdbool.h>
|
|
|
|
/* perl needs the following define, right after including stdbool.h */
|
|
|
|
#define HAS_BOOL
|
2012-08-29 09:55:32 -06:00
|
|
|
#include <EXTERN.h>
|
|
|
|
#include <perl.h>
|
|
|
|
|
2016-03-29 12:47:53 -03:00
|
|
|
#include "../callchain.h"
|
2019-08-30 11:11:01 -03:00
|
|
|
#include "../dso.h"
|
2016-03-29 12:47:53 -03:00
|
|
|
#include "../machine.h"
|
2019-01-27 13:42:37 +01:00
|
|
|
#include "../map.h"
|
2019-01-28 00:03:34 +01:00
|
|
|
#include "../symbol.h"
|
2011-11-28 07:56:39 -02:00
|
|
|
#include "../thread.h"
|
|
|
|
#include "../event.h"
|
2010-01-27 02:27:55 -06:00
|
|
|
#include "../trace-event.h"
|
perf script: Add generic perl handler to process events
The current perf scripting facility only supports tracepoints. This
patch implements a generic perl handler to support other events than
tracepoints too.
This patch introduces a function process_event() that is called by perf
for each sample. The function is called with byte streams as arguments
containing information about the event, its attributes, the sample and
raw data. Perl's unpack() function can easily be used for byte decoding.
The following is the default implementation for process_event() that can
also be generated with perf script:
# Packed byte string args of process_event():
#
# $event: union perf_event util/event.h
# $attr: struct perf_event_attr linux/perf_event.h
# $sample: struct perf_sample util/event.h
# $raw_data: perf_sample->raw_data util/event.h
sub process_event
{
my ($event, $attr, $sample, $raw_data) = @_;
my @event = unpack("LSS", $event);
my @attr = unpack("LLQQQQQLLQQ", $attr);
my @sample = unpack("QLLQQQQQLL", $sample);
my @raw_data = unpack("C*", $raw_data);
use Data::Dumper;
print Dumper \@event, \@attr, \@sample, \@raw_data;
}
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1323969824-9711-4-git-send-email-robert.richter@amd.com
Signed-off-by: Robert Richter <robert.richter@amd.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2011-12-15 18:23:43 +01:00
|
|
|
#include "../evsel.h"
|
2014-07-14 23:46:48 +02:00
|
|
|
#include "../debug.h"
|
2010-01-27 02:27:55 -06:00
|
|
|
|
|
|
|
void boot_Perf__Trace__Context(pTHX_ CV *cv);
|
|
|
|
void boot_DynaLoader(pTHX_ CV *cv);
|
|
|
|
typedef PerlInterpreter * INTERP;
|
2009-11-25 01:15:48 -06:00
|
|
|
|
2009-11-25 01:15:50 -06:00
|
|
|
void xs_init(pTHX);
|
|
|
|
|
|
|
|
void xs_init(pTHX)
|
|
|
|
{
|
|
|
|
const char *file = __FILE__;
|
|
|
|
dXSUB_SYS;
|
|
|
|
|
|
|
|
newXS("Perf::Trace::Context::bootstrap", boot_Perf__Trace__Context,
|
|
|
|
file);
|
|
|
|
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
|
|
|
|
}
|
|
|
|
|
2009-11-25 01:15:48 -06:00
|
|
|
INTERP my_perl;
|
|
|
|
|
2015-05-13 13:44:36 -04:00
|
|
|
#define TRACE_EVENT_TYPE_MAX \
|
2009-11-25 01:15:48 -06:00
|
|
|
((1 << (sizeof(unsigned short) * 8)) - 1)
|
|
|
|
|
2010-01-27 02:27:55 -06:00
|
|
|
extern struct scripting_context *scripting_context;
|
2009-11-25 01:15:48 -06:00
|
|
|
|
|
|
|
static char *cur_field_name;
|
|
|
|
static int zero_flag_atom;
|
|
|
|
|
|
|
|
static void define_symbolic_value(const char *ev_name,
|
|
|
|
const char *field_name,
|
|
|
|
const char *field_value,
|
|
|
|
const char *field_str)
|
|
|
|
{
|
|
|
|
unsigned long long value;
|
|
|
|
dSP;
|
|
|
|
|
|
|
|
value = eval_flag(field_value);
|
|
|
|
|
|
|
|
ENTER;
|
|
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP);
|
|
|
|
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
|
|
|
|
XPUSHs(sv_2mortal(newSVuv(value)));
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
|
|
|
|
|
|
|
|
PUTBACK;
|
|
|
|
if (get_cv("main::define_symbolic_value", 0))
|
|
|
|
call_pv("main::define_symbolic_value", G_SCALAR);
|
|
|
|
SPAGAIN;
|
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
|
|
|
}
|
|
|
|
|
2018-09-19 14:56:49 -04:00
|
|
|
static void define_symbolic_values(struct tep_print_flag_sym *field,
|
2009-11-25 01:15:48 -06:00
|
|
|
const char *ev_name,
|
|
|
|
const char *field_name)
|
|
|
|
{
|
|
|
|
define_symbolic_value(ev_name, field_name, field->value, field->str);
|
|
|
|
if (field->next)
|
|
|
|
define_symbolic_values(field->next, ev_name, field_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void define_symbolic_field(const char *ev_name,
|
|
|
|
const char *field_name)
|
|
|
|
{
|
|
|
|
dSP;
|
|
|
|
|
|
|
|
ENTER;
|
|
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP);
|
|
|
|
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
|
|
|
|
|
|
|
|
PUTBACK;
|
|
|
|
if (get_cv("main::define_symbolic_field", 0))
|
|
|
|
call_pv("main::define_symbolic_field", G_SCALAR);
|
|
|
|
SPAGAIN;
|
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void define_flag_value(const char *ev_name,
|
|
|
|
const char *field_name,
|
|
|
|
const char *field_value,
|
|
|
|
const char *field_str)
|
|
|
|
{
|
|
|
|
unsigned long long value;
|
|
|
|
dSP;
|
|
|
|
|
|
|
|
value = eval_flag(field_value);
|
|
|
|
|
|
|
|
ENTER;
|
|
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP);
|
|
|
|
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
|
|
|
|
XPUSHs(sv_2mortal(newSVuv(value)));
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
|
|
|
|
|
|
|
|
PUTBACK;
|
|
|
|
if (get_cv("main::define_flag_value", 0))
|
|
|
|
call_pv("main::define_flag_value", G_SCALAR);
|
|
|
|
SPAGAIN;
|
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
|
|
|
}
|
|
|
|
|
2018-09-19 14:56:49 -04:00
|
|
|
static void define_flag_values(struct tep_print_flag_sym *field,
|
2009-11-25 01:15:48 -06:00
|
|
|
const char *ev_name,
|
|
|
|
const char *field_name)
|
|
|
|
{
|
|
|
|
define_flag_value(ev_name, field_name, field->value, field->str);
|
|
|
|
if (field->next)
|
|
|
|
define_flag_values(field->next, ev_name, field_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void define_flag_field(const char *ev_name,
|
|
|
|
const char *field_name,
|
|
|
|
const char *delim)
|
|
|
|
{
|
|
|
|
dSP;
|
|
|
|
|
|
|
|
ENTER;
|
|
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP);
|
|
|
|
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(delim, 0)));
|
|
|
|
|
|
|
|
PUTBACK;
|
|
|
|
if (get_cv("main::define_flag_field", 0))
|
|
|
|
call_pv("main::define_flag_field", G_SCALAR);
|
|
|
|
SPAGAIN;
|
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
|
|
|
}
|
|
|
|
|
2018-11-30 10:44:07 -05:00
|
|
|
static void define_event_symbols(struct tep_event *event,
|
2009-11-25 01:15:48 -06:00
|
|
|
const char *ev_name,
|
2018-09-19 14:56:49 -04:00
|
|
|
struct tep_print_arg *args)
|
2009-11-25 01:15:48 -06:00
|
|
|
{
|
2016-02-26 00:12:59 +09:00
|
|
|
if (args == NULL)
|
|
|
|
return;
|
|
|
|
|
2009-11-25 01:15:48 -06:00
|
|
|
switch (args->type) {
|
2018-09-19 14:56:50 -04:00
|
|
|
case TEP_PRINT_NULL:
|
2009-11-25 01:15:48 -06:00
|
|
|
break;
|
2018-09-19 14:56:50 -04:00
|
|
|
case TEP_PRINT_ATOM:
|
2009-11-25 01:15:48 -06:00
|
|
|
define_flag_value(ev_name, cur_field_name, "0",
|
|
|
|
args->atom.atom);
|
|
|
|
zero_flag_atom = 0;
|
|
|
|
break;
|
2018-09-19 14:56:50 -04:00
|
|
|
case TEP_PRINT_FIELD:
|
2013-12-26 15:54:57 -03:00
|
|
|
free(cur_field_name);
|
2009-11-25 01:15:48 -06:00
|
|
|
cur_field_name = strdup(args->field.name);
|
|
|
|
break;
|
2018-09-19 14:56:50 -04:00
|
|
|
case TEP_PRINT_FLAGS:
|
2009-11-25 01:15:48 -06:00
|
|
|
define_event_symbols(event, ev_name, args->flags.field);
|
|
|
|
define_flag_field(ev_name, cur_field_name, args->flags.delim);
|
|
|
|
define_flag_values(args->flags.flags, ev_name, cur_field_name);
|
|
|
|
break;
|
2018-09-19 14:56:50 -04:00
|
|
|
case TEP_PRINT_SYMBOL:
|
2009-11-25 01:15:48 -06:00
|
|
|
define_event_symbols(event, ev_name, args->symbol.field);
|
|
|
|
define_symbolic_field(ev_name, cur_field_name);
|
|
|
|
define_symbolic_values(args->symbol.symbols, ev_name,
|
|
|
|
cur_field_name);
|
|
|
|
break;
|
2018-09-19 14:56:50 -04:00
|
|
|
case TEP_PRINT_HEX:
|
|
|
|
case TEP_PRINT_HEX_STR:
|
2012-06-27 09:41:41 +09:00
|
|
|
define_event_symbols(event, ev_name, args->hex.field);
|
|
|
|
define_event_symbols(event, ev_name, args->hex.size);
|
|
|
|
break;
|
2018-09-19 14:56:50 -04:00
|
|
|
case TEP_PRINT_INT_ARRAY:
|
2015-03-24 11:07:19 +00:00
|
|
|
define_event_symbols(event, ev_name, args->int_array.field);
|
|
|
|
define_event_symbols(event, ev_name, args->int_array.count);
|
|
|
|
define_event_symbols(event, ev_name, args->int_array.el_size);
|
|
|
|
break;
|
2018-09-19 14:56:50 -04:00
|
|
|
case TEP_PRINT_BSTRING:
|
|
|
|
case TEP_PRINT_DYNAMIC_ARRAY:
|
|
|
|
case TEP_PRINT_DYNAMIC_ARRAY_LEN:
|
|
|
|
case TEP_PRINT_STRING:
|
|
|
|
case TEP_PRINT_BITMASK:
|
2009-11-25 01:15:48 -06:00
|
|
|
break;
|
2018-09-19 14:56:50 -04:00
|
|
|
case TEP_PRINT_TYPE:
|
2009-11-25 01:15:48 -06:00
|
|
|
define_event_symbols(event, ev_name, args->typecast.item);
|
|
|
|
break;
|
2018-09-19 14:56:50 -04:00
|
|
|
case TEP_PRINT_OP:
|
2009-11-25 01:15:48 -06:00
|
|
|
if (strcmp(args->op.op, ":") == 0)
|
|
|
|
zero_flag_atom = 1;
|
|
|
|
define_event_symbols(event, ev_name, args->op.left);
|
|
|
|
define_event_symbols(event, ev_name, args->op.right);
|
|
|
|
break;
|
2018-09-19 14:56:50 -04:00
|
|
|
case TEP_PRINT_FUNC:
|
2009-11-25 01:15:48 -06:00
|
|
|
default:
|
2012-05-22 16:30:48 +02:00
|
|
|
pr_err("Unsupported print arg type\n");
|
2009-11-25 01:15:48 -06:00
|
|
|
/* we should warn... */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (args->next)
|
|
|
|
define_event_symbols(event, ev_name, args->next);
|
|
|
|
}
|
|
|
|
|
2016-03-29 12:47:53 -03:00
|
|
|
static SV *perl_process_callchain(struct perf_sample *sample,
|
2019-07-21 13:23:51 +02:00
|
|
|
struct evsel *evsel,
|
2016-03-29 12:47:53 -03:00
|
|
|
struct addr_location *al)
|
|
|
|
{
|
2023-06-08 16:28:21 -07:00
|
|
|
struct callchain_cursor *cursor;
|
2016-03-29 12:47:53 -03:00
|
|
|
AV *list;
|
|
|
|
|
|
|
|
list = newAV();
|
|
|
|
if (!list)
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
if (!symbol_conf.use_callchain || !sample->callchain)
|
|
|
|
goto exit;
|
|
|
|
|
2023-06-08 16:28:21 -07:00
|
|
|
cursor = get_tls_callchain_cursor();
|
|
|
|
|
|
|
|
if (thread__resolve_callchain(al->thread, cursor, evsel,
|
2016-05-19 11:34:06 -03:00
|
|
|
sample, NULL, NULL, scripting_max_stack) != 0) {
|
2016-03-29 12:47:53 -03:00
|
|
|
pr_err("Failed to resolve callchain. Skipping\n");
|
|
|
|
goto exit;
|
|
|
|
}
|
2023-06-08 16:28:21 -07:00
|
|
|
callchain_cursor_commit(cursor);
|
2016-03-29 12:47:53 -03:00
|
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
HV *elem;
|
|
|
|
struct callchain_cursor_node *node;
|
2023-06-08 16:28:21 -07:00
|
|
|
node = callchain_cursor_current(cursor);
|
2016-03-29 12:47:53 -03:00
|
|
|
if (!node)
|
|
|
|
break;
|
|
|
|
|
|
|
|
elem = newHV();
|
|
|
|
if (!elem)
|
|
|
|
goto exit;
|
|
|
|
|
2016-04-05 12:21:44 -03:00
|
|
|
if (!hv_stores(elem, "ip", newSVuv(node->ip))) {
|
|
|
|
hv_undef(elem);
|
|
|
|
goto exit;
|
|
|
|
}
|
2016-03-29 12:47:53 -03:00
|
|
|
|
2019-11-04 12:14:32 -03:00
|
|
|
if (node->ms.sym) {
|
2016-03-29 12:47:53 -03:00
|
|
|
HV *sym = newHV();
|
2016-04-05 12:21:44 -03:00
|
|
|
if (!sym) {
|
|
|
|
hv_undef(elem);
|
|
|
|
goto exit;
|
|
|
|
}
|
2019-11-04 12:14:32 -03:00
|
|
|
if (!hv_stores(sym, "start", newSVuv(node->ms.sym->start)) ||
|
|
|
|
!hv_stores(sym, "end", newSVuv(node->ms.sym->end)) ||
|
|
|
|
!hv_stores(sym, "binding", newSVuv(node->ms.sym->binding)) ||
|
|
|
|
!hv_stores(sym, "name", newSVpvn(node->ms.sym->name,
|
|
|
|
node->ms.sym->namelen)) ||
|
2016-04-05 12:21:44 -03:00
|
|
|
!hv_stores(elem, "sym", newRV_noinc((SV*)sym))) {
|
|
|
|
hv_undef(sym);
|
|
|
|
hv_undef(elem);
|
2016-03-29 12:47:53 -03:00
|
|
|
goto exit;
|
2016-04-05 12:21:44 -03:00
|
|
|
}
|
2016-03-29 12:47:53 -03:00
|
|
|
}
|
|
|
|
|
2019-11-04 12:14:32 -03:00
|
|
|
if (node->ms.map) {
|
|
|
|
struct map *map = node->ms.map;
|
2023-03-20 14:22:35 -07:00
|
|
|
struct dso *dso = map ? map__dso(map) : NULL;
|
2016-03-29 12:47:53 -03:00
|
|
|
const char *dsoname = "[unknown]";
|
2023-03-20 14:22:35 -07:00
|
|
|
|
|
|
|
if (dso) {
|
|
|
|
if (symbol_conf.show_kernel_path && dso->long_name)
|
|
|
|
dsoname = dso->long_name;
|
2017-02-13 17:11:03 -03:00
|
|
|
else
|
2023-03-20 14:22:35 -07:00
|
|
|
dsoname = dso->name;
|
2016-03-29 12:47:53 -03:00
|
|
|
}
|
2016-04-05 12:21:44 -03:00
|
|
|
if (!hv_stores(elem, "dso", newSVpv(dsoname,0))) {
|
|
|
|
hv_undef(elem);
|
|
|
|
goto exit;
|
|
|
|
}
|
2016-03-29 12:47:53 -03:00
|
|
|
}
|
|
|
|
|
2023-06-08 16:28:21 -07:00
|
|
|
callchain_cursor_advance(cursor);
|
2016-03-29 12:47:53 -03:00
|
|
|
av_push(list, newRV_noinc((SV*)elem));
|
|
|
|
}
|
|
|
|
|
|
|
|
exit:
|
|
|
|
return newRV_noinc((SV*)list);
|
|
|
|
}
|
|
|
|
|
2013-12-19 16:39:31 -03:00
|
|
|
static void perl_process_tracepoint(struct perf_sample *sample,
|
2019-07-21 13:23:51 +02:00
|
|
|
struct evsel *evsel,
|
2016-03-29 12:47:53 -03:00
|
|
|
struct addr_location *al)
|
2009-11-25 01:15:48 -06:00
|
|
|
{
|
2016-03-29 12:47:53 -03:00
|
|
|
struct thread *thread = al->thread;
|
2018-11-30 10:44:07 -05:00
|
|
|
struct tep_event *event = evsel->tp_format;
|
2018-09-19 14:56:45 -04:00
|
|
|
struct tep_format_field *field;
|
2009-11-25 01:15:48 -06:00
|
|
|
static char handler[256];
|
|
|
|
unsigned long long val;
|
|
|
|
unsigned long s, ns;
|
|
|
|
int pid;
|
2011-03-09 22:23:23 -07:00
|
|
|
int cpu = sample->cpu;
|
|
|
|
void *data = sample->raw_data;
|
|
|
|
unsigned long long nsecs = sample->time;
|
2013-09-11 14:46:56 +02:00
|
|
|
const char *comm = thread__comm_str(thread);
|
2023-05-26 11:33:58 -07:00
|
|
|
DECLARE_BITMAP(events_defined, TRACE_EVENT_TYPE_MAX);
|
2009-11-25 01:15:48 -06:00
|
|
|
|
2023-05-26 11:33:58 -07:00
|
|
|
bitmap_zero(events_defined, TRACE_EVENT_TYPE_MAX);
|
2009-11-25 01:15:48 -06:00
|
|
|
dSP;
|
|
|
|
|
2019-07-21 13:24:29 +02:00
|
|
|
if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
|
perf script: Add generic perl handler to process events
The current perf scripting facility only supports tracepoints. This
patch implements a generic perl handler to support other events than
tracepoints too.
This patch introduces a function process_event() that is called by perf
for each sample. The function is called with byte streams as arguments
containing information about the event, its attributes, the sample and
raw data. Perl's unpack() function can easily be used for byte decoding.
The following is the default implementation for process_event() that can
also be generated with perf script:
# Packed byte string args of process_event():
#
# $event: union perf_event util/event.h
# $attr: struct perf_event_attr linux/perf_event.h
# $sample: struct perf_sample util/event.h
# $raw_data: perf_sample->raw_data util/event.h
sub process_event
{
my ($event, $attr, $sample, $raw_data) = @_;
my @event = unpack("LSS", $event);
my @attr = unpack("LLQQQQQLLQQ", $attr);
my @sample = unpack("QLLQQQQQLL", $sample);
my @raw_data = unpack("C*", $raw_data);
use Data::Dumper;
print Dumper \@event, \@attr, \@sample, \@raw_data;
}
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1323969824-9711-4-git-send-email-robert.richter@amd.com
Signed-off-by: Robert Richter <robert.richter@amd.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2011-12-15 18:23:43 +01:00
|
|
|
return;
|
|
|
|
|
2017-01-24 13:19:06 -03:00
|
|
|
if (!event) {
|
2019-07-21 13:24:29 +02:00
|
|
|
pr_debug("ug! no event found for type %" PRIu64, (u64)evsel->core.attr.config);
|
2017-01-24 13:19:06 -03:00
|
|
|
return;
|
|
|
|
}
|
2009-11-25 01:15:48 -06:00
|
|
|
|
2012-08-07 23:50:21 -03:00
|
|
|
pid = raw_field_value(event, "common_pid", data);
|
2009-11-25 01:15:48 -06:00
|
|
|
|
|
|
|
sprintf(handler, "%s::%s", event->system, event->name);
|
|
|
|
|
2022-11-19 01:34:46 +00:00
|
|
|
if (!__test_and_set_bit(event->id, events_defined))
|
2014-10-26 23:44:04 +01:00
|
|
|
define_event_symbols(event, handler, event->print_fmt.args);
|
|
|
|
|
2016-08-05 15:40:30 -03:00
|
|
|
s = nsecs / NSEC_PER_SEC;
|
|
|
|
ns = nsecs - s * NSEC_PER_SEC;
|
2009-11-25 01:15:48 -06:00
|
|
|
|
|
|
|
ENTER;
|
|
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP);
|
|
|
|
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(handler, 0)));
|
|
|
|
XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
|
|
|
|
XPUSHs(sv_2mortal(newSVuv(cpu)));
|
|
|
|
XPUSHs(sv_2mortal(newSVuv(s)));
|
|
|
|
XPUSHs(sv_2mortal(newSVuv(ns)));
|
|
|
|
XPUSHs(sv_2mortal(newSViv(pid)));
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(comm, 0)));
|
2016-03-29 12:47:53 -03:00
|
|
|
XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al)));
|
2009-11-25 01:15:48 -06:00
|
|
|
|
|
|
|
/* common fields other than pid can be accessed via xsub fns */
|
|
|
|
|
|
|
|
for (field = event->format.fields; field; field = field->next) {
|
2018-09-19 14:56:46 -04:00
|
|
|
if (field->flags & TEP_FIELD_IS_STRING) {
|
2009-11-25 01:15:48 -06:00
|
|
|
int offset;
|
2018-09-19 14:56:46 -04:00
|
|
|
if (field->flags & TEP_FIELD_IS_DYNAMIC) {
|
2009-11-25 01:15:48 -06:00
|
|
|
offset = *(int *)(data + field->offset);
|
|
|
|
offset &= 0xffff;
|
2023-01-10 23:06:40 -08:00
|
|
|
if (tep_field_is_relative(field->flags))
|
2021-11-22 18:30:48 +09:00
|
|
|
offset += field->offset + field->size;
|
2009-11-25 01:15:48 -06:00
|
|
|
} else
|
|
|
|
offset = field->offset;
|
|
|
|
XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
|
|
|
|
} else { /* FIELD_IS_NUMERIC */
|
2012-08-07 23:50:21 -03:00
|
|
|
val = read_size(event, data + field->offset,
|
2012-06-27 13:08:42 -03:00
|
|
|
field->size);
|
2018-09-19 14:56:46 -04:00
|
|
|
if (field->flags & TEP_FIELD_IS_SIGNED) {
|
2009-11-25 01:15:48 -06:00
|
|
|
XPUSHs(sv_2mortal(newSViv(val)));
|
|
|
|
} else {
|
|
|
|
XPUSHs(sv_2mortal(newSVuv(val)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PUTBACK;
|
2009-11-25 01:15:50 -06:00
|
|
|
|
2009-11-25 01:15:48 -06:00
|
|
|
if (get_cv(handler, 0))
|
|
|
|
call_pv(handler, G_SCALAR);
|
|
|
|
else if (get_cv("main::trace_unhandled", 0)) {
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(handler, 0)));
|
|
|
|
XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
|
|
|
|
XPUSHs(sv_2mortal(newSVuv(cpu)));
|
|
|
|
XPUSHs(sv_2mortal(newSVuv(nsecs)));
|
|
|
|
XPUSHs(sv_2mortal(newSViv(pid)));
|
|
|
|
XPUSHs(sv_2mortal(newSVpv(comm, 0)));
|
2016-03-29 12:47:53 -03:00
|
|
|
XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al)));
|
2009-11-25 01:15:48 -06:00
|
|
|
call_pv("main::trace_unhandled", G_SCALAR);
|
|
|
|
}
|
|
|
|
SPAGAIN;
|
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
|
|
|
}
|
|
|
|
|
2012-08-07 23:50:21 -03:00
|
|
|
static void perl_process_event_generic(union perf_event *event,
|
perf script: Add generic perl handler to process events
The current perf scripting facility only supports tracepoints. This
patch implements a generic perl handler to support other events than
tracepoints too.
This patch introduces a function process_event() that is called by perf
for each sample. The function is called with byte streams as arguments
containing information about the event, its attributes, the sample and
raw data. Perl's unpack() function can easily be used for byte decoding.
The following is the default implementation for process_event() that can
also be generated with perf script:
# Packed byte string args of process_event():
#
# $event: union perf_event util/event.h
# $attr: struct perf_event_attr linux/perf_event.h
# $sample: struct perf_sample util/event.h
# $raw_data: perf_sample->raw_data util/event.h
sub process_event
{
my ($event, $attr, $sample, $raw_data) = @_;
my @event = unpack("LSS", $event);
my @attr = unpack("LLQQQQQLLQQ", $attr);
my @sample = unpack("QLLQQQQQLL", $sample);
my @raw_data = unpack("C*", $raw_data);
use Data::Dumper;
print Dumper \@event, \@attr, \@sample, \@raw_data;
}
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1323969824-9711-4-git-send-email-robert.richter@amd.com
Signed-off-by: Robert Richter <robert.richter@amd.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2011-12-15 18:23:43 +01:00
|
|
|
struct perf_sample *sample,
|
2019-07-21 13:23:51 +02:00
|
|
|
struct evsel *evsel)
|
perf script: Add generic perl handler to process events
The current perf scripting facility only supports tracepoints. This
patch implements a generic perl handler to support other events than
tracepoints too.
This patch introduces a function process_event() that is called by perf
for each sample. The function is called with byte streams as arguments
containing information about the event, its attributes, the sample and
raw data. Perl's unpack() function can easily be used for byte decoding.
The following is the default implementation for process_event() that can
also be generated with perf script:
# Packed byte string args of process_event():
#
# $event: union perf_event util/event.h
# $attr: struct perf_event_attr linux/perf_event.h
# $sample: struct perf_sample util/event.h
# $raw_data: perf_sample->raw_data util/event.h
sub process_event
{
my ($event, $attr, $sample, $raw_data) = @_;
my @event = unpack("LSS", $event);
my @attr = unpack("LLQQQQQLLQQ", $attr);
my @sample = unpack("QLLQQQQQLL", $sample);
my @raw_data = unpack("C*", $raw_data);
use Data::Dumper;
print Dumper \@event, \@attr, \@sample, \@raw_data;
}
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1323969824-9711-4-git-send-email-robert.richter@amd.com
Signed-off-by: Robert Richter <robert.richter@amd.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2011-12-15 18:23:43 +01:00
|
|
|
{
|
|
|
|
dSP;
|
|
|
|
|
|
|
|
if (!get_cv("process_event", 0))
|
|
|
|
return;
|
|
|
|
|
|
|
|
ENTER;
|
|
|
|
SAVETMPS;
|
|
|
|
PUSHMARK(SP);
|
2012-08-07 23:50:21 -03:00
|
|
|
XPUSHs(sv_2mortal(newSVpvn((const char *)event, event->header.size)));
|
2019-07-21 13:24:29 +02:00
|
|
|
XPUSHs(sv_2mortal(newSVpvn((const char *)&evsel->core.attr, sizeof(evsel->core.attr))));
|
perf script: Add generic perl handler to process events
The current perf scripting facility only supports tracepoints. This
patch implements a generic perl handler to support other events than
tracepoints too.
This patch introduces a function process_event() that is called by perf
for each sample. The function is called with byte streams as arguments
containing information about the event, its attributes, the sample and
raw data. Perl's unpack() function can easily be used for byte decoding.
The following is the default implementation for process_event() that can
also be generated with perf script:
# Packed byte string args of process_event():
#
# $event: union perf_event util/event.h
# $attr: struct perf_event_attr linux/perf_event.h
# $sample: struct perf_sample util/event.h
# $raw_data: perf_sample->raw_data util/event.h
sub process_event
{
my ($event, $attr, $sample, $raw_data) = @_;
my @event = unpack("LSS", $event);
my @attr = unpack("LLQQQQQLLQQ", $attr);
my @sample = unpack("QLLQQQQQLL", $sample);
my @raw_data = unpack("C*", $raw_data);
use Data::Dumper;
print Dumper \@event, \@attr, \@sample, \@raw_data;
}
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1323969824-9711-4-git-send-email-robert.richter@amd.com
Signed-off-by: Robert Richter <robert.richter@amd.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2011-12-15 18:23:43 +01:00
|
|
|
XPUSHs(sv_2mortal(newSVpvn((const char *)sample, sizeof(*sample))));
|
|
|
|
XPUSHs(sv_2mortal(newSVpvn((const char *)sample->raw_data, sample->raw_size)));
|
|
|
|
PUTBACK;
|
|
|
|
call_pv("process_event", G_SCALAR);
|
|
|
|
SPAGAIN;
|
|
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
|
|
LEAVE;
|
|
|
|
}
|
|
|
|
|
2012-06-27 13:08:42 -03:00
|
|
|
static void perl_process_event(union perf_event *event,
|
perf script: Add generic perl handler to process events
The current perf scripting facility only supports tracepoints. This
patch implements a generic perl handler to support other events than
tracepoints too.
This patch introduces a function process_event() that is called by perf
for each sample. The function is called with byte streams as arguments
containing information about the event, its attributes, the sample and
raw data. Perl's unpack() function can easily be used for byte decoding.
The following is the default implementation for process_event() that can
also be generated with perf script:
# Packed byte string args of process_event():
#
# $event: union perf_event util/event.h
# $attr: struct perf_event_attr linux/perf_event.h
# $sample: struct perf_sample util/event.h
# $raw_data: perf_sample->raw_data util/event.h
sub process_event
{
my ($event, $attr, $sample, $raw_data) = @_;
my @event = unpack("LSS", $event);
my @attr = unpack("LLQQQQQLLQQ", $attr);
my @sample = unpack("QLLQQQQQLL", $sample);
my @raw_data = unpack("C*", $raw_data);
use Data::Dumper;
print Dumper \@event, \@attr, \@sample, \@raw_data;
}
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1323969824-9711-4-git-send-email-robert.richter@amd.com
Signed-off-by: Robert Richter <robert.richter@amd.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2011-12-15 18:23:43 +01:00
|
|
|
struct perf_sample *sample,
|
2019-07-21 13:23:51 +02:00
|
|
|
struct evsel *evsel,
|
2021-05-25 12:51:05 +03:00
|
|
|
struct addr_location *al,
|
2021-05-30 22:22:58 +03:00
|
|
|
struct addr_location *addr_al)
|
perf script: Add generic perl handler to process events
The current perf scripting facility only supports tracepoints. This
patch implements a generic perl handler to support other events than
tracepoints too.
This patch introduces a function process_event() that is called by perf
for each sample. The function is called with byte streams as arguments
containing information about the event, its attributes, the sample and
raw data. Perl's unpack() function can easily be used for byte decoding.
The following is the default implementation for process_event() that can
also be generated with perf script:
# Packed byte string args of process_event():
#
# $event: union perf_event util/event.h
# $attr: struct perf_event_attr linux/perf_event.h
# $sample: struct perf_sample util/event.h
# $raw_data: perf_sample->raw_data util/event.h
sub process_event
{
my ($event, $attr, $sample, $raw_data) = @_;
my @event = unpack("LSS", $event);
my @attr = unpack("LLQQQQQLLQQ", $attr);
my @sample = unpack("QLLQQQQQLL", $sample);
my @raw_data = unpack("C*", $raw_data);
use Data::Dumper;
print Dumper \@event, \@attr, \@sample, \@raw_data;
}
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1323969824-9711-4-git-send-email-robert.richter@amd.com
Signed-off-by: Robert Richter <robert.richter@amd.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2011-12-15 18:23:43 +01:00
|
|
|
{
|
2021-05-30 22:22:58 +03:00
|
|
|
scripting_context__update(scripting_context, event, sample, evsel, al, addr_al);
|
2016-03-29 12:47:53 -03:00
|
|
|
perl_process_tracepoint(sample, evsel, al);
|
2013-12-19 16:39:31 -03:00
|
|
|
perl_process_event_generic(event, sample, evsel);
|
perf script: Add generic perl handler to process events
The current perf scripting facility only supports tracepoints. This
patch implements a generic perl handler to support other events than
tracepoints too.
This patch introduces a function process_event() that is called by perf
for each sample. The function is called with byte streams as arguments
containing information about the event, its attributes, the sample and
raw data. Perl's unpack() function can easily be used for byte decoding.
The following is the default implementation for process_event() that can
also be generated with perf script:
# Packed byte string args of process_event():
#
# $event: union perf_event util/event.h
# $attr: struct perf_event_attr linux/perf_event.h
# $sample: struct perf_sample util/event.h
# $raw_data: perf_sample->raw_data util/event.h
sub process_event
{
my ($event, $attr, $sample, $raw_data) = @_;
my @event = unpack("LSS", $event);
my @attr = unpack("LLQQQQQLLQQ", $attr);
my @sample = unpack("QLLQQQQQLL", $sample);
my @raw_data = unpack("C*", $raw_data);
use Data::Dumper;
print Dumper \@event, \@attr, \@sample, \@raw_data;
}
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1323969824-9711-4-git-send-email-robert.richter@amd.com
Signed-off-by: Robert Richter <robert.richter@amd.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2011-12-15 18:23:43 +01:00
|
|
|
}
|
|
|
|
|
2009-11-25 01:15:48 -06:00
|
|
|
static void run_start_sub(void)
|
|
|
|
{
|
|
|
|
dSP; /* access to Perl stack */
|
|
|
|
PUSHMARK(SP);
|
|
|
|
|
|
|
|
if (get_cv("main::trace_begin", 0))
|
|
|
|
call_pv("main::trace_begin", G_DISCARD | G_NOARGS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start trace script
|
|
|
|
*/
|
2021-05-30 22:22:59 +03:00
|
|
|
static int perl_start_script(const char *script, int argc, const char **argv,
|
|
|
|
struct perf_session *session)
|
2009-11-25 01:15:48 -06:00
|
|
|
{
|
2009-12-15 02:53:35 -06:00
|
|
|
const char **command_line;
|
|
|
|
int i, err = 0;
|
2009-11-25 01:15:48 -06:00
|
|
|
|
2021-05-30 22:22:59 +03:00
|
|
|
scripting_context->session = session;
|
|
|
|
|
2009-12-15 02:53:35 -06:00
|
|
|
command_line = malloc((argc + 2) * sizeof(const char *));
|
|
|
|
command_line[0] = "";
|
2009-11-25 01:15:48 -06:00
|
|
|
command_line[1] = script;
|
2009-12-15 02:53:35 -06:00
|
|
|
for (i = 2; i < argc + 2; i++)
|
|
|
|
command_line[i] = argv[i - 2];
|
2009-11-25 01:15:48 -06:00
|
|
|
|
|
|
|
my_perl = perl_alloc();
|
|
|
|
perl_construct(my_perl);
|
|
|
|
|
2009-12-15 02:53:35 -06:00
|
|
|
if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
|
|
|
|
(char **)NULL)) {
|
|
|
|
err = -1;
|
|
|
|
goto error;
|
|
|
|
}
|
2009-11-25 01:15:48 -06:00
|
|
|
|
2009-12-15 02:53:37 -06:00
|
|
|
if (perl_run(my_perl)) {
|
|
|
|
err = -1;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-12-15 02:53:35 -06:00
|
|
|
if (SvTRUE(ERRSV)) {
|
|
|
|
err = -1;
|
|
|
|
goto error;
|
|
|
|
}
|
2009-11-25 01:15:48 -06:00
|
|
|
|
|
|
|
run_start_sub();
|
|
|
|
|
2009-12-15 02:53:35 -06:00
|
|
|
free(command_line);
|
2009-11-25 01:15:48 -06:00
|
|
|
return 0;
|
2009-12-15 02:53:35 -06:00
|
|
|
error:
|
|
|
|
perl_free(my_perl);
|
|
|
|
free(command_line);
|
|
|
|
|
|
|
|
return err;
|
2009-11-25 01:15:48 -06:00
|
|
|
}
|
|
|
|
|
2014-08-15 22:08:37 +03:00
|
|
|
static int perl_flush_script(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-11-25 01:15:48 -06:00
|
|
|
/*
|
|
|
|
* Stop trace script
|
|
|
|
*/
|
|
|
|
static int perl_stop_script(void)
|
|
|
|
{
|
|
|
|
dSP; /* access to Perl stack */
|
|
|
|
PUSHMARK(SP);
|
|
|
|
|
|
|
|
if (get_cv("main::trace_end", 0))
|
|
|
|
call_pv("main::trace_end", G_DISCARD | G_NOARGS);
|
|
|
|
|
|
|
|
perl_destruct(my_perl);
|
|
|
|
perl_free(my_perl);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-08-08 14:02:46 -04:00
|
|
|
static int perl_generate_script(struct tep_handle *pevent, const char *outfile)
|
2009-11-25 01:15:48 -06:00
|
|
|
{
|
2019-10-17 17:05:22 -04:00
|
|
|
int i, not_first, count, nr_events;
|
|
|
|
struct tep_event **all_events;
|
2018-11-30 10:44:07 -05:00
|
|
|
struct tep_event *event = NULL;
|
2018-09-19 14:56:45 -04:00
|
|
|
struct tep_format_field *f;
|
2009-11-25 01:15:48 -06:00
|
|
|
char fname[PATH_MAX];
|
|
|
|
FILE *ofp;
|
|
|
|
|
|
|
|
sprintf(fname, "%s.pl", outfile);
|
|
|
|
ofp = fopen(fname, "w");
|
|
|
|
if (ofp == NULL) {
|
|
|
|
fprintf(stderr, "couldn't open %s\n", fname);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-11-16 18:45:39 +01:00
|
|
|
fprintf(ofp, "# perf script event handlers, "
|
|
|
|
"generated by perf script -g perl\n");
|
2009-11-25 01:15:48 -06:00
|
|
|
|
|
|
|
fprintf(ofp, "# Licensed under the terms of the GNU GPL"
|
|
|
|
" License version 2\n\n");
|
|
|
|
|
|
|
|
fprintf(ofp, "# The common_* event handler fields are the most useful "
|
|
|
|
"fields common to\n");
|
|
|
|
|
|
|
|
fprintf(ofp, "# all events. They don't necessarily correspond to "
|
|
|
|
"the 'common_*' fields\n");
|
|
|
|
|
|
|
|
fprintf(ofp, "# in the format files. Those fields not available as "
|
|
|
|
"handler params can\n");
|
|
|
|
|
|
|
|
fprintf(ofp, "# be retrieved using Perl functions of the form "
|
|
|
|
"common_*($context).\n");
|
|
|
|
|
|
|
|
fprintf(ofp, "# See Context.pm for the list of available "
|
|
|
|
"functions.\n\n");
|
|
|
|
|
|
|
|
fprintf(ofp, "use lib \"$ENV{'PERF_EXEC_PATH'}/scripts/perl/"
|
|
|
|
"Perf-Trace-Util/lib\";\n");
|
|
|
|
|
|
|
|
fprintf(ofp, "use lib \"./Perf-Trace-Util/lib\";\n");
|
|
|
|
fprintf(ofp, "use Perf::Trace::Core;\n");
|
|
|
|
fprintf(ofp, "use Perf::Trace::Context;\n");
|
|
|
|
fprintf(ofp, "use Perf::Trace::Util;\n\n");
|
|
|
|
|
|
|
|
fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n");
|
2016-03-29 12:47:53 -03:00
|
|
|
fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n");
|
|
|
|
|
|
|
|
|
|
|
|
fprintf(ofp, "\n\
|
|
|
|
sub print_backtrace\n\
|
|
|
|
{\n\
|
|
|
|
my $callchain = shift;\n\
|
|
|
|
for my $node (@$callchain)\n\
|
|
|
|
{\n\
|
|
|
|
if(exists $node->{sym})\n\
|
|
|
|
{\n\
|
|
|
|
printf( \"\\t[\\%%x] \\%%s\\n\", $node->{ip}, $node->{sym}{name});\n\
|
|
|
|
}\n\
|
|
|
|
else\n\
|
|
|
|
{\n\
|
|
|
|
printf( \"\\t[\\%%x]\\n\", $node{ip});\n\
|
|
|
|
}\n\
|
|
|
|
}\n\
|
|
|
|
}\n\n\
|
|
|
|
");
|
|
|
|
|
2019-10-17 17:05:22 -04:00
|
|
|
nr_events = tep_get_events_count(pevent);
|
|
|
|
all_events = tep_list_events(pevent, TEP_EVENT_SORT_ID);
|
2009-11-25 01:15:48 -06:00
|
|
|
|
2019-10-17 17:05:22 -04:00
|
|
|
for (i = 0; all_events && i < nr_events; i++) {
|
|
|
|
event = all_events[i];
|
2009-11-25 01:15:48 -06:00
|
|
|
fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
|
|
|
|
fprintf(ofp, "\tmy (");
|
|
|
|
|
|
|
|
fprintf(ofp, "$event_name, ");
|
|
|
|
fprintf(ofp, "$context, ");
|
|
|
|
fprintf(ofp, "$common_cpu, ");
|
|
|
|
fprintf(ofp, "$common_secs, ");
|
|
|
|
fprintf(ofp, "$common_nsecs,\n");
|
|
|
|
fprintf(ofp, "\t $common_pid, ");
|
2016-03-29 12:47:53 -03:00
|
|
|
fprintf(ofp, "$common_comm, ");
|
|
|
|
fprintf(ofp, "$common_callchain,\n\t ");
|
2009-11-25 01:15:48 -06:00
|
|
|
|
|
|
|
not_first = 0;
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
for (f = event->format.fields; f; f = f->next) {
|
|
|
|
if (not_first++)
|
|
|
|
fprintf(ofp, ", ");
|
|
|
|
if (++count % 5 == 0)
|
|
|
|
fprintf(ofp, "\n\t ");
|
|
|
|
|
|
|
|
fprintf(ofp, "$%s", f->name);
|
|
|
|
}
|
|
|
|
fprintf(ofp, ") = @_;\n\n");
|
|
|
|
|
|
|
|
fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
|
|
|
|
"$common_secs, $common_nsecs,\n\t "
|
2016-03-29 12:47:53 -03:00
|
|
|
"$common_pid, $common_comm, $common_callchain);\n\n");
|
2009-11-25 01:15:48 -06:00
|
|
|
|
|
|
|
fprintf(ofp, "\tprintf(\"");
|
|
|
|
|
|
|
|
not_first = 0;
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
for (f = event->format.fields; f; f = f->next) {
|
|
|
|
if (not_first++)
|
|
|
|
fprintf(ofp, ", ");
|
|
|
|
if (count && count % 4 == 0) {
|
|
|
|
fprintf(ofp, "\".\n\t \"");
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
|
|
|
|
fprintf(ofp, "%s=", f->name);
|
2018-09-19 14:56:46 -04:00
|
|
|
if (f->flags & TEP_FIELD_IS_STRING ||
|
|
|
|
f->flags & TEP_FIELD_IS_FLAG ||
|
|
|
|
f->flags & TEP_FIELD_IS_SYMBOLIC)
|
2009-11-25 01:15:48 -06:00
|
|
|
fprintf(ofp, "%%s");
|
2018-09-19 14:56:46 -04:00
|
|
|
else if (f->flags & TEP_FIELD_IS_SIGNED)
|
2009-11-25 01:15:48 -06:00
|
|
|
fprintf(ofp, "%%d");
|
|
|
|
else
|
|
|
|
fprintf(ofp, "%%u");
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(ofp, "\\n\",\n\t ");
|
|
|
|
|
|
|
|
not_first = 0;
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
for (f = event->format.fields; f; f = f->next) {
|
|
|
|
if (not_first++)
|
|
|
|
fprintf(ofp, ", ");
|
|
|
|
|
|
|
|
if (++count % 5 == 0)
|
|
|
|
fprintf(ofp, "\n\t ");
|
|
|
|
|
2018-09-19 14:56:46 -04:00
|
|
|
if (f->flags & TEP_FIELD_IS_FLAG) {
|
2009-11-25 01:15:48 -06:00
|
|
|
if ((count - 1) % 5 != 0) {
|
|
|
|
fprintf(ofp, "\n\t ");
|
|
|
|
count = 4;
|
|
|
|
}
|
|
|
|
fprintf(ofp, "flag_str(\"");
|
|
|
|
fprintf(ofp, "%s::%s\", ", event->system,
|
|
|
|
event->name);
|
|
|
|
fprintf(ofp, "\"%s\", $%s)", f->name,
|
|
|
|
f->name);
|
2018-09-19 14:56:46 -04:00
|
|
|
} else if (f->flags & TEP_FIELD_IS_SYMBOLIC) {
|
2009-11-25 01:15:48 -06:00
|
|
|
if ((count - 1) % 5 != 0) {
|
|
|
|
fprintf(ofp, "\n\t ");
|
|
|
|
count = 4;
|
|
|
|
}
|
|
|
|
fprintf(ofp, "symbol_str(\"");
|
|
|
|
fprintf(ofp, "%s::%s\", ", event->system,
|
|
|
|
event->name);
|
|
|
|
fprintf(ofp, "\"%s\", $%s)", f->name,
|
|
|
|
f->name);
|
|
|
|
} else
|
|
|
|
fprintf(ofp, "$%s", f->name);
|
|
|
|
}
|
|
|
|
|
2016-03-29 12:47:53 -03:00
|
|
|
fprintf(ofp, ");\n\n");
|
|
|
|
|
|
|
|
fprintf(ofp, "\tprint_backtrace($common_callchain);\n");
|
|
|
|
|
2009-11-25 01:15:48 -06:00
|
|
|
fprintf(ofp, "}\n\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, "
|
|
|
|
"$common_cpu, $common_secs, $common_nsecs,\n\t "
|
2016-03-29 12:47:53 -03:00
|
|
|
"$common_pid, $common_comm, $common_callchain) = @_;\n\n");
|
2009-11-25 01:15:48 -06:00
|
|
|
|
|
|
|
fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
|
|
|
|
"$common_secs, $common_nsecs,\n\t $common_pid, "
|
2016-03-29 12:47:53 -03:00
|
|
|
"$common_comm, $common_callchain);\n");
|
|
|
|
fprintf(ofp, "\tprint_backtrace($common_callchain);\n");
|
|
|
|
fprintf(ofp, "}\n\n");
|
2009-11-25 01:15:48 -06:00
|
|
|
|
|
|
|
fprintf(ofp, "sub print_header\n{\n"
|
|
|
|
"\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
|
|
|
|
"\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t "
|
perf script: Add generic perl handler to process events
The current perf scripting facility only supports tracepoints. This
patch implements a generic perl handler to support other events than
tracepoints too.
This patch introduces a function process_event() that is called by perf
for each sample. The function is called with byte streams as arguments
containing information about the event, its attributes, the sample and
raw data. Perl's unpack() function can easily be used for byte decoding.
The following is the default implementation for process_event() that can
also be generated with perf script:
# Packed byte string args of process_event():
#
# $event: union perf_event util/event.h
# $attr: struct perf_event_attr linux/perf_event.h
# $sample: struct perf_sample util/event.h
# $raw_data: perf_sample->raw_data util/event.h
sub process_event
{
my ($event, $attr, $sample, $raw_data) = @_;
my @event = unpack("LSS", $event);
my @attr = unpack("LLQQQQQLLQQ", $attr);
my @sample = unpack("QLLQQQQQLL", $sample);
my @raw_data = unpack("C*", $raw_data);
use Data::Dumper;
print Dumper \@event, \@attr, \@sample, \@raw_data;
}
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1323969824-9711-4-git-send-email-robert.richter@amd.com
Signed-off-by: Robert Richter <robert.richter@amd.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2011-12-15 18:23:43 +01:00
|
|
|
"$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}\n");
|
|
|
|
|
|
|
|
fprintf(ofp,
|
|
|
|
"\n# Packed byte string args of process_event():\n"
|
|
|
|
"#\n"
|
|
|
|
"# $event:\tunion perf_event\tutil/event.h\n"
|
|
|
|
"# $attr:\tstruct perf_event_attr\tlinux/perf_event.h\n"
|
|
|
|
"# $sample:\tstruct perf_sample\tutil/event.h\n"
|
|
|
|
"# $raw_data:\tperf_sample->raw_data\tutil/event.h\n"
|
|
|
|
"\n"
|
|
|
|
"sub process_event\n"
|
|
|
|
"{\n"
|
|
|
|
"\tmy ($event, $attr, $sample, $raw_data) = @_;\n"
|
|
|
|
"\n"
|
|
|
|
"\tmy @event\t= unpack(\"LSS\", $event);\n"
|
|
|
|
"\tmy @attr\t= unpack(\"LLQQQQQLLQQ\", $attr);\n"
|
|
|
|
"\tmy @sample\t= unpack(\"QLLQQQQQLL\", $sample);\n"
|
|
|
|
"\tmy @raw_data\t= unpack(\"C*\", $raw_data);\n"
|
|
|
|
"\n"
|
|
|
|
"\tuse Data::Dumper;\n"
|
|
|
|
"\tprint Dumper \\@event, \\@attr, \\@sample, \\@raw_data;\n"
|
|
|
|
"}\n");
|
2009-11-25 01:15:48 -06:00
|
|
|
|
|
|
|
fclose(ofp);
|
|
|
|
|
|
|
|
fprintf(stderr, "generated Perl script: %s\n", fname);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct scripting_ops perl_scripting_ops = {
|
|
|
|
.name = "Perl",
|
2021-05-24 09:57:18 +03:00
|
|
|
.dirname = "perl",
|
2009-11-25 01:15:48 -06:00
|
|
|
.start_script = perl_start_script,
|
2014-08-15 22:08:37 +03:00
|
|
|
.flush_script = perl_flush_script,
|
2009-11-25 01:15:48 -06:00
|
|
|
.stop_script = perl_stop_script,
|
|
|
|
.process_event = perl_process_event,
|
|
|
|
.generate_script = perl_generate_script,
|
|
|
|
};
|