perf: Rename 'perf trace' to 'perf script'
authorIngo Molnar <mingo@elte.hu>
Tue, 16 Nov 2010 17:45:39 +0000 (18:45 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Tue, 16 Nov 2010 18:37:44 +0000 (19:37 +0100)
Free the perf trace name space and rename the trace to 'script' which is a
better match for the scripting engine.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
16 files changed:
tools/perf/Documentation/perf-script-perl.txt [new file with mode: 0644]
tools/perf/Documentation/perf-script-python.txt [new file with mode: 0644]
tools/perf/Documentation/perf-script.txt [new file with mode: 0644]
tools/perf/Documentation/perf-trace-perl.txt [deleted file]
tools/perf/Documentation/perf-trace-python.txt [deleted file]
tools/perf/Documentation/perf-trace.txt [deleted file]
tools/perf/Makefile
tools/perf/builtin-lock.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c [new file with mode: 0644]
tools/perf/builtin-trace.c [deleted file]
tools/perf/builtin.h
tools/perf/perf.c
tools/perf/scripts/python/Perf-Trace-Util/Context.c
tools/perf/util/scripting-engines/trace-event-perl.c
tools/perf/util/scripting-engines/trace-event-python.c

diff --git a/tools/perf/Documentation/perf-script-perl.txt b/tools/perf/Documentation/perf-script-perl.txt
new file mode 100644 (file)
index 0000000..5bb41e5
--- /dev/null
@@ -0,0 +1,217 @@
+perf-script-perl(1)
+==================
+
+NAME
+----
+perf-script-perl - Process trace data with a Perl script
+
+SYNOPSIS
+--------
+[verse]
+'perf script' [-s [Perl]:script[.pl] ]
+
+DESCRIPTION
+-----------
+
+This perf script option is used to process perf script data using perf's
+built-in Perl interpreter.  It reads and processes the input file and
+displays the results of the trace analysis implemented in the given
+Perl script, if any.
+
+STARTER SCRIPTS
+---------------
+
+You can avoid reading the rest of this document by running 'perf script
+-g perl' in the same directory as an existing perf.data trace file.
+That will generate a starter script containing a handler for each of
+the event types in the trace file; it simply prints every available
+field for each event in the trace file.
+
+You can also look at the existing scripts in
+~/libexec/perf-core/scripts/perl for typical examples showing how to
+do basic things like aggregate event data, print results, etc.  Also,
+the check-perf-script.pl script, while not interesting for its results,
+attempts to exercise all of the main scripting features.
+
+EVENT HANDLERS
+--------------
+
+When perf script is invoked using a trace script, a user-defined
+'handler function' is called for each event in the trace.  If there's
+no handler function defined for a given event type, the event is
+ignored (or passed to a 'trace_handled' function, see below) and the
+next event is processed.
+
+Most of the event's field values are passed as arguments to the
+handler function; some of the less common ones aren't - those are
+available as calls back into the perf executable (see below).
+
+As an example, the following perf record command can be used to record
+all sched_wakeup events in the system:
+
+ # perf record -a -e sched:sched_wakeup
+
+Traces meant to be processed using a script should be recorded with
+the above option: -a to enable system-wide collection.
+
+The format file for the sched_wakep event defines the following fields
+(see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format):
+
+----
+ format:
+        field:unsigned short common_type;
+        field:unsigned char common_flags;
+        field:unsigned char common_preempt_count;
+        field:int common_pid;
+        field:int common_lock_depth;
+
+        field:char comm[TASK_COMM_LEN];
+        field:pid_t pid;
+        field:int prio;
+        field:int success;
+        field:int target_cpu;
+----
+
+The handler function for this event would be defined as:
+
+----
+sub sched::sched_wakeup
+{
+   my ($event_name, $context, $common_cpu, $common_secs,
+       $common_nsecs, $common_pid, $common_comm,
+       $comm, $pid, $prio, $success, $target_cpu) = @_;
+}
+----
+
+The handler function takes the form subsystem::event_name.
+
+The $common_* arguments in the handler's argument list are the set of
+arguments passed to all event handlers; some of the fields correspond
+to the common_* fields in the format file, but some are synthesized,
+and some of the common_* fields aren't common enough to to be passed
+to every event as arguments but are available as library functions.
+
+Here's a brief description of each of the invariant event args:
+
+ $event_name               the name of the event as text
+ $context                  an opaque 'cookie' used in calls back into perf
+ $common_cpu               the cpu the event occurred on
+ $common_secs              the secs portion of the event timestamp
+ $common_nsecs             the nsecs portion of the event timestamp
+ $common_pid               the pid of the current task
+ $common_comm              the name of the current process
+
+All of the remaining fields in the event's format file have
+counterparts as handler function arguments of the same name, as can be
+seen in the example above.
+
+The above provides the basics needed to directly access every field of
+every event in a trace, which covers 90% of what you need to know to
+write a useful trace script.  The sections below cover the rest.
+
+SCRIPT LAYOUT
+-------------
+
+Every perf script Perl script should start by setting up a Perl module
+search path and 'use'ing a few support modules (see module
+descriptions below):
+
+----
+ use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/perf-script-Util/lib";
+ use lib "./perf-script-Util/lib";
+ use Perf::Trace::Core;
+ use Perf::Trace::Context;
+ use Perf::Trace::Util;
+----
+
+The rest of the script can contain handler functions and support
+functions in any order.
+
+Aside from the event handler functions discussed above, every script
+can implement a set of optional functions:
+
+*trace_begin*, if defined, is called before any event is processed and
+gives scripts a chance to do setup tasks:
+
+----
+ sub trace_begin
+ {
+ }
+----
+
+*trace_end*, if defined, is called after all events have been
+ processed and gives scripts a chance to do end-of-script tasks, such
+ as display results:
+
+----
+sub trace_end
+{
+}
+----
+
+*trace_unhandled*, if defined, is called after for any event that
+ doesn't have a handler explicitly defined for it.  The standard set
+ of common arguments are passed into it:
+
+----
+sub trace_unhandled
+{
+    my ($event_name, $context, $common_cpu, $common_secs,
+        $common_nsecs, $common_pid, $common_comm) = @_;
+}
+----
+
+The remaining sections provide descriptions of each of the available
+built-in perf script Perl modules and their associated functions.
+
+AVAILABLE MODULES AND FUNCTIONS
+-------------------------------
+
+The following sections describe the functions and variables available
+via the various Perf::Trace::* Perl modules.  To use the functions and
+variables from the given module, add the corresponding 'use
+Perf::Trace::XXX' line to your perf script script.
+
+Perf::Trace::Core Module
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+These functions provide some essential functions to user scripts.
+
+The *flag_str* and *symbol_str* functions provide human-readable
+strings for flag and symbolic fields.  These correspond to the strings
+and values parsed from the 'print fmt' fields of the event format
+files:
+
+  flag_str($event_name, $field_name, $field_value) - returns the string represention corresponding to $field_value for the flag field $field_name of event $event_name
+  symbol_str($event_name, $field_name, $field_value) - returns the string represention corresponding to $field_value for the symbolic field $field_name of event $event_name
+
+Perf::Trace::Context Module
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some of the 'common' fields in the event format file aren't all that
+common, but need to be made accessible to user scripts nonetheless.
+
+Perf::Trace::Context defines a set of functions that can be used to
+access this data in the context of the current event.  Each of these
+functions expects a $context variable, which is the same as the
+$context variable passed into every event handler as the second
+argument.
+
+ common_pc($context) - returns common_preempt count for the current event
+ common_flags($context) - returns common_flags for the current event
+ common_lock_depth($context) - returns common_lock_depth for the current event
+
+Perf::Trace::Util Module
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Various utility functions for use with perf script:
+
+  nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair
+  nsecs_secs($nsecs) - returns whole secs portion given nsecs
+  nsecs_nsecs($nsecs) - returns nsecs remainder given nsecs
+  nsecs_str($nsecs) - returns printable string in the form secs.nsecs
+  avg($total, $n) - returns average given a sum and a total number of values
+
+SEE ALSO
+--------
+linkperf:perf-script[1]
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt
new file mode 100644 (file)
index 0000000..36b3827
--- /dev/null
@@ -0,0 +1,623 @@
+perf-script-python(1)
+====================
+
+NAME
+----
+perf-script-python - Process trace data with a Python script
+
+SYNOPSIS
+--------
+[verse]
+'perf script' [-s [Python]:script[.py] ]
+
+DESCRIPTION
+-----------
+
+This perf script option is used to process perf script data using perf's
+built-in Python interpreter.  It reads and processes the input file and
+displays the results of the trace analysis implemented in the given
+Python script, if any.
+
+A QUICK EXAMPLE
+---------------
+
+This section shows the process, start to finish, of creating a working
+Python script that aggregates and extracts useful information from a
+raw perf script stream.  You can avoid reading the rest of this
+document if an example is enough for you; the rest of the document
+provides more details on each step and lists the library functions
+available to script writers.
+
+This example actually details the steps that were used to create the
+'syscall-counts' script you see when you list the available perf script
+scripts via 'perf script -l'.  As such, this script also shows how to
+integrate your script into the list of general-purpose 'perf script'
+scripts listed by that command.
+
+The syscall-counts script is a simple script, but demonstrates all the
+basic ideas necessary to create a useful script.  Here's an example
+of its output (syscall names are not yet supported, they will appear
+as numbers):
+
+----
+syscall events:
+
+event                                          count
+----------------------------------------  -----------
+sys_write                                     455067
+sys_getdents                                    4072
+sys_close                                       3037
+sys_swapoff                                     1769
+sys_read                                         923
+sys_sched_setparam                               826
+sys_open                                         331
+sys_newfstat                                     326
+sys_mmap                                         217
+sys_munmap                                       216
+sys_futex                                        141
+sys_select                                       102
+sys_poll                                          84
+sys_setitimer                                     12
+sys_writev                                         8
+15                                                 8
+sys_lseek                                          7
+sys_rt_sigprocmask                                 6
+sys_wait4                                          3
+sys_ioctl                                          3
+sys_set_robust_list                                1
+sys_exit                                           1
+56                                                 1
+sys_access                                         1
+----
+
+Basically our task is to keep a per-syscall tally that gets updated
+every time a system call occurs in the system.  Our script will do
+that, but first we need to record the data that will be processed by
+that script.  Theoretically, there are a couple of ways we could do
+that:
+
+- we could enable every event under the tracing/events/syscalls
+  directory, but this is over 600 syscalls, well beyond the number
+  allowable by perf.  These individual syscall events will however be
+  useful if we want to later use the guidance we get from the
+  general-purpose scripts to drill down and get more detail about
+  individual syscalls of interest.
+
+- we can enable the sys_enter and/or sys_exit syscalls found under
+  tracing/events/raw_syscalls.  These are called for all syscalls; the
+  'id' field can be used to distinguish between individual syscall
+  numbers.
+
+For this script, we only need to know that a syscall was entered; we
+don't care how it exited, so we'll use 'perf record' to record only
+the sys_enter events:
+
+----
+# perf record -a -e raw_syscalls:sys_enter
+
+^C[ perf record: Woken up 1 times to write data ]
+[ perf record: Captured and wrote 56.545 MB perf.data (~2470503 samples) ]
+----
+
+The options basically say to collect data for every syscall event
+system-wide and multiplex the per-cpu output into a single stream.
+That single stream will be recorded in a file in the current directory
+called perf.data.
+
+Once we have a perf.data file containing our data, we can use the -g
+'perf script' option to generate a Python script that will contain a
+callback handler for each event type found in the perf.data trace
+stream (for more details, see the STARTER SCRIPTS section).
+
+----
+# perf script -g python
+generated Python script: perf-script.py
+
+The output file created also in the current directory is named
+perf-script.py.  Here's the file in its entirety:
+
+# perf script event handlers, generated by perf script -g python
+# Licensed under the terms of the GNU GPL License version 2
+
+# The common_* event handler fields are the most useful fields common to
+# all events.  They don't necessarily correspond to the 'common_*' fields
+# in the format files.  Those fields not available as handler params can
+# be retrieved using Python functions of the form common_*(context).
+# See the perf-script-python Documentation for the list of available functions.
+
+import os
+import sys
+
+sys.path.append(os.environ['PERF_EXEC_PATH'] + \
+       '/scripts/python/perf-script-Util/lib/Perf/Trace')
+
+from perf_trace_context import *
+from Core import *
+
+def trace_begin():
+       print "in trace_begin"
+
+def trace_end():
+       print "in trace_end"
+
+def raw_syscalls__sys_enter(event_name, context, common_cpu,
+       common_secs, common_nsecs, common_pid, common_comm,
+       id, args):
+               print_header(event_name, common_cpu, common_secs, common_nsecs,
+                       common_pid, common_comm)
+
+               print "id=%d, args=%s\n" % \
+               (id, args),
+
+def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs,
+               common_pid, common_comm):
+               print_header(event_name, common_cpu, common_secs, common_nsecs,
+               common_pid, common_comm)
+
+def print_header(event_name, cpu, secs, nsecs, pid, comm):
+       print "%-20s %5u %05u.%09u %8u %-20s " % \
+       (event_name, cpu, secs, nsecs, pid, comm),
+----
+
+At the top is a comment block followed by some import statements and a
+path append which every perf script script should include.
+
+Following that are a couple generated functions, trace_begin() and
+trace_end(), which are called at the beginning and the end of the
+script respectively (for more details, see the SCRIPT_LAYOUT section
+below).
+
+Following those are the 'event handler' functions generated one for
+every event in the 'perf record' output.  The handler functions take
+the form subsystem__event_name, and contain named parameters, one for
+each field in the event; in this case, there's only one event,
+raw_syscalls__sys_enter().  (see the EVENT HANDLERS section below for
+more info on event handlers).
+
+The final couple of functions are, like the begin and end functions,
+generated for every script.  The first, trace_unhandled(), is called
+every time the script finds an event in the perf.data file that
+doesn't correspond to any event handler in the script.  This could
+mean either that the record step recorded event types that it wasn't
+really interested in, or the script was run against a trace file that
+doesn't correspond to the script.
+
+The script generated by -g option simply prints a line for each
+event found in the trace stream i.e. it basically just dumps the event
+and its parameter values to stdout.  The print_header() function is
+simply a utility function used for that purpose.  Let's rename the
+script and run it to see the default output:
+
+----
+# mv perf-script.py syscall-counts.py
+# perf script -s syscall-counts.py
+
+raw_syscalls__sys_enter     1 00840.847582083     7506 perf                  id=1, args=
+raw_syscalls__sys_enter     1 00840.847595764     7506 perf                  id=1, args=
+raw_syscalls__sys_enter     1 00840.847620860     7506 perf                  id=1, args=
+raw_syscalls__sys_enter     1 00840.847710478     6533 npviewer.bin          id=78, args=
+raw_syscalls__sys_enter     1 00840.847719204     6533 npviewer.bin          id=142, args=
+raw_syscalls__sys_enter     1 00840.847755445     6533 npviewer.bin          id=3, args=
+raw_syscalls__sys_enter     1 00840.847775601     6533 npviewer.bin          id=3, args=
+raw_syscalls__sys_enter     1 00840.847781820     6533 npviewer.bin          id=3, args=
+.
+.
+.
+----
+
+Of course, for this script, we're not interested in printing every
+trace event, but rather aggregating it in a useful way.  So we'll get
+rid of everything to do with printing as well as the trace_begin() and
+trace_unhandled() functions, which we won't be using.  That leaves us
+with this minimalistic skeleton:
+
+----
+import os
+import sys
+
+sys.path.append(os.environ['PERF_EXEC_PATH'] + \
+       '/scripts/python/perf-script-Util/lib/Perf/Trace')
+
+from perf_trace_context import *
+from Core import *
+
+def trace_end():
+       print "in trace_end"
+
+def raw_syscalls__sys_enter(event_name, context, common_cpu,
+       common_secs, common_nsecs, common_pid, common_comm,
+       id, args):
+----
+
+In trace_end(), we'll simply print the results, but first we need to
+generate some results to print.  To do that we need to have our
+sys_enter() handler do the necessary tallying until all events have
+been counted.  A hash table indexed by syscall id is a good way to
+store that information; every time the sys_enter() handler is called,
+we simply increment a count associated with that hash entry indexed by
+that syscall id:
+
+----
+  syscalls = autodict()
+
+  try:
+    syscalls[id] += 1
+  except TypeError:
+    syscalls[id] = 1
+----
+
+The syscalls 'autodict' object is a special kind of Python dictionary
+(implemented in Core.py) that implements Perl's 'autovivifying' hashes
+in Python i.e. with autovivifying hashes, you can assign nested hash
+values without having to go to the trouble of creating intermediate
+levels if they don't exist e.g syscalls[comm][pid][id] = 1 will create
+the intermediate hash levels and finally assign the value 1 to the
+hash entry for 'id' (because the value being assigned isn't a hash
+object itself, the initial value is assigned in the TypeError
+exception.  Well, there may be a better way to do this in Python but
+that's what works for now).
+
+Putting that code into the raw_syscalls__sys_enter() handler, we
+effectively end up with a single-level dictionary keyed on syscall id
+and having the counts we've tallied as values.
+
+The print_syscall_totals() function iterates over the entries in the
+dictionary and displays a line for each entry containing the syscall
+name (the dictonary keys contain the syscall ids, which are passed to
+the Util function syscall_name(), which translates the raw syscall
+numbers to the corresponding syscall name strings).  The output is
+displayed after all the events in the trace have been processed, by
+calling the print_syscall_totals() function from the trace_end()
+handler called at the end of script processing.
+
+The final script producing the output shown above is shown in its
+entirety below (syscall_name() helper is not yet available, you can
+only deal with id's for now):
+
+----
+import os
+import sys
+
+sys.path.append(os.environ['PERF_EXEC_PATH'] + \
+       '/scripts/python/perf-script-Util/lib/Perf/Trace')
+
+from perf_trace_context import *
+from Core import *
+from Util import *
+
+syscalls = autodict()
+
+def trace_end():
+       print_syscall_totals()
+
+def raw_syscalls__sys_enter(event_name, context, common_cpu,
+       common_secs, common_nsecs, common_pid, common_comm,
+       id, args):
+       try:
+               syscalls[id] += 1
+       except TypeError:
+               syscalls[id] = 1
+
+def print_syscall_totals():
+    if for_comm is not None:
+           print "\nsyscall events for %s:\n\n" % (for_comm),
+    else:
+           print "\nsyscall events:\n\n",
+
+    print "%-40s  %10s\n" % ("event", "count"),
+    print "%-40s  %10s\n" % ("----------------------------------------", \
+                                 "-----------"),
+
+    for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
+                                 reverse = True):
+           print "%-40s  %10d\n" % (syscall_name(id), val),
+----
+
+The script can be run just as before:
+
+  # perf script -s syscall-counts.py
+
+So those are the essential steps in writing and running a script.  The
+process can be generalized to any tracepoint or set of tracepoints
+you're interested in - basically find the tracepoint(s) you're
+interested in by looking at the list of available events shown by
+'perf list' and/or look in /sys/kernel/debug/tracing events for
+detailed event and field info, record the corresponding trace data
+using 'perf record', passing it the list of interesting events,
+generate a skeleton script using 'perf script -g python' and modify the
+code to aggregate and display it for your particular needs.
+
+After you've done that you may end up with a general-purpose script
+that you want to keep around and have available for future use.  By
+writing a couple of very simple shell scripts and putting them in the
+right place, you can have your script listed alongside the other
+scripts listed by the 'perf script -l' command e.g.:
+
+----
+root@tropicana:~# perf script -l
+List of available trace scripts:
+  workqueue-stats                      workqueue stats (ins/exe/create/destroy)
+  wakeup-latency                       system-wide min/max/avg wakeup latency
+  rw-by-file <comm>                    r/w activity for a program, by file
+  rw-by-pid                            system-wide r/w activity
+----
+
+A nice side effect of doing this is that you also then capture the
+probably lengthy 'perf record' command needed to record the events for
+the script.
+
+To have the script appear as a 'built-in' script, you write two simple
+scripts, one for recording and one for 'reporting'.
+
+The 'record' script is a shell script with the same base name as your
+script, but with -record appended.  The shell script should be put
+into the perf/scripts/python/bin directory in the kernel source tree.
+In that script, you write the 'perf record' command-line needed for
+your script:
+
+----
+# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-record
+
+#!/bin/bash
+perf record -a -e raw_syscalls:sys_enter
+----
+
+The 'report' script is also a shell script with the same base name as
+your script, but with -report appended.  It should also be located in
+the perf/scripts/python/bin directory.  In that script, you write the
+'perf script -s' command-line needed for running your script:
+
+----
+# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-report
+
+#!/bin/bash
+# description: system-wide syscall counts
+perf script -s ~/libexec/perf-core/scripts/python/syscall-counts.py
+----
+
+Note that the location of the Python script given in the shell script
+is in the libexec/perf-core/scripts/python directory - this is where
+the script will be copied by 'make install' when you install perf.
+For the installation to install your script there, your script needs
+to be located in the perf/scripts/python directory in the kernel
+source tree:
+
+----
+# ls -al kernel-source/tools/perf/scripts/python
+
+root@tropicana:/home/trz/src/tip# ls -al tools/perf/scripts/python
+total 32
+drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 .
+drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 ..
+drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin
+-rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-script.py
+drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 perf-script-Util
+-rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py
+----
+
+Once you've done that (don't forget to do a new 'make install',
+otherwise your script won't show up at run-time), 'perf script -l'
+should show a new entry for your script:
+
+----
+root@tropicana:~# perf script -l
+List of available trace scripts:
+  workqueue-stats                      workqueue stats (ins/exe/create/destroy)
+  wakeup-latency                       system-wide min/max/avg wakeup latency
+  rw-by-file <comm>                    r/w activity for a program, by file
+  rw-by-pid                            system-wide r/w activity
+  syscall-counts                       system-wide syscall counts
+----
+
+You can now perform the record step via 'perf script record':
+
+  # perf script record syscall-counts
+
+and display the output using 'perf script report':
+
+  # perf script report syscall-counts
+
+STARTER SCRIPTS
+---------------
+
+You can quickly get started writing a script for a particular set of
+trace data by generating a skeleton script using 'perf script -g
+python' in the same directory as an existing perf.data trace file.
+That will generate a starter script containing a handler for each of
+the event types in the trace file; it simply prints every available
+field for each event in the trace file.
+
+You can also look at the existing scripts in
+~/libexec/perf-core/scripts/python for typical examples showing how to
+do basic things like aggregate event data, print results, etc.  Also,
+the check-perf-script.py script, while not interesting for its results,
+attempts to exercise all of the main scripting features.
+
+EVENT HANDLERS
+--------------
+
+When perf script is invoked using a trace script, a user-defined
+'handler function' is called for each event in the trace.  If there's
+no handler function defined for a given event type, the event is
+ignored (or passed to a 'trace_handled' function, see below) and the
+next event is processed.
+
+Most of the event's field values are passed as arguments to the
+handler function; some of the less common ones aren't - those are
+available as calls back into the perf executable (see below).
+
+As an example, the following perf record command can be used to record
+all sched_wakeup events in the system:
+
+ # perf record -a -e sched:sched_wakeup
+
+Traces meant to be processed using a script should be recorded with
+the above option: -a to enable system-wide collection.
+
+The format file for the sched_wakep event defines the following fields
+(see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format):
+
+----
+ format:
+        field:unsigned short common_type;
+        field:unsigned char common_flags;
+        field:unsigned char common_preempt_count;
+        field:int common_pid;
+        field:int common_lock_depth;
+
+        field:char comm[TASK_COMM_LEN];
+        field:pid_t pid;
+        field:int prio;
+        field:int success;
+        field:int target_cpu;
+----
+
+The handler function for this event would be defined as:
+
+----
+def sched__sched_wakeup(event_name, context, common_cpu, common_secs,
+       common_nsecs, common_pid, common_comm,
+       comm, pid, prio, success, target_cpu):
+       pass
+----
+
+The handler function takes the form subsystem__event_name.
+
+The common_* arguments in the handler's argument list are the set of
+arguments passed to all event handlers; some of the fields correspond
+to the common_* fields in the format file, but some are synthesized,
+and some of the common_* fields aren't common enough to to be passed
+to every event as arguments but are available as library functions.
+
+Here's a brief description of each of the invariant event args:
+
+ event_name                the name of the event as text
+ context                   an opaque 'cookie' used in calls back into perf
+ common_cpu                the cpu the event occurred on
+ common_secs               the secs portion of the event timestamp
+ common_nsecs              the nsecs portion of the event timestamp
+ common_pid                the pid of the current task
+ common_comm               the name of the current process
+
+All of the remaining fields in the event's format file have
+counterparts as handler function arguments of the same name, as can be
+seen in the example above.
+
+The above provides the basics needed to directly access every field of
+every event in a trace, which covers 90% of what you need to know to
+write a useful trace script.  The sections below cover the rest.
+
+SCRIPT LAYOUT
+-------------
+
+Every perf script Python script should start by setting up a Python
+module search path and 'import'ing a few support modules (see module
+descriptions below):
+
+----
+ import os
+ import sys
+
+ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
+             '/scripts/python/perf-script-Util/lib/Perf/Trace')
+
+ from perf_trace_context import *
+ from Core import *
+----
+
+The rest of the script can contain handler functions and support
+functions in any order.
+
+Aside from the event handler functions discussed above, every script
+can implement a set of optional functions:
+
+*trace_begin*, if defined, is called before any event is processed and
+gives scripts a chance to do setup tasks:
+
+----
+def trace_begin:
+    pass
+----
+
+*trace_end*, if defined, is called after all events have been
+ processed and gives scripts a chance to do end-of-script tasks, such
+ as display results:
+
+----
+def trace_end:
+    pass
+----
+
+*trace_unhandled*, if defined, is called after for any event that
+ doesn't have a handler explicitly defined for it.  The standard set
+ of common arguments are passed into it:
+
+----
+def trace_unhandled(event_name, context, common_cpu, common_secs,
+        common_nsecs, common_pid, common_comm):
+    pass
+----
+
+The remaining sections provide descriptions of each of the available
+built-in perf script Python modules and their associated functions.
+
+AVAILABLE MODULES AND FUNCTIONS
+-------------------------------
+
+The following sections describe the functions and variables available
+via the various perf script Python modules.  To use the functions and
+variables from the given module, add the corresponding 'from XXXX
+import' line to your perf script script.
+
+Core.py Module
+~~~~~~~~~~~~~~
+
+These functions provide some essential functions to user scripts.
+
+The *flag_str* and *symbol_str* functions provide human-readable
+strings for flag and symbolic fields.  These correspond to the strings
+and values parsed from the 'print fmt' fields of the event format
+files:
+
+  flag_str(event_name, field_name, field_value) - returns the string represention corresponding to field_value for the flag field field_name of event event_name
+  symbol_str(event_name, field_name, field_value) - returns the string represention corresponding to field_value for the symbolic field field_name of event event_name
+
+The *autodict* function returns a special kind of Python
+dictionary that implements Perl's 'autovivifying' hashes in Python
+i.e. with autovivifying hashes, you can assign nested hash values
+without having to go to the trouble of creating intermediate levels if
+they don't exist.
+
+  autodict() - returns an autovivifying dictionary instance
+
+
+perf_trace_context Module
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some of the 'common' fields in the event format file aren't all that
+common, but need to be made accessible to user scripts nonetheless.
+
+perf_trace_context defines a set of functions that can be used to
+access this data in the context of the current event.  Each of these
+functions expects a context variable, which is the same as the
+context variable passed into every event handler as the second
+argument.
+
+ common_pc(context) - returns common_preempt count for the current event
+ common_flags(context) - returns common_flags for the current event
+ common_lock_depth(context) - returns common_lock_depth for the current event
+
+Util.py Module
+~~~~~~~~~~~~~~
+
+Various utility functions for use with perf script:
+
+  nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair
+  nsecs_secs(nsecs) - returns whole secs portion given nsecs
+  nsecs_nsecs(nsecs) - returns nsecs remainder given nsecs
+  nsecs_str(nsecs) - returns printable string in the form secs.nsecs
+  avg(total, n) - returns average given a sum and a total number of values
+
+SEE ALSO
+--------
+linkperf:perf-script[1]
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
new file mode 100644 (file)
index 0000000..f442acc
--- /dev/null
@@ -0,0 +1,111 @@
+perf-script(1)
+=============
+
+NAME
+----
+perf-script - Read perf.data (created by perf record) and display trace output
+
+SYNOPSIS
+--------
+[verse]
+'perf script' [<options>]
+'perf script' [<options>] record <script> [<record-options>] <command>
+'perf script' [<options>] report <script> [script-args]
+'perf script' [<options>] <script> <required-script-args> [<record-options>] <command>
+'perf script' [<options>] <top-script> [script-args]
+
+DESCRIPTION
+-----------
+This command reads the input file and displays the trace recorded.
+
+There are several variants of perf script:
+
+  'perf script' to see a detailed trace of the workload that was
+  recorded.
+
+  You can also run a set of pre-canned scripts that aggregate and
+  summarize the raw trace data in various ways (the list of scripts is
+  available via 'perf script -l').  The following variants allow you to
+  record and run those scripts:
+
+  'perf script record <script> <command>' to record the events required
+  for 'perf script report'.  <script> is the name displayed in the
+  output of 'perf script --list' i.e. the actual script name minus any
+  language extension.  If <command> is not specified, the events are
+  recorded using the -a (system-wide) 'perf record' option.
+
+  'perf script report <script> [args]' to run and display the results
+  of <script>.  <script> is the name displayed in the output of 'perf
+  trace --list' i.e. the actual script name minus any language
+  extension.  The perf.data output from a previous run of 'perf script
+  record <script>' is used and should be present for this command to
+  succeed.  [args] refers to the (mainly optional) args expected by
+  the script.
+
+  'perf script <script> <required-script-args> <command>' to both
+  record the events required for <script> and to run the <script>
+  using 'live-mode' i.e. without writing anything to disk.  <script>
+  is the name displayed in the output of 'perf script --list' i.e. the
+  actual script name minus any language extension.  If <command> is
+  not specified, the events are recorded using the -a (system-wide)
+  'perf record' option.  If <script> has any required args, they
+  should be specified before <command>.  This mode doesn't allow for
+  optional script args to be specified; if optional script args are
+  desired, they can be specified using separate 'perf script record'
+  and 'perf script report' commands, with the stdout of the record step
+  piped to the stdin of the report script, using the '-o -' and '-i -'
+  options of the corresponding commands.
+
+  'perf script <top-script>' to both record the events required for
+  <top-script> and to run the <top-script> using 'live-mode'
+  i.e. without writing anything to disk.  <top-script> is the name
+  displayed in the output of 'perf script --list' i.e. the actual
+  script name minus any language extension; a <top-script> is defined
+  as any script name ending with the string 'top'.
+
+  [<record-options>] can be passed to the record steps of 'perf script
+  record' and 'live-mode' variants; this isn't possible however for
+  <top-script> 'live-mode' or 'perf script report' variants.
+
+  See the 'SEE ALSO' section for links to language-specific
+  information on how to write and run your own trace scripts.
+
+OPTIONS
+-------
+<command>...::
+       Any command you can specify in a shell.
+
+-D::
+--dump-raw-script=::
+        Display verbose dump of the trace data.
+
+-L::
+--Latency=::
+        Show latency attributes (irqs/preemption disabled, etc).
+
+-l::
+--list=::
+        Display a list of available trace scripts.
+
+-s ['lang']::
+--script=::
+        Process trace data with the given script ([lang]:script[.ext]).
+       If the string 'lang' is specified in place of a script name, a
+        list of supported languages will be displayed instead.
+
+-g::
+--gen-script=::
+        Generate perf-script.[ext] starter script for given language,
+        using current perf.data.
+
+-a::
+        Force system-wide collection.  Scripts run without a <command>
+        normally use -a by default, while scripts run with a <command>
+        normally don't - this option allows the latter to be run in
+        system-wide mode.
+
+
+SEE ALSO
+--------
+linkperf:perf-record[1], linkperf:perf-script-perl[1],
+linkperf:perf-script-python[1]
diff --git a/tools/perf/Documentation/perf-trace-perl.txt b/tools/perf/Documentation/perf-trace-perl.txt
deleted file mode 100644 (file)
index ee6525e..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-perf-trace-perl(1)
-==================
-
-NAME
-----
-perf-trace-perl - Process trace data with a Perl script
-
-SYNOPSIS
---------
-[verse]
-'perf trace' [-s [Perl]:script[.pl] ]
-
-DESCRIPTION
------------
-
-This perf trace option is used to process perf trace data using perf's
-built-in Perl interpreter.  It reads and processes the input file and
-displays the results of the trace analysis implemented in the given
-Perl script, if any.
-
-STARTER SCRIPTS
----------------
-
-You can avoid reading the rest of this document by running 'perf trace
--g perl' in the same directory as an existing perf.data trace file.
-That will generate a starter script containing a handler for each of
-the event types in the trace file; it simply prints every available
-field for each event in the trace file.
-
-You can also look at the existing scripts in
-~/libexec/perf-core/scripts/perl for typical examples showing how to
-do basic things like aggregate event data, print results, etc.  Also,
-the check-perf-trace.pl script, while not interesting for its results,
-attempts to exercise all of the main scripting features.
-
-EVENT HANDLERS
---------------
-
-When perf trace is invoked using a trace script, a user-defined
-'handler function' is called for each event in the trace.  If there's
-no handler function defined for a given event type, the event is
-ignored (or passed to a 'trace_handled' function, see below) and the
-next event is processed.
-
-Most of the event's field values are passed as arguments to the
-handler function; some of the less common ones aren't - those are
-available as calls back into the perf executable (see below).
-
-As an example, the following perf record command can be used to record
-all sched_wakeup events in the system:
-
- # perf record -a -e sched:sched_wakeup
-
-Traces meant to be processed using a script should be recorded with
-the above option: -a to enable system-wide collection.
-
-The format file for the sched_wakep event defines the following fields
-(see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format):
-
-----
- format:
-        field:unsigned short common_type;
-        field:unsigned char common_flags;
-        field:unsigned char common_preempt_count;
-        field:int common_pid;
-        field:int common_lock_depth;
-
-        field:char comm[TASK_COMM_LEN];
-        field:pid_t pid;
-        field:int prio;
-        field:int success;
-        field:int target_cpu;
-----
-
-The handler function for this event would be defined as:
-
-----
-sub sched::sched_wakeup
-{
-   my ($event_name, $context, $common_cpu, $common_secs,
-       $common_nsecs, $common_pid, $common_comm,
-       $comm, $pid, $prio, $success, $target_cpu) = @_;
-}
-----
-
-The handler function takes the form subsystem::event_name.
-
-The $common_* arguments in the handler's argument list are the set of
-arguments passed to all event handlers; some of the fields correspond
-to the common_* fields in the format file, but some are synthesized,
-and some of the common_* fields aren't common enough to to be passed
-to every event as arguments but are available as library functions.
-
-Here's a brief description of each of the invariant event args:
-
- $event_name               the name of the event as text
- $context                  an opaque 'cookie' used in calls back into perf
- $common_cpu               the cpu the event occurred on
- $common_secs              the secs portion of the event timestamp
- $common_nsecs             the nsecs portion of the event timestamp
- $common_pid               the pid of the current task
- $common_comm              the name of the current process
-
-All of the remaining fields in the event's format file have
-counterparts as handler function arguments of the same name, as can be
-seen in the example above.
-
-The above provides the basics needed to directly access every field of
-every event in a trace, which covers 90% of what you need to know to
-write a useful trace script.  The sections below cover the rest.
-
-SCRIPT LAYOUT
--------------
-
-Every perf trace Perl script should start by setting up a Perl module
-search path and 'use'ing a few support modules (see module
-descriptions below):
-
-----
- 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;
-----
-
-The rest of the script can contain handler functions and support
-functions in any order.
-
-Aside from the event handler functions discussed above, every script
-can implement a set of optional functions:
-
-*trace_begin*, if defined, is called before any event is processed and
-gives scripts a chance to do setup tasks:
-
-----
- sub trace_begin
- {
- }
-----
-
-*trace_end*, if defined, is called after all events have been
- processed and gives scripts a chance to do end-of-script tasks, such
- as display results:
-
-----
-sub trace_end
-{
-}
-----
-
-*trace_unhandled*, if defined, is called after for any event that
- doesn't have a handler explicitly defined for it.  The standard set
- of common arguments are passed into it:
-
-----
-sub trace_unhandled
-{
-    my ($event_name, $context, $common_cpu, $common_secs,
-        $common_nsecs, $common_pid, $common_comm) = @_;
-}
-----
-
-The remaining sections provide descriptions of each of the available
-built-in perf trace Perl modules and their associated functions.
-
-AVAILABLE MODULES AND FUNCTIONS
--------------------------------
-
-The following sections describe the functions and variables available
-via the various Perf::Trace::* Perl modules.  To use the functions and
-variables from the given module, add the corresponding 'use
-Perf::Trace::XXX' line to your perf trace script.
-
-Perf::Trace::Core Module
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-These functions provide some essential functions to user scripts.
-
-The *flag_str* and *symbol_str* functions provide human-readable
-strings for flag and symbolic fields.  These correspond to the strings
-and values parsed from the 'print fmt' fields of the event format
-files:
-
-  flag_str($event_name, $field_name, $field_value) - returns the string represention corresponding to $field_value for the flag field $field_name of event $event_name
-  symbol_str($event_name, $field_name, $field_value) - returns the string represention corresponding to $field_value for the symbolic field $field_name of event $event_name
-
-Perf::Trace::Context Module
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Some of the 'common' fields in the event format file aren't all that
-common, but need to be made accessible to user scripts nonetheless.
-
-Perf::Trace::Context defines a set of functions that can be used to
-access this data in the context of the current event.  Each of these
-functions expects a $context variable, which is the same as the
-$context variable passed into every event handler as the second
-argument.
-
- common_pc($context) - returns common_preempt count for the current event
- common_flags($context) - returns common_flags for the current event
- common_lock_depth($context) - returns common_lock_depth for the current event
-
-Perf::Trace::Util Module
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-Various utility functions for use with perf trace:
-
-  nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair
-  nsecs_secs($nsecs) - returns whole secs portion given nsecs
-  nsecs_nsecs($nsecs) - returns nsecs remainder given nsecs
-  nsecs_str($nsecs) - returns printable string in the form secs.nsecs
-  avg($total, $n) - returns average given a sum and a total number of values
-
-SEE ALSO
---------
-linkperf:perf-trace[1]
diff --git a/tools/perf/Documentation/perf-trace-python.txt b/tools/perf/Documentation/perf-trace-python.txt
deleted file mode 100644 (file)
index 693be80..0000000
+++ /dev/null
@@ -1,623 +0,0 @@
-perf-trace-python(1)
-====================
-
-NAME
-----
-perf-trace-python - Process trace data with a Python script
-
-SYNOPSIS
---------
-[verse]
-'perf trace' [-s [Python]:script[.py] ]
-
-DESCRIPTION
------------
-
-This perf trace option is used to process perf trace data using perf's
-built-in Python interpreter.  It reads and processes the input file and
-displays the results of the trace analysis implemented in the given
-Python script, if any.
-
-A QUICK EXAMPLE
----------------
-
-This section shows the process, start to finish, of creating a working
-Python script that aggregates and extracts useful information from a
-raw perf trace stream.  You can avoid reading the rest of this
-document if an example is enough for you; the rest of the document
-provides more details on each step and lists the library functions
-available to script writers.
-
-This example actually details the steps that were used to create the
-'syscall-counts' script you see when you list the available perf trace
-scripts via 'perf trace -l'.  As such, this script also shows how to
-integrate your script into the list of general-purpose 'perf trace'
-scripts listed by that command.
-
-The syscall-counts script is a simple script, but demonstrates all the
-basic ideas necessary to create a useful script.  Here's an example
-of its output (syscall names are not yet supported, they will appear
-as numbers):
-
-----
-syscall events:
-
-event                                          count
-----------------------------------------  -----------
-sys_write                                     455067
-sys_getdents                                    4072
-sys_close                                       3037
-sys_swapoff                                     1769
-sys_read                                         923
-sys_sched_setparam                               826
-sys_open                                         331
-sys_newfstat                                     326
-sys_mmap                                         217
-sys_munmap                                       216
-sys_futex                                        141
-sys_select                                       102
-sys_poll                                          84
-sys_setitimer                                     12
-sys_writev                                         8
-15                                                 8
-sys_lseek                                          7
-sys_rt_sigprocmask                                 6
-sys_wait4                                          3
-sys_ioctl                                          3
-sys_set_robust_list                                1
-sys_exit                                           1
-56                                                 1
-sys_access                                         1
-----
-
-Basically our task is to keep a per-syscall tally that gets updated
-every time a system call occurs in the system.  Our script will do
-that, but first we need to record the data that will be processed by
-that script.  Theoretically, there are a couple of ways we could do
-that:
-
-- we could enable every event under the tracing/events/syscalls
-  directory, but this is over 600 syscalls, well beyond the number
-  allowable by perf.  These individual syscall events will however be
-  useful if we want to later use the guidance we get from the
-  general-purpose scripts to drill down and get more detail about
-  individual syscalls of interest.
-
-- we can enable the sys_enter and/or sys_exit syscalls found under
-  tracing/events/raw_syscalls.  These are called for all syscalls; the
-  'id' field can be used to distinguish between individual syscall
-  numbers.
-
-For this script, we only need to know that a syscall was entered; we
-don't care how it exited, so we'll use 'perf record' to record only
-the sys_enter events:
-
-----
-# perf record -a -e raw_syscalls:sys_enter
-
-^C[ perf record: Woken up 1 times to write data ]
-[ perf record: Captured and wrote 56.545 MB perf.data (~2470503 samples) ]
-----
-
-The options basically say to collect data for every syscall event
-system-wide and multiplex the per-cpu output into a single stream.
-That single stream will be recorded in a file in the current directory
-called perf.data.
-
-Once we have a perf.data file containing our data, we can use the -g
-'perf trace' option to generate a Python script that will contain a
-callback handler for each event type found in the perf.data trace
-stream (for more details, see the STARTER SCRIPTS section).
-
-----
-# perf trace -g python
-generated Python script: perf-trace.py
-
-The output file created also in the current directory is named
-perf-trace.py.  Here's the file in its entirety:
-
-# perf trace event handlers, generated by perf trace -g python
-# Licensed under the terms of the GNU GPL License version 2
-
-# The common_* event handler fields are the most useful fields common to
-# all events.  They don't necessarily correspond to the 'common_*' fields
-# in the format files.  Those fields not available as handler params can
-# be retrieved using Python functions of the form common_*(context).
-# See the perf-trace-python Documentation for the list of available functions.
-
-import os
-import sys
-
-sys.path.append(os.environ['PERF_EXEC_PATH'] + \
-       '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
-
-from perf_trace_context import *
-from Core import *
-
-def trace_begin():
-       print "in trace_begin"
-
-def trace_end():
-       print "in trace_end"
-
-def raw_syscalls__sys_enter(event_name, context, common_cpu,
-       common_secs, common_nsecs, common_pid, common_comm,
-       id, args):
-               print_header(event_name, common_cpu, common_secs, common_nsecs,
-                       common_pid, common_comm)
-
-               print "id=%d, args=%s\n" % \
-               (id, args),
-
-def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs,
-               common_pid, common_comm):
-               print_header(event_name, common_cpu, common_secs, common_nsecs,
-               common_pid, common_comm)
-
-def print_header(event_name, cpu, secs, nsecs, pid, comm):
-       print "%-20s %5u %05u.%09u %8u %-20s " % \
-       (event_name, cpu, secs, nsecs, pid, comm),
-----
-
-At the top is a comment block followed by some import statements and a
-path append which every perf trace script should include.
-
-Following that are a couple generated functions, trace_begin() and
-trace_end(), which are called at the beginning and the end of the
-script respectively (for more details, see the SCRIPT_LAYOUT section
-below).
-
-Following those are the 'event handler' functions generated one for
-every event in the 'perf record' output.  The handler functions take
-the form subsystem__event_name, and contain named parameters, one for
-each field in the event; in this case, there's only one event,
-raw_syscalls__sys_enter().  (see the EVENT HANDLERS section below for
-more info on event handlers).
-
-The final couple of functions are, like the begin and end functions,
-generated for every script.  The first, trace_unhandled(), is called
-every time the script finds an event in the perf.data file that
-doesn't correspond to any event handler in the script.  This could
-mean either that the record step recorded event types that it wasn't
-really interested in, or the script was run against a trace file that
-doesn't correspond to the script.
-
-The script generated by -g option simply prints a line for each
-event found in the trace stream i.e. it basically just dumps the event
-and its parameter values to stdout.  The print_header() function is
-simply a utility function used for that purpose.  Let's rename the
-script and run it to see the default output:
-
-----
-# mv perf-trace.py syscall-counts.py
-# perf trace -s syscall-counts.py
-
-raw_syscalls__sys_enter     1 00840.847582083     7506 perf                  id=1, args=
-raw_syscalls__sys_enter     1 00840.847595764     7506 perf                  id=1, args=
-raw_syscalls__sys_enter     1 00840.847620860     7506 perf                  id=1, args=
-raw_syscalls__sys_enter     1 00840.847710478     6533 npviewer.bin          id=78, args=
-raw_syscalls__sys_enter     1 00840.847719204     6533 npviewer.bin          id=142, args=
-raw_syscalls__sys_enter     1 00840.847755445     6533 npviewer.bin          id=3, args=
-raw_syscalls__sys_enter     1 00840.847775601     6533 npviewer.bin          id=3, args=
-raw_syscalls__sys_enter     1 00840.847781820     6533 npviewer.bin          id=3, args=
-.
-.
-.
-----
-
-Of course, for this script, we're not interested in printing every
-trace event, but rather aggregating it in a useful way.  So we'll get
-rid of everything to do with printing as well as the trace_begin() and
-trace_unhandled() functions, which we won't be using.  That leaves us
-with this minimalistic skeleton:
-
-----
-import os
-import sys
-
-sys.path.append(os.environ['PERF_EXEC_PATH'] + \
-       '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
-
-from perf_trace_context import *
-from Core import *
-
-def trace_end():
-       print "in trace_end"
-
-def raw_syscalls__sys_enter(event_name, context, common_cpu,
-       common_secs, common_nsecs, common_pid, common_comm,
-       id, args):
-----
-
-In trace_end(), we'll simply print the results, but first we need to
-generate some results to print.  To do that we need to have our
-sys_enter() handler do the necessary tallying until all events have
-been counted.  A hash table indexed by syscall id is a good way to
-store that information; every time the sys_enter() handler is called,
-we simply increment a count associated with that hash entry indexed by
-that syscall id:
-
-----
-  syscalls = autodict()
-
-  try:
-    syscalls[id] += 1
-  except TypeError:
-    syscalls[id] = 1
-----
-
-The syscalls 'autodict' object is a special kind of Python dictionary
-(implemented in Core.py) that implements Perl's 'autovivifying' hashes
-in Python i.e. with autovivifying hashes, you can assign nested hash
-values without having to go to the trouble of creating intermediate
-levels if they don't exist e.g syscalls[comm][pid][id] = 1 will create
-the intermediate hash levels and finally assign the value 1 to the
-hash entry for 'id' (because the value being assigned isn't a hash
-object itself, the initial value is assigned in the TypeError
-exception.  Well, there may be a better way to do this in Python but
-that's what works for now).
-
-Putting that code into the raw_syscalls__sys_enter() handler, we
-effectively end up with a single-level dictionary keyed on syscall id
-and having the counts we've tallied as values.
-
-The print_syscall_totals() function iterates over the entries in the
-dictionary and displays a line for each entry containing the syscall
-name (the dictonary keys contain the syscall ids, which are passed to
-the Util function syscall_name(), which translates the raw syscall
-numbers to the corresponding syscall name strings).  The output is
-displayed after all the events in the trace have been processed, by
-calling the print_syscall_totals() function from the trace_end()
-handler called at the end of script processing.
-
-The final script producing the output shown above is shown in its
-entirety below (syscall_name() helper is not yet available, you can
-only deal with id's for now):
-
-----
-import os
-import sys
-
-sys.path.append(os.environ['PERF_EXEC_PATH'] + \
-       '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
-
-from perf_trace_context import *
-from Core import *
-from Util import *
-
-syscalls = autodict()
-
-def trace_end():
-       print_syscall_totals()
-
-def raw_syscalls__sys_enter(event_name, context, common_cpu,
-       common_secs, common_nsecs, common_pid, common_comm,
-       id, args):
-       try:
-               syscalls[id] += 1
-       except TypeError:
-               syscalls[id] = 1
-
-def print_syscall_totals():
-    if for_comm is not None:
-           print "\nsyscall events for %s:\n\n" % (for_comm),
-    else:
-           print "\nsyscall events:\n\n",
-
-    print "%-40s  %10s\n" % ("event", "count"),
-    print "%-40s  %10s\n" % ("----------------------------------------", \
-                                 "-----------"),
-
-    for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
-                                 reverse = True):
-           print "%-40s  %10d\n" % (syscall_name(id), val),
-----
-
-The script can be run just as before:
-
-  # perf trace -s syscall-counts.py
-
-So those are the essential steps in writing and running a script.  The
-process can be generalized to any tracepoint or set of tracepoints
-you're interested in - basically find the tracepoint(s) you're
-interested in by looking at the list of available events shown by
-'perf list' and/or look in /sys/kernel/debug/tracing events for
-detailed event and field info, record the corresponding trace data
-using 'perf record', passing it the list of interesting events,
-generate a skeleton script using 'perf trace -g python' and modify the
-code to aggregate and display it for your particular needs.
-
-After you've done that you may end up with a general-purpose script
-that you want to keep around and have available for future use.  By
-writing a couple of very simple shell scripts and putting them in the
-right place, you can have your script listed alongside the other
-scripts listed by the 'perf trace -l' command e.g.:
-
-----
-root@tropicana:~# perf trace -l
-List of available trace scripts:
-  workqueue-stats                      workqueue stats (ins/exe/create/destroy)
-  wakeup-latency                       system-wide min/max/avg wakeup latency
-  rw-by-file <comm>                    r/w activity for a program, by file
-  rw-by-pid                            system-wide r/w activity
-----
-
-A nice side effect of doing this is that you also then capture the
-probably lengthy 'perf record' command needed to record the events for
-the script.
-
-To have the script appear as a 'built-in' script, you write two simple
-scripts, one for recording and one for 'reporting'.
-
-The 'record' script is a shell script with the same base name as your
-script, but with -record appended.  The shell script should be put
-into the perf/scripts/python/bin directory in the kernel source tree.
-In that script, you write the 'perf record' command-line needed for
-your script:
-
-----
-# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-record
-
-#!/bin/bash
-perf record -a -e raw_syscalls:sys_enter
-----
-
-The 'report' script is also a shell script with the same base name as
-your script, but with -report appended.  It should also be located in
-the perf/scripts/python/bin directory.  In that script, you write the
-'perf trace -s' command-line needed for running your script:
-
-----
-# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-report
-
-#!/bin/bash
-# description: system-wide syscall counts
-perf trace -s ~/libexec/perf-core/scripts/python/syscall-counts.py
-----
-
-Note that the location of the Python script given in the shell script
-is in the libexec/perf-core/scripts/python directory - this is where
-the script will be copied by 'make install' when you install perf.
-For the installation to install your script there, your script needs
-to be located in the perf/scripts/python directory in the kernel
-source tree:
-
-----
-# ls -al kernel-source/tools/perf/scripts/python
-
-root@tropicana:/home/trz/src/tip# ls -al tools/perf/scripts/python
-total 32
-drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 .
-drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 ..
-drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin
--rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-trace.py
-drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 Perf-Trace-Util
--rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py
-----
-
-Once you've done that (don't forget to do a new 'make install',
-otherwise your script won't show up at run-time), 'perf trace -l'
-should show a new entry for your script:
-
-----
-root@tropicana:~# perf trace -l
-List of available trace scripts:
-  workqueue-stats                      workqueue stats (ins/exe/create/destroy)
-  wakeup-latency                       system-wide min/max/avg wakeup latency
-  rw-by-file <comm>                    r/w activity for a program, by file
-  rw-by-pid                            system-wide r/w activity
-  syscall-counts                       system-wide syscall counts
-----
-
-You can now perform the record step via 'perf trace record':
-
-  # perf trace record syscall-counts
-
-and display the output using 'perf trace report':
-
-  # perf trace report syscall-counts
-
-STARTER SCRIPTS
----------------
-
-You can quickly get started writing a script for a particular set of
-trace data by generating a skeleton script using 'perf trace -g
-python' in the same directory as an existing perf.data trace file.
-That will generate a starter script containing a handler for each of
-the event types in the trace file; it simply prints every available
-field for each event in the trace file.
-
-You can also look at the existing scripts in
-~/libexec/perf-core/scripts/python for typical examples showing how to
-do basic things like aggregate event data, print results, etc.  Also,
-the check-perf-trace.py script, while not interesting for its results,
-attempts to exercise all of the main scripting features.
-
-EVENT HANDLERS
---------------
-
-When perf trace is invoked using a trace script, a user-defined
-'handler function' is called for each event in the trace.  If there's
-no handler function defined for a given event type, the event is
-ignored (or passed to a 'trace_handled' function, see below) and the
-next event is processed.
-
-Most of the event's field values are passed as arguments to the
-handler function; some of the less common ones aren't - those are
-available as calls back into the perf executable (see below).
-
-As an example, the following perf record command can be used to record
-all sched_wakeup events in the system:
-
- # perf record -a -e sched:sched_wakeup
-
-Traces meant to be processed using a script should be recorded with
-the above option: -a to enable system-wide collection.
-
-The format file for the sched_wakep event defines the following fields
-(see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format):
-
-----
- format:
-        field:unsigned short common_type;
-        field:unsigned char common_flags;
-        field:unsigned char common_preempt_count;
-        field:int common_pid;
-        field:int common_lock_depth;
-
-        field:char comm[TASK_COMM_LEN];
-        field:pid_t pid;
-        field:int prio;
-        field:int success;
-        field:int target_cpu;
-----
-
-The handler function for this event would be defined as:
-
-----
-def sched__sched_wakeup(event_name, context, common_cpu, common_secs,
-       common_nsecs, common_pid, common_comm,
-       comm, pid, prio, success, target_cpu):
-       pass
-----
-
-The handler function takes the form subsystem__event_name.
-
-The common_* arguments in the handler's argument list are the set of
-arguments passed to all event handlers; some of the fields correspond
-to the common_* fields in the format file, but some are synthesized,
-and some of the common_* fields aren't common enough to to be passed
-to every event as arguments but are available as library functions.
-
-Here's a brief description of each of the invariant event args:
-
- event_name                the name of the event as text
- context                   an opaque 'cookie' used in calls back into perf
- common_cpu                the cpu the event occurred on
- common_secs               the secs portion of the event timestamp
- common_nsecs              the nsecs portion of the event timestamp
- common_pid                the pid of the current task
- common_comm               the name of the current process
-
-All of the remaining fields in the event's format file have
-counterparts as handler function arguments of the same name, as can be
-seen in the example above.
-
-The above provides the basics needed to directly access every field of
-every event in a trace, which covers 90% of what you need to know to
-write a useful trace script.  The sections below cover the rest.
-
-SCRIPT LAYOUT
--------------
-
-Every perf trace Python script should start by setting up a Python
-module search path and 'import'ing a few support modules (see module
-descriptions below):
-
-----
- import os
- import sys
-
- sys.path.append(os.environ['PERF_EXEC_PATH'] + \
-             '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
-
- from perf_trace_context import *
- from Core import *
-----
-
-The rest of the script can contain handler functions and support
-functions in any order.
-
-Aside from the event handler functions discussed above, every script
-can implement a set of optional functions:
-
-*trace_begin*, if defined, is called before any event is processed and
-gives scripts a chance to do setup tasks:
-
-----
-def trace_begin:
-    pass
-----
-
-*trace_end*, if defined, is called after all events have been
- processed and gives scripts a chance to do end-of-script tasks, such
- as display results:
-
-----
-def trace_end:
-    pass
-----
-
-*trace_unhandled*, if defined, is called after for any event that
- doesn't have a handler explicitly defined for it.  The standard set
- of common arguments are passed into it:
-
-----
-def trace_unhandled(event_name, context, common_cpu, common_secs,
-        common_nsecs, common_pid, common_comm):
-    pass
-----
-
-The remaining sections provide descriptions of each of the available
-built-in perf trace Python modules and their associated functions.
-
-AVAILABLE MODULES AND FUNCTIONS
--------------------------------
-
-The following sections describe the functions and variables available
-via the various perf trace Python modules.  To use the functions and
-variables from the given module, add the corresponding 'from XXXX
-import' line to your perf trace script.
-
-Core.py Module
-~~~~~~~~~~~~~~
-
-These functions provide some essential functions to user scripts.
-
-The *flag_str* and *symbol_str* functions provide human-readable
-strings for flag and symbolic fields.  These correspond to the strings
-and values parsed from the 'print fmt' fields of the event format
-files:
-
-  flag_str(event_name, field_name, field_value) - returns the string represention corresponding to field_value for the flag field field_name of event event_name
-  symbol_str(event_name, field_name, field_value) - returns the string represention corresponding to field_value for the symbolic field field_name of event event_name
-
-The *autodict* function returns a special kind of Python
-dictionary that implements Perl's 'autovivifying' hashes in Python
-i.e. with autovivifying hashes, you can assign nested hash values
-without having to go to the trouble of creating intermediate levels if
-they don't exist.
-
-  autodict() - returns an autovivifying dictionary instance
-
-
-perf_trace_context Module
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Some of the 'common' fields in the event format file aren't all that
-common, but need to be made accessible to user scripts nonetheless.
-
-perf_trace_context defines a set of functions that can be used to
-access this data in the context of the current event.  Each of these
-functions expects a context variable, which is the same as the
-context variable passed into every event handler as the second
-argument.
-
- common_pc(context) - returns common_preempt count for the current event
- common_flags(context) - returns common_flags for the current event
- common_lock_depth(context) - returns common_lock_depth for the current event
-
-Util.py Module
-~~~~~~~~~~~~~~
-
-Various utility functions for use with perf trace:
-
-  nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair
-  nsecs_secs(nsecs) - returns whole secs portion given nsecs
-  nsecs_nsecs(nsecs) - returns nsecs remainder given nsecs
-  nsecs_str(nsecs) - returns printable string in the form secs.nsecs
-  avg(total, n) - returns average given a sum and a total number of values
-
-SEE ALSO
---------
-linkperf:perf-trace[1]
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
deleted file mode 100644 (file)
index 26aff6b..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-perf-trace(1)
-=============
-
-NAME
-----
-perf-trace - Read perf.data (created by perf record) and display trace output
-
-SYNOPSIS
---------
-[verse]
-'perf trace' [<options>]
-'perf trace' [<options>] record <script> [<record-options>] <command>
-'perf trace' [<options>] report <script> [script-args]
-'perf trace' [<options>] <script> <required-script-args> [<record-options>] <command>
-'perf trace' [<options>] <top-script> [script-args]
-
-DESCRIPTION
------------
-This command reads the input file and displays the trace recorded.
-
-There are several variants of perf trace:
-
-  'perf trace' to see a detailed trace of the workload that was
-  recorded.
-
-  You can also run a set of pre-canned scripts that aggregate and
-  summarize the raw trace data in various ways (the list of scripts is
-  available via 'perf trace -l').  The following variants allow you to
-  record and run those scripts:
-
-  'perf trace record <script> <command>' to record the events required
-  for 'perf trace report'.  <script> is the name displayed in the
-  output of 'perf trace --list' i.e. the actual script name minus any
-  language extension.  If <command> is not specified, the events are
-  recorded using the -a (system-wide) 'perf record' option.
-
-  'perf trace report <script> [args]' to run and display the results
-  of <script>.  <script> is the name displayed in the output of 'perf
-  trace --list' i.e. the actual script name minus any language
-  extension.  The perf.data output from a previous run of 'perf trace
-  record <script>' is used and should be present for this command to
-  succeed.  [args] refers to the (mainly optional) args expected by
-  the script.
-
-  'perf trace <script> <required-script-args> <command>' to both
-  record the events required for <script> and to run the <script>
-  using 'live-mode' i.e. without writing anything to disk.  <script>
-  is the name displayed in the output of 'perf trace --list' i.e. the
-  actual script name minus any language extension.  If <command> is
-  not specified, the events are recorded using the -a (system-wide)
-  'perf record' option.  If <script> has any required args, they
-  should be specified before <command>.  This mode doesn't allow for
-  optional script args to be specified; if optional script args are
-  desired, they can be specified using separate 'perf trace record'
-  and 'perf trace report' commands, with the stdout of the record step
-  piped to the stdin of the report script, using the '-o -' and '-i -'
-  options of the corresponding commands.
-
-  'perf trace <top-script>' to both record the events required for
-  <top-script> and to run the <top-script> using 'live-mode'
-  i.e. without writing anything to disk.  <top-script> is the name
-  displayed in the output of 'perf trace --list' i.e. the actual
-  script name minus any language extension; a <top-script> is defined
-  as any script name ending with the string 'top'.
-
-  [<record-options>] can be passed to the record steps of 'perf trace
-  record' and 'live-mode' variants; this isn't possible however for
-  <top-script> 'live-mode' or 'perf trace report' variants.
-
-  See the 'SEE ALSO' section for links to language-specific
-  information on how to write and run your own trace scripts.
-
-OPTIONS
--------
-<command>...::
-       Any command you can specify in a shell.
-
--D::
---dump-raw-trace=::
-        Display verbose dump of the trace data.
-
--L::
---Latency=::
-        Show latency attributes (irqs/preemption disabled, etc).
-
--l::
---list=::
-        Display a list of available trace scripts.
-
--s ['lang']::
---script=::
-        Process trace data with the given script ([lang]:script[.ext]).
-       If the string 'lang' is specified in place of a script name, a
-        list of supported languages will be displayed instead.
-
--g::
---gen-script=::
-        Generate perf-trace.[ext] starter script for given language,
-        using current perf.data.
-
--a::
-        Force system-wide collection.  Scripts run without a <command>
-        normally use -a by default, while scripts run with a <command>
-        normally don't - this option allows the latter to be run in
-        system-wide mode.
-
-
-SEE ALSO
---------
-linkperf:perf-record[1], linkperf:perf-trace-perl[1],
-linkperf:perf-trace-python[1]
index d1db0f676a4bf14850fa0264e78fe3d482d376dc..a9c19d013147e4199df1235a8f45141a1827f3a1 100644 (file)
@@ -485,7 +485,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-report.o
 BUILTIN_OBJS += $(OUTPUT)builtin-stat.o
 BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o
 BUILTIN_OBJS += $(OUTPUT)builtin-top.o
-BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
+BUILTIN_OBJS += $(OUTPUT)builtin-script.o
 BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
 BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
 BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
index 821c1586a22b7da92cd732ad1a4ee4e05b037085..8452a2ae21913c2033da1f59b0e233d7511885ad 100644 (file)
@@ -982,9 +982,9 @@ int cmd_lock(int argc, const char **argv, const char *prefix __used)
                                usage_with_options(report_usage, report_options);
                }
                __cmd_report();
-       } else if (!strcmp(argv[0], "trace")) {
-               /* Aliased to 'perf trace' */
-               return cmd_trace(argc, argv, prefix);
+       } else if (!strcmp(argv[0], "script")) {
+               /* Aliased to 'perf script' */
+               return cmd_script(argc, argv, prefix);
        } else if (!strcmp(argv[0], "info")) {
                if (argc) {
                        argc = parse_options(argc, argv,
index 55f3b5dcc731417198a2e5fd29ac8eefd96e1a5e..26523c9397917609047b68418b2e5034f8406846 100644 (file)
@@ -1888,10 +1888,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
                usage_with_options(sched_usage, sched_options);
 
        /*
-        * Aliased to 'perf trace' for now:
+        * Aliased to 'perf script' for now:
         */
-       if (!strcmp(argv[0], "trace"))
-               return cmd_trace(argc, argv, prefix);
+       if (!strcmp(argv[0], "script"))
+               return cmd_script(argc, argv, prefix);
 
        symbol__init();
        if (!strncmp(argv[0], "rec", 3)) {
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
new file mode 100644 (file)
index 0000000..492d19d
--- /dev/null
@@ -0,0 +1,826 @@
+#include "builtin.h"
+
+#include "perf.h"
+#include "util/cache.h"
+#include "util/debug.h"
+#include "util/exec_cmd.h"
+#include "util/header.h"
+#include "util/parse-options.h"
+#include "util/session.h"
+#include "util/symbol.h"
+#include "util/thread.h"
+#include "util/trace-event.h"
+#include "util/parse-options.h"
+#include "util/util.h"
+
+static char const              *script_name;
+static char const              *generate_script_lang;
+static bool                    debug_mode;
+static u64                     last_timestamp;
+static u64                     nr_unordered;
+extern const struct option     record_options[];
+
+static int default_start_script(const char *script __unused,
+                               int argc __unused,
+                               const char **argv __unused)
+{
+       return 0;
+}
+
+static int default_stop_script(void)
+{
+       return 0;
+}
+
+static int default_generate_script(const char *outfile __unused)
+{
+       return 0;
+}
+
+static struct scripting_ops default_scripting_ops = {
+       .start_script           = default_start_script,
+       .stop_script            = default_stop_script,
+       .process_event          = print_event,
+       .generate_script        = default_generate_script,
+};
+
+static struct scripting_ops    *scripting_ops;
+
+static void setup_scripting(void)
+{
+       setup_perl_scripting();
+       setup_python_scripting();
+
+       scripting_ops = &default_scripting_ops;
+}
+
+static int cleanup_scripting(void)
+{
+       pr_debug("\nperf script stopped\n");
+
+       return scripting_ops->stop_script();
+}
+
+static char const              *input_name = "perf.data";
+
+static int process_sample_event(event_t *event, struct perf_session *session)
+{
+       struct sample_data data;
+       struct thread *thread;
+
+       memset(&data, 0, sizeof(data));
+       data.time = -1;
+       data.cpu = -1;
+       data.period = 1;
+
+       event__parse_sample(event, session->sample_type, &data);
+
+       dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
+                   data.pid, data.tid, data.ip, data.period);
+
+       thread = perf_session__findnew(session, event->ip.pid);
+       if (thread == NULL) {
+               pr_debug("problem processing %d event, skipping it.\n",
+                        event->header.type);
+               return -1;
+       }
+
+       if (session->sample_type & PERF_SAMPLE_RAW) {
+               if (debug_mode) {
+                       if (data.time < last_timestamp) {
+                               pr_err("Samples misordered, previous: %llu "
+                                       "this: %llu\n", last_timestamp,
+                                       data.time);
+                               nr_unordered++;
+                       }
+                       last_timestamp = data.time;
+                       return 0;
+               }
+               /*
+                * FIXME: better resolve from pid from the struct trace_entry
+                * field, although it should be the same than this perf
+                * event pid
+                */
+               scripting_ops->process_event(data.cpu, data.raw_data,
+                                            data.raw_size,
+                                            data.time, thread->comm);
+       }
+
+       session->hists.stats.total_period += data.period;
+       return 0;
+}
+
+static u64 nr_lost;
+
+static int process_lost_event(event_t *event, struct perf_session *session __used)
+{
+       nr_lost += event->lost.lost;
+
+       return 0;
+}
+
+static struct perf_event_ops event_ops = {
+       .sample = process_sample_event,
+       .comm   = event__process_comm,
+       .attr   = event__process_attr,
+       .event_type = event__process_event_type,
+       .tracing_data = event__process_tracing_data,
+       .build_id = event__process_build_id,
+       .lost = process_lost_event,
+       .ordered_samples = true,
+};
+
+extern volatile int session_done;
+
+static void sig_handler(int sig __unused)
+{
+       session_done = 1;
+}
+
+static int __cmd_script(struct perf_session *session)
+{
+       int ret;
+
+       signal(SIGINT, sig_handler);
+
+       ret = perf_session__process_events(session, &event_ops);
+
+       if (debug_mode) {
+               pr_err("Misordered timestamps: %llu\n", nr_unordered);
+               pr_err("Lost events: %llu\n", nr_lost);
+       }
+
+       return ret;
+}
+
+struct script_spec {
+       struct list_head        node;
+       struct scripting_ops    *ops;
+       char                    spec[0];
+};
+
+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__delete(struct script_spec *s)
+{
+       free(s->spec);
+       free(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 struct script_spec *script_spec__findnew(const char *spec,
+                                               struct scripting_ops *ops)
+{
+       struct script_spec *s = script_spec__find(spec);
+
+       if (s)
+               return s;
+
+       s = script_spec__new(spec, ops);
+       if (!s)
+               goto out_delete_spec;
+
+       script_spec__add(s);
+
+       return s;
+
+out_delete_spec:
+       script_spec__delete(s);
+
+       return NULL;
+}
+
+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__findnew(spec, ops);
+       if (!s)
+               return -1;
+
+       return 0;
+}
+
+static struct scripting_ops *script_spec__lookup(const char *spec)
+{
+       struct script_spec *s = script_spec__find(spec);
+       if (!s)
+               return NULL;
+
+       return s->ops;
+}
+
+static void list_available_languages(void)
+{
+       struct script_spec *s;
+
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Scripting language extensions (used in "
+               "perf script -s [spec:]script.[spec]):\n\n");
+
+       list_for_each_entry(s, &script_specs, node)
+               fprintf(stderr, "  %-42s [%s]\n", s->spec, s->ops->name);
+
+       fprintf(stderr, "\n");
+}
+
+static int parse_scriptname(const struct option *opt __used,
+                           const char *str, int unset __used)
+{
+       char spec[PATH_MAX];
+       const char *script, *ext;
+       int len;
+
+       if (strcmp(str, "lang") == 0) {
+               list_available_languages();
+               exit(0);
+       }
+
+       script = strchr(str, ':');
+       if (script) {
+               len = script - str;
+               if (len >= PATH_MAX) {
+                       fprintf(stderr, "invalid language specifier");
+                       return -1;
+               }
+               strncpy(spec, str, len);
+               spec[len] = '\0';
+               scripting_ops = script_spec__lookup(spec);
+               if (!scripting_ops) {
+                       fprintf(stderr, "invalid language specifier");
+                       return -1;
+               }
+               script++;
+       } else {
+               script = str;
+               ext = strrchr(script, '.');
+               if (!ext) {
+                       fprintf(stderr, "invalid script extension");
+                       return -1;
+               }
+               scripting_ops = script_spec__lookup(++ext);
+               if (!scripting_ops) {
+                       fprintf(stderr, "invalid script extension");
+                       return -1;
+               }
+       }
+
+       script_name = strdup(script);
+
+       return 0;
+}
+
+#define for_each_lang(scripts_dir, lang_dirent, lang_next)             \
+       while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) &&     \
+              lang_next)                                               \
+               if (lang_dirent.d_type == DT_DIR &&                     \
+                   (strcmp(lang_dirent.d_name, ".")) &&                \
+                   (strcmp(lang_dirent.d_name, "..")))
+
+#define for_each_script(lang_dir, script_dirent, script_next)          \
+       while (!readdir_r(lang_dir, &script_dirent, &script_next) &&    \
+              script_next)                                             \
+               if (script_dirent.d_type != DT_DIR)
+
+
+#define RECORD_SUFFIX                  "-record"
+#define REPORT_SUFFIX                  "-report"
+
+struct script_desc {
+       struct list_head        node;
+       char                    *name;
+       char                    *half_liner;
+       char                    *args;
+};
+
+LIST_HEAD(script_descs);
+
+static struct script_desc *script_desc__new(const char *name)
+{
+       struct script_desc *s = zalloc(sizeof(*s));
+
+       if (s != NULL && name)
+               s->name = strdup(name);
+
+       return s;
+}
+
+static void script_desc__delete(struct script_desc *s)
+{
+       free(s->name);
+       free(s->half_liner);
+       free(s->args);
+       free(s);
+}
+
+static void script_desc__add(struct script_desc *s)
+{
+       list_add_tail(&s->node, &script_descs);
+}
+
+static struct script_desc *script_desc__find(const char *name)
+{
+       struct script_desc *s;
+
+       list_for_each_entry(s, &script_descs, node)
+               if (strcasecmp(s->name, name) == 0)
+                       return s;
+       return NULL;
+}
+
+static struct script_desc *script_desc__findnew(const char *name)
+{
+       struct script_desc *s = script_desc__find(name);
+
+       if (s)
+               return s;
+
+       s = script_desc__new(name);
+       if (!s)
+               goto out_delete_desc;
+
+       script_desc__add(s);
+
+       return s;
+
+out_delete_desc:
+       script_desc__delete(s);
+
+       return NULL;
+}
+
+static char *ends_with(char *str, const char *suffix)
+{
+       size_t suffix_len = strlen(suffix);
+       char *p = str;
+
+       if (strlen(str) > suffix_len) {
+               p = str + strlen(str) - suffix_len;
+               if (!strncmp(p, suffix, suffix_len))
+                       return p;
+       }
+
+       return NULL;
+}
+
+static char *ltrim(char *str)
+{
+       int len = strlen(str);
+
+       while (len && isspace(*str)) {
+               len--;
+               str++;
+       }
+
+       return str;
+}
+
+static int read_script_info(struct script_desc *desc, const char *filename)
+{
+       char line[BUFSIZ], *p;
+       FILE *fp;
+
+       fp = fopen(filename, "r");
+       if (!fp)
+               return -1;
+
+       while (fgets(line, sizeof(line), fp)) {
+               p = ltrim(line);
+               if (strlen(p) == 0)
+                       continue;
+               if (*p != '#')
+                       continue;
+               p++;
+               if (strlen(p) && *p == '!')
+                       continue;
+
+               p = ltrim(p);
+               if (strlen(p) && p[strlen(p) - 1] == '\n')
+                       p[strlen(p) - 1] = '\0';
+
+               if (!strncmp(p, "description:", strlen("description:"))) {
+                       p += strlen("description:");
+                       desc->half_liner = strdup(ltrim(p));
+                       continue;
+               }
+
+               if (!strncmp(p, "args:", strlen("args:"))) {
+                       p += strlen("args:");
+                       desc->args = strdup(ltrim(p));
+                       continue;
+               }
+       }
+
+       fclose(fp);
+
+       return 0;
+}
+
+static int list_available_scripts(const struct option *opt __used,
+                                 const char *s __used, int unset __used)
+{
+       struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
+       char scripts_path[MAXPATHLEN];
+       DIR *scripts_dir, *lang_dir;
+       char script_path[MAXPATHLEN];
+       char lang_path[MAXPATHLEN];
+       struct script_desc *desc;
+       char first_half[BUFSIZ];
+       char *script_root;
+       char *str;
+
+       snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
+
+       scripts_dir = opendir(scripts_path);
+       if (!scripts_dir)
+               return -1;
+
+       for_each_lang(scripts_dir, lang_dirent, lang_next) {
+               snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
+                        lang_dirent.d_name);
+               lang_dir = opendir(lang_path);
+               if (!lang_dir)
+                       continue;
+
+               for_each_script(lang_dir, script_dirent, script_next) {
+                       script_root = strdup(script_dirent.d_name);
+                       str = ends_with(script_root, REPORT_SUFFIX);
+                       if (str) {
+                               *str = '\0';
+                               desc = script_desc__findnew(script_root);
+                               snprintf(script_path, MAXPATHLEN, "%s/%s",
+                                        lang_path, script_dirent.d_name);
+                               read_script_info(desc, script_path);
+                       }
+                       free(script_root);
+               }
+       }
+
+       fprintf(stdout, "List of available trace scripts:\n");
+       list_for_each_entry(desc, &script_descs, node) {
+               sprintf(first_half, "%s %s", desc->name,
+                       desc->args ? desc->args : "");
+               fprintf(stdout, "  %-36s %s\n", first_half,
+                       desc->half_liner ? desc->half_liner : "");
+       }
+
+       exit(0);
+}
+
+static char *get_script_path(const char *script_root, const char *suffix)
+{
+       struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
+       char scripts_path[MAXPATHLEN];
+       char script_path[MAXPATHLEN];
+       DIR *scripts_dir, *lang_dir;
+       char lang_path[MAXPATHLEN];
+       char *str, *__script_root;
+       char *path = NULL;
+
+       snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
+
+       scripts_dir = opendir(scripts_path);
+       if (!scripts_dir)
+               return NULL;
+
+       for_each_lang(scripts_dir, lang_dirent, lang_next) {
+               snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
+                        lang_dirent.d_name);
+               lang_dir = opendir(lang_path);
+               if (!lang_dir)
+                       continue;
+
+               for_each_script(lang_dir, script_dirent, script_next) {
+                       __script_root = strdup(script_dirent.d_name);
+                       str = ends_with(__script_root, suffix);
+                       if (str) {
+                               *str = '\0';
+                               if (strcmp(__script_root, script_root))
+                                       continue;
+                               snprintf(script_path, MAXPATHLEN, "%s/%s",
+                                        lang_path, script_dirent.d_name);
+                               path = strdup(script_path);
+                               free(__script_root);
+                               break;
+                       }
+                       free(__script_root);
+               }
+       }
+
+       return path;
+}
+
+static bool is_top_script(const char *script_path)
+{
+       return ends_with((char *)script_path, "top") == NULL ? false : true;
+}
+
+static int has_required_arg(char *script_path)
+{
+       struct script_desc *desc;
+       int n_args = 0;
+       char *p;
+
+       desc = script_desc__new(NULL);
+
+       if (read_script_info(desc, script_path))
+               goto out;
+
+       if (!desc->args)
+               goto out;
+
+       for (p = desc->args; *p; p++)
+               if (*p == '<')
+                       n_args++;
+out:
+       script_desc__delete(desc);
+
+       return n_args;
+}
+
+static const char * const script_usage[] = {
+       "perf script [<options>]",
+       "perf script [<options>] record <script> [<record-options>] <command>",
+       "perf script [<options>] report <script> [script-args]",
+       "perf script [<options>] <script> [<record-options>] <command>",
+       "perf script [<options>] <top-script> [script-args]",
+       NULL
+};
+
+static const struct option options[] = {
+       OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
+                   "dump raw trace in ASCII"),
+       OPT_INCR('v', "verbose", &verbose,
+                   "be more verbose (show symbol address, etc)"),
+       OPT_BOOLEAN('L', "Latency", &latency_format,
+                   "show latency attributes (irqs/preemption disabled, etc)"),
+       OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
+                          list_available_scripts),
+       OPT_CALLBACK('s', "script", NULL, "name",
+                    "script file name (lang:script name, script name, or *)",
+                    parse_scriptname),
+       OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
+                  "generate perf-script.xx script in specified language"),
+       OPT_STRING('i', "input", &input_name, "file",
+                   "input file name"),
+       OPT_BOOLEAN('d', "debug-mode", &debug_mode,
+                  "do various checks like samples ordering and lost events"),
+
+       OPT_END()
+};
+
+static bool have_cmd(int argc, const char **argv)
+{
+       char **__argv = malloc(sizeof(const char *) * argc);
+
+       if (!__argv)
+               die("malloc");
+       memcpy(__argv, argv, sizeof(const char *) * argc);
+       argc = parse_options(argc, (const char **)__argv, record_options,
+                            NULL, PARSE_OPT_STOP_AT_NON_OPTION);
+       free(__argv);
+
+       return argc != 0;
+}
+
+int cmd_script(int argc, const char **argv, const char *prefix __used)
+{
+       char *rec_script_path = NULL;
+       char *rep_script_path = NULL;
+       struct perf_session *session;
+       char *script_path = NULL;
+       const char **__argv;
+       bool system_wide;
+       int i, j, err;
+
+       setup_scripting();
+
+       argc = parse_options(argc, argv, options, script_usage,
+                            PARSE_OPT_STOP_AT_NON_OPTION);
+
+       if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
+               rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
+               if (!rec_script_path)
+                       return cmd_record(argc, argv, NULL);
+       }
+
+       if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) {
+               rep_script_path = get_script_path(argv[1], REPORT_SUFFIX);
+               if (!rep_script_path) {
+                       fprintf(stderr,
+                               "Please specify a valid report script"
+                               "(see 'perf script -l' for listing)\n");
+                       return -1;
+               }
+       }
+
+       /* make sure PERF_EXEC_PATH is set for scripts */
+       perf_set_argv_exec_path(perf_exec_path());
+
+       if (argc && !script_name && !rec_script_path && !rep_script_path) {
+               int live_pipe[2];
+               int rep_args;
+               pid_t pid;
+
+               rec_script_path = get_script_path(argv[0], RECORD_SUFFIX);
+               rep_script_path = get_script_path(argv[0], REPORT_SUFFIX);
+
+               if (!rec_script_path && !rep_script_path) {
+                       fprintf(stderr, " Couldn't find script %s\n\n See perf"
+                               " script -l for available scripts.\n", argv[0]);
+                       usage_with_options(script_usage, options);
+               }
+
+               if (is_top_script(argv[0])) {
+                       rep_args = argc - 1;
+               } else {
+                       int rec_args;
+
+                       rep_args = has_required_arg(rep_script_path);
+                       rec_args = (argc - 1) - rep_args;
+                       if (rec_args < 0) {
+                               fprintf(stderr, " %s script requires options."
+                                       "\n\n See perf script -l for available "
+                                       "scripts and options.\n", argv[0]);
+                               usage_with_options(script_usage, options);
+                       }
+               }
+
+               if (pipe(live_pipe) < 0) {
+                       perror("failed to create pipe");
+                       exit(-1);
+               }
+
+               pid = fork();
+               if (pid < 0) {
+                       perror("failed to fork");
+                       exit(-1);
+               }
+
+               if (!pid) {
+                       system_wide = true;
+                       j = 0;
+
+                       dup2(live_pipe[1], 1);
+                       close(live_pipe[0]);
+
+                       if (!is_top_script(argv[0]))
+                               system_wide = !have_cmd(argc - rep_args,
+                                                       &argv[rep_args]);
+
+                       __argv = malloc((argc + 6) * sizeof(const char *));
+                       if (!__argv)
+                               die("malloc");
+
+                       __argv[j++] = "/bin/sh";
+                       __argv[j++] = rec_script_path;
+                       if (system_wide)
+                               __argv[j++] = "-a";
+                       __argv[j++] = "-q";
+                       __argv[j++] = "-o";
+                       __argv[j++] = "-";
+                       for (i = rep_args + 1; i < argc; i++)
+                               __argv[j++] = argv[i];
+                       __argv[j++] = NULL;
+
+                       execvp("/bin/sh", (char **)__argv);
+                       free(__argv);
+                       exit(-1);
+               }
+
+               dup2(live_pipe[0], 0);
+               close(live_pipe[1]);
+
+               __argv = malloc((argc + 4) * sizeof(const char *));
+               if (!__argv)
+                       die("malloc");
+               j = 0;
+               __argv[j++] = "/bin/sh";
+               __argv[j++] = rep_script_path;
+               for (i = 1; i < rep_args + 1; i++)
+                       __argv[j++] = argv[i];
+               __argv[j++] = "-i";
+               __argv[j++] = "-";
+               __argv[j++] = NULL;
+
+               execvp("/bin/sh", (char **)__argv);
+               free(__argv);
+               exit(-1);
+       }
+
+       if (rec_script_path)
+               script_path = rec_script_path;
+       if (rep_script_path)
+               script_path = rep_script_path;
+
+       if (script_path) {
+               system_wide = false;
+               j = 0;
+
+               if (rec_script_path)
+                       system_wide = !have_cmd(argc - 1, &argv[1]);
+
+               __argv = malloc((argc + 2) * sizeof(const char *));
+               if (!__argv)
+                       die("malloc");
+               __argv[j++] = "/bin/sh";
+               __argv[j++] = script_path;
+               if (system_wide)
+                       __argv[j++] = "-a";
+               for (i = 2; i < argc; i++)
+                       __argv[j++] = argv[i];
+               __argv[j++] = NULL;
+
+               execvp("/bin/sh", (char **)__argv);
+               free(__argv);
+               exit(-1);
+       }
+
+       if (symbol__init() < 0)
+               return -1;
+       if (!script_name)
+               setup_pager();
+
+       session = perf_session__new(input_name, O_RDONLY, 0, false);
+       if (session == NULL)
+               return -ENOMEM;
+
+       if (strcmp(input_name, "-") &&
+           !perf_session__has_traces(session, "record -R"))
+               return -EINVAL;
+
+       if (generate_script_lang) {
+               struct stat perf_stat;
+
+               int input = open(input_name, O_RDONLY);
+               if (input < 0) {
+                       perror("failed to open file");
+                       exit(-1);
+               }
+
+               err = fstat(input, &perf_stat);
+               if (err < 0) {
+                       perror("failed to stat file");
+                       exit(-1);
+               }
+
+               if (!perf_stat.st_size) {
+                       fprintf(stderr, "zero-sized file, nothing to do!\n");
+                       exit(0);
+               }
+
+               scripting_ops = script_spec__lookup(generate_script_lang);
+               if (!scripting_ops) {
+                       fprintf(stderr, "invalid language specifier");
+                       return -1;
+               }
+
+               err = scripting_ops->generate_script("perf-script");
+               goto out;
+       }
+
+       if (script_name) {
+               err = scripting_ops->start_script(script_name, argc, argv);
+               if (err)
+                       goto out;
+               pr_debug("perf script started with script %s\n\n", script_name);
+       }
+
+       err = __cmd_script(session);
+
+       perf_session__delete(session);
+       cleanup_scripting();
+out:
+       return err;
+}
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
deleted file mode 100644 (file)
index 86cfe38..0000000
+++ /dev/null
@@ -1,826 +0,0 @@
-#include "builtin.h"
-
-#include "perf.h"
-#include "util/cache.h"
-#include "util/debug.h"
-#include "util/exec_cmd.h"
-#include "util/header.h"
-#include "util/parse-options.h"
-#include "util/session.h"
-#include "util/symbol.h"
-#include "util/thread.h"
-#include "util/trace-event.h"
-#include "util/parse-options.h"
-#include "util/util.h"
-
-static char const              *script_name;
-static char const              *generate_script_lang;
-static bool                    debug_mode;
-static u64                     last_timestamp;
-static u64                     nr_unordered;
-extern const struct option     record_options[];
-
-static int default_start_script(const char *script __unused,
-                               int argc __unused,
-                               const char **argv __unused)
-{
-       return 0;
-}
-
-static int default_stop_script(void)
-{
-       return 0;
-}
-
-static int default_generate_script(const char *outfile __unused)
-{
-       return 0;
-}
-
-static struct scripting_ops default_scripting_ops = {
-       .start_script           = default_start_script,
-       .stop_script            = default_stop_script,
-       .process_event          = print_event,
-       .generate_script        = default_generate_script,
-};
-
-static struct scripting_ops    *scripting_ops;
-
-static void setup_scripting(void)
-{
-       setup_perl_scripting();
-       setup_python_scripting();
-
-       scripting_ops = &default_scripting_ops;
-}
-
-static int cleanup_scripting(void)
-{
-       pr_debug("\nperf trace script stopped\n");
-
-       return scripting_ops->stop_script();
-}
-
-static char const              *input_name = "perf.data";
-
-static int process_sample_event(event_t *event, struct perf_session *session)
-{
-       struct sample_data data;
-       struct thread *thread;
-
-       memset(&data, 0, sizeof(data));
-       data.time = -1;
-       data.cpu = -1;
-       data.period = 1;
-
-       event__parse_sample(event, session->sample_type, &data);
-
-       dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
-                   data.pid, data.tid, data.ip, data.period);
-
-       thread = perf_session__findnew(session, event->ip.pid);
-       if (thread == NULL) {
-               pr_debug("problem processing %d event, skipping it.\n",
-                        event->header.type);
-               return -1;
-       }
-
-       if (session->sample_type & PERF_SAMPLE_RAW) {
-               if (debug_mode) {
-                       if (data.time < last_timestamp) {
-                               pr_err("Samples misordered, previous: %llu "
-                                       "this: %llu\n", last_timestamp,
-                                       data.time);
-                               nr_unordered++;
-                       }
-                       last_timestamp = data.time;
-                       return 0;
-               }
-               /*
-                * FIXME: better resolve from pid from the struct trace_entry
-                * field, although it should be the same than this perf
-                * event pid
-                */
-               scripting_ops->process_event(data.cpu, data.raw_data,
-                                            data.raw_size,
-                                            data.time, thread->comm);
-       }
-
-       session->hists.stats.total_period += data.period;
-       return 0;
-}
-
-static u64 nr_lost;
-
-static int process_lost_event(event_t *event, struct perf_session *session __used)
-{
-       nr_lost += event->lost.lost;
-
-       return 0;
-}
-
-static struct perf_event_ops event_ops = {
-       .sample = process_sample_event,
-       .comm   = event__process_comm,
-       .attr   = event__process_attr,
-       .event_type = event__process_event_type,
-       .tracing_data = event__process_tracing_data,
-       .build_id = event__process_build_id,
-       .lost = process_lost_event,
-       .ordered_samples = true,
-};
-
-extern volatile int session_done;
-
-static void sig_handler(int sig __unused)
-{
-       session_done = 1;
-}
-
-static int __cmd_trace(struct perf_session *session)
-{
-       int ret;
-
-       signal(SIGINT, sig_handler);
-
-       ret = perf_session__process_events(session, &event_ops);
-
-       if (debug_mode) {
-               pr_err("Misordered timestamps: %llu\n", nr_unordered);
-               pr_err("Lost events: %llu\n", nr_lost);
-       }
-
-       return ret;
-}
-
-struct script_spec {
-       struct list_head        node;
-       struct scripting_ops    *ops;
-       char                    spec[0];
-};
-
-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__delete(struct script_spec *s)
-{
-       free(s->spec);
-       free(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 struct script_spec *script_spec__findnew(const char *spec,
-                                               struct scripting_ops *ops)
-{
-       struct script_spec *s = script_spec__find(spec);
-
-       if (s)
-               return s;
-
-       s = script_spec__new(spec, ops);
-       if (!s)
-               goto out_delete_spec;
-
-       script_spec__add(s);
-
-       return s;
-
-out_delete_spec:
-       script_spec__delete(s);
-
-       return NULL;
-}
-
-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__findnew(spec, ops);
-       if (!s)
-               return -1;
-
-       return 0;
-}
-
-static struct scripting_ops *script_spec__lookup(const char *spec)
-{
-       struct script_spec *s = script_spec__find(spec);
-       if (!s)
-               return NULL;
-
-       return s->ops;
-}
-
-static void list_available_languages(void)
-{
-       struct script_spec *s;
-
-       fprintf(stderr, "\n");
-       fprintf(stderr, "Scripting language extensions (used in "
-               "perf trace -s [spec:]script.[spec]):\n\n");
-
-       list_for_each_entry(s, &script_specs, node)
-               fprintf(stderr, "  %-42s [%s]\n", s->spec, s->ops->name);
-
-       fprintf(stderr, "\n");
-}
-
-static int parse_scriptname(const struct option *opt __used,
-                           const char *str, int unset __used)
-{
-       char spec[PATH_MAX];
-       const char *script, *ext;
-       int len;
-
-       if (strcmp(str, "lang") == 0) {
-               list_available_languages();
-               exit(0);
-       }
-
-       script = strchr(str, ':');
-       if (script) {
-               len = script - str;
-               if (len >= PATH_MAX) {
-                       fprintf(stderr, "invalid language specifier");
-                       return -1;
-               }
-               strncpy(spec, str, len);
-               spec[len] = '\0';
-               scripting_ops = script_spec__lookup(spec);
-               if (!scripting_ops) {
-                       fprintf(stderr, "invalid language specifier");
-                       return -1;
-               }
-               script++;
-       } else {
-               script = str;
-               ext = strrchr(script, '.');
-               if (!ext) {
-                       fprintf(stderr, "invalid script extension");
-                       return -1;
-               }
-               scripting_ops = script_spec__lookup(++ext);
-               if (!scripting_ops) {
-                       fprintf(stderr, "invalid script extension");
-                       return -1;
-               }
-       }
-
-       script_name = strdup(script);
-
-       return 0;
-}
-
-#define for_each_lang(scripts_dir, lang_dirent, lang_next)             \
-       while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) &&     \
-              lang_next)                                               \
-               if (lang_dirent.d_type == DT_DIR &&                     \
-                   (strcmp(lang_dirent.d_name, ".")) &&                \
-                   (strcmp(lang_dirent.d_name, "..")))
-
-#define for_each_script(lang_dir, script_dirent, script_next)          \
-       while (!readdir_r(lang_dir, &script_dirent, &script_next) &&    \
-              script_next)                                             \
-               if (script_dirent.d_type != DT_DIR)
-
-
-#define RECORD_SUFFIX                  "-record"
-#define REPORT_SUFFIX                  "-report"
-
-struct script_desc {
-       struct list_head        node;
-       char                    *name;
-       char                    *half_liner;
-       char                    *args;
-};
-
-LIST_HEAD(script_descs);
-
-static struct script_desc *script_desc__new(const char *name)
-{
-       struct script_desc *s = zalloc(sizeof(*s));
-
-       if (s != NULL && name)
-               s->name = strdup(name);
-
-       return s;
-}
-
-static void script_desc__delete(struct script_desc *s)
-{
-       free(s->name);
-       free(s->half_liner);
-       free(s->args);
-       free(s);
-}
-
-static void script_desc__add(struct script_desc *s)
-{
-       list_add_tail(&s->node, &script_descs);
-}
-
-static struct script_desc *script_desc__find(const char *name)
-{
-       struct script_desc *s;
-
-       list_for_each_entry(s, &script_descs, node)
-               if (strcasecmp(s->name, name) == 0)
-                       return s;
-       return NULL;
-}
-
-static struct script_desc *script_desc__findnew(const char *name)
-{
-       struct script_desc *s = script_desc__find(name);
-
-       if (s)
-               return s;
-
-       s = script_desc__new(name);
-       if (!s)
-               goto out_delete_desc;
-
-       script_desc__add(s);
-
-       return s;
-
-out_delete_desc:
-       script_desc__delete(s);
-
-       return NULL;
-}
-
-static char *ends_with(char *str, const char *suffix)
-{
-       size_t suffix_len = strlen(suffix);
-       char *p = str;
-
-       if (strlen(str) > suffix_len) {
-               p = str + strlen(str) - suffix_len;
-               if (!strncmp(p, suffix, suffix_len))
-                       return p;
-       }
-
-       return NULL;
-}
-
-static char *ltrim(char *str)
-{
-       int len = strlen(str);
-
-       while (len && isspace(*str)) {
-               len--;
-               str++;
-       }
-
-       return str;
-}
-
-static int read_script_info(struct script_desc *desc, const char *filename)
-{
-       char line[BUFSIZ], *p;
-       FILE *fp;
-
-       fp = fopen(filename, "r");
-       if (!fp)
-               return -1;
-
-       while (fgets(line, sizeof(line), fp)) {
-               p = ltrim(line);
-               if (strlen(p) == 0)
-                       continue;
-               if (*p != '#')
-                       continue;
-               p++;
-               if (strlen(p) && *p == '!')
-                       continue;
-
-               p = ltrim(p);
-               if (strlen(p) && p[strlen(p) - 1] == '\n')
-                       p[strlen(p) - 1] = '\0';
-
-               if (!strncmp(p, "description:", strlen("description:"))) {
-                       p += strlen("description:");
-                       desc->half_liner = strdup(ltrim(p));
-                       continue;
-               }
-
-               if (!strncmp(p, "args:", strlen("args:"))) {
-                       p += strlen("args:");
-                       desc->args = strdup(ltrim(p));
-                       continue;
-               }
-       }
-
-       fclose(fp);
-
-       return 0;
-}
-
-static int list_available_scripts(const struct option *opt __used,
-                                 const char *s __used, int unset __used)
-{
-       struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
-       char scripts_path[MAXPATHLEN];
-       DIR *scripts_dir, *lang_dir;
-       char script_path[MAXPATHLEN];
-       char lang_path[MAXPATHLEN];
-       struct script_desc *desc;
-       char first_half[BUFSIZ];
-       char *script_root;
-       char *str;
-
-       snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
-
-       scripts_dir = opendir(scripts_path);
-       if (!scripts_dir)
-               return -1;
-
-       for_each_lang(scripts_dir, lang_dirent, lang_next) {
-               snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
-                        lang_dirent.d_name);
-               lang_dir = opendir(lang_path);
-               if (!lang_dir)
-                       continue;
-
-               for_each_script(lang_dir, script_dirent, script_next) {
-                       script_root = strdup(script_dirent.d_name);
-                       str = ends_with(script_root, REPORT_SUFFIX);
-                       if (str) {
-                               *str = '\0';
-                               desc = script_desc__findnew(script_root);
-                               snprintf(script_path, MAXPATHLEN, "%s/%s",
-                                        lang_path, script_dirent.d_name);
-                               read_script_info(desc, script_path);
-                       }
-                       free(script_root);
-               }
-       }
-
-       fprintf(stdout, "List of available trace scripts:\n");
-       list_for_each_entry(desc, &script_descs, node) {
-               sprintf(first_half, "%s %s", desc->name,
-                       desc->args ? desc->args : "");
-               fprintf(stdout, "  %-36s %s\n", first_half,
-                       desc->half_liner ? desc->half_liner : "");
-       }
-
-       exit(0);
-}
-
-static char *get_script_path(const char *script_root, const char *suffix)
-{
-       struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
-       char scripts_path[MAXPATHLEN];
-       char script_path[MAXPATHLEN];
-       DIR *scripts_dir, *lang_dir;
-       char lang_path[MAXPATHLEN];
-       char *str, *__script_root;
-       char *path = NULL;
-
-       snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
-
-       scripts_dir = opendir(scripts_path);
-       if (!scripts_dir)
-               return NULL;
-
-       for_each_lang(scripts_dir, lang_dirent, lang_next) {
-               snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
-                        lang_dirent.d_name);
-               lang_dir = opendir(lang_path);
-               if (!lang_dir)
-                       continue;
-
-               for_each_script(lang_dir, script_dirent, script_next) {
-                       __script_root = strdup(script_dirent.d_name);
-                       str = ends_with(__script_root, suffix);
-                       if (str) {
-                               *str = '\0';
-                               if (strcmp(__script_root, script_root))
-                                       continue;
-                               snprintf(script_path, MAXPATHLEN, "%s/%s",
-                                        lang_path, script_dirent.d_name);
-                               path = strdup(script_path);
-                               free(__script_root);
-                               break;
-                       }
-                       free(__script_root);
-               }
-       }
-
-       return path;
-}
-
-static bool is_top_script(const char *script_path)
-{
-       return ends_with((char *)script_path, "top") == NULL ? false : true;
-}
-
-static int has_required_arg(char *script_path)
-{
-       struct script_desc *desc;
-       int n_args = 0;
-       char *p;
-
-       desc = script_desc__new(NULL);
-
-       if (read_script_info(desc, script_path))
-               goto out;
-
-       if (!desc->args)
-               goto out;
-
-       for (p = desc->args; *p; p++)
-               if (*p == '<')
-                       n_args++;
-out:
-       script_desc__delete(desc);
-
-       return n_args;
-}
-
-static const char * const trace_usage[] = {
-       "perf trace [<options>]",
-       "perf trace [<options>] record <script> [<record-options>] <command>",
-       "perf trace [<options>] report <script> [script-args]",
-       "perf trace [<options>] <script> [<record-options>] <command>",
-       "perf trace [<options>] <top-script> [script-args]",
-       NULL
-};
-
-static const struct option options[] = {
-       OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
-                   "dump raw trace in ASCII"),
-       OPT_INCR('v', "verbose", &verbose,
-                   "be more verbose (show symbol address, etc)"),
-       OPT_BOOLEAN('L', "Latency", &latency_format,
-                   "show latency attributes (irqs/preemption disabled, etc)"),
-       OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
-                          list_available_scripts),
-       OPT_CALLBACK('s', "script", NULL, "name",
-                    "script file name (lang:script name, script name, or *)",
-                    parse_scriptname),
-       OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
-                  "generate perf-trace.xx script in specified language"),
-       OPT_STRING('i', "input", &input_name, "file",
-                   "input file name"),
-       OPT_BOOLEAN('d', "debug-mode", &debug_mode,
-                  "do various checks like samples ordering and lost events"),
-
-       OPT_END()
-};
-
-static bool have_cmd(int argc, const char **argv)
-{
-       char **__argv = malloc(sizeof(const char *) * argc);
-
-       if (!__argv)
-               die("malloc");
-       memcpy(__argv, argv, sizeof(const char *) * argc);
-       argc = parse_options(argc, (const char **)__argv, record_options,
-                            NULL, PARSE_OPT_STOP_AT_NON_OPTION);
-       free(__argv);
-
-       return argc != 0;
-}
-
-int cmd_trace(int argc, const char **argv, const char *prefix __used)
-{
-       char *rec_script_path = NULL;
-       char *rep_script_path = NULL;
-       struct perf_session *session;
-       char *script_path = NULL;
-       const char **__argv;
-       bool system_wide;
-       int i, j, err;
-
-       setup_scripting();
-
-       argc = parse_options(argc, argv, options, trace_usage,
-                            PARSE_OPT_STOP_AT_NON_OPTION);
-
-       if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
-               rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
-               if (!rec_script_path)
-                       return cmd_record(argc, argv, NULL);
-       }
-
-       if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) {
-               rep_script_path = get_script_path(argv[1], REPORT_SUFFIX);
-               if (!rep_script_path) {
-                       fprintf(stderr,
-                               "Please specify a valid report script"
-                               "(see 'perf trace -l' for listing)\n");
-                       return -1;
-               }
-       }
-
-       /* make sure PERF_EXEC_PATH is set for scripts */
-       perf_set_argv_exec_path(perf_exec_path());
-
-       if (argc && !script_name && !rec_script_path && !rep_script_path) {
-               int live_pipe[2];
-               int rep_args;
-               pid_t pid;
-
-               rec_script_path = get_script_path(argv[0], RECORD_SUFFIX);
-               rep_script_path = get_script_path(argv[0], REPORT_SUFFIX);
-
-               if (!rec_script_path && !rep_script_path) {
-                       fprintf(stderr, " Couldn't find script %s\n\n See perf"
-                               " trace -l for available scripts.\n", argv[0]);
-                       usage_with_options(trace_usage, options);
-               }
-
-               if (is_top_script(argv[0])) {
-                       rep_args = argc - 1;
-               } else {
-                       int rec_args;
-
-                       rep_args = has_required_arg(rep_script_path);
-                       rec_args = (argc - 1) - rep_args;
-                       if (rec_args < 0) {
-                               fprintf(stderr, " %s script requires options."
-                                       "\n\n See perf trace -l for available "
-                                       "scripts and options.\n", argv[0]);
-                               usage_with_options(trace_usage, options);
-                       }
-               }
-
-               if (pipe(live_pipe) < 0) {
-                       perror("failed to create pipe");
-                       exit(-1);
-               }
-
-               pid = fork();
-               if (pid < 0) {
-                       perror("failed to fork");
-                       exit(-1);
-               }
-
-               if (!pid) {
-                       system_wide = true;
-                       j = 0;
-
-                       dup2(live_pipe[1], 1);
-                       close(live_pipe[0]);
-
-                       if (!is_top_script(argv[0]))
-                               system_wide = !have_cmd(argc - rep_args,
-                                                       &argv[rep_args]);
-
-                       __argv = malloc((argc + 6) * sizeof(const char *));
-                       if (!__argv)
-                               die("malloc");
-
-                       __argv[j++] = "/bin/sh";
-                       __argv[j++] = rec_script_path;
-                       if (system_wide)
-                               __argv[j++] = "-a";
-                       __argv[j++] = "-q";
-                       __argv[j++] = "-o";
-                       __argv[j++] = "-";
-                       for (i = rep_args + 1; i < argc; i++)
-                               __argv[j++] = argv[i];
-                       __argv[j++] = NULL;
-
-                       execvp("/bin/sh", (char **)__argv);
-                       free(__argv);
-                       exit(-1);
-               }
-
-               dup2(live_pipe[0], 0);
-               close(live_pipe[1]);
-
-               __argv = malloc((argc + 4) * sizeof(const char *));
-               if (!__argv)
-                       die("malloc");
-               j = 0;
-               __argv[j++] = "/bin/sh";
-               __argv[j++] = rep_script_path;
-               for (i = 1; i < rep_args + 1; i++)
-                       __argv[j++] = argv[i];
-               __argv[j++] = "-i";
-               __argv[j++] = "-";
-               __argv[j++] = NULL;
-
-               execvp("/bin/sh", (char **)__argv);
-               free(__argv);
-               exit(-1);
-       }
-
-       if (rec_script_path)
-               script_path = rec_script_path;
-       if (rep_script_path)
-               script_path = rep_script_path;
-
-       if (script_path) {
-               system_wide = false;
-               j = 0;
-
-               if (rec_script_path)
-                       system_wide = !have_cmd(argc - 1, &argv[1]);
-
-               __argv = malloc((argc + 2) * sizeof(const char *));
-               if (!__argv)
-                       die("malloc");
-               __argv[j++] = "/bin/sh";
-               __argv[j++] = script_path;
-               if (system_wide)
-                       __argv[j++] = "-a";
-               for (i = 2; i < argc; i++)
-                       __argv[j++] = argv[i];
-               __argv[j++] = NULL;
-
-               execvp("/bin/sh", (char **)__argv);
-               free(__argv);
-               exit(-1);
-       }
-
-       if (symbol__init() < 0)
-               return -1;
-       if (!script_name)
-               setup_pager();
-
-       session = perf_session__new(input_name, O_RDONLY, 0, false);
-       if (session == NULL)
-               return -ENOMEM;
-
-       if (strcmp(input_name, "-") &&
-           !perf_session__has_traces(session, "record -R"))
-               return -EINVAL;
-
-       if (generate_script_lang) {
-               struct stat perf_stat;
-
-               int input = open(input_name, O_RDONLY);
-               if (input < 0) {
-                       perror("failed to open file");
-                       exit(-1);
-               }
-
-               err = fstat(input, &perf_stat);
-               if (err < 0) {
-                       perror("failed to stat file");
-                       exit(-1);
-               }
-
-               if (!perf_stat.st_size) {
-                       fprintf(stderr, "zero-sized file, nothing to do!\n");
-                       exit(0);
-               }
-
-               scripting_ops = script_spec__lookup(generate_script_lang);
-               if (!scripting_ops) {
-                       fprintf(stderr, "invalid language specifier");
-                       return -1;
-               }
-
-               err = scripting_ops->generate_script("perf-trace");
-               goto out;
-       }
-
-       if (script_name) {
-               err = scripting_ops->start_script(script_name, argc, argv);
-               if (err)
-                       goto out;
-               pr_debug("perf trace started with script %s\n\n", script_name);
-       }
-
-       err = __cmd_trace(session);
-
-       perf_session__delete(session);
-       cleanup_scripting();
-out:
-       return err;
-}
index 921245b28583e448cce49008b2482e0f59193454..c7798c7f24ed737f03a4376485be5a2e14b3aef4 100644 (file)
@@ -27,7 +27,7 @@ extern int cmd_report(int argc, const char **argv, const char *prefix);
 extern int cmd_stat(int argc, const char **argv, const char *prefix);
 extern int cmd_timechart(int argc, const char **argv, const char *prefix);
 extern int cmd_top(int argc, const char **argv, const char *prefix);
