perf script: Support standalone scripts and remove embedded scripting

Refactor 'perf script' to launch standalone scripts directly via fork()
and execvp() and remove the legacy embedded Perl and Python scripting
engines:
- Remove the embedded Perl scripting engine
  (util/scripting-engines/trace-event-perl.c), Perl scripts, bin
  wrappers, and Trace-Util library
  (scripts/perl/Perf-Trace-Util/), and script_perl.sh test.
- Remove libperl feature checks from Makefile.config, Makefile.perf,
  builtin-check.c, and Documentation/perf-check.txt.
- Remove -g / --gen-script option and scripting_ops dispatch table from
  builtin-script.c and trace-event-scripting.c.
- Hide the legacy -s / --script option and update script discovery in
  find_script() and list_available_scripts() to prioritize the system
  'python' directory over bare filenames in the current directory.
- Update the Python script shell tests (test_arm_coresight_disasm.sh,
  test_task_analyzer.sh, and test_*_python.sh) to invoke scripts via
  'perf script <script>' rather than running the Python interpreter
  directly on the script file path.

Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Ian Rogers 2026-09-25 23:20:15 -07:00 committed by Arnaldo Carvalho de Melo
parent 1b7e0280e2
commit b02aa1d134
72 changed files with 608 additions and 3613 deletions

View File

@ -121,7 +121,6 @@ FEATURE_TESTS_EXTRA := \
libbfd-liberty \
libbfd-liberty-z \
libopencsd \
libperl \
llvm \
libbpf \
libpfm4 \

View File

@ -31,7 +31,6 @@ FILES= \
test-libdebuginfod.bin \
test-libnuma.bin \
test-numa_num_possible_cpus.bin \
test-libperl.bin \
test-python-module.bin \
test-libslang.bin \
test-libtraceevent.bin \
@ -242,25 +241,6 @@ $(OUTPUT)test-libtracefs.bin:
$(OUTPUT)test-gtk4.bin:
$(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk4 2>/dev/null)
grep-libs = $(filter -l%,$(1))
strip-libs = $(filter-out -l%,$(1))
PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
PERL_EMBED_CCOPTS = $(shell perl -MExtUtils::Embed -e ccopts 2>/dev/null)
FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
ifeq ($(CC_NO_CLANG), 0)
PERL_EMBED_LDOPTS := $(filter-out -specs=%,$(PERL_EMBED_LDOPTS))
PERL_EMBED_CCOPTS := $(filter-out -flto=auto -ffat-lto-objects, $(PERL_EMBED_CCOPTS))
PERL_EMBED_CCOPTS := $(filter-out -specs=%,$(PERL_EMBED_CCOPTS))
FLAGS_PERL_EMBED += -Wno-compound-token-split-by-macro
endif
$(OUTPUT)test-libperl.bin:
$(BUILD) $(FLAGS_PERL_EMBED)
$(OUTPUT)test-python-module.bin:
$(BUILD) $(FLAGS_PYTHON_EMBED)

View File

@ -1,10 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <EXTERN.h>
#include <perl.h>
int main(void)
{
perl_alloc();
return 0;
}

View File

@ -61,7 +61,6 @@ perf-util-y += arch/
perf-y += arch/
perf-test-y += arch/
perf-ui-y += ui/
perf-util-y += scripts/
gtk-y += ui/gtk/

View File

@ -58,7 +58,6 @@ feature::
libLLVM / HAVE_LIBLLVM_SUPPORT
libnuma / HAVE_LIBNUMA_SUPPORT
libopencsd / HAVE_CSTRACE_SUPPORT
libperl / HAVE_LIBPERL_SUPPORT
libpfm4 / HAVE_LIBPFM
libslang / HAVE_SLANG_SUPPORT
libtraceevent / HAVE_LIBTRACEEVENT

View File

@ -1296,7 +1296,6 @@ $(call detected_var,tipdir_SQ)
$(call detected_var,srcdir_SQ)
$(call detected_var,LIBDIR)
$(call detected_var,GTK_CFLAGS)
$(call detected_var,PERL_EMBED_CCOPTS)
$(call detected_var,PYTHON_EMBED_CCOPTS)
ifneq ($(BISON_FILE_PREFIX_MAP),)
$(call detected_var,BISON_FILE_PREFIX_MAP)

View File

@ -17,7 +17,6 @@ include ../scripts/utilities.mak
#
# Define CROSS_COMPILE as prefix name of compiler if you want cross-builds.
#
# Define LIBPERL to enable perl script extension.
#
# Define NO_PYTHON_MODULE to disable python script extension.
#
@ -483,11 +482,6 @@ OTHER_PROGRAMS = $(OUTPUT)perf
ifndef SHELL_PATH
SHELL_PATH = /bin/sh
endif
ifndef PERL_PATH
PERL_PATH = /usr/bin/perl
endif
export PERL_PATH
LIBPERF_BENCH_IN := $(OUTPUT)perf-bench-in.o
LIBPERF_BENCH := $(OUTPUT)libperf-bench.a
@ -892,14 +886,6 @@ endif
$(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
$(call QUIET_INSTALL, perf-iostat) \
$(INSTALL) $(OUTPUT)perf-iostat -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
ifdef LIBPERL
$(call QUIET_INSTALL, perl-scripts) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
$(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
$(INSTALL) scripts/perl/*.pl -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'; \
$(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
endif
ifndef NO_PYTHON_MODULE
$(call QUIET_INSTALL, python-scripts) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/python' && \

View File

@ -51,7 +51,6 @@ struct feature_status supported_features[] = {
FEATURE_STATUS("libLLVM", HAVE_LIBLLVM_SUPPORT),
FEATURE_STATUS("libnuma", HAVE_LIBNUMA_SUPPORT),
FEATURE_STATUS("libopencsd", HAVE_CSTRACE_SUPPORT),
FEATURE_STATUS_TIP("libperl", HAVE_LIBPERL_SUPPORT, "Deprecated, use LIBPERL=1 and install perl-ExtUtils-Embed/libperl-dev to build with it"),
FEATURE_STATUS("python-module", HAVE_PYTHON_MODULE_SUPPORT),
FEATURE_STATUS("libpfm4", HAVE_LIBPFM),
FEATURE_STATUS("libslang", HAVE_SLANG_SUPPORT),

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +0,0 @@
ifeq ($(CONFIG_LIBTRACEEVENT),y)
perf-util-$(CONFIG_LIBPERL) += perl/Perf-Trace-Util/
endif

View File

@ -1,9 +0,0 @@
perf-util-y += Context.o
CFLAGS_Context.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-bad-function-cast -Wno-declaration-after-statement -Wno-switch-enum
CFLAGS_Context.o += -Wno-unused-parameter -Wno-nested-externs -Wno-undef
CFLAGS_Context.o += -Wno-switch-default -Wno-shadow -Wno-thread-safety-analysis
ifeq ($(CC_NO_CLANG), 1)
CFLAGS_Context.o += -Wno-unused-command-line-argument
endif

View File

@ -1,122 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* This file was generated automatically by ExtUtils::ParseXS version 2.18_02 from the
* contents of Context.xs. Do not edit this file, edit Context.xs instead.
*
* ANY CHANGES MADE HERE WILL BE LOST!
*/
#include <stdbool.h>
#ifndef HAS_BOOL
# define HAS_BOOL 1
#endif
#line 1 "Context.xs"
/*
* Context.xs. XS interfaces for perf script.
*
* Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
*/
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "../../../util/trace-event.h"
#ifndef PERL_UNUSED_VAR
# define PERL_UNUSED_VAR(var) if (0) var = var
#endif
#line 42 "Context.c"
XS(XS_Perf__Trace__Context_common_pc); /* prototype to pass -Wmissing-prototypes */
XS(XS_Perf__Trace__Context_common_pc)
{
#ifdef dVAR
dVAR; dXSARGS;
#else
dXSARGS;
#endif
if (items != 1)
Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_pc", "context");
PERL_UNUSED_VAR(cv); /* -W */
{
struct scripting_context * context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
int RETVAL;
dXSTARG;
RETVAL = common_pc(context);
XSprePUSH; PUSHi((IV)RETVAL);
}
XSRETURN(1);
}
XS(XS_Perf__Trace__Context_common_flags); /* prototype to pass -Wmissing-prototypes */
XS(XS_Perf__Trace__Context_common_flags)
{
#ifdef dVAR
dVAR; dXSARGS;
#else
dXSARGS;
#endif
if (items != 1)
Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_flags", "context");
PERL_UNUSED_VAR(cv); /* -W */
{
struct scripting_context * context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
int RETVAL;
dXSTARG;
RETVAL = common_flags(context);
XSprePUSH; PUSHi((IV)RETVAL);
}
XSRETURN(1);
}
XS(XS_Perf__Trace__Context_common_lock_depth); /* prototype to pass -Wmissing-prototypes */
XS(XS_Perf__Trace__Context_common_lock_depth)
{
#ifdef dVAR
dVAR; dXSARGS;
#else
dXSARGS;
#endif
if (items != 1)
Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_lock_depth", "context");
PERL_UNUSED_VAR(cv); /* -W */
{
struct scripting_context * context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
int RETVAL;
dXSTARG;
RETVAL = common_lock_depth(context);
XSprePUSH; PUSHi((IV)RETVAL);
}
XSRETURN(1);
}
#ifdef __cplusplus
extern "C"
#endif
XS(boot_Perf__Trace__Context); /* prototype to pass -Wmissing-prototypes */
XS(boot_Perf__Trace__Context)
{
#ifdef dVAR
dVAR; dXSARGS;
#else
dXSARGS;
#endif
const char* file = __FILE__;
PERL_UNUSED_VAR(cv); /* -W */
PERL_UNUSED_VAR(items); /* -W */
XS_VERSION_BOOTCHECK ;
newXSproto("Perf::Trace::Context::common_pc", XS_Perf__Trace__Context_common_pc, file, "$");
newXSproto("Perf::Trace::Context::common_flags", XS_Perf__Trace__Context_common_flags, file, "$");
newXSproto("Perf::Trace::Context::common_lock_depth", XS_Perf__Trace__Context_common_lock_depth, file, "$");
if (PL_unitcheckav)
call_list(PL_scopestack_ix, PL_unitcheckav);
XSRETURN_YES;
}

View File

@ -1,42 +0,0 @@
/*
* Context.xs. XS interfaces for perf script.
*
* 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
*
*/
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "../../../perf.h"
#include "../../../util/trace-event.h"
MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context
PROTOTYPES: ENABLE
int
common_pc(context)
struct scripting_context * context
int
common_flags(context)
struct scripting_context * context
int
common_lock_depth(context)
struct scripting_context * context

View File

@ -1,18 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
use 5.010000;
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
NAME => 'Perf::Trace::Context',
VERSION_FROM => 'lib/Perf/Trace/Context.pm', # finds $VERSION
PREREQ_PM => {}, # e.g., Module::Name => 1.1
($] >= 5.005 ? ## Add these new keywords supported since 5.005
(ABSTRACT_FROM => 'lib/Perf/Trace/Context.pm', # retrieve abstract from module
AUTHOR => 'Tom Zanussi <tzanussi@gmail.com>') : ()),
LIBS => [''], # e.g., '-lm'
DEFINE => '-I ../..', # e.g., '-DHAVE_SOMETHING'
INC => '-I.', # e.g., '-I. -I/usr/include/other'
# Un-comment this if you add C files to link with later:
OBJECT => 'Context.o', # link all the C files too
);

View File

