aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/scripts/python/export-to-postgresql.py
diff options
context:
space:
mode:
authorChris Phlipot <cphlipot0@gmail.com>2016-04-28 04:19:11 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-05-06 12:00:55 -0400
commit3521f3bc9dae4a79cfb9cc9ffcf6d961bbb7cbac (patch)
treef9ab06040883d80fb89a99c842f0aca31a0afd17 /tools/perf/scripts/python/export-to-postgresql.py
parent2c15f5eb04e9e7e19a2c8be6b50c63a4c6062a44 (diff)
perf script: Update export-to-postgresql to support callchain export
Update the export-to-postgresql.py to support the newly introduced callchain export. callchains are added into the existing call_paths table and can now be associated with samples when the "callpaths" commandline option is used with the script. Ex.: $ perf script -s export-to-postgresql.py example_db all callchains Includes the following changes to enable callchain export via the python export APIs: - Add the "callchains" commandline option, which is used to enable callchain export by setting the perf_db_export_callchains global - Add perf_db_export_callchains checks for call_path table creation and population. - Add call_path_id to samples_table to conform with the new API example usage and output using a small test app: test_app.c: volatile int x = 0; void inc_x_loop() { int i; for(i=0; i<100000000; i++) x++; } void a() { inc_x_loop(); } void b() { inc_x_loop(); } int main() { a(); b(); return 0; } example usage: $ gcc -g -O0 test_app.c $ perf record --call-graph=dwarf ./a.out [ perf record: Woken up 77 times to write data ] [ perf record: Captured and wrote 19.373 MB perf.data (2404 samples) ] $ perf script -s scripts/python/export-to-postgresql.py example_db all callchains $ psql example_db example_db=# SELECT (SELECT name FROM symbols WHERE id = cps.symbol_id) as symbol, (SELECT name FROM symbols WHERE id = (SELECT symbol_id from call_paths where id = cps.parent_id)) as parent_symbol, sum(period) as event_count FROM samples join call_paths as cps on call_path_id = cps.id GROUP BY cps.id,evsel_id ORDER BY event_count DESC LIMIT 5; symbol | parent_symbol | event_count ------------------+--------------------------+------------- inc_x_loop | a | 734250982 inc_x_loop | b | 731028057 unknown | unknown | 1335858 task_tick_fair | scheduler_tick | 1238842 update_wall_time | tick_do_update_jiffies64 | 650373 (5 rows) The above data shows total "self time" in cycles for each call path that was sampled. It is intended to demonstrate how it accounts separately for the two ways to reach the "inc_x_loop" function(via "a" and "b"). Recursive common table expressions can be used as well to get cumulative time spent in a function as well, but that is beyond the scope of this basic example. Signed-off-by: Chris Phlipot <cphlipot0@gmail.com> Acked-by: Adrian Hunter <adrian.hunter@intel.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/1461831551-12213-7-git-send-email-cphlipot0@gmail.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/scripts/python/export-to-postgresql.py')
-rw-r--r--tools/perf/scripts/python/export-to-postgresql.py47
1 files changed, 30 insertions, 17 deletions
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py
index 6f0ca6873c17..7656ff8aa066 100644
--- a/tools/perf/scripts/python/export-to-postgresql.py
+++ b/tools/perf/scripts/python/export-to-postgresql.py
@@ -223,11 +223,14 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
223 223
224perf_db_export_mode = True 224perf_db_export_mode = True
225perf_db_export_calls = False 225perf_db_export_calls = False
226perf_db_export_callchains = False
227
226 228
227def usage(): 229def usage():
228 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>]"
229 print >> sys.stderr, "where: columns 'all' or 'branches'" 231 print >> sys.stderr, "where: columns 'all' or 'branches'"
230 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"
231 raise Exception("Too few arguments") 234 raise Exception("Too few arguments")
232 235
233if (len(sys.argv) < 2): 236if (len(sys.argv) < 2):
@@ -245,9 +248,11 @@ if columns not in ("all", "branches"):
245 248
246branches = (columns == "branches") 249branches = (columns == "branches")
247 250
248if (len(sys.argv) >= 4): 251for i in range(3,len(sys.argv)):
249 if (sys.argv[3] == "calls"): 252 if (sys.argv[i] == "calls"):
250 perf_db_export_calls = True 253 perf_db_export_calls = True
254 elif (sys.argv[i] == "callchains"):
255 perf_db_export_callchains = True
251 else: 256 else:
252 usage() 257 usage()
253 258
@@ -358,14 +363,16 @@ else:
358 'transaction bigint,' 363 'transaction bigint,'
359 'data_src bigint,' 364 'data_src bigint,'
360 'branch_type integer,' 365 'branch_type integer,'
361 'in_tx boolean)') 366 'in_tx boolean,'
367 'call_path_id bigint)')
362 368
363if perf_db_export_calls: 369if perf_db_export_calls or perf_db_export_callchains:
364 do_query(query, 'CREATE TABLE call_paths (' 370 do_query(query, 'CREATE TABLE call_paths ('
365 'id bigint NOT NULL,' 371 'id bigint NOT NULL,'
366 'parent_id bigint,' 372 'parent_id bigint,'
367 'symbol_id bigint,' 373 'symbol_id bigint,'
368 'ip bigint)') 374 'ip bigint)')
375if perf_db_export_calls:
369 do_query(query, 'CREATE TABLE calls (' 376 do_query(query, 'CREATE TABLE calls ('
370 'id bigint NOT NULL,' 377 'id bigint NOT NULL,'
371 'thread_id bigint,' 378 'thread_id bigint,'
@@ -427,7 +434,7 @@ do_query(query, 'CREATE VIEW comm_threads_view AS '
427 '(SELECT tid FROM threads WHERE id = thread_id) AS tid' 434 '(SELECT tid FROM threads WHERE id = thread_id) AS tid'
428 ' FROM comm_threads') 435 ' FROM comm_threads')
429 436
430if perf_db_export_calls: 437if perf_db_export_calls or perf_db_export_callchains:
431 do_query(query, 'CREATE VIEW call_paths_view AS ' 438 do_query(query, 'CREATE VIEW call_paths_view AS '
432 'SELECT ' 439 'SELECT '
433 'c.id,' 440 'c.id,'
@@ -443,6 +450,7 @@ if perf_db_export_calls:
443 '(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,'
444 '(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'
445 ' 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:
446 do_query(query, 'CREATE VIEW calls_view AS ' 454 do_query(query, 'CREATE VIEW calls_view AS '
447 'SELECT ' 455 'SELECT '
448 'calls.id,' 456 'calls.id,'
@@ -540,8 +548,9 @@ dso_file = open_output_file("dso_table.bin")
540symbol_file = open_output_file("symbol_table.bin") 548symbol_file = open_output_file("symbol_table.bin")
541branch_type_file = open_output_file("branch_type_table.bin") 549branch_type_file = open_output_file("branch_type_table.bin")
542sample_file = open_output_file("sample_table.bin") 550sample_file = open_output_file("sample_table.bin")
543if perf_db_export_calls: 551if perf_db_export_calls or perf_db_export_callchains:
544 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:
545 call_file = open_output_file("call_table.bin") 554 call_file = open_output_file("call_table.bin")
546 555
547def trace_begin(): 556def trace_begin():
@@ -553,8 +562,8 @@ def trace_begin():
553 comm_table(0, "unknown") 562 comm_table(0, "unknown")
554 dso_table(0, 0, "unknown", "unknown", "") 563 dso_table(0, 0, "unknown", "unknown", "")
555 symbol_table(0, 0, 0, 0, 0, "unknown") 564 symbol_table(0, 0, 0, 0, 0, "unknown")
556 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)
557 if perf_db_export_calls: 566 if perf_db_export_calls or perf_db_export_callchains:
558 call_path_table(0, 0, 0, 0) 567 call_path_table(0, 0, 0, 0)
559 568
560unhandled_count = 0 569unhandled_count = 0
@@ -570,8 +579,9 @@ def trace_end():
570 copy_output_file(symbol_file, "symbols") 579 copy_output_file(symbol_file, "symbols")
571 copy_output_file(branch_type_file, "branch_types") 580 copy_output_file(branch_type_file, "branch_types")
572 copy_output_file(sample_file, "samples") 581 copy_output_file(sample_file, "samples")
573 if perf_db_export_calls: 582 if perf_db_export_calls or perf_db_export_callchains:
574 copy_output_file(call_path_file, "call_paths") 583 copy_output_file(call_path_file, "call_paths")
584 if perf_db_export_calls:
575 copy_output_file(call_file, "calls") 585 copy_output_file(call_file, "calls")
576 586
577 print datetime.datetime.today(), "Removing intermediate files..." 587 print datetime.datetime.today(), "Removing intermediate files..."
@@ -584,8 +594,9 @@ def trace_end():
584 remove_output_file(symbol_file) 594 remove_output_file(symbol_file)
585 remove_output_file(branch_type_file) 595 remove_output_file(branch_type_file)
586 remove_output_file(sample_file) 596 remove_output_file(sample_file)
587 if perf_db_export_calls: 597 if perf_db_export_calls or perf_db_export_callchains:
588 remove_output_file(call_path_file) 598 remove_output_file(call_path_file)
599 if perf_db_export_calls:
589 remove_output_file(call_file) 600 remove_output_file(call_file)
590 os.rmdir(output_dir_name) 601 os.rmdir(output_dir_name)
591 print datetime.datetime.today(), "Adding primary keys" 602 print datetime.datetime.today(), "Adding primary keys"
@@ -598,8 +609,9 @@ def trace_end():
598 do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)') 609 do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)')
599 do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)') 610 do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)')
600 do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)') 611 do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)')
601 if perf_db_export_calls: 612 if perf_db_export_calls or perf_db_export_callchains:
602 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:
603 do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)') 615 do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)')
604 616
605 print datetime.datetime.today(), "Adding foreign keys" 617 print datetime.datetime.today(), "Adding foreign keys"
@@ -622,10 +634,11 @@ def trace_end():
622 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),' 634 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),'
623 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),' 635 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),'
624 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)') 636 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)')
625 if perf_db_export_calls: 637 if perf_db_export_calls or perf_db_export_callchains:
626 do_query(query, 'ALTER TABLE call_paths ' 638 do_query(query, 'ALTER TABLE call_paths '
627 'ADD CONSTRAINT parentfk FOREIGN KEY (parent_id) REFERENCES call_paths (id),' 639 'ADD CONSTRAINT parentfk FOREIGN KEY (parent_id) REFERENCES call_paths (id),'
628 '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:
629 do_query(query, 'ALTER TABLE calls ' 642 do_query(query, 'ALTER TABLE calls '
630 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),' 643 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),'
631 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),' 644 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),'
@@ -693,11 +706,11 @@ def branch_type_table(branch_type, name, *x):
693 value = struct.pack(fmt, 2, 4, branch_type, n, name) 706 value = struct.pack(fmt, 2, 4, branch_type, n, name)
694 branch_type_file.write(value) 707 branch_type_file.write(value)
695 708
696def 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):
697 if branches: 710 if branches:
698 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)
699 else: 712 else:
700 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)
701 sample_file.write(value) 714 sample_file.write(value)
702 715
703def call_path_table(cp_id, parent_id, symbol_id, ip, *x): 716def call_path_table(cp_id, parent_id, symbol_id, ip, *x):