-extern int cmd_trace(int argc, const char **argv, const char *prefix);
+extern int cmd_script(int argc, const char **argv, const char *prefix);
 extern int cmd_version(int argc, const char **argv, const char *prefix);
 extern int cmd_probe(int argc, const char **argv, const char *prefix);
 extern int cmd_kmem(int argc, const char **argv, const char *prefix);
index cdd6c03f1e14c132e550b85e07b22e7621a710d2..595d0f4a7103eb45ccac7b5ad47fd3ebfee8ab0d 100644 (file)
@@ -323,7 +323,7 @@ static void handle_internal_command(int argc, const char **argv)
                { "top",        cmd_top,        0 },
                { "annotate",   cmd_annotate,   0 },
                { "version",    cmd_version,    0 },
-               { "trace",      cmd_trace,      0 },
+               { "script",     cmd_script,     0 },
                { "sched",      cmd_sched,      0 },
                { "probe",      cmd_probe,      0 },
                { "kmem",       cmd_kmem,       0 },
index 957085dd5d8d1a2ff17ee4bb6ad3c3160f8df508..315067b8f5522ae9cafbef1df506aca814e93012 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Context.c.  Python interfaces for perf trace.
+ * Context.c.  Python interfaces for perf script.
  *
  * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com>
  *
index b059dc50cc2db9021b75435e9aac132174c6dbec..93680818e244ca8a2e58f49e59af0ca729eeb50e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * trace-event-perl.  Feed perf trace events to an embedded Perl interpreter.
+ * trace-event-perl.  Feed perf script events to an embedded Perl interpreter.
  *
  * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
  *
@@ -411,8 +411,8 @@ static int perl_generate_script(const char *outfile)
                return -1;
        }
 
-       fprintf(ofp, "# perf trace event handlers, "
-               "generated by perf trace -g perl\n");
+       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");
index 33a632523743deff80cb9e3636bd9144b84b2f76..c6d99334bdfa836c1adba2d613b658fadf20797b 100644 (file)
@@ -442,8 +442,8 @@ static int python_generate_script(const char *outfile)
                fprintf(stderr, "couldn't open %s\n", fname);
                return -1;
        }
-       fprintf(ofp, "# perf trace event handlers, "
-               "generated by perf trace -g python\n");
+       fprintf(ofp, "# perf script event handlers, "
+               "generated by perf script -g python\n");
 
        fprintf(ofp, "# Licensed under the terms of the GNU GPL"
                " License version 2\n\n");