1*4882a593Smuzhiyunperf-script-python(1) 2*4882a593Smuzhiyun==================== 3*4882a593Smuzhiyun 4*4882a593SmuzhiyunNAME 5*4882a593Smuzhiyun---- 6*4882a593Smuzhiyunperf-script-python - Process trace data with a Python script 7*4882a593Smuzhiyun 8*4882a593SmuzhiyunSYNOPSIS 9*4882a593Smuzhiyun-------- 10*4882a593Smuzhiyun[verse] 11*4882a593Smuzhiyun'perf script' [-s [Python]:script[.py] ] 12*4882a593Smuzhiyun 13*4882a593SmuzhiyunDESCRIPTION 14*4882a593Smuzhiyun----------- 15*4882a593Smuzhiyun 16*4882a593SmuzhiyunThis perf script option is used to process perf script data using perf's 17*4882a593Smuzhiyunbuilt-in Python interpreter. It reads and processes the input file and 18*4882a593Smuzhiyundisplays the results of the trace analysis implemented in the given 19*4882a593SmuzhiyunPython script, if any. 20*4882a593Smuzhiyun 21*4882a593SmuzhiyunA QUICK EXAMPLE 22*4882a593Smuzhiyun--------------- 23*4882a593Smuzhiyun 24*4882a593SmuzhiyunThis section shows the process, start to finish, of creating a working 25*4882a593SmuzhiyunPython script that aggregates and extracts useful information from a 26*4882a593Smuzhiyunraw perf script stream. You can avoid reading the rest of this 27*4882a593Smuzhiyundocument if an example is enough for you; the rest of the document 28*4882a593Smuzhiyunprovides more details on each step and lists the library functions 29*4882a593Smuzhiyunavailable to script writers. 30*4882a593Smuzhiyun 31*4882a593SmuzhiyunThis example actually details the steps that were used to create the 32*4882a593Smuzhiyun'syscall-counts' script you see when you list the available perf script 33*4882a593Smuzhiyunscripts via 'perf script -l'. As such, this script also shows how to 34*4882a593Smuzhiyunintegrate your script into the list of general-purpose 'perf script' 35*4882a593Smuzhiyunscripts listed by that command. 36*4882a593Smuzhiyun 37*4882a593SmuzhiyunThe syscall-counts script is a simple script, but demonstrates all the 38*4882a593Smuzhiyunbasic ideas necessary to create a useful script. Here's an example 39*4882a593Smuzhiyunof its output (syscall names are not yet supported, they will appear 40*4882a593Smuzhiyunas numbers): 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun---- 43*4882a593Smuzhiyunsyscall events: 44*4882a593Smuzhiyun 45*4882a593Smuzhiyunevent count 46*4882a593Smuzhiyun---------------------------------------- ----------- 47*4882a593Smuzhiyunsys_write 455067 48*4882a593Smuzhiyunsys_getdents 4072 49*4882a593Smuzhiyunsys_close 3037 50*4882a593Smuzhiyunsys_swapoff 1769 51*4882a593Smuzhiyunsys_read 923 52*4882a593Smuzhiyunsys_sched_setparam 826 53*4882a593Smuzhiyunsys_open 331 54*4882a593Smuzhiyunsys_newfstat 326 55*4882a593Smuzhiyunsys_mmap 217 56*4882a593Smuzhiyunsys_munmap 216 57*4882a593Smuzhiyunsys_futex 141 58*4882a593Smuzhiyunsys_select 102 59*4882a593Smuzhiyunsys_poll 84 60*4882a593Smuzhiyunsys_setitimer 12 61*4882a593Smuzhiyunsys_writev 8 62*4882a593Smuzhiyun15 8 63*4882a593Smuzhiyunsys_lseek 7 64*4882a593Smuzhiyunsys_rt_sigprocmask 6 65*4882a593Smuzhiyunsys_wait4 3 66*4882a593Smuzhiyunsys_ioctl 3 67*4882a593Smuzhiyunsys_set_robust_list 1 68*4882a593Smuzhiyunsys_exit 1 69*4882a593Smuzhiyun56 1 70*4882a593Smuzhiyunsys_access 1 71*4882a593Smuzhiyun---- 72*4882a593Smuzhiyun 73*4882a593SmuzhiyunBasically our task is to keep a per-syscall tally that gets updated 74*4882a593Smuzhiyunevery time a system call occurs in the system. Our script will do 75*4882a593Smuzhiyunthat, but first we need to record the data that will be processed by 76*4882a593Smuzhiyunthat script. Theoretically, there are a couple of ways we could do 77*4882a593Smuzhiyunthat: 78*4882a593Smuzhiyun 79*4882a593Smuzhiyun- we could enable every event under the tracing/events/syscalls 80*4882a593Smuzhiyun directory, but this is over 600 syscalls, well beyond the number 81*4882a593Smuzhiyun allowable by perf. These individual syscall events will however be 82*4882a593Smuzhiyun useful if we want to later use the guidance we get from the 83*4882a593Smuzhiyun general-purpose scripts to drill down and get more detail about 84*4882a593Smuzhiyun individual syscalls of interest. 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun- we can enable the sys_enter and/or sys_exit syscalls found under 87*4882a593Smuzhiyun tracing/events/raw_syscalls. These are called for all syscalls; the 88*4882a593Smuzhiyun 'id' field can be used to distinguish between individual syscall 89*4882a593Smuzhiyun numbers. 90*4882a593Smuzhiyun 91*4882a593SmuzhiyunFor this script, we only need to know that a syscall was entered; we 92*4882a593Smuzhiyundon't care how it exited, so we'll use 'perf record' to record only 93*4882a593Smuzhiyunthe sys_enter events: 94*4882a593Smuzhiyun 95*4882a593Smuzhiyun---- 96*4882a593Smuzhiyun# perf record -a -e raw_syscalls:sys_enter 97*4882a593Smuzhiyun 98*4882a593Smuzhiyun^C[ perf record: Woken up 1 times to write data ] 99*4882a593Smuzhiyun[ perf record: Captured and wrote 56.545 MB perf.data (~2470503 samples) ] 100*4882a593Smuzhiyun---- 101*4882a593Smuzhiyun 102*4882a593SmuzhiyunThe options basically say to collect data for every syscall event 103*4882a593Smuzhiyunsystem-wide and multiplex the per-cpu output into a single stream. 104*4882a593SmuzhiyunThat single stream will be recorded in a file in the current directory 105*4882a593Smuzhiyuncalled perf.data. 106*4882a593Smuzhiyun 107*4882a593SmuzhiyunOnce we have a perf.data file containing our data, we can use the -g 108*4882a593Smuzhiyun'perf script' option to generate a Python script that will contain a 109*4882a593Smuzhiyuncallback handler for each event type found in the perf.data trace 110*4882a593Smuzhiyunstream (for more details, see the STARTER SCRIPTS section). 111*4882a593Smuzhiyun 112*4882a593Smuzhiyun---- 113*4882a593Smuzhiyun# perf script -g python 114*4882a593Smuzhiyungenerated Python script: perf-script.py 115*4882a593Smuzhiyun 116*4882a593SmuzhiyunThe output file created also in the current directory is named 117*4882a593Smuzhiyunperf-script.py. Here's the file in its entirety: 118*4882a593Smuzhiyun 119*4882a593Smuzhiyun# perf script event handlers, generated by perf script -g python 120*4882a593Smuzhiyun# Licensed under the terms of the GNU GPL License version 2 121*4882a593Smuzhiyun 122*4882a593Smuzhiyun# The common_* event handler fields are the most useful fields common to 123*4882a593Smuzhiyun# all events. They don't necessarily correspond to the 'common_*' fields 124*4882a593Smuzhiyun# in the format files. Those fields not available as handler params can 125*4882a593Smuzhiyun# be retrieved using Python functions of the form common_*(context). 126*4882a593Smuzhiyun# See the perf-script-python Documentation for the list of available functions. 127*4882a593Smuzhiyun 128*4882a593Smuzhiyunimport os 129*4882a593Smuzhiyunimport sys 130*4882a593Smuzhiyun 131*4882a593Smuzhiyunsys.path.append(os.environ['PERF_EXEC_PATH'] + \ 132*4882a593Smuzhiyun '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 133*4882a593Smuzhiyun 134*4882a593Smuzhiyunfrom perf_trace_context import * 135*4882a593Smuzhiyunfrom Core import * 136*4882a593Smuzhiyun 137*4882a593Smuzhiyundef trace_begin(): 138*4882a593Smuzhiyun print "in trace_begin" 139*4882a593Smuzhiyun 140*4882a593Smuzhiyundef trace_end(): 141*4882a593Smuzhiyun print "in trace_end" 142*4882a593Smuzhiyun 143*4882a593Smuzhiyundef raw_syscalls__sys_enter(event_name, context, common_cpu, 144*4882a593Smuzhiyun common_secs, common_nsecs, common_pid, common_comm, 145*4882a593Smuzhiyun id, args): 146*4882a593Smuzhiyun print_header(event_name, common_cpu, common_secs, common_nsecs, 147*4882a593Smuzhiyun common_pid, common_comm) 148*4882a593Smuzhiyun 149*4882a593Smuzhiyun print "id=%d, args=%s\n" % \ 150*4882a593Smuzhiyun (id, args), 151*4882a593Smuzhiyun 152*4882a593Smuzhiyundef trace_unhandled(event_name, context, event_fields_dict): 153*4882a593Smuzhiyun print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())]) 154*4882a593Smuzhiyun 155*4882a593Smuzhiyundef print_header(event_name, cpu, secs, nsecs, pid, comm): 156*4882a593Smuzhiyun print "%-20s %5u %05u.%09u %8u %-20s " % \ 157*4882a593Smuzhiyun (event_name, cpu, secs, nsecs, pid, comm), 158*4882a593Smuzhiyun---- 159*4882a593Smuzhiyun 160*4882a593SmuzhiyunAt the top is a comment block followed by some import statements and a 161*4882a593Smuzhiyunpath append which every perf script script should include. 162*4882a593Smuzhiyun 163*4882a593SmuzhiyunFollowing that are a couple generated functions, trace_begin() and 164*4882a593Smuzhiyuntrace_end(), which are called at the beginning and the end of the 165*4882a593Smuzhiyunscript respectively (for more details, see the SCRIPT_LAYOUT section 166*4882a593Smuzhiyunbelow). 167*4882a593Smuzhiyun 168*4882a593SmuzhiyunFollowing those are the 'event handler' functions generated one for 169*4882a593Smuzhiyunevery event in the 'perf record' output. The handler functions take 170*4882a593Smuzhiyunthe form subsystem__event_name, and contain named parameters, one for 171*4882a593Smuzhiyuneach field in the event; in this case, there's only one event, 172*4882a593Smuzhiyunraw_syscalls__sys_enter(). (see the EVENT HANDLERS section below for 173*4882a593Smuzhiyunmore info on event handlers). 174*4882a593Smuzhiyun 175*4882a593SmuzhiyunThe final couple of functions are, like the begin and end functions, 176*4882a593Smuzhiyungenerated for every script. The first, trace_unhandled(), is called 177*4882a593Smuzhiyunevery time the script finds an event in the perf.data file that 178*4882a593Smuzhiyundoesn't correspond to any event handler in the script. This could 179*4882a593Smuzhiyunmean either that the record step recorded event types that it wasn't 180*4882a593Smuzhiyunreally interested in, or the script was run against a trace file that 181*4882a593Smuzhiyundoesn't correspond to the script. 182*4882a593Smuzhiyun 183*4882a593SmuzhiyunThe script generated by -g option simply prints a line for each 184*4882a593Smuzhiyunevent found in the trace stream i.e. it basically just dumps the event 185*4882a593Smuzhiyunand its parameter values to stdout. The print_header() function is 186*4882a593Smuzhiyunsimply a utility function used for that purpose. Let's rename the 187*4882a593Smuzhiyunscript and run it to see the default output: 188*4882a593Smuzhiyun 189*4882a593Smuzhiyun---- 190*4882a593Smuzhiyun# mv perf-script.py syscall-counts.py 191*4882a593Smuzhiyun# perf script -s syscall-counts.py 192*4882a593Smuzhiyun 193*4882a593Smuzhiyunraw_syscalls__sys_enter 1 00840.847582083 7506 perf id=1, args= 194*4882a593Smuzhiyunraw_syscalls__sys_enter 1 00840.847595764 7506 perf id=1, args= 195*4882a593Smuzhiyunraw_syscalls__sys_enter 1 00840.847620860 7506 perf id=1, args= 196*4882a593Smuzhiyunraw_syscalls__sys_enter 1 00840.847710478 6533 npviewer.bin id=78, args= 197*4882a593Smuzhiyunraw_syscalls__sys_enter 1 00840.847719204 6533 npviewer.bin id=142, args= 198*4882a593Smuzhiyunraw_syscalls__sys_enter 1 00840.847755445 6533 npviewer.bin id=3, args= 199*4882a593Smuzhiyunraw_syscalls__sys_enter 1 00840.847775601 6533 npviewer.bin id=3, args= 200*4882a593Smuzhiyunraw_syscalls__sys_enter 1 00840.847781820 6533 npviewer.bin id=3, args= 201*4882a593Smuzhiyun. 202*4882a593Smuzhiyun. 203*4882a593Smuzhiyun. 204*4882a593Smuzhiyun---- 205*4882a593Smuzhiyun 206*4882a593SmuzhiyunOf course, for this script, we're not interested in printing every 207*4882a593Smuzhiyuntrace event, but rather aggregating it in a useful way. So we'll get 208*4882a593Smuzhiyunrid of everything to do with printing as well as the trace_begin() and 209*4882a593Smuzhiyuntrace_unhandled() functions, which we won't be using. That leaves us 210*4882a593Smuzhiyunwith this minimalistic skeleton: 211*4882a593Smuzhiyun 212*4882a593Smuzhiyun---- 213*4882a593Smuzhiyunimport os 214*4882a593Smuzhiyunimport sys 215*4882a593Smuzhiyun 216*4882a593Smuzhiyunsys.path.append(os.environ['PERF_EXEC_PATH'] + \ 217*4882a593Smuzhiyun '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 218*4882a593Smuzhiyun 219*4882a593Smuzhiyunfrom perf_trace_context import * 220*4882a593Smuzhiyunfrom Core import * 221*4882a593Smuzhiyun 222*4882a593Smuzhiyundef trace_end(): 223*4882a593Smuzhiyun print "in trace_end" 224*4882a593Smuzhiyun 225*4882a593Smuzhiyundef raw_syscalls__sys_enter(event_name, context, common_cpu, 226*4882a593Smuzhiyun common_secs, common_nsecs, common_pid, common_comm, 227*4882a593Smuzhiyun id, args): 228*4882a593Smuzhiyun---- 229*4882a593Smuzhiyun 230*4882a593SmuzhiyunIn trace_end(), we'll simply print the results, but first we need to 231*4882a593Smuzhiyungenerate some results to print. To do that we need to have our 232*4882a593Smuzhiyunsys_enter() handler do the necessary tallying until all events have 233*4882a593Smuzhiyunbeen counted. A hash table indexed by syscall id is a good way to 234*4882a593Smuzhiyunstore that information; every time the sys_enter() handler is called, 235*4882a593Smuzhiyunwe simply increment a count associated with that hash entry indexed by 236*4882a593Smuzhiyunthat syscall id: 237*4882a593Smuzhiyun 238*4882a593Smuzhiyun---- 239*4882a593Smuzhiyun syscalls = autodict() 240*4882a593Smuzhiyun 241*4882a593Smuzhiyun try: 242*4882a593Smuzhiyun syscalls[id] += 1 243*4882a593Smuzhiyun except TypeError: 244*4882a593Smuzhiyun syscalls[id] = 1 245*4882a593Smuzhiyun---- 246*4882a593Smuzhiyun 247*4882a593SmuzhiyunThe syscalls 'autodict' object is a special kind of Python dictionary 248*4882a593Smuzhiyun(implemented in Core.py) that implements Perl's 'autovivifying' hashes 249*4882a593Smuzhiyunin Python i.e. with autovivifying hashes, you can assign nested hash 250*4882a593Smuzhiyunvalues without having to go to the trouble of creating intermediate 251*4882a593Smuzhiyunlevels if they don't exist e.g syscalls[comm][pid][id] = 1 will create 252*4882a593Smuzhiyunthe intermediate hash levels and finally assign the value 1 to the 253*4882a593Smuzhiyunhash entry for 'id' (because the value being assigned isn't a hash 254*4882a593Smuzhiyunobject itself, the initial value is assigned in the TypeError 255*4882a593Smuzhiyunexception. Well, there may be a better way to do this in Python but 256*4882a593Smuzhiyunthat's what works for now). 257*4882a593Smuzhiyun 258*4882a593SmuzhiyunPutting that code into the raw_syscalls__sys_enter() handler, we 259*4882a593Smuzhiyuneffectively end up with a single-level dictionary keyed on syscall id 260*4882a593Smuzhiyunand having the counts we've tallied as values. 261*4882a593Smuzhiyun 262*4882a593SmuzhiyunThe print_syscall_totals() function iterates over the entries in the 263*4882a593Smuzhiyundictionary and displays a line for each entry containing the syscall 264*4882a593Smuzhiyunname (the dictionary keys contain the syscall ids, which are passed to 265*4882a593Smuzhiyunthe Util function syscall_name(), which translates the raw syscall 266*4882a593Smuzhiyunnumbers to the corresponding syscall name strings). The output is 267*4882a593Smuzhiyundisplayed after all the events in the trace have been processed, by 268*4882a593Smuzhiyuncalling the print_syscall_totals() function from the trace_end() 269*4882a593Smuzhiyunhandler called at the end of script processing. 270*4882a593Smuzhiyun 271*4882a593SmuzhiyunThe final script producing the output shown above is shown in its 272*4882a593Smuzhiyunentirety below (syscall_name() helper is not yet available, you can 273*4882a593Smuzhiyunonly deal with id's for now): 274*4882a593Smuzhiyun 275*4882a593Smuzhiyun---- 276*4882a593Smuzhiyunimport os 277*4882a593Smuzhiyunimport sys 278*4882a593Smuzhiyun 279*4882a593Smuzhiyunsys.path.append(os.environ['PERF_EXEC_PATH'] + \ 280*4882a593Smuzhiyun '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 281*4882a593Smuzhiyun 282*4882a593Smuzhiyunfrom perf_trace_context import * 283*4882a593Smuzhiyunfrom Core import * 284*4882a593Smuzhiyunfrom Util import * 285*4882a593Smuzhiyun 286*4882a593Smuzhiyunsyscalls = autodict() 287*4882a593Smuzhiyun 288*4882a593Smuzhiyundef trace_end(): 289*4882a593Smuzhiyun print_syscall_totals() 290*4882a593Smuzhiyun 291*4882a593Smuzhiyundef raw_syscalls__sys_enter(event_name, context, common_cpu, 292*4882a593Smuzhiyun common_secs, common_nsecs, common_pid, common_comm, 293*4882a593Smuzhiyun id, args): 294*4882a593Smuzhiyun try: 295*4882a593Smuzhiyun syscalls[id] += 1 296*4882a593Smuzhiyun except TypeError: 297*4882a593Smuzhiyun syscalls[id] = 1 298*4882a593Smuzhiyun 299*4882a593Smuzhiyundef print_syscall_totals(): 300*4882a593Smuzhiyun if for_comm is not None: 301*4882a593Smuzhiyun print "\nsyscall events for %s:\n\n" % (for_comm), 302*4882a593Smuzhiyun else: 303*4882a593Smuzhiyun print "\nsyscall events:\n\n", 304*4882a593Smuzhiyun 305*4882a593Smuzhiyun print "%-40s %10s\n" % ("event", "count"), 306*4882a593Smuzhiyun print "%-40s %10s\n" % ("----------------------------------------", \ 307*4882a593Smuzhiyun "-----------"), 308*4882a593Smuzhiyun 309*4882a593Smuzhiyun for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \ 310*4882a593Smuzhiyun reverse = True): 311*4882a593Smuzhiyun print "%-40s %10d\n" % (syscall_name(id), val), 312*4882a593Smuzhiyun---- 313*4882a593Smuzhiyun 314*4882a593SmuzhiyunThe script can be run just as before: 315*4882a593Smuzhiyun 316*4882a593Smuzhiyun # perf script -s syscall-counts.py 317*4882a593Smuzhiyun 318*4882a593SmuzhiyunSo those are the essential steps in writing and running a script. The 319*4882a593Smuzhiyunprocess can be generalized to any tracepoint or set of tracepoints 320*4882a593Smuzhiyunyou're interested in - basically find the tracepoint(s) you're 321*4882a593Smuzhiyuninterested in by looking at the list of available events shown by 322*4882a593Smuzhiyun'perf list' and/or look in /sys/kernel/debug/tracing/events/ for 323*4882a593Smuzhiyundetailed event and field info, record the corresponding trace data 324*4882a593Smuzhiyunusing 'perf record', passing it the list of interesting events, 325*4882a593Smuzhiyungenerate a skeleton script using 'perf script -g python' and modify the 326*4882a593Smuzhiyuncode to aggregate and display it for your particular needs. 327*4882a593Smuzhiyun 328*4882a593SmuzhiyunAfter you've done that you may end up with a general-purpose script 329*4882a593Smuzhiyunthat you want to keep around and have available for future use. By 330*4882a593Smuzhiyunwriting a couple of very simple shell scripts and putting them in the 331*4882a593Smuzhiyunright place, you can have your script listed alongside the other 332*4882a593Smuzhiyunscripts listed by the 'perf script -l' command e.g.: 333*4882a593Smuzhiyun 334*4882a593Smuzhiyun---- 335*4882a593Smuzhiyun# perf script -l 336*4882a593SmuzhiyunList of available trace scripts: 337*4882a593Smuzhiyun wakeup-latency system-wide min/max/avg wakeup latency 338*4882a593Smuzhiyun rw-by-file <comm> r/w activity for a program, by file 339*4882a593Smuzhiyun rw-by-pid system-wide r/w activity 340*4882a593Smuzhiyun---- 341*4882a593Smuzhiyun 342*4882a593SmuzhiyunA nice side effect of doing this is that you also then capture the 343*4882a593Smuzhiyunprobably lengthy 'perf record' command needed to record the events for 344*4882a593Smuzhiyunthe script. 345*4882a593Smuzhiyun 346*4882a593SmuzhiyunTo have the script appear as a 'built-in' script, you write two simple 347*4882a593Smuzhiyunscripts, one for recording and one for 'reporting'. 348*4882a593Smuzhiyun 349*4882a593SmuzhiyunThe 'record' script is a shell script with the same base name as your 350*4882a593Smuzhiyunscript, but with -record appended. The shell script should be put 351*4882a593Smuzhiyuninto the perf/scripts/python/bin directory in the kernel source tree. 352*4882a593SmuzhiyunIn that script, you write the 'perf record' command-line needed for 353*4882a593Smuzhiyunyour script: 354*4882a593Smuzhiyun 355*4882a593Smuzhiyun---- 356*4882a593Smuzhiyun# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-record 357*4882a593Smuzhiyun 358*4882a593Smuzhiyun#!/bin/bash 359*4882a593Smuzhiyunperf record -a -e raw_syscalls:sys_enter 360*4882a593Smuzhiyun---- 361*4882a593Smuzhiyun 362*4882a593SmuzhiyunThe 'report' script is also a shell script with the same base name as 363*4882a593Smuzhiyunyour script, but with -report appended. It should also be located in 364*4882a593Smuzhiyunthe perf/scripts/python/bin directory. In that script, you write the 365*4882a593Smuzhiyun'perf script -s' command-line needed for running your script: 366*4882a593Smuzhiyun 367*4882a593Smuzhiyun---- 368*4882a593Smuzhiyun# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-report 369*4882a593Smuzhiyun 370*4882a593Smuzhiyun#!/bin/bash 371*4882a593Smuzhiyun# description: system-wide syscall counts 372*4882a593Smuzhiyunperf script -s ~/libexec/perf-core/scripts/python/syscall-counts.py 373*4882a593Smuzhiyun---- 374*4882a593Smuzhiyun 375*4882a593SmuzhiyunNote that the location of the Python script given in the shell script 376*4882a593Smuzhiyunis in the libexec/perf-core/scripts/python directory - this is where 377*4882a593Smuzhiyunthe script will be copied by 'make install' when you install perf. 378*4882a593SmuzhiyunFor the installation to install your script there, your script needs 379*4882a593Smuzhiyunto be located in the perf/scripts/python directory in the kernel 380*4882a593Smuzhiyunsource tree: 381*4882a593Smuzhiyun 382*4882a593Smuzhiyun---- 383*4882a593Smuzhiyun# ls -al kernel-source/tools/perf/scripts/python 384*4882a593Smuzhiyuntotal 32 385*4882a593Smuzhiyundrwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 . 386*4882a593Smuzhiyundrwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 .. 387*4882a593Smuzhiyundrwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin 388*4882a593Smuzhiyun-rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-script.py 389*4882a593Smuzhiyundrwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 Perf-Trace-Util 390*4882a593Smuzhiyun-rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py 391*4882a593Smuzhiyun---- 392*4882a593Smuzhiyun 393*4882a593SmuzhiyunOnce you've done that (don't forget to do a new 'make install', 394*4882a593Smuzhiyunotherwise your script won't show up at run-time), 'perf script -l' 395*4882a593Smuzhiyunshould show a new entry for your script: 396*4882a593Smuzhiyun 397*4882a593Smuzhiyun---- 398*4882a593Smuzhiyun# perf script -l 399*4882a593SmuzhiyunList of available trace scripts: 400*4882a593Smuzhiyun wakeup-latency system-wide min/max/avg wakeup latency 401*4882a593Smuzhiyun rw-by-file <comm> r/w activity for a program, by file 402*4882a593Smuzhiyun rw-by-pid system-wide r/w activity 403*4882a593Smuzhiyun syscall-counts system-wide syscall counts 404*4882a593Smuzhiyun---- 405*4882a593Smuzhiyun 406*4882a593SmuzhiyunYou can now perform the record step via 'perf script record': 407*4882a593Smuzhiyun 408*4882a593Smuzhiyun # perf script record syscall-counts 409*4882a593Smuzhiyun 410*4882a593Smuzhiyunand display the output using 'perf script report': 411*4882a593Smuzhiyun 412*4882a593Smuzhiyun # perf script report syscall-counts 413*4882a593Smuzhiyun 414*4882a593SmuzhiyunSTARTER SCRIPTS 415*4882a593Smuzhiyun--------------- 416*4882a593Smuzhiyun 417*4882a593SmuzhiyunYou can quickly get started writing a script for a particular set of 418*4882a593Smuzhiyuntrace data by generating a skeleton script using 'perf script -g 419*4882a593Smuzhiyunpython' in the same directory as an existing perf.data trace file. 420*4882a593SmuzhiyunThat will generate a starter script containing a handler for each of 421*4882a593Smuzhiyunthe event types in the trace file; it simply prints every available 422*4882a593Smuzhiyunfield for each event in the trace file. 423*4882a593Smuzhiyun 424*4882a593SmuzhiyunYou can also look at the existing scripts in 425*4882a593Smuzhiyun~/libexec/perf-core/scripts/python for typical examples showing how to 426*4882a593Smuzhiyundo basic things like aggregate event data, print results, etc. Also, 427*4882a593Smuzhiyunthe check-perf-script.py script, while not interesting for its results, 428*4882a593Smuzhiyunattempts to exercise all of the main scripting features. 429*4882a593Smuzhiyun 430*4882a593SmuzhiyunEVENT HANDLERS 431*4882a593Smuzhiyun-------------- 432*4882a593Smuzhiyun 433*4882a593SmuzhiyunWhen perf script is invoked using a trace script, a user-defined 434*4882a593Smuzhiyun'handler function' is called for each event in the trace. If there's 435*4882a593Smuzhiyunno handler function defined for a given event type, the event is 436*4882a593Smuzhiyunignored (or passed to a 'trace_unhandled' function, see below) and the 437*4882a593Smuzhiyunnext event is processed. 438*4882a593Smuzhiyun 439*4882a593SmuzhiyunMost of the event's field values are passed as arguments to the 440*4882a593Smuzhiyunhandler function; some of the less common ones aren't - those are 441*4882a593Smuzhiyunavailable as calls back into the perf executable (see below). 442*4882a593Smuzhiyun 443*4882a593SmuzhiyunAs an example, the following perf record command can be used to record 444*4882a593Smuzhiyunall sched_wakeup events in the system: 445*4882a593Smuzhiyun 446*4882a593Smuzhiyun # perf record -a -e sched:sched_wakeup 447*4882a593Smuzhiyun 448*4882a593SmuzhiyunTraces meant to be processed using a script should be recorded with 449*4882a593Smuzhiyunthe above option: -a to enable system-wide collection. 450*4882a593Smuzhiyun 451*4882a593SmuzhiyunThe format file for the sched_wakep event defines the following fields 452*4882a593Smuzhiyun(see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format): 453*4882a593Smuzhiyun 454*4882a593Smuzhiyun---- 455*4882a593Smuzhiyun format: 456*4882a593Smuzhiyun field:unsigned short common_type; 457*4882a593Smuzhiyun field:unsigned char common_flags; 458*4882a593Smuzhiyun field:unsigned char common_preempt_count; 459*4882a593Smuzhiyun field:int common_pid; 460*4882a593Smuzhiyun 461*4882a593Smuzhiyun field:char comm[TASK_COMM_LEN]; 462*4882a593Smuzhiyun field:pid_t pid; 463*4882a593Smuzhiyun field:int prio; 464*4882a593Smuzhiyun field:int success; 465*4882a593Smuzhiyun field:int target_cpu; 466*4882a593Smuzhiyun---- 467*4882a593Smuzhiyun 468*4882a593SmuzhiyunThe handler function for this event would be defined as: 469*4882a593Smuzhiyun 470*4882a593Smuzhiyun---- 471*4882a593Smuzhiyundef sched__sched_wakeup(event_name, context, common_cpu, common_secs, 472*4882a593Smuzhiyun common_nsecs, common_pid, common_comm, 473*4882a593Smuzhiyun comm, pid, prio, success, target_cpu): 474*4882a593Smuzhiyun pass 475*4882a593Smuzhiyun---- 476*4882a593Smuzhiyun 477*4882a593SmuzhiyunThe handler function takes the form subsystem__event_name. 478*4882a593Smuzhiyun 479*4882a593SmuzhiyunThe common_* arguments in the handler's argument list are the set of 480*4882a593Smuzhiyunarguments passed to all event handlers; some of the fields correspond 481*4882a593Smuzhiyunto the common_* fields in the format file, but some are synthesized, 482*4882a593Smuzhiyunand some of the common_* fields aren't common enough to to be passed 483*4882a593Smuzhiyunto every event as arguments but are available as library functions. 484*4882a593Smuzhiyun 485*4882a593SmuzhiyunHere's a brief description of each of the invariant event args: 486*4882a593Smuzhiyun 487*4882a593Smuzhiyun event_name the name of the event as text 488*4882a593Smuzhiyun context an opaque 'cookie' used in calls back into perf 489*4882a593Smuzhiyun common_cpu the cpu the event occurred on 490*4882a593Smuzhiyun common_secs the secs portion of the event timestamp 491*4882a593Smuzhiyun common_nsecs the nsecs portion of the event timestamp 492*4882a593Smuzhiyun common_pid the pid of the current task 493*4882a593Smuzhiyun common_comm the name of the current process 494*4882a593Smuzhiyun 495*4882a593SmuzhiyunAll of the remaining fields in the event's format file have 496*4882a593Smuzhiyuncounterparts as handler function arguments of the same name, as can be 497*4882a593Smuzhiyunseen in the example above. 498*4882a593Smuzhiyun 499*4882a593SmuzhiyunThe above provides the basics needed to directly access every field of 500*4882a593Smuzhiyunevery event in a trace, which covers 90% of what you need to know to 501*4882a593Smuzhiyunwrite a useful trace script. The sections below cover the rest. 502*4882a593Smuzhiyun 503*4882a593SmuzhiyunSCRIPT LAYOUT 504*4882a593Smuzhiyun------------- 505*4882a593Smuzhiyun 506*4882a593SmuzhiyunEvery perf script Python script should start by setting up a Python 507*4882a593Smuzhiyunmodule search path and 'import'ing a few support modules (see module 508*4882a593Smuzhiyundescriptions below): 509*4882a593Smuzhiyun 510*4882a593Smuzhiyun---- 511*4882a593Smuzhiyun import os 512*4882a593Smuzhiyun import sys 513*4882a593Smuzhiyun 514*4882a593Smuzhiyun sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 515*4882a593Smuzhiyun '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 516*4882a593Smuzhiyun 517*4882a593Smuzhiyun from perf_trace_context import * 518*4882a593Smuzhiyun from Core import * 519*4882a593Smuzhiyun---- 520*4882a593Smuzhiyun 521*4882a593SmuzhiyunThe rest of the script can contain handler functions and support 522*4882a593Smuzhiyunfunctions in any order. 523*4882a593Smuzhiyun 524*4882a593SmuzhiyunAside from the event handler functions discussed above, every script 525*4882a593Smuzhiyuncan implement a set of optional functions: 526*4882a593Smuzhiyun 527*4882a593Smuzhiyun*trace_begin*, if defined, is called before any event is processed and 528*4882a593Smuzhiyungives scripts a chance to do setup tasks: 529*4882a593Smuzhiyun 530*4882a593Smuzhiyun---- 531*4882a593Smuzhiyundef trace_begin(): 532*4882a593Smuzhiyun pass 533*4882a593Smuzhiyun---- 534*4882a593Smuzhiyun 535*4882a593Smuzhiyun*trace_end*, if defined, is called after all events have been 536*4882a593Smuzhiyun processed and gives scripts a chance to do end-of-script tasks, such 537*4882a593Smuzhiyun as display results: 538*4882a593Smuzhiyun 539*4882a593Smuzhiyun---- 540*4882a593Smuzhiyundef trace_end(): 541*4882a593Smuzhiyun pass 542*4882a593Smuzhiyun---- 543*4882a593Smuzhiyun 544*4882a593Smuzhiyun*trace_unhandled*, if defined, is called after for any event that 545*4882a593Smuzhiyun doesn't have a handler explicitly defined for it. The standard set 546*4882a593Smuzhiyun of common arguments are passed into it: 547*4882a593Smuzhiyun 548*4882a593Smuzhiyun---- 549*4882a593Smuzhiyundef trace_unhandled(event_name, context, event_fields_dict): 550*4882a593Smuzhiyun pass 551*4882a593Smuzhiyun---- 552*4882a593Smuzhiyun 553*4882a593SmuzhiyunThe remaining sections provide descriptions of each of the available 554*4882a593Smuzhiyunbuilt-in perf script Python modules and their associated functions. 555*4882a593Smuzhiyun 556*4882a593SmuzhiyunAVAILABLE MODULES AND FUNCTIONS 557*4882a593Smuzhiyun------------------------------- 558*4882a593Smuzhiyun 559*4882a593SmuzhiyunThe following sections describe the functions and variables available 560*4882a593Smuzhiyunvia the various perf script Python modules. To use the functions and 561*4882a593Smuzhiyunvariables from the given module, add the corresponding 'from XXXX 562*4882a593Smuzhiyunimport' line to your perf script script. 563*4882a593Smuzhiyun 564*4882a593SmuzhiyunCore.py Module 565*4882a593Smuzhiyun~~~~~~~~~~~~~~ 566*4882a593Smuzhiyun 567*4882a593SmuzhiyunThese functions provide some essential functions to user scripts. 568*4882a593Smuzhiyun 569*4882a593SmuzhiyunThe *flag_str* and *symbol_str* functions provide human-readable 570*4882a593Smuzhiyunstrings for flag and symbolic fields. These correspond to the strings 571*4882a593Smuzhiyunand values parsed from the 'print fmt' fields of the event format 572*4882a593Smuzhiyunfiles: 573*4882a593Smuzhiyun 574*4882a593Smuzhiyun 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 575*4882a593Smuzhiyun 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 576*4882a593Smuzhiyun 577*4882a593SmuzhiyunThe *autodict* function returns a special kind of Python 578*4882a593Smuzhiyundictionary that implements Perl's 'autovivifying' hashes in Python 579*4882a593Smuzhiyuni.e. with autovivifying hashes, you can assign nested hash values 580*4882a593Smuzhiyunwithout having to go to the trouble of creating intermediate levels if 581*4882a593Smuzhiyunthey don't exist. 582*4882a593Smuzhiyun 583*4882a593Smuzhiyun autodict() - returns an autovivifying dictionary instance 584*4882a593Smuzhiyun 585*4882a593Smuzhiyun 586*4882a593Smuzhiyunperf_trace_context Module 587*4882a593Smuzhiyun~~~~~~~~~~~~~~~~~~~~~~~~~ 588*4882a593Smuzhiyun 589*4882a593SmuzhiyunSome of the 'common' fields in the event format file aren't all that 590*4882a593Smuzhiyuncommon, but need to be made accessible to user scripts nonetheless. 591*4882a593Smuzhiyun 592*4882a593Smuzhiyunperf_trace_context defines a set of functions that can be used to 593*4882a593Smuzhiyunaccess this data in the context of the current event. Each of these 594*4882a593Smuzhiyunfunctions expects a context variable, which is the same as the 595*4882a593Smuzhiyuncontext variable passed into every event handler as the second 596*4882a593Smuzhiyunargument. 597*4882a593Smuzhiyun 598*4882a593Smuzhiyun common_pc(context) - returns common_preempt count for the current event 599*4882a593Smuzhiyun common_flags(context) - returns common_flags for the current event 600*4882a593Smuzhiyun common_lock_depth(context) - returns common_lock_depth for the current event 601*4882a593Smuzhiyun 602*4882a593SmuzhiyunUtil.py Module 603*4882a593Smuzhiyun~~~~~~~~~~~~~~ 604*4882a593Smuzhiyun 605*4882a593SmuzhiyunVarious utility functions for use with perf script: 606*4882a593Smuzhiyun 607*4882a593Smuzhiyun nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair 608*4882a593Smuzhiyun nsecs_secs(nsecs) - returns whole secs portion given nsecs 609*4882a593Smuzhiyun nsecs_nsecs(nsecs) - returns nsecs remainder given nsecs 610*4882a593Smuzhiyun nsecs_str(nsecs) - returns printable string in the form secs.nsecs 611*4882a593Smuzhiyun avg(total, n) - returns average given a sum and a total number of values 612*4882a593Smuzhiyun 613*4882a593SmuzhiyunSUPPORTED FIELDS 614*4882a593Smuzhiyun---------------- 615*4882a593Smuzhiyun 616*4882a593SmuzhiyunCurrently supported fields: 617*4882a593Smuzhiyun 618*4882a593Smuzhiyunev_name, comm, pid, tid, cpu, ip, time, period, phys_addr, addr, 619*4882a593Smuzhiyunsymbol, dso, time_enabled, time_running, values, callchain, 620*4882a593Smuzhiyunbrstack, brstacksym, datasrc, datasrc_decode, iregs, uregs, 621*4882a593Smuzhiyunweight, transaction, raw_buf, attr. 622*4882a593Smuzhiyun 623*4882a593SmuzhiyunSome fields have sub items: 624*4882a593Smuzhiyun 625*4882a593Smuzhiyunbrstack: 626*4882a593Smuzhiyun from, to, from_dsoname, to_dsoname, mispred, 627*4882a593Smuzhiyun predicted, in_tx, abort, cycles. 628*4882a593Smuzhiyun 629*4882a593Smuzhiyunbrstacksym: 630*4882a593Smuzhiyun items: from, to, pred, in_tx, abort (converted string) 631*4882a593Smuzhiyun 632*4882a593SmuzhiyunFor example, 633*4882a593SmuzhiyunWe can use this code to print brstack "from", "to", "cycles". 634*4882a593Smuzhiyun 635*4882a593Smuzhiyunif 'brstack' in dict: 636*4882a593Smuzhiyun for entry in dict['brstack']: 637*4882a593Smuzhiyun print "from %s, to %s, cycles %s" % (entry["from"], entry["to"], entry["cycles"]) 638*4882a593Smuzhiyun 639*4882a593SmuzhiyunSEE ALSO 640*4882a593Smuzhiyun-------- 641*4882a593Smuzhiyunlinkperf:perf-script[1] 642