@ -1,59 +0,0 @@
Perf-Trace-Util version 0.01
============================
This module contains utility functions for use with perf script.
Core.pm and Util.pm are pure Perl modules; Core.pm contains routines
that the core perf support for Perl calls on and should always be
'used', while Util.pm contains useful but optional utility functions
that scripts may want to use. Context.pm contains the Perl->C
interface that allows scripts to access data in the embedding perf
executable; scripts wishing to do that should 'use Context.pm'.
The Perl->C perf interface is completely driven by Context.xs. If you
want to add new Perl functions that end up accessing C data in the
perf executable, you add desciptions of the new functions here.
scripting_context is a pointer to the perf data in the perf executable
that you want to access - it's passed as the second parameter,
$context, to all handler functions.
After you do that:
perl Makefile.PL # to create a Makefile for the next step
make # to create Context.c
edit Context.c to add const to the char* file = __FILE__ line in
XS(boot_Perf__Trace__Context) to silence a warning/error.
You can delete the Makefile, object files and anything else that was
generated e.g. blib and shared library, etc, except for of course
Context.c
You should then be able to run the normal perf make as usual.
INSTALLATION
Building perf with perf script Perl scripting should install this
module in the right place.
You should make sure libperl and ExtUtils/Embed.pm are installed first
e.g. apt-get install libperl-dev or yum install perl-ExtUtils-Embed.
DEPENDENCIES
This module requires these other modules and libraries:
None
COPYRIGHT AND LICENCE
Copyright (C) 2009 by Tom Zanussi <tzanussi@gmail.com>
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.
Alternatively, this software may be distributed under the terms of the
GNU General Public License ("GPL") version 2 as published by the Free
Software Foundation.

View File

@ -1,55 +0,0 @@
package Perf::Trace::Context;
use 5.010000;
use strict;
use warnings;
require Exporter;
our @ISA = qw(Exporter);
our %EXPORT_TAGS = ( 'all' => [ qw(
) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(
common_pc common_flags common_lock_depth
);
our $VERSION = '0.01';
require XSLoader;
XSLoader::load('Perf::Trace::Context', $VERSION);
1;
__END__
=head1 NAME
Perf::Trace::Context - Perl extension for accessing functions in perf.
=head1 SYNOPSIS
use Perf::Trace::Context;
=head1 SEE ALSO
Perf (script) documentation
=head1 AUTHOR
Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2009 by Tom Zanussi
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.
Alternatively, this software may be distributed under the terms of the
GNU General Public License ("GPL") version 2 as published by the Free
Software Foundation.
=cut

View File

@ -1,192 +0,0 @@
package Perf::Trace::Core;
use 5.010000;
use strict;
use warnings;
require Exporter;
our @ISA = qw(Exporter);
our %EXPORT_TAGS = ( 'all' => [ qw(
) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(
define_flag_field define_flag_value flag_str dump_flag_fields
define_symbolic_field define_symbolic_value symbol_str dump_symbolic_fields
trace_flag_str
);
our $VERSION = '0.01';
my %trace_flags = (0x00 => "NONE",
0x01 => "IRQS_OFF",
0x02 => "IRQS_NOSUPPORT",
0x04 => "NEED_RESCHED",
0x08 => "HARDIRQ",
0x10 => "SOFTIRQ");
sub trace_flag_str
{
my ($value) = @_;
my $string;
my $print_delim = 0;
foreach my $idx (sort {$a <=> $b} keys %trace_flags) {
if (!$value && !$idx) {
$string .= "NONE";
last;
}
if ($idx && ($value & $idx) == $idx) {
if ($print_delim) {
$string .= " | ";
}
$string .= "$trace_flags{$idx}";
$print_delim = 1;
$value &= ~$idx;
}
}
return $string;
}
my %flag_fields;
my %symbolic_fields;
sub flag_str
{
my ($event_name, $field_name, $value) = @_;
my $string;
if ($flag_fields{$event_name}{$field_name}) {
my $print_delim = 0;
foreach my $idx (sort {$a <=> $b} keys %{$flag_fields{$event_name}{$field_name}{"values"}}) {
if (!$value && !$idx) {
$string .= "$flag_fields{$event_name}{$field_name}{'values'}{$idx}";
last;
}
if ($idx && ($value & $idx) == $idx) {
if ($print_delim && $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;
}
sub define_flag_field
{
my ($event_name, $field_name, $delim) = @_;
$flag_fields{$event_name}{$field_name}{"delim"} = $delim;
}
sub define_flag_value
{
my ($event_name, $field_name, $value, $field_str) = @_;
$flag_fields{$event_name}{$field_name}{"values"}{$value} = $field_str;
}
sub dump_flag_fields
{
for my $event (keys %flag_fields) {
print "event $event:\n";
for my $field (keys %{$flag_fields{$event}}) {
print " field: $field:\n";
print " delim: $flag_fields{$event}{$field}{'delim'}\n";
foreach my $idx (sort {$a <=> $b} keys %{$flag_fields{$event}{$field}{"values"}}) {
print " value $idx: $flag_fields{$event}{$field}{'values'}{$idx}\n";
}
}
}
}
sub symbol_str
{
my ($event_name, $field_name, $value) = @_;
if ($symbolic_fields{$event_name}{$field_name}) {
foreach my $idx (sort {$a <=> $b} keys %{$symbolic_fields{$event_name}{$field_name}{"values"}}) {
if (!$value && !$idx) {
return "$symbolic_fields{$event_name}{$field_name}{'values'}{$idx}";
last;
}
if ($value == $idx) {
return "$symbolic_fields{$event_name}{$field_name}{'values'}{$idx}";
}
}
}
return undef;
}
sub define_symbolic_field
{
my ($event_name, $field_name) = @_;
# nothing to do, really
}
sub define_symbolic_value
{
my ($event_name, $field_name, $value, $field_str) = @_;
$symbolic_fields{$event_name}{$field_name}{"values"}{$value} = $field_str;
}
sub dump_symbolic_fields
{
for my $event (keys %symbolic_fields) {
print "event $event:\n";
for my $field (keys %{$symbolic_fields{$event}}) {
print " field: $field:\n";
foreach my $idx (sort {$a <=> $b} keys %{$symbolic_fields{$event}{$field}{"values"}}) {
print " value $idx: $symbolic_fields{$event}{$field}{'values'}{$idx}\n";
}
}
}
}
1;
__END__
=head1 NAME
Perf::Trace::Core - Perl extension for perf script
=head1 SYNOPSIS
use Perf::Trace::Core
=head1 SEE ALSO
Perf (script) documentation
=head1 AUTHOR
Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2009 by Tom Zanussi
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.
Alternatively, this software may be distributed under the terms of the
GNU General Public License ("GPL") version 2 as published by the Free
Software Foundation.
=cut

View File

@ -1,94 +0,0 @@
package Perf::Trace::Util;
use 5.010000;
use strict;
use warnings;
require Exporter;
our @ISA = qw(Exporter);
our %EXPORT_TAGS = ( 'all' => [ qw(
) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(
avg nsecs nsecs_secs nsecs_nsecs nsecs_usecs print_nsecs
clear_term
);
our $VERSION = '0.01';
sub avg
{
my ($total, $n) = @_;
return $total / $n;
}
my $NSECS_PER_SEC = 1000000000;
sub nsecs
{
my ($secs, $nsecs) = @_;
return $secs * $NSECS_PER_SEC + $nsecs;
}
sub nsecs_secs {
my ($nsecs) = @_;
return $nsecs / $NSECS_PER_SEC;
}
sub nsecs_nsecs {
my ($nsecs) = @_;
return $nsecs % $NSECS_PER_SEC;
}
sub nsecs_str {
my ($nsecs) = @_;
my $str = sprintf("%5u.%09u", nsecs_secs($nsecs), nsecs_nsecs($nsecs));
return $str;
}
sub clear_term
{
print "\x1b[H\x1b[2J";
}
1;
__END__
=head1 NAME
Perf::Trace::Util - Perl extension for perf script
=head1 SYNOPSIS
use Perf::Trace::Util;
=head1 SEE ALSO
Perf (script) documentation
=head1 AUTHOR
Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2009 by Tom Zanussi
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.
Alternatively, this software may be distributed under the terms of the
GNU General Public License ("GPL") version 2 as published by the Free
Software Foundation.
=cut

View File

@ -1 +0,0 @@
struct scripting_context * T_PTR

View File

@ -1,2 +0,0 @@
#!/bin/bash
perf record -a -e kmem:kmalloc -e irq:softirq_entry -e kmem:kfree

View File

@ -1,3 +0,0 @@
#!/bin/bash
(perf record -e raw_syscalls:sys_exit $@ || \
perf record -e syscalls:sys_exit $@) 2> /dev/null

View File

@ -1,10 +0,0 @@
#!/bin/bash
# description: system-wide failed syscalls
# args: [comm]
if [ $# -gt 0 ] ; then
if ! expr match "$1" "-" > /dev/null ; then
comm=$1
shift
fi
fi
perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/failed-syscalls.pl $comm

View File

@ -1,3 +0,0 @@
#!/bin/bash
perf record -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@

View File

@ -1,10 +0,0 @@
#!/bin/bash
# description: r/w activity for a program, by file
# args: <comm>
if [ $# -lt 1 ] ; then
echo "usage: rw-by-file <comm>"
exit
fi
comm=$1
shift
perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-file.pl $comm

View File

@ -1,2 +0,0 @@
#!/bin/bash
perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@

View File

@ -1,3 +0,0 @@
#!/bin/bash
# description: system-wide r/w activity
perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-pid.pl

View File

@ -1,2 +0,0 @@
#!/bin/bash
perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@

View File

@ -1,20 +0,0 @@
#!/bin/bash
# description: system-wide r/w top
# args: [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 1 ] ; then
echo "usage: rwtop-report [interval]"
exit
fi
if [ "$n_args" -gt 0 ] ; then
interval=$1
shift
fi
perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/rwtop.pl $interval

View File

@ -1,6 +0,0 @@
#!/bin/bash
perf record -e sched:sched_switch -e sched:sched_wakeup $@

View File

@ -1,3 +0,0 @@
#!/bin/bash
# description: system-wide min/max/avg wakeup latency
perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/wakeup-latency.pl

View File

@ -1,106 +0,0 @@
# perf script event handlers, generated by perf script -g perl
# (c) 2009, 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, perl scripting support should be ok.
use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
use lib "./Perf-Trace-Util/lib";
use Perf::Trace::Core;
use Perf::Trace::Context;
use Perf::Trace::Util;
sub trace_begin
{
print "trace_begin\n";
}
sub trace_end
{
print "trace_end\n";
print_unhandled();
}
sub irq::softirq_entry
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain,
$vec) = @_;
print_header($event_name, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm);
print_uncommon($context);
printf("vec=%s\n",
symbol_str("irq::softirq_entry", "vec", $vec));
}
sub kmem::kmalloc
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain,
$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);
printf("call_site=%p, ptr=%p, 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));
}
# print trace fields not included in handler args
sub print_uncommon
{
my ($context) = @_;
printf("common_preempt_count=%d, common_flags=%s, common_lock_depth=%d, ",
common_pc($context), trace_flag_str(common_flags($context)),
common_lock_depth($context));
}
my %unhandled;
sub print_unhandled
{
if ((scalar keys %unhandled) == 0) {
return;
}
print "\nunhandled events:\n\n";
printf("%-40s %10s\n", "event", "count");
printf("%-40s %10s\n", "----------------------------------------",
"-----------");
foreach my $event_name (keys %unhandled) {
printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
}
}
sub trace_unhandled
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain) = @_;
$unhandled{$event_name}++;
}
sub print_header
{
my ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;
printf("%-20s %5u %05u.%09u %8u %-20s ",
$event_name, $cpu, $secs, $nsecs, $pid, $comm);
}

View File

@ -1,47 +0,0 @@
# failed system call counts
# (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
# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
use lib "./Perf-Trace-Util/lib";
use Perf::Trace::Core;
use Perf::Trace::Context;
use Perf::Trace::Util;
my $for_comm = shift;
my %failed_syscalls;
sub raw_syscalls::sys_exit
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain,
$id, $ret) = @_;
if ($ret < 0) {
$failed_syscalls{$common_comm}++;
}
}
sub syscalls::sys_exit
{
raw_syscalls::sys_exit(@_)
}
sub trace_end
{
printf("\nfailed syscalls by comm:\n\n");
printf("%-20s %10s\n", "comm", "# errors");
printf("%-20s %6s %10s\n", "--------------------", "----------");
foreach my $comm (sort {$failed_syscalls{$b} <=> $failed_syscalls{$a}}
keys %failed_syscalls) {
next if ($for_comm && $comm ne $for_comm);
printf("%-20s %10s\n", $comm, $failed_syscalls{$comm});
}
}

View File

@ -1,106 +0,0 @@
#!/usr/bin/perl -w
# SPDX-License-Identifier: GPL-2.0-only
# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
# Display r/w activity for files read/written to for a given program
# The common_* event handler fields are the most useful fields common to
# all events. They don't necessarily correspond to the 'common_*' fields
# in the status files. Those fields not available as handler params can
# be retrieved via script functions of the form get_common_*().
use 5.010000;
use strict;
use warnings;
use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
use lib "./Perf-Trace-Util/lib";
use Perf::Trace::Core;
use Perf::Trace::Util;
my $usage = "perf script -s rw-by-file.pl <comm>\n";
my $for_comm = shift or die $usage;
my %reads;
my %writes;
sub syscalls::sys_enter_read
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain, $nr, $fd, $buf, $count) = @_;
if ($common_comm eq $for_comm) {
$reads{$fd}{bytes_requested} += $count;
$reads{$fd}{total_reads}++;
}
}
sub syscalls::sys_enter_write
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain, $nr, $fd, $buf, $count) = @_;
if ($common_comm eq $for_comm) {
$writes{$fd}{bytes_written} += $count;
$writes{$fd}{total_writes}++;
}
}
sub trace_end
{
printf("file read counts for $for_comm:\n\n");
printf("%6s %10s %10s\n", "fd", "# reads", "bytes_requested");
printf("%6s %10s %10s\n", "------", "----------", "-----------");
foreach my $fd (sort {$reads{$b}{bytes_requested} <=>
$reads{$a}{bytes_requested}} keys %reads) {
my $total_reads = $reads{$fd}{total_reads};
my $bytes_requested = $reads{$fd}{bytes_requested};
printf("%6u %10u %10u\n", $fd, $total_reads, $bytes_requested);
}
printf("\nfile write counts for $for_comm:\n\n");
printf("%6s %10s %10s\n", "fd", "# writes", "bytes_written");
printf("%6s %10s %10s\n", "------", "----------", "-----------");
foreach my $fd (sort {$writes{$b}{bytes_written} <=>
$writes{$a}{bytes_written}} keys %writes) {
my $total_writes = $writes{$fd}{total_writes};
my $bytes_written = $writes{$fd}{bytes_written};
printf("%6u %10u %10u\n", $fd, $total_writes, $bytes_written);
}
print_unhandled();
}
my %unhandled;
sub print_unhandled
{
if ((scalar keys %unhandled) == 0) {
return;
}
print "\nunhandled events:\n\n";
printf("%-40s %10s\n", "event", "count");
printf("%-40s %10s\n", "----------------------------------------",
"-----------");
foreach my $event_name (keys %unhandled) {
printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
}
}
sub trace_unhandled
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain) = @_;
$unhandled{$event_name}++;
}

