aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/scripts/python
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/scripts/python')
-rwxr-xr-xtools/perf/scripts/python/bin/stackcollapse-record8
-rwxr-xr-xtools/perf/scripts/python/bin/stackcollapse-report3
-rw-r--r--tools/perf/scripts/python/export-to-postgresql.py52
-rw-r--r--tools/perf/scripts/python/netdev-times.py11
-rwxr-xr-xtools/perf/scripts/python/stackcollapse.py125
5 files changed, 175 insertions, 24 deletions
diff --git a/tools/perf/scripts/python/bin/stackcollapse-record b/tools/perf/scripts/python/bin/stackcollapse-record
new file mode 100755
index 000000000000..9d8f9f0f3a17
--- /dev/null
+++ b/tools/perf/scripts/python/bin/stackcollapse-record
@@ -0,0 +1,8 @@
1#!/bin/sh
2
3#
4# stackcollapse.py can cover all type of perf samples including
5# the tracepoints, so no special record requirements, just record what
6# you want to analyze.
7#
8perf record "$@"
diff --git a/tools/perf/scripts/python/bin/stackcollapse-report b/tools/perf/scripts/python/bin/stackcollapse-report
new file mode 100755
index 000000000000..356b9656393d
--- /dev/null
+++ b/tools/perf/scripts/python/bin/stackcollapse-report
@@ -0,0 +1,3 @@
1#!/bin/sh
2# description: produce callgraphs in short form for scripting use
3perf script -s "$PERF_EXEC_PATH"/scripts/python/stackcollapse.py -- "$@"
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py
index 1b02cdc0cab6..7656ff8aa066 100644
--- a/tools/perf/scripts/python/export-to-postgresql.py
+++ b/tools/perf/scripts/python/export-to-postgresql.py
@@ -34,10 +34,9 @@ import datetime
34# 34#
35# ubuntu: 35# ubuntu:
36# 36#
37# $ sudo apt-get install postgresql 37# $ sudo apt-get install postgresql python-pyside.qtsql libqt4-sql-psql
38# $ sudo su - postgres 38# $ sudo su - postgres
39# $ createuser <your user id here> 39# $ createuser -s <your user id here>
40# Shall the new role be a superuser? (y/n) y
41# 40#
42# An example of using this script with Intel PT: 41# An example of using this script with Intel PT:
43# 42#
@@ -224,11 +223,14 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
224 223
225perf_db_export_mode = True 224perf_db_export_mode = True
226perf_db_export_calls = False 225perf_db_export_calls = False
226perf_db_export_callchains = False
227
227 228
228def usage(): 229def usage():
229 print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>]" 230 print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>] [<callchains>]"
230 print >> sys.stderr, "where: columns 'all' or 'branches'" 231 print >> sys.stderr, "where: columns 'all' or 'branches'"
231 print >> sys.stderr, " calls 'calls' => create calls table" 232 print >> sys.stderr, " calls 'calls' => create calls and call_paths table"
233 print >> sys.stderr, " callchains 'callchains' => create call_paths table"
232 raise Exception("Too few arguments") 234 raise Exception("Too few arguments")
233 235
234if (len(sys.argv) < 2): 236if (len(sys.argv) < 2):
@@ -246,9 +248,11 @@ if columns not in ("all", "branches"):
246 248
247branches = (columns == "branches") 249branches = (columns == "branches")
248 250
249if (len(sys.argv) >= 4): 251for i in range(3,len(sys.argv)):
250 if (sys.argv[3] == "calls"): 252 if (sys.argv[i] == "calls"):
251 perf_db_export_calls = True 253 perf_db_export_calls = True
254 elif (sys.argv[i] == "callchains"):
255 perf_db_export_callchains = True
252 else: 256 else:
253 usage() 257 usage()
254 258
@@ -359,14 +363,16 @@ else:
359 'transaction bigint,' 363 'transaction bigint,'
360 'data_src bigint,' 364 'data_src bigint,'
361 'branch_type integer,' 365 'branch_type integer,'
362 'in_tx boolean)') 366 'in_tx boolean,'
367 'call_path_id bigint)')
363 368
364if perf_db_export_calls: 369if perf_db_export_calls or perf_db_export_callchains:
365 do_query(query, 'CREATE TABLE call_paths (' 370 do_query(query, 'CREATE TABLE call_paths ('
366 'id bigint NOT NULL,' 371 'id bigint NOT NULL,'
367 'parent_id bigint,' 372 'parent_id bigint,'
368 'symbol_id bigint,' 373 'symbol_id bigint,'
369 'ip bigint)') 374 'ip bigint)')
375if perf_db_export_calls:
370 do_query(query, 'CREATE TABLE calls (' 376 do_query(query, 'CREATE TABLE calls ('
371 'id bigint NOT NULL,' 377 'id bigint NOT NULL,'
372 'thread_id bigint,' 378 'thread_id bigint,'
@@ -428,7 +434,7 @@ do_query(query, 'CREATE VIEW comm_threads_view AS '
428 '(SELECT tid FROM threads WHERE id = thread_id) AS tid' 434 '(SELECT tid FROM threads WHERE id = thread_id) AS tid'
429 ' FROM comm_threads') 435 ' FROM comm_threads')
430 436
431if perf_db_export_calls: 437if perf_db_export_calls or perf_db_export_callchains:
432 do_query(query, 'CREATE VIEW call_paths_view AS ' 438 do_query(query, 'CREATE VIEW call_paths_view AS '
433 'SELECT ' 439 'SELECT '
434 'c.id,' 440 'c.id,'
@@ -444,6 +450,7 @@ if perf_db_export_calls:
444 '(SELECT dso_id FROM symbols WHERE id = p.symbol_id) AS parent_dso_id,' 450 '(SELECT dso_id FROM symbols WHERE id = p.symbol_id) AS parent_dso_id,'
445 '(SELECT dso FROM symbols_view WHERE id = p.symbol_id) AS parent_dso_short_name' 451 '(SELECT dso FROM symbols_view WHERE id = p.symbol_id) AS parent_dso_short_name'
446 ' FROM call_paths c INNER JOIN call_paths p ON p.id = c.parent_id') 452 ' FROM call_paths c INNER JOIN call_paths p ON p.id = c.parent_id')
453if perf_db_export_calls:
447 do_query(query, 'CREATE VIEW calls_view AS ' 454 do_query(query, 'CREATE VIEW calls_view AS '
448 'SELECT ' 455 'SELECT '
449 'calls.id,' 456 'calls.id,'
@@ -541,8 +548,9 @@ dso_file = open_output_file("dso_table.bin")
541symbol_file = open_output_file("symbol_table.bin") 548symbol_file = open_output_file("symbol_table.bin")
542branch_type_file = open_output_file("branch_type_table.bin") 549branch_type_file = open_output_file("branch_type_table.bin")
543sample_file = open_output_file("sample_table.bin") 550sample_file = open_output_file("sample_table.bin")
544if perf_db_export_calls: 551if perf_db_export_calls or perf_db_export_callchains:
545 call_path_file = open_output_file("call_path_table.bin") 552 call_path_file = open_output_file("call_path_table.bin")
553if perf_db_export_calls:
546 call_file = open_output_file("call_table.bin") 554 call_file = open_output_file("call_table.bin")
547 555
548def trace_begin(): 556def trace_begin():
@@ -554,8 +562,8 @@ def trace_begin():
554 comm_table(0, "unknown") 562 comm_table(0, "unknown")
555 dso_table(0, 0, "unknown", "unknown", "") 563 dso_table(0, 0, "unknown", "unknown", "")
556 symbol_table(0, 0, 0, 0, 0, "unknown") 564 symbol_table(0, 0, 0, 0, 0, "unknown")
557 sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 565 sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
558 if perf_db_export_calls: 566 if perf_db_export_calls or perf_db_export_callchains:
559 call_path_table(0, 0, 0, 0) 567 call_path_table(0, 0, 0, 0)
560 568
561unhandled_count = 0 569unhandled_count = 0
@@ -571,8 +579,9 @@ def trace_end():
571 copy_output_file(symbol_file, "symbols") 579 copy_output_file(symbol_file, "symbols")
572 copy_output_file(branch_type_file, "branch_types") 580 copy_output_file(branch_type_file, "branch_types")
573 copy_output_file(sample_file, "samples") 581 copy_output_file(sample_file, "samples")
574 if perf_db_export_calls: 582 if perf_db_export_calls or perf_db_export_callchains:
575 copy_output_file(call_path_file, "call_paths") 583 copy_output_file(call_path_file, "call_paths")
584 if perf_db_export_calls:
576 copy_output_file(call_file, "calls") 585 copy_output_file(call_file, "calls")
577 586
578 print datetime.datetime.today(), "Removing intermediate files..." 587 print datetime.datetime.today(), "Removing intermediate files..."
@@ -585,8 +594,9 @@ def trace_end():
585 remove_output_file(symbol_file) 594 remove_output_file(symbol_file)
586 remove_output_file(branch_type_file) 595 remove_output_file(branch_type_file)
587 remove_output_file(sample_file) 596 remove_output_file(sample_file)
588 if perf_db_export_calls: 597 if perf_db_export_calls or perf_db_export_callchains:
589 remove_output_file(call_path_file) 598 remove_output_file(call_path_file)
599 if perf_db_export_calls:
590 remove_output_file(call_file) 600 remove_output_file(call_file)
591 os.rmdir(output_dir_name) 601 os.rmdir(output_dir_name)
592 print datetime.datetime.today(), "Adding primary keys" 602 print datetime.datetime.today(), "Adding primary keys"
@@ -599,8 +609,9 @@ def trace_end():
599 do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)') 609 do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)')
600 do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)') 610 do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)')
601 do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)') 611 do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)')
602 if perf_db_export_calls: 612 if perf_db_export_calls or perf_db_export_callchains:
603 do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)') 613 do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)')
614 if perf_db_export_calls:
604 do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)') 615 do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)')
605 616
606 print datetime.datetime.today(), "Adding foreign keys" 617 print datetime.datetime.today(), "Adding foreign keys"
@@ -623,10 +634,11 @@ def trace_end():
623 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),' 634 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),'
624 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),' 635 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),'
625 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)') 636 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)')
626 if perf_db_export_calls: 637 if perf_db_export_calls or perf_db_export_callchains:
627 do_query(query, 'ALTER TABLE call_paths ' 638 do_query(query, 'ALTER TABLE call_paths '
628 'ADD CONSTRAINT parentfk FOREIGN KEY (parent_id) REFERENCES call_paths (id),' 639 'ADD CONSTRAINT parentfk FOREIGN KEY (parent_id) REFERENCES call_paths (id),'
629 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id)') 640 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id)')
641 if perf_db_export_calls:
630 do_query(query, 'ALTER TABLE calls ' 642 do_query(query, 'ALTER TABLE calls '
631 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),' 643 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),'
632 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),' 644 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),'
@@ -694,11 +706,11 @@ def branch_type_table(branch_type, name, *x):
694 value = struct.pack(fmt, 2, 4, branch_type, n, name) 706 value = struct.pack(fmt, 2, 4, branch_type, n, name)
695 branch_type_file.write(value) 707 branch_type_file.write(value)
696 708
697def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, branch_type, in_tx, *x): 709def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, branch_type, in_tx, call_path_id, *x):
698 if branches: 710 if branches:
699 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiB", 17, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 4, branch_type, 1, in_tx) 711 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiBiq", 18, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 4, branch_type, 1, in_tx, 8, call_path_id)
700 else: 712 else:
701 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiB", 21, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx) 713 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiBiq", 22, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx, 8, call_path_id)
702 sample_file.write(value) 714 sample_file.write(value)
703 715
704def call_path_table(cp_id, parent_id, symbol_id, ip, *x): 716def call_path_table(cp_id, parent_id, symbol_id, ip, *x):
diff --git a/tools/perf/scripts/python/netdev-times.py b/tools/perf/scripts/python/netdev-times.py
index 4d21ef2d601d..4c6f09ac7d12 100644
--- a/tools/perf/scripts/python/netdev-times.py
+++ b/tools/perf/scripts/python/netdev-times.py
@@ -252,9 +252,10 @@ def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, callchain, i
252 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret) 252 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret)
253 all_event_list.append(event_info) 253 all_event_list.append(event_info)
254 254
255def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, callchain, napi, dev_name): 255def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, callchain, napi,
256 dev_name, work=None, budget=None):
256 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 257 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
257 napi, dev_name) 258 napi, dev_name, work, budget)
258 all_event_list.append(event_info) 259 all_event_list.append(event_info)
259 260
260def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, 261def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr,
@@ -354,11 +355,13 @@ def handle_irq_softirq_exit(event_info):
354 receive_hunk_list.append(rec_data) 355 receive_hunk_list.append(rec_data)
355 356
356def handle_napi_poll(event_info): 357def handle_napi_poll(event_info):
357 (name, context, cpu, time, pid, comm, napi, dev_name) = event_info 358 (name, context, cpu, time, pid, comm, napi, dev_name,
359 work, budget) = event_info
358 if cpu in net_rx_dic.keys(): 360 if cpu in net_rx_dic.keys():
359 event_list = net_rx_dic[cpu]['event_list'] 361 event_list = net_rx_dic[cpu]['event_list']
360 rec_data = {'event_name':'napi_poll', 362 rec_data = {'event_name':'napi_poll',
361 'dev':dev_name, 'event_t':time} 363 'dev':dev_name, 'event_t':time,
364 'work':work, 'budget':budget}
362 event_list.append(rec_data) 365 event_list.append(rec_data)
363 366
364def handle_netif_rx(event_info): 367def handle_netif_rx(event_info):
diff --git a/tools/perf/scripts/python/stackcollapse.py b/tools/perf/scripts/python/stackcollapse.py
new file mode 100755
index 000000000000..5a605f70ef32
--- /dev/null
+++ b/tools/perf/scripts/python/stackcollapse.py
@@ -0,0 +1,125 @@
1# stackcollapse.py - format perf samples with one line per distinct call stack
2#
3# This script's output has two space-separated fields. The first is a semicolon
4# separated stack including the program name (from the "comm" field) and the
5# function names from the call stack. The second is a count:
6#
7# swapper;start_kernel;rest_init;cpu_idle;default_idle;native_safe_halt 2
8#
9# The file is sorted according to the first field.
10#
11# Input may be created and processed using:
12#
13# perf record -a -g -F 99 sleep 60
14# perf script report stackcollapse > out.stacks-folded
15#
16# (perf script record stackcollapse works too).
17#
18# Written by Paolo Bonzini <pbonzini@redhat.com>
19# Based on Brendan Gregg's stackcollapse-perf.pl script.
20
21import os
22import sys
23from collections import defaultdict
24from optparse import OptionParser, make_option
25
26sys.path.append(os.environ['PERF_EXEC_PATH'] + \
27 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
28
29from perf_trace_context import *
30from Core import *
31from EventClass import *
32
33# command line parsing
34
35option_list = [
36 # formatting options for the bottom entry of the stack
37 make_option("--include-tid", dest="include_tid",
38 action="store_true", default=False,
39 help="include thread id in stack"),
40 make_option("--include-pid", dest="include_pid",
41 action="store_true", default=False,
42 help="include process id in stack"),
43 make_option("--no-comm", dest="include_comm",
44 action="store_false", default=True,
45 help="do not separate stacks according to comm"),
46 make_option("--tidy-java", dest="tidy_java",
47 action="store_true", default=False,
48 help="beautify Java signatures"),
49 make_option("--kernel", dest="annotate_kernel",
50 action="store_true", default=False,
51 help="annotate kernel functions with _[k]")
52]
53
54parser = OptionParser(option_list=option_list)
55(opts, args) = parser.parse_args()
56
57if len(args) != 0:
58 parser.error("unexpected command line argument")
59if opts.include_tid and not opts.include_comm:
60 parser.error("requesting tid but not comm is invalid")
61if opts.include_pid and not opts.include_comm:
62 parser.error("requesting pid but not comm is invalid")
63
64# event handlers
65
66lines = defaultdict(lambda: 0)
67
68def process_event(param_dict):
69 def tidy_function_name(sym, dso):
70 if sym is None:
71 sym = '[unknown]'
72
73 sym = sym.replace(';', ':')
74 if opts.tidy_java:
75 # the original stackcollapse-perf.pl script gives the
76 # example of converting this:
77 # Lorg/mozilla/javascript/MemberBox;.<init>(Ljava/lang/reflect/Method;)V
78 # to this:
79 # org/mozilla/javascript/MemberBox:.init
80 sym = sym.replace('<', '')
81 sym = sym.replace('>', '')
82 if sym[0] == 'L' and sym.find('/'):
83 sym = sym[1:]
84 try:
85 sym = sym[:sym.index('(')]
86 except ValueError:
87 pass
88
89 if opts.annotate_kernel and dso == '[kernel.kallsyms]':
90 return sym + '_[k]'
91 else:
92 return sym
93
94 stack = list()
95 if 'callchain' in param_dict:
96 for entry in param_dict['callchain']:
97 entry.setdefault('sym', dict())
98 entry['sym'].setdefault('name', None)
99 entry.setdefault('dso', None)
100 stack.append(tidy_function_name(entry['sym']['name'],
101 entry['dso']))
102 else:
103 param_dict.setdefault('symbol', None)
104 param_dict.setdefault('dso', None)
105 stack.append(tidy_function_name(param_dict['symbol'],
106 param_dict['dso']))
107
108 if opts.include_comm:
109 comm = param_dict["comm"].replace(' ', '_')
110 sep = "-"
111 if opts.include_pid:
112 comm = comm + sep + str(param_dict['sample']['pid'])
113 sep = "/"
114 if opts.include_tid:
115 comm = comm + sep + str(param_dict['sample']['tid'])
116 stack.append(comm)
117
118 stack_string = ';'.join(reversed(stack))
119 lines[stack_string] = lines[stack_string] + 1
120
121def trace_end():
122 list = lines.keys()
123 list.sort()
124 for stack in list:
125 print "%s %d" % (stack, lines[stack])