other versions
PERF_4.8-SCRIPT-PYTHON(1) | perf Manual | PERF_4.8-SCRIPT-PYTHON(1) |
NAME¶
perf-script-python - Process trace data with a Python scriptSYNOPSIS¶
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):.ft C 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 .ft
•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:
.ft C # 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) ] .ft
.ft C # 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-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), .ft
.ft C # 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= . . . .ft
.ft C 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): .ft
.ft C syscalls = autodict() try: syscalls[id] += 1 except TypeError: syscalls[id] = 1 .ft
.ft C 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), .ft
# perf script -s syscall-counts.py
.ft C root@tropicana:~# perf script -l List of available trace scripts: 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 .ft
.ft C # cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-record #!/bin/bash perf record -a -e raw_syscalls:sys_enter .ft
.ft C # 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 .ft
.ft C # 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-Trace-Util -rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py .ft
.ft C root@tropicana:~# perf script -l List of available trace scripts: 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 .ft
# perf script record syscall-counts
# 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
.ft C format: field:unsigned short common_type; field:unsigned char common_flags; field:unsigned char common_preempt_count; field:int common_pid; field:char comm[TASK_COMM_LEN]; field:pid_t pid; field:int prio; field:int success; field:int target_cpu; .ft
.ft C def sched__sched_wakeup(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, comm, pid, prio, success, target_cpu): pass .ft
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
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):.ft C 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 * .ft
.ft C def trace_begin: pass .ft
.ft C def trace_end: pass .ft
.ft C def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm): pass .ft
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 representation 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 representation corresponding to field_value for the symbolic field field_name of event event_name
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¶
perf_4.8-script(1)2017-01-17 | perf |