View File

@ -1,184 +0,0 @@
#!/usr/bin/perl -w
# SPDX-License-Identifier: GPL-2.0-only
# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
# Display r/w activity for all processes
# The common_* event handler fields are the most useful fields common to
# all events. They don't necessarily correspond to the 'common_*' fields
# in the status files. Those fields not available as handler params can
# be retrieved via script functions of the form get_common_*().
use 5.010000;
use strict;
use warnings;
use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
use lib "./Perf-Trace-Util/lib";
use Perf::Trace::Core;
use Perf::Trace::Util;
my %reads;
my %writes;
sub syscalls::sys_exit_read
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain,
$nr, $ret) = @_;
if ($ret > 0) {
$reads{$common_pid}{bytes_read} += $ret;
} else {
if (!defined ($reads{$common_pid}{bytes_read})) {
$reads{$common_pid}{bytes_read} = 0;
}
$reads{$common_pid}{errors}{$ret}++;
}
}
sub syscalls::sys_enter_read
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain,
$nr, $fd, $buf, $count) = @_;
$reads{$common_pid}{bytes_requested} += $count;
$reads{$common_pid}{total_reads}++;
$reads{$common_pid}{comm} = $common_comm;
}
sub syscalls::sys_exit_write
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain,
$nr, $ret) = @_;
if ($ret <= 0) {
$writes{$common_pid}{errors}{$ret}++;
}
}
sub syscalls::sys_enter_write
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain,
$nr, $fd, $buf, $count) = @_;
$writes{$common_pid}{bytes_written} += $count;
$writes{$common_pid}{total_writes}++;
$writes{$common_pid}{comm} = $common_comm;
}
sub trace_end
{
printf("read counts by pid:\n\n");
printf("%6s %20s %10s %10s %10s\n", "pid", "comm",
"# reads", "bytes_requested", "bytes_read");
printf("%6s %-20s %10s %10s %10s\n", "------", "--------------------",
"-----------", "----------", "----------");
foreach my $pid (sort { ($reads{$b}{bytes_read} || 0) <=>
($reads{$a}{bytes_read} || 0) } keys %reads) {
my $comm = $reads{$pid}{comm} || "";
my $total_reads = $reads{$pid}{total_reads} || 0;
my $bytes_requested = $reads{$pid}{bytes_requested} || 0;
my $bytes_read = $reads{$pid}{bytes_read} || 0;
printf("%6s %-20s %10s %10s %10s\n", $pid, $comm,
$total_reads, $bytes_requested, $bytes_read);
}
printf("\nfailed reads by pid:\n\n");
printf("%6s %20s %6s %10s\n", "pid", "comm", "error #", "# errors");
printf("%6s %20s %6s %10s\n", "------", "--------------------",
"------", "----------");
my @errcounts = ();
foreach my $pid (keys %reads) {
foreach my $error (keys %{$reads{$pid}{errors}}) {
my $comm = $reads{$pid}{comm} || "";
my $errcount = $reads{$pid}{errors}{$error} || 0;
push @errcounts, [$pid, $comm, $error, $errcount];
}
}
@errcounts = sort { $b->[3] <=> $a->[3] } @errcounts;
for my $i (0 .. $#errcounts) {
printf("%6d %-20s %6d %10s\n", $errcounts[$i][0],
$errcounts[$i][1], $errcounts[$i][2], $errcounts[$i][3]);
}
printf("\nwrite counts by pid:\n\n");
printf("%6s %20s %10s %10s\n", "pid", "comm",
"# writes", "bytes_written");
printf("%6s %-20s %10s %10s\n", "------", "--------------------",
"-----------", "----------");
foreach my $pid (sort { ($writes{$b}{bytes_written} || 0) <=>
($writes{$a}{bytes_written} || 0)} keys %writes) {
my $comm = $writes{$pid}{comm} || "";
my $total_writes = $writes{$pid}{total_writes} || 0;
my $bytes_written = $writes{$pid}{bytes_written} || 0;
printf("%6s %-20s %10s %10s\n", $pid, $comm,
$total_writes, $bytes_written);
}
printf("\nfailed writes by pid:\n\n");
printf("%6s %20s %6s %10s\n", "pid", "comm", "error #", "# errors");
printf("%6s %20s %6s %10s\n", "------", "--------------------",
"------", "----------");
@errcounts = ();
foreach my $pid (keys %writes) {
foreach my $error (keys %{$writes{$pid}{errors}}) {
my $comm = $writes{$pid}{comm} || "";
my $errcount = $writes{$pid}{errors}{$error} || 0;
push @errcounts, [$pid, $comm, $error, $errcount];
}
}
@errcounts = sort { $b->[3] <=> $a->[3] } @errcounts;
for my $i (0 .. $#errcounts) {
printf("%6d %-20s %6d %10s\n", $errcounts[$i][0],
$errcounts[$i][1], $errcounts[$i][2], $errcounts[$i][3]);
}
print_unhandled();
}
my %unhandled;
sub print_unhandled
{
if ((scalar keys %unhandled) == 0) {
return;
}
print "\nunhandled events:\n\n";
printf("%-40s %10s\n", "event", "count");
printf("%-40s %10s\n", "----------------------------------------",
"-----------");
foreach my $event_name (keys %unhandled) {
printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
}
}
sub trace_unhandled
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain) = @_;
$unhandled{$event_name}++;
}

View File

@ -1,203 +0,0 @@
#!/usr/bin/perl -w
# SPDX-License-Identifier: GPL-2.0-only
# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
# read/write top
#
# Periodically displays system-wide r/w call activity, broken down by
# pid. If an [interval] arg is specified, the display will be
# refreshed every [interval] seconds. The default interval is 3
# seconds.
use 5.010000;
use strict;
use warnings;
use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
use lib "./Perf-Trace-Util/lib";
use Perf::Trace::Core;
use Perf::Trace::Util;
use POSIX qw/SIGALRM SA_RESTART/;
my $default_interval = 3;
my $nlines = 20;
my $print_thread;
my $print_pending = 0;
my %reads;
my %writes;
my $interval = shift;
if (!$interval) {
$interval = $default_interval;
}
sub syscalls::sys_exit_read
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain,
$nr, $ret) = @_;
print_check();
if ($ret > 0) {
$reads{$common_pid}{bytes_read} += $ret;
} else {
if (!defined ($reads{$common_pid}{bytes_read})) {
$reads{$common_pid}{bytes_read} = 0;
}
$reads{$common_pid}{errors}{$ret}++;
}
}
sub syscalls::sys_enter_read
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain,
$nr, $fd, $buf, $count) = @_;
print_check();
$reads{$common_pid}{bytes_requested} += $count;
$reads{$common_pid}{total_reads}++;
$reads{$common_pid}{comm} = $common_comm;
}
sub syscalls::sys_exit_write
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain,
$nr, $ret) = @_;
print_check();
if ($ret <= 0) {
$writes{$common_pid}{errors}{$ret}++;
}
}
sub syscalls::sys_enter_write
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain,
$nr, $fd, $buf, $count) = @_;
print_check();
$writes{$common_pid}{bytes_written} += $count;
$writes{$common_pid}{total_writes}++;
$writes{$common_pid}{comm} = $common_comm;
}
sub trace_begin
{
my $sa = POSIX::SigAction->new(\&set_print_pending);
$sa->flags(SA_RESTART);
$sa->safe(1);
POSIX::sigaction(SIGALRM, $sa) or die "Can't set SIGALRM handler: $!\n";
alarm 1;
}
sub trace_end
{
print_unhandled();
print_totals();
}
sub print_check()
{
if ($print_pending == 1) {
$print_pending = 0;
print_totals();
}
}
sub set_print_pending()
{
$print_pending = 1;
alarm $interval;
}
sub print_totals
{
my $count;
$count = 0;
clear_term();
printf("\nread counts by pid:\n\n");
printf("%6s %20s %10s %10s %10s\n", "pid", "comm",
"# reads", "bytes_req", "bytes_read");
printf("%6s %-20s %10s %10s %10s\n", "------", "--------------------",
"----------", "----------", "----------");
foreach my $pid (sort { ($reads{$b}{bytes_read} || 0) <=>
($reads{$a}{bytes_read} || 0) } keys %reads) {
my $comm = $reads{$pid}{comm} || "";
my $total_reads = $reads{$pid}{total_reads} || 0;
my $bytes_requested = $reads{$pid}{bytes_requested} || 0;
my $bytes_read = $reads{$pid}{bytes_read} || 0;
printf("%6s %-20s %10s %10s %10s\n", $pid, $comm,
$total_reads, $bytes_requested, $bytes_read);
if (++$count == $nlines) {
last;
}
}
$count = 0;
printf("\nwrite counts by pid:\n\n");
printf("%6s %20s %10s %13s\n", "pid", "comm",
"# writes", "bytes_written");
printf("%6s %-20s %10s %13s\n", "------", "--------------------",
"----------", "-------------");
foreach my $pid (sort { ($writes{$b}{bytes_written} || 0) <=>
($writes{$a}{bytes_written} || 0)} keys %writes) {
my $comm = $writes{$pid}{comm} || "";
my $total_writes = $writes{$pid}{total_writes} || 0;
my $bytes_written = $writes{$pid}{bytes_written} || 0;
printf("%6s %-20s %10s %13s\n", $pid, $comm,
$total_writes, $bytes_written);
if (++$count == $nlines) {
last;
}
}
%reads = ();
%writes = ();
}
my %unhandled;
sub print_unhandled
{
if ((scalar keys %unhandled) == 0) {
return;
}
print "\nunhandled events:\n\n";
printf("%-40s %10s\n", "event", "count");
printf("%-40s %10s\n", "----------------------------------------",
"-----------");
foreach my $event_name (keys %unhandled) {
printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
}
}
sub trace_unhandled
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain) = @_;
$unhandled{$event_name}++;
}

View File

@ -1,107 +0,0 @@
#!/usr/bin/perl -w
# SPDX-License-Identifier: GPL-2.0-only
# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
# Display avg/min/max wakeup latency
# The common_* event handler fields are the most useful fields common to
# all events. They don't necessarily correspond to the 'common_*' fields
# in the status files. Those fields not available as handler params can
# be retrieved via script functions of the form get_common_*().
use 5.010000;
use strict;
use warnings;
use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
use lib "./Perf-Trace-Util/lib";
use Perf::Trace::Core;
use Perf::Trace::Util;
my %last_wakeup;
my $max_wakeup_latency;
my $min_wakeup_latency;
my $total_wakeup_latency = 0;
my $total_wakeups = 0;
sub sched::sched_switch
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain,
$prev_comm, $prev_pid, $prev_prio, $prev_state, $next_comm, $next_pid,
$next_prio) = @_;
my $wakeup_ts = $last_wakeup{$common_cpu}{ts};
if ($wakeup_ts) {
my $switch_ts = nsecs($common_secs, $common_nsecs);
my $wakeup_latency = $switch_ts - $wakeup_ts;
if ($wakeup_latency > $max_wakeup_latency) {
$max_wakeup_latency = $wakeup_latency;
}
if ($wakeup_latency < $min_wakeup_latency) {
$min_wakeup_latency = $wakeup_latency;
}
$total_wakeup_latency += $wakeup_latency;
$total_wakeups++;
}
$last_wakeup{$common_cpu}{ts} = 0;
}
sub sched::sched_wakeup
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain,
$comm, $pid, $prio, $success, $target_cpu) = @_;
$last_wakeup{$target_cpu}{ts} = nsecs($common_secs, $common_nsecs);
}
sub trace_begin
{
$min_wakeup_latency = 1000000000;
$max_wakeup_latency = 0;
}
sub trace_end
{
printf("wakeup_latency stats:\n\n");
print "total_wakeups: $total_wakeups\n";
if ($total_wakeups) {
printf("avg_wakeup_latency (ns): %u\n",
avg($total_wakeup_latency, $total_wakeups));
} else {
printf("avg_wakeup_latency (ns): N/A\n");
}
printf("min_wakeup_latency (ns): %u\n", $min_wakeup_latency);
printf("max_wakeup_latency (ns): %u\n", $max_wakeup_latency);
print_unhandled();
}
my %unhandled;
sub print_unhandled
{
if ((scalar keys %unhandled) == 0) {
return;
}
print "\nunhandled events:\n\n";
printf("%-40s %10s\n", "event", "count");
printf("%-40s %10s\n", "----------------------------------------",
"-----------");
foreach my $event_name (keys %unhandled) {
printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
}
}
sub trace_unhandled
{
my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
$common_pid, $common_comm, $common_callchain) = @_;
$unhandled{$event_name}++;
}

View File

@ -79,7 +79,6 @@ make_no_jevents := NO_JEVENTS=1
make_jevents_all := JEVENTS_ARCH=all
make_no_bpf_skel := BUILD_BPF_SKEL=0
make_gen_vmlinux_h := GEN_VMLINUX_H=1
make_libperl := LIBPERL=1
make_no_python_module := NO_PYTHON_MODULE=1
make_no_scripts := NO_PYTHON_MODULE=1
make_no_slang := NO_SLANG=1
@ -175,7 +174,6 @@ run += make_no_jevents
run += make_jevents_all
run += make_no_bpf_skel
run += make_gen_vmlinux_h
run += make_libperl
run += make_no_python_module
run += make_no_scripts
run += make_no_slang

View File

@ -20,13 +20,6 @@ skip_if_no_cs_etm_event || exit 2
set -e
glb_err=1
# Relative path works whether it's installed or running from repo
if [ -n "$PERF_EXEC_PATH" ] && [ -e "$PERF_EXEC_PATH/python/arm-cs-trace-disasm.py" ]; then
script_path="$PERF_EXEC_PATH/python/arm-cs-trace-disasm.py"
else
script_path=$(dirname "$0")/../../../python/arm-cs-trace-disasm.py
fi
# shellcheck source=lib/setup_python.sh
. "$(dirname "$0")"/../lib/setup_python.sh
$PYTHON -c "import perf" 2>/dev/null || {
@ -56,8 +49,8 @@ branch_search='[[:space:]](bl|b(\.(eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al)
if [ "$(id -u)" == 0 ] && [ -e /proc/kcore ]; then
echo "Testing kernel disassembly"
perf record -o ${perfdata} -e cs_etm//k --kcore -Se -m,64K -- touch $file > /dev/null 2>&1
$PYTHON ${script_path} -i ${perfdata} -d --stop-sample=2 \
-k ${perfdata}/kcore_dir/kcore 2> /dev/null > ${file}
perf script -i ${perfdata} arm-cs-trace-disasm -- \
-d --stop-sample=2 -k ${perfdata}/kcore_dir/kcore 2> /dev/null > ${file}
grep -q -E ${branch_search} ${file}
echo "Found kernel branches"
else
@ -68,7 +61,8 @@ fi
## Test user ##
echo "Testing userspace disassembly"
perf record -o ${perfdata} -e cs_etm//u -Se -m,64K -- touch $file > /dev/null 2>&1
$PYTHON ${script_path} -i ${perfdata} -d --stop-sample=2 2> /dev/null > ${file}
perf script -i ${perfdata} arm-cs-trace-disasm -- \
-d --stop-sample=2 2> /dev/null > ${file}
grep -q -E ${branch_search} ${file}
echo "Found userspace branches"

View File

@ -1,102 +0,0 @@
#!/bin/bash
# perf script perl tests
# SPDX-License-Identifier: GPL-2.0
set -e
# set PERF_EXEC_PATH to find scripts in the source directory
perfdir=$(dirname "$0")/../..
if [ -e "$perfdir/scripts/perl/Perf-Trace-Util" ]; then
export PERF_EXEC_PATH=$perfdir
fi
perfdata=$(mktemp /tmp/__perf_test_script_perl.perf.data.XXXXX)
generated_script=$(mktemp /tmp/__perf_test_script.XXXXX.pl)
cleanup() {
rm -f "${perfdata}"
rm -f "${generated_script}"
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit 1
}
trap trap_cleanup TERM INT
trap cleanup EXIT
check_perl_support() {
if perf check feature -q libperl; then
return 0
fi
echo "perf script perl test [Skipped: no libperl support]"
return 2
}
test_script() {
local event_name=$1
local expected_output=$2
local record_opts=$3
echo "Testing event: $event_name"
# Try to record. If this fails, it might be permissions or lack of support.
# We return 2 to indicate "skip this event" rather than "fail test".
if ! perf record -o "${perfdata}" -e "$event_name" $record_opts -- perf test -w thloop > /dev/null 2>&1; then
echo "perf script perl test [Skipped: failed to record $event_name]"
return 2
fi
echo "Generating perl script..."
if ! perf script -i "${perfdata}" -g "${generated_script}"; then
echo "perf script perl test [Failed: script generation for $event_name]"
return 1
fi
if [ ! -f "${generated_script}" ]; then
echo "perf script perl test [Failed: script not generated for $event_name]"
return 1
fi
echo "Executing perl script..."
output=$(perf script -i "${perfdata}" -s "${generated_script}" 2>&1)
if echo "$output" | grep -q "$expected_output"; then
echo "perf script perl test [Success: $event_name triggered $expected_output]"
return 0
else
echo "perf script perl test [Failed: $event_name did not trigger $expected_output]"
echo "Output was:"
echo "$output" | head -n 20
return 1
fi
}
check_perl_support || exit 2
# Try tracepoint first
test_script "sched:sched_switch" "sched::sched_switch" "-c 1" && res=0 || res=$?
if [ $res -eq 0 ]; then
exit 0
elif [ $res -eq 1 ]; then
exit 1
fi
# If tracepoint skipped (res=2), try task-clock
# For generic events like task-clock, the generated script uses process_event()
# which dumps data using Data::Dumper. We check for "$VAR1" which is standard Dumper output.
test_script "task-clock" "\$VAR1" "-c 100" && res=0 || res=$?
if [ $res -eq 0 ]; then
exit 0
elif [ $res -eq 1 ]; then
exit 1
fi
# If both skipped
echo "perf script perl test [Skipped: Could not record tracepoint or task-clock]"
exit 2

View File

@ -68,7 +68,7 @@ test_file_mode() {
fi
# Run the script
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script check-perf-trace -i "${temp_data}" > "${temp_out}"; then
echo "File mode test failed."
err=1
elif ! grep -q "in trace_begin" "${temp_out}" || \

View File

@ -58,7 +58,7 @@ test_file_mode() {
fi
# Run the script with some filters to validate filtering logic
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script compaction-times -i "${temp_data}" > "${temp_out}"; then
echo "File mode default test failed."
err=1
elif ! grep -q "total:" "${temp_out}"; then
@ -66,7 +66,7 @@ test_file_mode() {
err=1
fi
if ! "$PYTHON" "$script_path" -i "${temp_data}" "0-0" > "${temp_out}"; then
if ! perf script compaction-times -i "${temp_data}" "0-0" > "${temp_out}"; then
echo "File mode strict PID filter test failed."
err=1
elif ! grep -q "total:" "${temp_out}"; then
@ -74,7 +74,7 @@ test_file_mode() {
err=1
fi
if ! "$PYTHON" "$script_path" -i "${temp_data}" "sleep" > "${temp_out}"; then
if ! perf script compaction-times -i "${temp_data}" "sleep" > "${temp_out}"; then
echo "File mode comm filter test failed."
err=1
elif ! grep -q "total:" "${temp_out}"; then

View File

@ -45,7 +45,8 @@ test_file_mode() {
fi
# Run the script
if ! "$PYTHON" "$script_path" -i "${temp_data}" -d "${temp_db}" > "${temp_dir}/perf.out" 2>&1; then
if ! perf script event_analyzing_sample -i "${temp_data}" \
-d "${temp_db}" > "${temp_dir}/perf.out" 2>&1; then
echo "File mode test failed."
err=1
elif ! grep -q "Statistics about the general events" "${temp_dir}/perf.out" || \

View File

@ -54,7 +54,8 @@ test_file_mode() {
echo "Testing export-to-postgresql.py..."
# Verify that invalid URI / key-value database names are rejected
if "$PYTHON" "$script_path" -i /dev/null -o "dbname=foo host=evil" >/dev/null 2>&1; then
if perf script export-to-postgresql -i /dev/null \
-o "dbname=foo host=evil" >/dev/null 2>&1; then
echo "Connection parameter injection check failed."
err=1
fi
@ -71,7 +72,7 @@ test_file_mode() {
psql -c "DROP DATABASE IF EXISTS ${temp_db}" postgres >/dev/null 2>&1 || true
# Run the script
if ! "$PYTHON" "$script_path" -i "${temp_data}" -o "${temp_db}" >/dev/null; then
if ! perf script export-to-postgresql -i "${temp_data}" -o "${temp_db}" >/dev/null; then
echo "File mode test failed."
err=1
else
@ -101,7 +102,8 @@ test_intel_pt() {
fi
# Run the script with --itrace cr to synthesize call_returns
if ! "$PYTHON" "$script_path" -i "${temp_data}" -o "${temp_db}" --itrace cr >/dev/null; then
if ! perf script export-to-postgresql -i "${temp_data}" \
-o "${temp_db}" --itrace cr >/dev/null; then
echo "intel_pt file mode test failed."
err=1
else

View File

@ -55,7 +55,7 @@ test_file_mode() {
fi
# Run the script
if ! "$PYTHON" "$script_path" -i "${temp_data}" -o "${temp_db}" >/dev/null; then
if ! perf script export-to-sqlite -i "${temp_data}" -o "${temp_db}" >/dev/null; then
echo "File mode test failed."
err=1
else
@ -86,7 +86,7 @@ test_intel_pt() {
fi
# Run the script with --itrace cr to synthesize call_returns
if ! "$PYTHON" "$script_path" -i "${temp_data}" -o "${temp_db}" --itrace cr; then
if ! perf script export-to-sqlite -i "${temp_data}" -o "${temp_db}" --itrace cr; then
echo "intel_pt file mode test failed."
err=1
else

View File

@ -63,14 +63,14 @@ test_file_mode() {
fi
# Run the script and check output
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script failed-syscalls-by-pid -i "${temp_data}" > "${temp_out}"; then
echo "failed-syscalls-by-pid test failed."
err=1
elif ! grep -n -q "err = ENOENT" "${temp_out}"; then
echo "Failed to find expected failed syscalls"
cat "${temp_out}"
err=1
elif ! "$PYTHON" "$script_path" -i "${temp_data}" "ls" > "${temp_out}.comm" || \
elif ! perf script failed-syscalls-by-pid -i "${temp_data}" "ls" > "${temp_out}.comm" || \
! grep -q "err = ENOENT" "${temp_out}.comm"; then
echo "failed-syscalls-by-pid comm filter test failed."
cat "${temp_out}.comm"
@ -78,7 +78,8 @@ test_file_mode() {
else
ls_pid=$(sed -n 's/^ls \[\([0-9][0-9]*\)\].*/\1/p' "${temp_out}.comm" | head -n 1)
if [ -z "${ls_pid}" ] || \
! "$PYTHON" "$script_path" -i "${temp_data}" "${ls_pid}" > "${temp_out}.pid" || \
! perf script failed-syscalls-by-pid -i "${temp_data}" \
"${ls_pid}" > "${temp_out}.pid" || \
! grep -q "err = ENOENT" "${temp_out}.pid"; then
echo "failed-syscalls-by-pid PID filter test failed."
cat "${temp_out}.pid" 2>/dev/null || true

View File

@ -63,7 +63,7 @@ if [ ! -s "${temp_data}" ]; then
fi
# Check that the script executes
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script failed-syscalls -i "${temp_data}" > "${temp_out}"; then
echo "failed-syscalls.py test failed"
err=1
else

View File

@ -66,7 +66,7 @@ test_file_mode() {
fi
# Run the script in file mode and validate JSON output
if ! "$PYTHON" "$script_path" -i "${temp_data}" -f json -o "${temp_json}" >/dev/null; then
if ! perf script flamegraph -i "${temp_data}" -f json -o "${temp_json}" >/dev/null; then
echo "File mode JSON test failed."
err=1
else
@ -76,7 +76,7 @@ test_file_mode() {
# Run the script in pipe ('-') mode and validate JSON output
rm -f "${temp_json}"
if ! perf record -g -o - -- perf test -w noploop 2>/dev/null | \
"$PYTHON" "$script_path" -i - -f json -o "${temp_json}" >/dev/null; then
perf script flamegraph -i - -f json -o "${temp_json}" >/dev/null; then
echo "Pipe stdin JSON mode test failed."
err=1
else
@ -84,7 +84,7 @@ test_file_mode() {
fi
# Run the script, dump as html to temp_html using MINIMAL_HTML fallback
if ! "$PYTHON" "$script_path" -i "${temp_data}" -f html \
if ! perf script flamegraph -i "${temp_data}" -f html \
--template /nonexistent/template.html -o "${temp_html}" >/dev/null 2>&1; then
echo "File mode HTML test failed."
err=1
@ -105,7 +105,7 @@ const opts = /** @options_json **/;
const data = /** @flamegraph_json **/;
</script></body></html>
EOF
if ! "$PYTHON" "$script_path" -i "${temp_data}" -f html --template "${temp_tpl}" \
if ! perf script flamegraph -i "${temp_data}" -f html --template "${temp_tpl}" \
--colorscheme blue-green -o "${temp_html}" >/dev/null 2>&1; then
echo "Custom template HTML test failed."
err=1

View File

@ -101,7 +101,7 @@ test_file_mode() {
return
fi
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script futex-contention -i "${temp_data}" > "${temp_out}"; then
echo "File mode test failed."
err=1
else

View File

@ -45,7 +45,7 @@ test_file_mode() {
fi
# Run the script in save-only mode with custom product and category colors
if ! "$PYTHON" "$script_path" -i "${temp_data}" \
if ! perf script gecko -i "${temp_data}" \
--product "perf-test-product" --user-color blue --kernel-color red \
--save-only "${temp_json}" >/dev/null; then
echo "File mode test failed."

View File

@ -49,7 +49,7 @@ test_intel_pt() {
fi
# Run the script and check output
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script intel-pt-events -i "${temp_data}" > "${temp_out}"; then
echo "intel-pt-events.py test failed."
err=1
else

View File

@ -87,7 +87,8 @@ test_file_mode() {
fi
# Run the script with custom --iomem
if ! "$PYTHON" "$script_path" -i "${temp_data}" --iomem "${temp_iomem}" > "${temp_out}" || \
if ! perf script mem-phys-addr -i "${temp_data}" \
--iomem "${temp_iomem}" > "${temp_out}" || \
[ ! -s "${temp_out}" ]; then
echo "File mode test failed."
err=1

View File

@ -59,7 +59,7 @@ if [ ! -s "${temp_data}" ]; then
fi
# Check that the script executes and outputs table header
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script net_dropmonitor -i "${temp_data}" > "${temp_out}"; then
echo "net_dropmonitor.py test failed"
err=1
else

View File

@ -93,7 +93,7 @@ if ! perf record -e skb:kfree_skb -a -o "${temp_data}" \
fi
# Check that the script executes
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script netdev-times -i "${temp_data}" > "${temp_out}"; then
echo "netdev-times.py test failed"
err=1
else

View File

@ -79,7 +79,7 @@ if [ ! -s "${temp_data}" ]; then
fi
# Check that the script executes on recorded perf.data
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script powerpc-hcalls -i "${temp_data}" > "${temp_out}"; then
echo "powerpc-hcalls.py test failed"
err=1
else

View File

@ -52,7 +52,7 @@ if [ ! -s "${temp_data}" ]; then
fi
# Check that the script executes - filtering for "dd" since that's what we ran
if ! "$PYTHON" "$script_path" -i "${temp_data}" "dd" > "${temp_out}"; then
if ! perf script rw-by-file -i "${temp_data}" "dd" > "${temp_out}"; then
echo "rw-by-file.py test failed"
err=1
else

View File

@ -58,7 +58,7 @@ if [ ! -s "${temp_data}" ]; then
fi
# Check that the script executes
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script rw-by-pid -i "${temp_data}" > "${temp_out}"; then
echo "rw-by-pid.py test failed"
err=1
else

View File

@ -58,7 +58,7 @@ if [ ! -s "${temp_data}" ]; then
fi
# Check that the script executes
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script rwtop -i "${temp_data}" > "${temp_out}"; then
echo "rwtop.py test failed"
err=1
else

View File

@ -58,7 +58,7 @@ if [ ! -s "${temp_data}" ]; then
fi
# Check that the script executes
if ! "$PYTHON" "$script_path" -v --no-gui -i "${temp_data}" > "${temp_out}"; then
if ! perf script sched-migration -v --no-gui -i "${temp_data}" > "${temp_out}"; then
echo "sched-migration.py test failed"
err=1
elif [ "$has_sched" -eq 1 ] && ! grep -q "Timeslices:" "${temp_out}"; then

View File

@ -56,13 +56,13 @@ if [ ! -s "${temp_data}" ]; then
fi
# Check that the script executes
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script sctop -i "${temp_data}" > "${temp_out}"; then
echo "sctop.py test failed"
err=1
elif ! grep -E -q "[0-9]+$" "${temp_out}"; then
echo "Failed to find metric data rows in default run"
err=1
elif ! "$PYTHON" "$script_path" -i "${temp_data}" sleep 1 > "${temp_out}"; then
elif ! perf script sctop -i "${temp_data}" sleep 1 > "${temp_out}"; then
echo "sctop.py comm+interval test failed"
err=1
else

View File

@ -47,7 +47,7 @@ if [ ! -s "${temp_data}" ]; then
fi
# Check that the script executes with default options
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script stackcollapse -i "${temp_data}" > "${temp_out}"; then
echo "stackcollapse.py test failed"
err=1
else
@ -61,12 +61,12 @@ else
fi
# Test CLI flags (--include-pid, --include-tid, --tidy-java, --kernel) and BrokenPipeError
if ! "$PYTHON" "$script_path" -i "${temp_data}" \
if ! perf script stackcollapse -i "${temp_data}" \
--include-pid --include-tid --tidy-java --kernel | head -n 1 > "${temp_out}" || \
[ ! -s "${temp_out}" ]; then
echo "stackcollapse.py options/pipe test failed"
err=1
elif ! "$PYTHON" "$script_path" -i "${temp_data}" --no-comm > "${temp_out}" || \
elif ! perf script stackcollapse -i "${temp_data}" --no-comm > "${temp_out}" || \
[ ! -s "${temp_out}" ]; then
echo "stackcollapse.py --no-comm test failed"
err=1

View File

@ -62,7 +62,7 @@ test_live_mode() {
ran=1
# Run live mode for 1 interval in the background, give it a tiny sleep, then interrupt
"$PYTHON" "$script_path" -I 0.1 -p "$workload_pid" > "${temp_out}" &
perf script stat-cpi -I 0.1 -p "$workload_pid" > "${temp_out}" &
pid=$!
sleep 0.5
kill -INT "$pid" 2>/dev/null || true
@ -96,7 +96,7 @@ test_file_mode() {
fi
ran=1
out=$("$PYTHON" "$script_path" -i "${temp_data}")
out=$(perf script stat-cpi -i "${temp_data}")
if ! echo "$out" | grep -q "cpi"; then
echo "File mode test failed."
err=1

View File

@ -53,7 +53,7 @@ test_file_mode() {
-- sleep 0.5 >/dev/null 2>&1 || \
{ echo "Skipping test, perf record failed"; exit 2; }
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script syscall-counts-by-pid -i "${temp_data}" > "${temp_out}"; then
echo "File mode test failed."
err=1
elif ! grep -E -q "^ [a-zA-Z0-9_]+ +[0-9]+$" "${temp_out}"; then
@ -64,7 +64,7 @@ test_file_mode() {
fi
# Test with a comm argument
if ! "$PYTHON" "$script_path" -i "${temp_data}" "sleep" > "${temp_out}"; then
if ! perf script syscall-counts-by-pid -i "${temp_data}" "sleep" > "${temp_out}"; then
echo "Comm filter test failed."
err=1
elif ! grep -E -q "^ [a-zA-Z0-9_]+ +[0-9]+$" "${temp_out}"; then
@ -76,7 +76,8 @@ test_file_mode() {
# Extract sleep PID from "sleep [<pid>]" header and test with a numeric PID filter argument
sleep_pid=$(sed -n 's/^sleep \[\([0-9]\+\)\]$/\1/p' "${temp_out}" | head -n 1)
if [ -z "${sleep_pid}" ] || ! "$PYTHON" "$script_path" -i "${temp_data}" "${sleep_pid}" > "${temp_out}"; then
if [ -z "${sleep_pid}" ] || \
! perf script syscall-counts-by-pid -i "${temp_data}" "${sleep_pid}" > "${temp_out}"; then
echo "PID filter test failed."
err=1
elif ! grep -E -q "^ [a-zA-Z0-9_]+ +[0-9]+$" "${temp_out}"; then

View File

@ -54,7 +54,7 @@ test_file_mode() {
exit 2
fi
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script syscall-counts -i "${temp_data}" > "${temp_out}"; then
echo "File mode test failed."
err=1
elif ! grep -E -q "^[a-zA-Z0-9_]+ +[0-9]+$" "${temp_out}"; then
@ -65,7 +65,7 @@ test_file_mode() {
fi
# Test with a comm argument
if ! "$PYTHON" "$script_path" -i "${temp_data}" "sleep" > "${temp_out}"; then
if ! perf script syscall-counts -i "${temp_data}" "sleep" > "${temp_out}"; then
echo "Comm filter test failed."
err=1
elif ! grep -E -q "^[a-zA-Z0-9_]+ +[0-9]+$" "${temp_out}"; then

View File

@ -11,16 +11,6 @@ csv="$tmpdir/csv"
csvsummary="$tmpdir/csvsummary"
err=0
# Set up perfdir and PERF_EXEC_PATH
if [ "x$PERF_EXEC_PATH" = "x" ]; then
perfdir="$(dirname "$0")/../.."
if [ -f "$perfdir/python/task-analyzer.py" ]; then
export PERF_EXEC_PATH="$perfdir"
fi
else
perfdir="$PERF_EXEC_PATH"
fi
# Disable lsan to avoid warnings about python memory leaks.
export ASAN_OPTIONS=detect_leaks=0
@ -81,17 +71,17 @@ prepare_perf_data() {
# check standard inkvokation with no arguments
test_basic() {
out="$tmpdir/perf.out"
$PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" > "$out"
check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata}"
perf script -i "${perfdata}" task-analyzer > "$out"
check_exec_0 "perf script -i ${perfdata} task-analyzer"
find_str_or_fail "Comm" "$out" "${FUNCNAME[0]}"
}
test_ns_rename(){
out="$tmpdir/perf.out"
$PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" \
perf script -i "${perfdata}" task-analyzer \
--ns \
--rename-comms-by-tids 0:random > "$out"
check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \
check_exec_0 "perf script -i ${perfdata} task-analyzer \
--ns \
--rename-comms-by-tids 0:random"
find_str_or_fail "Comm" "$out" "${FUNCNAME[0]}"
@ -99,20 +89,20 @@ test_ns_rename(){
test_ms_filtertasks_highlight(){
out="$tmpdir/perf.out"
$PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" \
perf script -i "${perfdata}" task-analyzer \
--ms --filter-tasks perf --highlight-tasks perf \
> "$out"
check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \
check_exec_0 "perf script -i ${perfdata} task-analyzer \
--ms --filter-tasks perf --highlight-tasks perf"
find_str_or_fail "Comm" "$out" "${FUNCNAME[0]}"
}
test_extended_times_timelimit_limittasks() {
out="$tmpdir/perf.out"
$PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" --extended-times \
perf script -i "${perfdata}" task-analyzer --extended-times \
--time-limit :99999 \
--limit-to-tasks perf > "$out"
check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \
check_exec_0 "perf script -i ${perfdata} task-analyzer \
--extended-times \
--time-limit :99999 --limit-to-tasks perf"
find_str_or_fail "Out-Out" "$out" "${FUNCNAME[0]}"
@ -120,30 +110,30 @@ test_extended_times_timelimit_limittasks() {
test_summary() {
out="$tmpdir/perf.out"
$PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" --summary > "$out"
check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} --summary"
perf script -i "${perfdata}" task-analyzer --summary > "$out"
check_exec_0 "perf script -i ${perfdata} task-analyzer --summary"
find_str_or_fail "Summary" "$out" "${FUNCNAME[0]}"
}
test_summaryextended() {
out="$tmpdir/perf.out"
$PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" --summary-extended > "$out"
check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} --summary-extended"
perf script -i "${perfdata}" task-analyzer --summary-extended > "$out"
check_exec_0 "perf script -i ${perfdata} task-analyzer --summary-extended"
find_str_or_fail "Inter Task Times" "$out" "${FUNCNAME[0]}"
}
test_summaryonly() {
out="$tmpdir/perf.out"
$PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" --summary-only > "$out"
check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} --summary-only"
perf script -i "${perfdata}" task-analyzer --summary-only > "$out"
check_exec_0 "perf script -i ${perfdata} task-analyzer --summary-only"
find_str_or_fail "Summary" "$out" "${FUNCNAME[0]}"
}
test_extended_times_summary_ns() {
out="$tmpdir/perf.out"
$PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" --extended-times \
perf script -i "${perfdata}" task-analyzer --extended-times \
--summary --ns > "$out"
check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \
check_exec_0 "perf script -i ${perfdata} task-analyzer \
--extended-times \
--summary \
--ns"
@ -152,34 +142,34 @@ test_extended_times_summary_ns() {
}
test_csv() {
$PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" --csv "${csv}" > /dev/null
check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} --csv ${csv}"
perf script -i "${perfdata}" task-analyzer --csv "${csv}" > /dev/null
check_exec_0 "perf script -i ${perfdata} task-analyzer --csv ${csv}"
find_str_or_fail "Comm;" "${csv}" "${FUNCNAME[0]}"
}
test_csv_extended_times() {
$PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" \
perf script -i "${perfdata}" task-analyzer \
--csv "${csv}" \
--extended-times > /dev/null
check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \
check_exec_0 "perf script -i ${perfdata} task-analyzer \
--csv ${csv} \
--extended-times"
find_str_or_fail "Out-Out;" "${csv}" "${FUNCNAME[0]}"
}
test_csvsummary() {
$PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" \
perf script -i "${perfdata}" task-analyzer \
--csv-summary "${csvsummary}" > /dev/null
check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \
check_exec_0 "perf script -i ${perfdata} task-analyzer \
--csv-summary ${csvsummary}"
find_str_or_fail "Comm;" "${csvsummary}" "${FUNCNAME[0]}"
}
test_csvsummary_extended() {
$PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" \
perf script -i "${perfdata}" task-analyzer \
--csv-summary "${csvsummary}" --summary-extended \
>/dev/null
check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \
check_exec_0 "perf script -i ${perfdata} task-analyzer \
--csv-summary ${csvsummary} --summary-extended"
find_str_or_fail "Out-Out;" "${csvsummary}" "${FUNCNAME[0]}"
}

View File

@ -57,7 +57,7 @@ if [ ! -s "${temp_data}" ]; then
fi
# Check that the script executes
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then
if ! perf script wakeup-latency -i "${temp_data}" > "${temp_out}"; then
echo "wakeup-latency.py test failed"
err=1
else
@ -71,7 +71,7 @@ fi
# Also test zero-wakeups / unhandled events path to verify division-by-zero protection
if perf record -e cycles -o "${temp_data}" -- perf test -w noploop >/dev/null 2>&1; then
if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}" || \
if ! perf script wakeup-latency -i "${temp_data}" > "${temp_out}" || \
! grep -q "avg_wakeup_latency (ns): N/A" "${temp_out}"; then
echo "wakeup-latency zero-wakeups guard test failed"
err=1

View File

@ -86,75 +86,6 @@ static int scripts_config(const char *var, const char *value, void *data)
return 0;
}
/*
* Some scripts specify the required events in their "xxx-record" file,
* this function will check if the events in perf.data match those
* mentioned in the "xxx-record".
*
* Fixme: All existing "xxx-record" are all in good formats "-e event ",
* which is covered well now. And new parsing code should be added to
* cover the future complex formats like event groups etc.
*/
static int check_ev_match(int dir_fd, const char *scriptname, struct perf_session *session)
{
char line[BUFSIZ];
FILE *fp;
{
char filename[NAME_MAX + 5];
int fd;
scnprintf(filename, sizeof(filename), "bin/%s-record", scriptname);
fd = openat(dir_fd, filename, O_RDONLY);
if (fd == -1)
return -1;
fp = fdopen(fd, "r");
if (!fp)
return -1;
}
while (fgets(line, sizeof(line), fp)) {
char *p = skip_spaces(line);
if (*p == '#')
continue;
while (strlen(p)) {
int match, len;
struct evsel *pos;
char evname[128];
p = strstr(p, "-e");
if (!p)
break;
p += 2;
p = skip_spaces(p);
len = strcspn(p, " \t");
if (!len)
break;
snprintf(evname, sizeof(evname), "%.*s", (int)len, p);
match = 0;
evlist__for_each_entry(session->evlist, pos) {
if (evsel__name_is(pos, evname)) {
match = 1;
break;
}
}
if (!match) {
fclose(fp);
return -1;
}
}
}
fclose(fp);
return 0;
}
/*
* Return -1 if none is found, otherwise the actual scripts number.
*
@ -162,95 +93,18 @@ static int check_ev_match(int dir_fd, const char *scriptname, struct perf_sessio
* will list all statically runnable scripts, select one, execute it and
* show the output in a perf browser.
*/
static int find_scripts(char **scripts_array, char **scripts_path_array, int num,
int pathlen)
static int find_scripts(char **scripts_array __maybe_unused,
char **scripts_path_array __maybe_unused, int num __maybe_unused,
int pathlen __maybe_unused)
{
int namelen;
struct dirent *script_dirent, *lang_dirent;
int scripts_dir_fd, lang_dir_fd;
DIR *scripts_dir, *lang_dir;
struct perf_session *session;
struct perf_data data = {
.path = input_name,
.mode = PERF_DATA_MODE_READ,
};
char *temp;
int i = 0;
const char *exec_path = get_argv_exec_path();
session = perf_session__new(&data, NULL);
if (IS_ERR(session))
return PTR_ERR(session);
{
char scripts_path[PATH_MAX];
snprintf(scripts_path, sizeof(scripts_path), "%s/scripts", exec_path);
scripts_dir_fd = open(scripts_path, O_DIRECTORY);
}
if (scripts_dir_fd != -1) {
scripts_dir = fdopendir(scripts_dir_fd);
if (scripts_dir) {
while ((lang_dirent = readdir(scripts_dir)) != NULL) {
if (lang_dirent->d_type != DT_DIR &&
(lang_dirent->d_type == DT_UNKNOWN &&
!is_directory_at(scripts_dir_fd, lang_dirent->d_name)))
continue;
if (!strcmp(lang_dirent->d_name, ".") ||
!strcmp(lang_dirent->d_name, ".."))
continue;
if (strstr(lang_dirent->d_name, "python"))
continue;
lang_dir_fd = openat(scripts_dir_fd, lang_dirent->d_name,
O_DIRECTORY);
if (lang_dir_fd == -1)
continue;
lang_dir = fdopendir(lang_dir_fd);
if (!lang_dir) {
close(lang_dir_fd);
continue;
}
while ((script_dirent = readdir(lang_dir)) != NULL) {
if (script_dirent->d_type == DT_DIR)
continue;
if (script_dirent->d_type == DT_UNKNOWN &&
is_directory_at(lang_dir_fd, script_dirent->d_name))
continue;
/* Skip those real time scripts: xxxtop.p[yl] */
if (strstr(script_dirent->d_name, "top."))
continue;
if (i >= num)
break;
scnprintf(scripts_path_array[i], pathlen,
"%s/scripts/%s/%s", exec_path,
lang_dirent->d_name,
script_dirent->d_name);
temp = strrchr(script_dirent->d_name, '.');
namelen = temp ? (int)(temp - script_dirent->d_name)
: (int)strlen(script_dirent->d_name);
if (namelen >= SCRIPT_NAMELEN)
namelen = SCRIPT_NAMELEN - 1;
snprintf(scripts_array[i], namelen + 1, "%s",
script_dirent->d_name);
if (check_ev_match(lang_dir_fd, scripts_array[i], session))
continue;
i++;
}
closedir(lang_dir);
}
closedir(scripts_dir);
} else {
close(scripts_dir_fd);
}
}
#ifdef HAVE_PYTHON_MODULE_SUPPORT
{
int namelen;
struct dirent *script_dirent;
char *temp;
const char *exec_path = get_argv_exec_path();
char py_scripts_path[PATH_MAX];
int py_scripts_dir_fd;
DIR *py_scripts_dir;
@ -299,7 +153,6 @@ static int find_scripts(char **scripts_array, char **scripts_path_array, int num
}
}
#endif
perf_session__delete(session);
return i;
}

View File

@ -95,7 +95,6 @@ perf-util-y += tool_pmu.o
perf-util-y += tp_pmu.o
perf-util-y += svghelper.o
perf-util-y += trace-event-info.o
perf-util-y += trace-event-scripting.o
perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event.o
perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event-parse.o
perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event-read.o
@ -236,8 +235,6 @@ endif
perf-util-y += data-convert-json.o
perf-util-y += scripting-engines/
perf-util-$(CONFIG_ZLIB) += zlib.o
perf-util-$(CONFIG_LZMA) += lzma.o
perf-util-$(CONFIG_ZSTD) += zstd.o

View File

@ -1,5 +0,0 @@
ifeq ($(CONFIG_LIBTRACEEVENT),y)
perf-util-$(CONFIG_LIBPERL) += trace-event-perl.o
endif
CFLAGS_trace-event-perl.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-nested-externs -Wno-undef -Wno-switch-default -Wno-bad-function-cast -Wno-declaration-after-statement -Wno-switch-enum -Wno-thread-safety-analysis

View File

@ -1,770 +0,0 @@
/*
* trace-event-perl. Feed perf script events to an embedded Perl interpreter.
*
* 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
*
*/
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <linux/bitmap.h>
#include <linux/time64.h>
#include <event-parse.h>
#include <stdbool.h>
/* perl needs the following define, right after including stdbool.h */
#define HAS_BOOL
#include <EXTERN.h>
#include <perl.h>
#include "../callchain.h"
#include "../dso.h"
#include "../machine.h"
#include "../map.h"
#include "../symbol.h"
#include "../thread.h"
#include "../event.h"
#include "../trace-event.h"
#include "../evsel.h"
#include "../debug.h"
void boot_Perf__Trace__Context(pTHX_ CV *cv);
void boot_DynaLoader(pTHX_ CV *cv);
typedef PerlInterpreter * INTERP;
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);
}
INTERP my_perl;
#define TRACE_EVENT_TYPE_MAX \
((1 << (sizeof(unsigned short) * 8)) - 1)
extern struct scripting_context *scripting_context;
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;
}
static void define_symbolic_values(struct tep_print_flag_sym *field,
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;
}
static void define_flag_values(struct tep_print_flag_sym *field,
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;
}
static void define_event_symbols(struct tep_event *event,
const char *ev_name,
struct tep_print_arg *args)
{
if (args == NULL)
return;
switch (args->type) {
case TEP_PRINT_NULL:
break;
case TEP_PRINT_ATOM:
define_flag_value(ev_name, cur_field_name, "0",
args->atom.atom);
zero_flag_atom = 0;
break;
case TEP_PRINT_FIELD:
free(cur_field_name);
cur_field_name = strdup(args->field.name);
break;
case TEP_PRINT_FLAGS:
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;
case TEP_PRINT_SYMBOL:
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;
case TEP_PRINT_HEX:
case TEP_PRINT_HEX_STR:
define_event_symbols(event, ev_name, args->hex.field);
define_event_symbols(event, ev_name, args->hex.size);
break;
case TEP_PRINT_INT_ARRAY:
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;
case TEP_PRINT_BSTRING:
case TEP_PRINT_DYNAMIC_ARRAY:
case TEP_PRINT_DYNAMIC_ARRAY_LEN:
case TEP_PRINT_STRING:
case TEP_PRINT_BITMASK:
break;
case TEP_PRINT_TYPE:
define_event_symbols(event, ev_name, args->typecast.item);
break;
case TEP_PRINT_OP:
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;
case TEP_PRINT_FUNC:
default:
pr_err("Unsupported print arg type\n");
/* we should warn... */
return;
}
if (args->next)
define_event_symbols(event, ev_name, args->next);
}
static SV *perl_process_callchain(struct perf_sample *sample,
struct addr_location *al)
{
struct callchain_cursor *cursor;
AV *list;
list = newAV();
if (!list)
goto exit;
if (!symbol_conf.use_callchain || !sample->callchain)
goto exit;
cursor = get_tls_callchain_cursor();
if (thread__resolve_callchain(al->thread, cursor,
sample, NULL, NULL, scripting_max_stack) != 0) {
pr_err("Failed to resolve callchain. Skipping\n");
goto exit;
}
callchain_cursor_commit(cursor);
while (1) {
HV *elem;
struct callchain_cursor_node *node;
node = callchain_cursor_current(cursor);
if (!node)
break;
elem = newHV();
if (!elem)
goto exit;
if (!hv_stores(elem, "ip", newSVuv(node->ip))) {
hv_undef(elem);
goto exit;
}
if (node->ms.sym) {
HV *sym = newHV();
if (!sym) {
hv_undef(elem);
goto exit;
}
if (!hv_stores(sym, "start", newSVuv(node->ms.sym->start)) ||
!hv_stores(sym, "end", newSVuv(node->ms.sym->end)) ||
!hv_stores(sym, "binding", newSVuv(symbol__binding(node->ms.sym))) ||
!hv_stores(sym, "name", newSVpvn(node->ms.sym->name,
node->ms.sym->namelen)) ||
!hv_stores(elem, "sym", newRV_noinc((SV*)sym))) {
hv_undef(sym);
hv_undef(elem);
goto exit;
}
}
if (node->ms.map) {
struct map *map = node->ms.map;
struct dso *dso = map ? map__dso(map) : NULL;
const char *dsoname = "[unknown]";
if (dso) {
if (symbol_conf.show_kernel_path && dso__long_name(dso))
dsoname = dso__long_name(dso);
else
dsoname = dso__name(dso);
}
if (!hv_stores(elem, "dso", newSVpv(dsoname,0))) {
hv_undef(elem);
goto exit;
}
}
callchain_cursor_advance(cursor);
av_push(list, newRV_noinc((SV*)elem));
}
exit:
return newRV_noinc((SV*)list);
}
static void perl_process_tracepoint(struct perf_sample *sample,
struct addr_location *al)
{
struct thread *thread = al->thread;
struct tep_event *event;
struct tep_format_field *field;
static char handler[256];
unsigned long long val;
unsigned long s, ns;
int pid;
int cpu = sample->cpu;
void *data = sample->raw_data;
unsigned long long nsecs = sample->time;
const char *comm = thread__comm_str(thread);
DECLARE_BITMAP(events_defined, TRACE_EVENT_TYPE_MAX);
struct evsel *evsel = sample->evsel;
bitmap_zero(events_defined, TRACE_EVENT_TYPE_MAX);
dSP;
if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
return;
event = evsel__tp_format(evsel);
if (!event) {
pr_debug("ug! no event found for type %" PRIu64, (u64)evsel->core.attr.config);
return;
}
pid = raw_field_value(event, "common_pid", data);
sprintf(handler, "%s::%s", event->system, event->name);
if (!__test_and_set_bit(event->id, events_defined))
define_event_symbols(event, handler, event->print_fmt.args);
s = nsecs / NSEC_PER_SEC;
ns = nsecs - s * NSEC_PER_SEC;
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)));
XPUSHs(sv_2mortal(perl_process_callchain(sample, al)));
/* common fields other than pid can be accessed via xsub fns */
for (field = event->format.fields; field; field = field->next) {
if (field->flags & TEP_FIELD_IS_STRING) {
int offset;
if (field->flags & TEP_FIELD_IS_DYNAMIC) {
offset = *(int *)(data + field->offset);
offset &= 0xffff;
if (tep_field_is_relative(field->flags))
offset += field->offset + field->size;
} else
offset = field->offset;
XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
} else { /* FIELD_IS_NUMERIC */
val = read_size(event, data + field->offset,
field->size);
if (field->flags & TEP_FIELD_IS_SIGNED) {
XPUSHs(sv_2mortal(newSViv(val)));
} else {
XPUSHs(sv_2mortal(newSVuv(val)));
}
}
}
PUTBACK;
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)));
XPUSHs(sv_2mortal(perl_process_callchain(sample, al)));
call_pv("main::trace_unhandled", G_SCALAR);
}
SPAGAIN;
PUTBACK;
FREETMPS;
LEAVE;
}
static void perl_process_event_generic(union perf_event *event, struct perf_sample *sample)
{
dSP;
if (!get_cv("process_event", 0))
return;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpvn((const char *)event, event->header.size)));
XPUSHs(sv_2mortal(newSVpvn((const char *)&sample->evsel->core.attr,
sizeof(sample->evsel->core.attr))));
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;
}
static void perl_process_event(union perf_event *event,
struct perf_sample *sample,
struct addr_location *al,
struct addr_location *addr_al)
{
scripting_context__update(scripting_context, event, sample, al, addr_al);
perl_process_tracepoint(sample, al);
perl_process_event_generic(event, sample);
}
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
*/
static int perl_start_script(const char *script, int argc, const char **argv,
struct perf_session *session)
{
const char **command_line;
int i, err = 0;
scripting_context->session = session;
command_line = malloc((argc + 2) * sizeof(const char *));
if (!command_line)
return -ENOMEM;
command_line[0] = "";
command_line[1] = script;
for (i = 2; i < argc + 2; i++)
command_line[i] = argv[i - 2];
my_perl = perl_alloc();
perl_construct(my_perl);
if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
(char **)NULL)) {
err = -1;
goto error;
}
if (perl_run(my_perl)) {
err = -1;
goto error;
}
if (SvTRUE(ERRSV)) {
err = -1;
goto error;
}
run_start_sub();
free(command_line);
return 0;
error:
perl_free(my_perl);
free(command_line);
return err;
}
static int perl_flush_script(void)
{
return 0;
}
/*
* 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;
}
static int perl_generate_script(struct tep_handle *pevent, const char *outfile)
{
int i, not_first, count, nr_events;
struct tep_event **all_events;
struct tep_event *event = NULL;
struct tep_format_field *f;
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;
}
fprintf(ofp, "# perf script event handlers, "
"generated by perf script -g perl\n");
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");
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\
");
nr_events = tep_get_events_count(pevent);
all_events = tep_list_events(pevent, TEP_EVENT_SORT_ID);
for (i = 0; all_events && i < nr_events; i++) {
event = all_events[i];
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, ");
fprintf(ofp, "$common_comm, ");
fprintf(ofp, "$common_callchain,\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 ");
fprintf(ofp, "$%s", f->name);
}
fprintf(ofp, ") = @_;\n\n");
fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
"$common_secs, $common_nsecs,\n\t "
"$common_pid, $common_comm, $common_callchain);\n\n");
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);
if (f->flags & TEP_FIELD_IS_STRING ||
f->flags & TEP_FIELD_IS_FLAG ||
f->flags & TEP_FIELD_IS_SYMBOLIC)
fprintf(ofp, "%%s");
else if (f->flags & TEP_FIELD_IS_SIGNED)
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 ");
if (f->flags & TEP_FIELD_IS_FLAG) {
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);
} else if (f->flags & TEP_FIELD_IS_SYMBOLIC) {
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);
}
fprintf(ofp, ");\n\n");
fprintf(ofp, "\tprint_backtrace($common_callchain);\n");
fprintf(ofp, "}\n\n");
}
fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, "
"$common_cpu, $common_secs, $common_nsecs,\n\t "
"$common_pid, $common_comm, $common_callchain) = @_;\n\n");
fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
"$common_secs, $common_nsecs,\n\t $common_pid, "
"$common_comm, $common_callchain);\n");
fprintf(ofp, "\tprint_backtrace($common_callchain);\n");
fprintf(ofp, "}\n\n");
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 "
"$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");
fclose(ofp);
fprintf(stderr, "generated Perl script: %s\n", fname);
return 0;
}
struct scripting_ops perl_scripting_ops = {
.name = "Perl",
.dirname = "perl",
.start_script = perl_start_script,
.flush_script = perl_flush_script,
.stop_script = perl_stop_script,
.process_event = perl_process_event,
.generate_script = perl_generate_script,
};

View File

@ -14,71 +14,6 @@
#include <linux/kernel.h>
#include <event-parse.h>
static int get_common_field(struct scripting_context *context,
int *offset, int *size, const char *type)
{
struct tep_handle *pevent = context->pevent;
struct tep_event *event;
struct tep_format_field *field;
if (!*size) {
event = tep_get_first_event(pevent);
if (!event)
return 0;
field = tep_find_common_field(event, type);
if (!field)
return 0;
*offset = field->offset;
*size = field->size;
}
return tep_read_number(pevent, context->event_data + *offset, *size);
}
int common_lock_depth(struct scripting_context *context)
{
static int offset;
static int size;
int ret;
ret = get_common_field(context, &size, &offset,
"common_lock_depth");
if (ret < 0)
return -1;
return ret;
}
int common_flags(struct scripting_context *context)
{
static int offset;
static int size;
int ret;
ret = get_common_field(context, &size, &offset,
"common_flags");
if (ret < 0)
return -1;
return ret;
}
int common_pc(struct scripting_context *context)
{
static int offset;
static int size;
int ret;
ret = get_common_field(context, &size, &offset,
"common_preempt_count");
if (ret < 0)
return -1;
return ret;
}
unsigned long long
raw_field_value(struct tep_event *event, const char *name, void *data)
{

View File

@ -1,398 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* trace-event-scripting. Scripting engine common and initialization code.
*
* Copyright (C) 2009-2010 Tom Zanussi <tzanussi@gmail.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_LIBTRACEEVENT
#include <event-parse.h>
#endif
#include "debug.h"
#include "event.h"
#include "trace-event.h"
#include "evsel.h"
#include <linux/perf_event.h>
#include <linux/zalloc.h>
#include "util/sample.h"
unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
struct scripting_context *scripting_context;
struct script_spec {
struct list_head node;
struct scripting_ops *ops;
char spec[];
};
static LIST_HEAD(script_specs);
static struct script_spec *script_spec__new(const char *spec,
struct scripting_ops *ops)
{
struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
if (s != NULL) {
strcpy(s->spec, spec);
s->ops = ops;
}
return s;
}
static void script_spec__add(struct script_spec *s)
{
list_add_tail(&s->node, &script_specs);
}
static struct script_spec *script_spec__find(const char *spec)
{
struct script_spec *s;
list_for_each_entry(s, &script_specs, node)
if (strcasecmp(s->spec, spec) == 0)
return s;
return NULL;
}
static int script_spec_register(const char *spec, struct scripting_ops *ops)
{
struct script_spec *s;
s = script_spec__find(spec);
if (s)
return -1;
s = script_spec__new(spec, ops);
if (!s)
return -1;
script_spec__add(s);
return 0;
}
struct scripting_ops *script_spec__lookup(const char *spec)
{
struct script_spec *s = script_spec__find(spec);
if (!s)
return NULL;
return s->ops;
}
int script_spec__for_each(int (*cb)(struct scripting_ops *ops, const char *spec))
{
struct script_spec *s;
int ret = 0;
list_for_each_entry(s, &script_specs, node) {
ret = cb(s->ops, s->spec);
if (ret)
break;
}
return ret;
}
void scripting_context__update(struct scripting_context *c,
union perf_event *event,
struct perf_sample *sample,
struct addr_location *al,
struct addr_location *addr_al)
{
#ifdef HAVE_LIBTRACEEVENT
const struct tep_event *tp_format = evsel__tp_format(sample->evsel);
c->pevent = tp_format ? tp_format->tep : NULL;
#else
c->pevent = NULL;
#endif
c->event_data = sample->raw_data;
c->event = event;
c->sample = sample;
c->al = al;
c->addr_al = addr_al;
}
static int flush_script_unsupported(void)
{
return 0;
}
static int stop_script_unsupported(void)
{
return 0;
}
static void process_event_unsupported(union perf_event *event __maybe_unused,
struct perf_sample *sample __maybe_unused,
struct addr_location *al __maybe_unused,
struct addr_location *addr_al __maybe_unused)
{
}
static void print_python_unsupported_msg(void)
{
fprintf(stderr, "Python scripting not supported."
" Install libpython and rebuild perf to enable it.\n"
"For example:\n # apt-get install python-dev (ubuntu)"
"\n # yum install python-devel (Fedora)"
"\n etc.\n");
}
static int python_start_script_unsupported(const char *script __maybe_unused,
int argc __maybe_unused,
const char **argv __maybe_unused,
struct perf_session *session __maybe_unused)
{
print_python_unsupported_msg();
return -1;
}
static int python_generate_script_unsupported(struct tep_handle *pevent
__maybe_unused,
const char *outfile
__maybe_unused)
{
print_python_unsupported_msg();
return -1;
}
struct scripting_ops python_scripting_unsupported_ops = {
.name = "Python",
.dirname = "python",
.start_script = python_start_script_unsupported,
.flush_script = flush_script_unsupported,
.stop_script = stop_script_unsupported,
.process_event = process_event_unsupported,
.generate_script = python_generate_script_unsupported,
};
static void register_python_scripting(struct scripting_ops *scripting_ops)
{
if (scripting_context == NULL)
scripting_context = malloc(sizeof(*scripting_context));
if (scripting_context == NULL ||
script_spec_register("Python", scripting_ops) ||
script_spec_register("py", scripting_ops)) {
pr_err("Error registering Python script extension: disabling it\n");
zfree(&scripting_context);
}
}
void setup_python_scripting(void)
{
register_python_scripting(&python_scripting_unsupported_ops);
}
#ifdef HAVE_LIBTRACEEVENT
static void print_perl_unsupported_msg(void)
{
fprintf(stderr, "Perl scripting not supported."
" Install libperl and rebuild perf to enable it.\n"
"For example:\n # apt-get install libperl-dev (ubuntu)"
"\n # yum install 'perl(ExtUtils::Embed)' (Fedora)"
"\n etc.\n");
}
static int perl_start_script_unsupported(const char *script __maybe_unused,
int argc __maybe_unused,
const char **argv __maybe_unused,
struct perf_session *session __maybe_unused)
{
print_perl_unsupported_msg();
return -1;
}
static int perl_generate_script_unsupported(struct tep_handle *pevent
__maybe_unused,
const char *outfile __maybe_unused)
{
print_perl_unsupported_msg();
return -1;
}
struct scripting_ops perl_scripting_unsupported_ops = {
.name = "Perl",
.dirname = "perl",
.start_script = perl_start_script_unsupported,
.flush_script = flush_script_unsupported,
.stop_script = stop_script_unsupported,
.process_event = process_event_unsupported,
.generate_script = perl_generate_script_unsupported,
};
static void register_perl_scripting(struct scripting_ops *scripting_ops)
{
if (scripting_context == NULL)
scripting_context = malloc(sizeof(*scripting_context));
if (scripting_context == NULL ||
script_spec_register("Perl", scripting_ops) ||
script_spec_register("pl", scripting_ops)) {
pr_err("Error registering Perl script extension: disabling it\n");
zfree(&scripting_context);
}
}
#ifndef HAVE_LIBPERL_SUPPORT
void setup_perl_scripting(void)
{
register_perl_scripting(&perl_scripting_unsupported_ops);
}
#else
extern struct scripting_ops perl_scripting_ops;
void setup_perl_scripting(void)
{
register_perl_scripting(&perl_scripting_ops);
}
#endif
#endif
static const struct {
u32 flags;
const char *name;
} sample_flags[] = {
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "jcc"},
{PERF_IP_FLAG_BRANCH, "jmp"},
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT, "int"},
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT, "iret"},
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET, "syscall"},
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET, "sysret"},
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "async"},
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | PERF_IP_FLAG_INTERRUPT,
"hw int"},
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "tx abrt"},
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "tr strt"},
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "tr end"},
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMENTRY, "vmentry"},
{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMEXIT, "vmexit"},
{0, NULL}
};
static const struct {
u32 flags;
const char *name;
} branch_events[] = {
{PERF_IP_FLAG_BRANCH_MISS, "miss"},
{PERF_IP_FLAG_NOT_TAKEN, "not_taken"},
{0, NULL}
};
static int sample_flags_to_name(u32 flags, char *str, size_t size)
{
int i;
const char *prefix;
int pos = 0, ret, ev_idx = 0;
u32 xf = flags & PERF_ADDITIONAL_STATE_MASK;
u32 types, events;
char xs[16] = { 0 };
/* Clear additional state bits */
flags &= ~PERF_ADDITIONAL_STATE_MASK;
if (flags & PERF_IP_FLAG_TRACE_BEGIN)
prefix = "tr strt ";
else if (flags & PERF_IP_FLAG_TRACE_END)
prefix = "tr end ";
else
prefix = "";
ret = snprintf(str + pos, size - pos, "%s", prefix);
if (ret < 0)
return ret;
pos += ret;
flags &= ~(PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END);
types = flags & ~PERF_IP_FLAG_BRANCH_EVENT_MASK;
for (i = 0; sample_flags[i].name; i++) {
if (sample_flags[i].flags != types)
continue;
ret = snprintf(str + pos, size - pos, "%s", sample_flags[i].name);
if (ret < 0)
return ret;
pos += ret;
break;
}
events = flags & PERF_IP_FLAG_BRANCH_EVENT_MASK;
for (i = 0; branch_events[i].name; i++) {
if (!(branch_events[i].flags & events))
continue;
ret = snprintf(str + pos, size - pos, !ev_idx ? "/%s" : ",%s",
branch_events[i].name);
if (ret < 0)
return ret;
pos += ret;
ev_idx++;
}
/* Add an end character '/' for events */
if (ev_idx) {
ret = snprintf(str + pos, size - pos, "/");
if (ret < 0)
return ret;
pos += ret;
}
if (!xf)
return pos;
snprintf(xs, sizeof(xs), "(%s%s%s)",
flags & PERF_IP_FLAG_IN_TX ? "x" : "",
flags & PERF_IP_FLAG_INTR_DISABLE ? "D" : "",
flags & PERF_IP_FLAG_INTR_TOGGLE ? "t" : "");
/* Right align the string if its length is less than the limit */
if ((pos + strlen(xs)) < SAMPLE_FLAGS_STR_ALIGNED_SIZE)
ret = snprintf(str + pos, size - pos, "%*s",
(int)(SAMPLE_FLAGS_STR_ALIGNED_SIZE - ret), xs);
else
ret = snprintf(str + pos, size - pos, " %s", xs);
if (ret < 0)
return ret;
return pos + ret;
}
int perf_sample__sprintf_flags(u32 flags, char *str, size_t sz)
{
const char *chars = PERF_IP_FLAG_CHARS;
const size_t n = strlen(PERF_IP_FLAG_CHARS);
size_t i, pos = 0;
int ret;
ret = sample_flags_to_name(flags, str, sz);
if (ret > 0)
return ret;
for (i = 0; i < n; i++, flags >>= 1) {
if ((flags & 1) && pos < sz)
str[pos++] = chars[i];
}
for (; i < 32; i++, flags >>= 1) {
if ((flags & 1) && pos < sz)
str[pos++] = '?';
}
if (pos < sz)
str[pos] = 0;
return pos;
}

View File

@ -7,15 +7,9 @@
#include <sys/types.h>
#include <linux/types.h>
struct evlist;
struct machine;
struct perf_sample;
union perf_event;
struct perf_tool;
struct thread;
struct tep_plugin_list;
struct evsel;
struct tep_format_field;
struct tep_plugin_list;
struct trace_event {
struct tep_handle *pevent;
@ -80,70 +74,6 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
int fd, bool temp);
int tracing_data_put(struct tracing_data *tdata);
struct addr_location;
struct perf_session;
struct perf_stat_config;
struct scripting_ops {
const char *name;
const char *dirname; /* For script path .../scripts/<dirname>/... */
int (*start_script)(const char *script, int argc, const char **argv,
struct perf_session *session);
int (*flush_script) (void);
int (*stop_script) (void);
void (*process_event) (union perf_event *event,
struct perf_sample *sample,
struct addr_location *al,
struct addr_location *addr_al);
void (*process_switch)(union perf_event *event,
struct perf_sample *sample,
struct machine *machine);
void (*process_auxtrace_error)(struct perf_session *session,
union perf_event *event);
void (*process_stat)(struct perf_stat_config *config,
struct evsel *evsel, u64 tstamp);
void (*process_stat_interval)(u64 tstamp);
void (*process_throttle)(union perf_event *event,
struct perf_sample *sample,
struct machine *machine);
int (*generate_script) (struct tep_handle *pevent, const char *outfile);
};
extern unsigned int scripting_max_stack;
struct scripting_ops *script_spec__lookup(const char *spec);
int script_spec__for_each(int (*cb)(struct scripting_ops *ops, const char *spec));
void setup_perl_scripting(void);
void setup_python_scripting(void);
struct scripting_context {
struct tep_handle *pevent;
void *event_data;
union perf_event *event;
struct perf_sample *sample;
struct addr_location *al;
struct addr_location *addr_al;
struct perf_session *session;
};
void scripting_context__update(struct scripting_context *scripting_context,
union perf_event *event,
struct perf_sample *sample,
struct addr_location *al,
struct addr_location *addr_al);
int common_pc(struct scripting_context *context);
int common_flags(struct scripting_context *context);
int common_lock_depth(struct scripting_context *context);
#define SAMPLE_FLAGS_BUF_SIZE 64
#define SAMPLE_FLAGS_STR_ALIGNED_SIZE 21
int perf_sample__sprintf_flags(u32 flags, char *str, size_t sz);
#if defined(LIBTRACEEVENT_VERSION) && LIBTRACEEVENT_VERSION >= MAKE_LIBTRACEEVENT_VERSION(1, 5, 0)
#include <event-parse.h>