aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/scripts/python
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2019-07-08 12:06:57 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2019-07-08 12:06:57 -0400
commite3b22a65348ab54261a98b6bc90ecf8977ff8ebf (patch)
tree81c517d6f0e5585be7af5ffa1a4d4136b1f4a9c6 /tools/perf/scripts/python
parent05c78468a60f2fd961cd0a0c01c27f288bf81204 (diff)
parent552a031ba12a4236be107a5b082a399237758a5d (diff)
Merge remote-tracking branch 'tip/perf/core' into perf/urgent
To pick up fixes. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/scripts/python')
-rw-r--r--tools/perf/scripts/python/export-to-postgresql.py330
-rw-r--r--tools/perf/scripts/python/export-to-sqlite.py319
-rwxr-xr-xtools/perf/scripts/python/exported-sql-viewer.py345
3 files changed, 874 insertions, 120 deletions
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py
index c3eae1d77d36..4447f0d7c754 100644
--- a/tools/perf/scripts/python/export-to-postgresql.py
+++ b/tools/perf/scripts/python/export-to-postgresql.py
@@ -27,18 +27,31 @@ import datetime
27# 27#
28# fedora: 28# fedora:
29# 29#
30# $ sudo yum install postgresql postgresql-server python-pyside qt-postgresql 30# $ sudo yum install postgresql postgresql-server qt-postgresql
31# $ sudo su - postgres -c initdb 31# $ sudo su - postgres -c initdb
32# $ sudo service postgresql start 32# $ sudo service postgresql start
33# $ sudo su - postgres 33# $ sudo su - postgres
34# $ createuser <your user id here> 34# $ createuser -s <your user id here> # Older versions may not support -s, in which case answer the prompt below:
35# Shall the new role be a superuser? (y/n) y 35# Shall the new role be a superuser? (y/n) y
36# $ sudo yum install python-pyside
37#
38# Alternately, to use Python3 and/or pyside 2, one of the following:
39# $ sudo yum install python3-pyside
40# $ pip install --user PySide2
41# $ pip3 install --user PySide2
36# 42#
37# ubuntu: 43# ubuntu:
38# 44#
39# $ sudo apt-get install postgresql python-pyside.qtsql libqt4-sql-psql 45# $ sudo apt-get install postgresql
40# $ sudo su - postgres 46# $ sudo su - postgres
41# $ createuser -s <your user id here> 47# $ createuser -s <your user id here>
48# $ sudo apt-get install python-pyside.qtsql libqt4-sql-psql
49#
50# Alternately, to use Python3 and/or pyside 2, one of the following:
51#
52# $ sudo apt-get install python3-pyside.qtsql libqt4-sql-psql
53# $ sudo apt-get install python-pyside2.qtsql libqt5sql5-psql
54# $ sudo apt-get install python3-pyside2.qtsql libqt5sql5-psql
42# 55#
43# An example of using this script with Intel PT: 56# An example of using this script with Intel PT:
44# 57#
@@ -199,7 +212,16 @@ import datetime
199# print "{0:>6} {1:>10} {2:>9} {3:<30} {4:>6} {5:<30}".format(query.value(0), query.value(1), query.value(2), query.value(3), query.value(4), query.value(5)) 212# print "{0:>6} {1:>10} {2:>9} {3:<30} {4:>6} {5:<30}".format(query.value(0), query.value(1), query.value(2), query.value(3), query.value(4), query.value(5))
200# call_path_id = query.value(6) 213# call_path_id = query.value(6)
201 214
202from PySide.QtSql import * 215pyside_version_1 = True
216if not "pyside-version-1" in sys.argv:
217 try:
218 from PySide2.QtSql import *
219 pyside_version_1 = False
220 except:
221 pass
222
223if pyside_version_1:
224 from PySide.QtSql import *
203 225
204if sys.version_info < (3, 0): 226if sys.version_info < (3, 0):
205 def toserverstr(str): 227 def toserverstr(str):
@@ -255,11 +277,12 @@ def printdate(*args, **kw_args):
255 print(datetime.datetime.today(), *args, sep=' ', **kw_args) 277 print(datetime.datetime.today(), *args, sep=' ', **kw_args)
256 278
257def usage(): 279def usage():
258 printerr("Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>] [<callchains>]") 280 printerr("Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>] [<callchains>] [<pyside-version-1>]");
259 printerr("where: columns 'all' or 'branches'") 281 printerr("where: columns 'all' or 'branches'");
260 printerr(" calls 'calls' => create calls and call_paths table") 282 printerr(" calls 'calls' => create calls and call_paths table");
261 printerr(" callchains 'callchains' => create call_paths table") 283 printerr(" callchains 'callchains' => create call_paths table");
262 raise Exception("Too few arguments") 284 printerr(" pyside-version-1 'pyside-version-1' => use pyside version 1");
285 raise Exception("Too few or bad arguments")
263 286
264if (len(sys.argv) < 2): 287if (len(sys.argv) < 2):
265 usage() 288 usage()
@@ -281,6 +304,8 @@ for i in range(3,len(sys.argv)):
281 perf_db_export_calls = True 304 perf_db_export_calls = True
282 elif (sys.argv[i] == "callchains"): 305 elif (sys.argv[i] == "callchains"):
283 perf_db_export_callchains = True 306 perf_db_export_callchains = True
307 elif (sys.argv[i] == "pyside-version-1"):
308 pass
284 else: 309 else:
285 usage() 310 usage()
286 311
@@ -369,7 +394,9 @@ if branches:
369 'to_ip bigint,' 394 'to_ip bigint,'
370 'branch_type integer,' 395 'branch_type integer,'
371 'in_tx boolean,' 396 'in_tx boolean,'
372 'call_path_id bigint)') 397 'call_path_id bigint,'
398 'insn_count bigint,'
399 'cyc_count bigint)')
373else: 400else:
374 do_query(query, 'CREATE TABLE samples (' 401 do_query(query, 'CREATE TABLE samples ('
375 'id bigint NOT NULL,' 402 'id bigint NOT NULL,'
@@ -393,7 +420,9 @@ else:
393 'data_src bigint,' 420 'data_src bigint,'
394 'branch_type integer,' 421 'branch_type integer,'
395 'in_tx boolean,' 422 'in_tx boolean,'
396 'call_path_id bigint)') 423 'call_path_id bigint,'
424 'insn_count bigint,'
425 'cyc_count bigint)')
397 426
398if perf_db_export_calls or perf_db_export_callchains: 427if perf_db_export_calls or perf_db_export_callchains:
399 do_query(query, 'CREATE TABLE call_paths (' 428 do_query(query, 'CREATE TABLE call_paths ('
@@ -414,7 +443,41 @@ if perf_db_export_calls:
414 'return_id bigint,' 443 'return_id bigint,'
415 'parent_call_path_id bigint,' 444 'parent_call_path_id bigint,'
416 'flags integer,' 445 'flags integer,'
417 'parent_id bigint)') 446 'parent_id bigint,'
447 'insn_count bigint,'
448 'cyc_count bigint)')
449
450do_query(query, 'CREATE TABLE ptwrite ('
451 'id bigint NOT NULL,'
452 'payload bigint,'
453 'exact_ip boolean)')
454
455do_query(query, 'CREATE TABLE cbr ('
456 'id bigint NOT NULL,'
457 'cbr integer,'
458 'mhz integer,'
459 'percent integer)')
460
461do_query(query, 'CREATE TABLE mwait ('
462 'id bigint NOT NULL,'
463 'hints integer,'
464 'extensions integer)')
465
466do_query(query, 'CREATE TABLE pwre ('
467 'id bigint NOT NULL,'
468 'cstate integer,'
469 'subcstate integer,'
470 'hw boolean)')
471
472do_query(query, 'CREATE TABLE exstop ('
473 'id bigint NOT NULL,'
474 'exact_ip boolean)')
475
476do_query(query, 'CREATE TABLE pwrx ('
477 'id bigint NOT NULL,'
478 'deepest_cstate integer,'
479 'last_cstate integer,'
480 'wake_reason integer)')
418 481
419do_query(query, 'CREATE VIEW machines_view AS ' 482do_query(query, 'CREATE VIEW machines_view AS '
420 'SELECT ' 483 'SELECT '
@@ -496,6 +559,9 @@ if perf_db_export_calls:
496 'return_time,' 559 'return_time,'
497 'return_time - call_time AS elapsed_time,' 560 'return_time - call_time AS elapsed_time,'
498 'branch_count,' 561 'branch_count,'
562 'insn_count,'
563 'cyc_count,'
564 'CASE WHEN cyc_count=0 THEN CAST(0 AS NUMERIC(20, 2)) ELSE CAST((CAST(insn_count AS FLOAT) / cyc_count) AS NUMERIC(20, 2)) END AS IPC,'
499 'call_id,' 565 'call_id,'
500 'return_id,' 566 'return_id,'
501 'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE CAST ( flags AS VARCHAR(6) ) END AS flags,' 567 'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE CAST ( flags AS VARCHAR(6) ) END AS flags,'
@@ -521,9 +587,110 @@ do_query(query, 'CREATE VIEW samples_view AS '
521 'to_sym_offset,' 587 'to_sym_offset,'
522 '(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name,' 588 '(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name,'
523 '(SELECT name FROM branch_types WHERE id = branch_type) AS branch_type_name,' 589 '(SELECT name FROM branch_types WHERE id = branch_type) AS branch_type_name,'
524 'in_tx' 590 'in_tx,'
591 'insn_count,'
592 'cyc_count,'
593 'CASE WHEN cyc_count=0 THEN CAST(0 AS NUMERIC(20, 2)) ELSE CAST((CAST(insn_count AS FLOAT) / cyc_count) AS NUMERIC(20, 2)) END AS IPC'
525 ' FROM samples') 594 ' FROM samples')
526 595
596do_query(query, 'CREATE VIEW ptwrite_view AS '
597 'SELECT '
598 'ptwrite.id,'
599 'time,'
600 'cpu,'
601 'to_hex(payload) AS payload_hex,'
602 'CASE WHEN exact_ip=FALSE THEN \'False\' ELSE \'True\' END AS exact_ip'
603 ' FROM ptwrite'
604 ' INNER JOIN samples ON samples.id = ptwrite.id')
605
606do_query(query, 'CREATE VIEW cbr_view AS '
607 'SELECT '
608 'cbr.id,'
609 'time,'
610 'cpu,'
611 'cbr,'
612 'mhz,'
613 'percent'
614 ' FROM cbr'
615 ' INNER JOIN samples ON samples.id = cbr.id')
616
617do_query(query, 'CREATE VIEW mwait_view AS '
618 'SELECT '
619 'mwait.id,'
620 'time,'
621 'cpu,'
622 'to_hex(hints) AS hints_hex,'
623 'to_hex(extensions) AS extensions_hex'
624 ' FROM mwait'
625 ' INNER JOIN samples ON samples.id = mwait.id')
626
627do_query(query, 'CREATE VIEW pwre_view AS '
628 'SELECT '
629 'pwre.id,'
630 'time,'
631 'cpu,'
632 'cstate,'
633 'subcstate,'
634 'CASE WHEN hw=FALSE THEN \'False\' ELSE \'True\' END AS hw'
635 ' FROM pwre'
636 ' INNER JOIN samples ON samples.id = pwre.id')
637
638do_query(query, 'CREATE VIEW exstop_view AS '
639 'SELECT '
640 'exstop.id,'
641 'time,'
642 'cpu,'
643 'CASE WHEN exact_ip=FALSE THEN \'False\' ELSE \'True\' END AS exact_ip'
644 ' FROM exstop'
645 ' INNER JOIN samples ON samples.id = exstop.id')
646
647do_query(query, 'CREATE VIEW pwrx_view AS '
648 'SELECT '
649 'pwrx.id,'
650 'time,'
651 'cpu,'
652 'deepest_cstate,'
653 'last_cstate,'
654 'CASE WHEN wake_reason=1 THEN \'Interrupt\''
655 ' WHEN wake_reason=2 THEN \'Timer Deadline\''
656 ' WHEN wake_reason=4 THEN \'Monitored Address\''
657 ' WHEN wake_reason=8 THEN \'HW\''
658 ' ELSE CAST ( wake_reason AS VARCHAR(2) )'
659 'END AS wake_reason'
660 ' FROM pwrx'
661 ' INNER JOIN samples ON samples.id = pwrx.id')
662
663do_query(query, 'CREATE VIEW power_events_view AS '
664 'SELECT '
665 'samples.id,'
666 'samples.time,'
667 'samples.cpu,'
668 'selected_events.name AS event,'
669 'FORMAT(\'%6s\', cbr.cbr) AS cbr,'
670 'FORMAT(\'%6s\', cbr.mhz) AS MHz,'
671 'FORMAT(\'%5s\', cbr.percent) AS percent,'
672 'to_hex(mwait.hints) AS hints_hex,'
673 'to_hex(mwait.extensions) AS extensions_hex,'
674 'FORMAT(\'%3s\', pwre.cstate) AS cstate,'
675 'FORMAT(\'%3s\', pwre.subcstate) AS subcstate,'
676 'CASE WHEN pwre.hw=FALSE THEN \'False\' WHEN pwre.hw=TRUE THEN \'True\' ELSE NULL END AS hw,'
677 'CASE WHEN exstop.exact_ip=FALSE THEN \'False\' WHEN exstop.exact_ip=TRUE THEN \'True\' ELSE NULL END AS exact_ip,'
678 'FORMAT(\'%3s\', pwrx.deepest_cstate) AS deepest_cstate,'
679 'FORMAT(\'%3s\', pwrx.last_cstate) AS last_cstate,'
680 'CASE WHEN pwrx.wake_reason=1 THEN \'Interrupt\''
681 ' WHEN pwrx.wake_reason=2 THEN \'Timer Deadline\''
682 ' WHEN pwrx.wake_reason=4 THEN \'Monitored Address\''
683 ' WHEN pwrx.wake_reason=8 THEN \'HW\''
684 ' ELSE FORMAT(\'%2s\', pwrx.wake_reason)'
685 'END AS wake_reason'
686 ' FROM cbr'
687 ' FULL JOIN mwait ON mwait.id = cbr.id'
688 ' FULL JOIN pwre ON pwre.id = cbr.id'
689 ' FULL JOIN exstop ON exstop.id = cbr.id'
690 ' FULL JOIN pwrx ON pwrx.id = cbr.id'
691 ' INNER JOIN samples ON samples.id = coalesce(cbr.id, mwait.id, pwre.id, exstop.id, pwrx.id)'
692 ' INNER JOIN selected_events ON selected_events.id = samples.evsel_id'
693 ' ORDER BY samples.id')
527 694
528file_header = struct.pack("!11sii", b"PGCOPY\n\377\r\n\0", 0, 0) 695file_header = struct.pack("!11sii", b"PGCOPY\n\377\r\n\0", 0, 0)
529file_trailer = b"\377\377" 696file_trailer = b"\377\377"
@@ -583,6 +750,12 @@ if perf_db_export_calls or perf_db_export_callchains:
583 call_path_file = open_output_file("call_path_table.bin") 750 call_path_file = open_output_file("call_path_table.bin")
584if perf_db_export_calls: 751if perf_db_export_calls:
585 call_file = open_output_file("call_table.bin") 752 call_file = open_output_file("call_table.bin")
753ptwrite_file = open_output_file("ptwrite_table.bin")
754cbr_file = open_output_file("cbr_table.bin")
755mwait_file = open_output_file("mwait_table.bin")
756pwre_file = open_output_file("pwre_table.bin")
757exstop_file = open_output_file("exstop_table.bin")
758pwrx_file = open_output_file("pwrx_table.bin")
586 759
587def trace_begin(): 760def trace_begin():
588 printdate("Writing to intermediate files...") 761 printdate("Writing to intermediate files...")
@@ -593,13 +766,23 @@ def trace_begin():
593 comm_table(0, "unknown") 766 comm_table(0, "unknown")
594 dso_table(0, 0, "unknown", "unknown", "") 767 dso_table(0, 0, "unknown", "unknown", "")
595 symbol_table(0, 0, 0, 0, 0, "unknown") 768 symbol_table(0, 0, 0, 0, 0, "unknown")
596 sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 769 sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
597 if perf_db_export_calls or perf_db_export_callchains: 770 if perf_db_export_calls or perf_db_export_callchains:
598 call_path_table(0, 0, 0, 0) 771 call_path_table(0, 0, 0, 0)
599 call_return_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 772 call_return_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
600 773
601unhandled_count = 0 774unhandled_count = 0
602 775
776def is_table_empty(table_name):
777 do_query(query, 'SELECT * FROM ' + table_name + ' LIMIT 1');
778 if query.next():
779 return False
780 return True
781
782def drop(table_name):
783 do_query(query, 'DROP VIEW ' + table_name + '_view');
784 do_query(query, 'DROP TABLE ' + table_name);
785
603def trace_end(): 786def trace_end():
604 printdate("Copying to database...") 787 printdate("Copying to database...")
605 copy_output_file(evsel_file, "selected_events") 788 copy_output_file(evsel_file, "selected_events")
@@ -615,6 +798,12 @@ def trace_end():
615 copy_output_file(call_path_file, "call_paths") 798 copy_output_file(call_path_file, "call_paths")
616 if perf_db_export_calls: 799 if perf_db_export_calls:
617 copy_output_file(call_file, "calls") 800 copy_output_file(call_file, "calls")
801 copy_output_file(ptwrite_file, "ptwrite")
802 copy_output_file(cbr_file, "cbr")
803 copy_output_file(mwait_file, "mwait")
804 copy_output_file(pwre_file, "pwre")
805 copy_output_file(exstop_file, "exstop")
806 copy_output_file(pwrx_file, "pwrx")
618 807
619 printdate("Removing intermediate files...") 808 printdate("Removing intermediate files...")
620 remove_output_file(evsel_file) 809 remove_output_file(evsel_file)
@@ -630,6 +819,12 @@ def trace_end():
630 remove_output_file(call_path_file) 819 remove_output_file(call_path_file)
631 if perf_db_export_calls: 820 if perf_db_export_calls:
632 remove_output_file(call_file) 821 remove_output_file(call_file)
822 remove_output_file(ptwrite_file)
823 remove_output_file(cbr_file)
824 remove_output_file(mwait_file)
825 remove_output_file(pwre_file)
826 remove_output_file(exstop_file)
827 remove_output_file(pwrx_file)
633 os.rmdir(output_dir_name) 828 os.rmdir(output_dir_name)
634 printdate("Adding primary keys") 829 printdate("Adding primary keys")
635 do_query(query, 'ALTER TABLE selected_events ADD PRIMARY KEY (id)') 830 do_query(query, 'ALTER TABLE selected_events ADD PRIMARY KEY (id)')
@@ -645,6 +840,12 @@ def trace_end():
645 do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)') 840 do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)')
646 if perf_db_export_calls: 841 if perf_db_export_calls:
647 do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)') 842 do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)')
843 do_query(query, 'ALTER TABLE ptwrite ADD PRIMARY KEY (id)')
844 do_query(query, 'ALTER TABLE cbr ADD PRIMARY KEY (id)')
845 do_query(query, 'ALTER TABLE mwait ADD PRIMARY KEY (id)')
846 do_query(query, 'ALTER TABLE pwre ADD PRIMARY KEY (id)')
847 do_query(query, 'ALTER TABLE exstop ADD PRIMARY KEY (id)')
848 do_query(query, 'ALTER TABLE pwrx ADD PRIMARY KEY (id)')
648 849
649 printdate("Adding foreign keys") 850 printdate("Adding foreign keys")
650 do_query(query, 'ALTER TABLE threads ' 851 do_query(query, 'ALTER TABLE threads '
@@ -680,6 +881,30 @@ def trace_end():
680 'ADD CONSTRAINT parent_call_pathfk FOREIGN KEY (parent_call_path_id) REFERENCES call_paths (id)') 881 'ADD CONSTRAINT parent_call_pathfk FOREIGN KEY (parent_call_path_id) REFERENCES call_paths (id)')
681 do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)') 882 do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
682 do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)') 883 do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)')
884 do_query(query, 'ALTER TABLE ptwrite '
885 'ADD CONSTRAINT idfk FOREIGN KEY (id) REFERENCES samples (id)')
886 do_query(query, 'ALTER TABLE cbr '
887 'ADD CONSTRAINT idfk FOREIGN KEY (id) REFERENCES samples (id)')
888 do_query(query, 'ALTER TABLE mwait '
889 'ADD CONSTRAINT idfk FOREIGN KEY (id) REFERENCES samples (id)')
890 do_query(query, 'ALTER TABLE pwre '
891 'ADD CONSTRAINT idfk FOREIGN KEY (id) REFERENCES samples (id)')
892 do_query(query, 'ALTER TABLE exstop '
893 'ADD CONSTRAINT idfk FOREIGN KEY (id) REFERENCES samples (id)')
894 do_query(query, 'ALTER TABLE pwrx '
895 'ADD CONSTRAINT idfk FOREIGN KEY (id) REFERENCES samples (id)')
896
897 printdate("Dropping unused tables")
898 if is_table_empty("ptwrite"):
899 drop("ptwrite")
900 if is_table_empty("mwait") and is_table_empty("pwre") and is_table_empty("exstop") and is_table_empty("pwrx"):
901 drop("mwait")
902 drop("pwre")
903 drop("exstop")
904 drop("pwrx")
905 do_query(query, 'DROP VIEW power_events_view');
906 if is_table_empty("cbr"):
907 drop("cbr")
683 908
684 if (unhandled_count): 909 if (unhandled_count):
685 printdate("Warning: ", unhandled_count, " unhandled events") 910 printdate("Warning: ", unhandled_count, " unhandled events")
@@ -747,11 +972,11 @@ def branch_type_table(branch_type, name, *x):
747 value = struct.pack(fmt, 2, 4, branch_type, n, name) 972 value = struct.pack(fmt, 2, 4, branch_type, n, name)
748 branch_type_file.write(value) 973 branch_type_file.write(value)
749 974
750def 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): 975def 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, insn_cnt, cyc_cnt, *x):
751 if branches: 976 if branches:
752 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) 977 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiBiqiqiq", 20, 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, 8, insn_cnt, 8, cyc_cnt)
753 else: 978 else:
754 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) 979 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiBiqiqiq", 24, 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, 8, insn_cnt, 8, cyc_cnt)
755 sample_file.write(value) 980 sample_file.write(value)
756 981
757def call_path_table(cp_id, parent_id, symbol_id, ip, *x): 982def call_path_table(cp_id, parent_id, symbol_id, ip, *x):
@@ -759,7 +984,70 @@ def call_path_table(cp_id, parent_id, symbol_id, ip, *x):
759 value = struct.pack(fmt, 4, 8, cp_id, 8, parent_id, 8, symbol_id, 8, ip) 984 value = struct.pack(fmt, 4, 8, cp_id, 8, parent_id, 8, symbol_id, 8, ip)
760 call_path_file.write(value) 985 call_path_file.write(value)
761 986
762def call_return_table(cr_id, thread_id, comm_id, call_path_id, call_time, return_time, branch_count, call_id, return_id, parent_call_path_id, flags, parent_id, *x): 987def call_return_table(cr_id, thread_id, comm_id, call_path_id, call_time, return_time, branch_count, call_id, return_id, parent_call_path_id, flags, parent_id, insn_cnt, cyc_cnt, *x):
763 fmt = "!hiqiqiqiqiqiqiqiqiqiqiiiq" 988 fmt = "!hiqiqiqiqiqiqiqiqiqiqiiiqiqiq"
764 value = struct.pack(fmt, 12, 8, cr_id, 8, thread_id, 8, comm_id, 8, call_path_id, 8, call_time, 8, return_time, 8, branch_count, 8, call_id, 8, return_id, 8, parent_call_path_id, 4, flags, 8, parent_id) 989 value = struct.pack(fmt, 14, 8, cr_id, 8, thread_id, 8, comm_id, 8, call_path_id, 8, call_time, 8, return_time, 8, branch_count, 8, call_id, 8, return_id, 8, parent_call_path_id, 4, flags, 8, parent_id, 8, insn_cnt, 8, cyc_cnt)
765 call_file.write(value) 990 call_file.write(value)
991
992def ptwrite(id, raw_buf):
993 data = struct.unpack_from("<IQ", raw_buf)
994 flags = data[0]
995 payload = data[1]
996 exact_ip = flags & 1
997 value = struct.pack("!hiqiqiB", 3, 8, id, 8, payload, 1, exact_ip)
998 ptwrite_file.write(value)
999
1000def cbr(id, raw_buf):
1001 data = struct.unpack_from("<BBBBII", raw_buf)
1002 cbr = data[0]
1003 MHz = (data[4] + 500) / 1000
1004 percent = ((cbr * 1000 / data[2]) + 5) / 10
1005 value = struct.pack("!hiqiiiiii", 4, 8, id, 4, cbr, 4, MHz, 4, percent)
1006 cbr_file.write(value)
1007
1008def mwait(id, raw_buf):
1009 data = struct.unpack_from("<IQ", raw_buf)
1010 payload = data[1]
1011 hints = payload & 0xff
1012 extensions = (payload >> 32) & 0x3
1013 value = struct.pack("!hiqiiii", 3, 8, id, 4, hints, 4, extensions)
1014 mwait_file.write(value)
1015
1016def pwre(id, raw_buf):
1017 data = struct.unpack_from("<IQ", raw_buf)
1018 payload = data[1]
1019 hw = (payload >> 7) & 1
1020 cstate = (payload >> 12) & 0xf
1021 subcstate = (payload >> 8) & 0xf
1022 value = struct.pack("!hiqiiiiiB", 4, 8, id, 4, cstate, 4, subcstate, 1, hw)
1023 pwre_file.write(value)
1024
1025def exstop(id, raw_buf):
1026 data = struct.unpack_from("<I", raw_buf)
1027 flags = data[0]
1028 exact_ip = flags & 1
1029 value = struct.pack("!hiqiB", 2, 8, id, 1, exact_ip)
1030 exstop_file.write(value)
1031
1032def pwrx(id, raw_buf):
1033 data = struct.unpack_from("<IQ", raw_buf)
1034 payload = data[1]
1035 deepest_cstate = payload & 0xf
1036 last_cstate = (payload >> 4) & 0xf
1037 wake_reason = (payload >> 8) & 0xf
1038 value = struct.pack("!hiqiiiiii", 4, 8, id, 4, deepest_cstate, 4, last_cstate, 4, wake_reason)
1039 pwrx_file.write(value)
1040
1041def synth_data(id, config, raw_buf, *x):
1042 if config == 0:
1043 ptwrite(id, raw_buf)
1044 elif config == 1:
1045 mwait(id, raw_buf)
1046 elif config == 2:
1047 pwre(id, raw_buf)
1048 elif config == 3:
1049 exstop(id, raw_buf)
1050 elif config == 4:
1051 pwrx(id, raw_buf)
1052 elif config == 5:
1053 cbr(id, raw_buf)
diff --git a/tools/perf/scripts/python/export-to-sqlite.py b/tools/perf/scripts/python/export-to-sqlite.py
index bf271fbc3a88..3222a83f4184 100644
--- a/tools/perf/scripts/python/export-to-sqlite.py
+++ b/tools/perf/scripts/python/export-to-sqlite.py
@@ -21,6 +21,26 @@ import datetime
21# provides LGPL-licensed Python bindings for Qt. You will also need the package 21# provides LGPL-licensed Python bindings for Qt. You will also need the package
22# libqt4-sql-sqlite for Qt sqlite3 support. 22# libqt4-sql-sqlite for Qt sqlite3 support.
23# 23#
24# Examples of installing pyside:
25#
26# ubuntu:
27#
28# $ sudo apt-get install python-pyside.qtsql libqt4-sql-psql
29#
30# Alternately, to use Python3 and/or pyside 2, one of the following:
31#
32# $ sudo apt-get install python3-pyside.qtsql libqt4-sql-psql
33# $ sudo apt-get install python-pyside2.qtsql libqt5sql5-psql
34# $ sudo apt-get install python3-pyside2.qtsql libqt5sql5-psql
35# fedora:
36#
37# $ sudo yum install python-pyside
38#
39# Alternately, to use Python3 and/or pyside 2, one of the following:
40# $ sudo yum install python3-pyside
41# $ pip install --user PySide2
42# $ pip3 install --user PySide2
43#
24# An example of using this script with Intel PT: 44# An example of using this script with Intel PT:
25# 45#
26# $ perf record -e intel_pt//u ls 46# $ perf record -e intel_pt//u ls
@@ -49,7 +69,16 @@ import datetime
49# difference is the 'transaction' column of the 'samples' table which is 69# difference is the 'transaction' column of the 'samples' table which is
50# renamed 'transaction_' in sqlite because 'transaction' is a reserved word. 70# renamed 'transaction_' in sqlite because 'transaction' is a reserved word.
51 71
52from PySide.QtSql import * 72pyside_version_1 = True
73if not "pyside-version-1" in sys.argv:
74 try:
75 from PySide2.QtSql import *
76 pyside_version_1 = False
77 except:
78 pass
79
80if pyside_version_1:
81 from PySide.QtSql import *
53 82
54sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 83sys.path.append(os.environ['PERF_EXEC_PATH'] + \
55 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 84 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
@@ -69,11 +98,12 @@ def printdate(*args, **kw_args):
69 print(datetime.datetime.today(), *args, sep=' ', **kw_args) 98 print(datetime.datetime.today(), *args, sep=' ', **kw_args)
70 99
71def usage(): 100def usage():
72 printerr("Usage is: export-to-sqlite.py <database name> [<columns>] [<calls>] [<callchains>]"); 101 printerr("Usage is: export-to-sqlite.py <database name> [<columns>] [<calls>] [<callchains>] [<pyside-version-1>]");
73 printerr("where: columns 'all' or 'branches'"); 102 printerr("where: columns 'all' or 'branches'");
74 printerr(" calls 'calls' => create calls and call_paths table"); 103 printerr(" calls 'calls' => create calls and call_paths table");
75 printerr(" callchains 'callchains' => create call_paths table"); 104 printerr(" callchains 'callchains' => create call_paths table");
76 raise Exception("Too few arguments") 105 printerr(" pyside-version-1 'pyside-version-1' => use pyside version 1");
106 raise Exception("Too few or bad arguments")
77 107
78if (len(sys.argv) < 2): 108if (len(sys.argv) < 2):
79 usage() 109 usage()
@@ -95,6 +125,8 @@ for i in range(3,len(sys.argv)):
95 perf_db_export_calls = True 125 perf_db_export_calls = True
96 elif (sys.argv[i] == "callchains"): 126 elif (sys.argv[i] == "callchains"):
97 perf_db_export_callchains = True 127 perf_db_export_callchains = True
128 elif (sys.argv[i] == "pyside-version-1"):
129 pass
98 else: 130 else:
99 usage() 131 usage()
100 132
@@ -186,7 +218,9 @@ if branches:
186 'to_ip bigint,' 218 'to_ip bigint,'
187 'branch_type integer,' 219 'branch_type integer,'
188 'in_tx boolean,' 220 'in_tx boolean,'
189 'call_path_id bigint)') 221 'call_path_id bigint,'
222 'insn_count bigint,'
223 'cyc_count bigint)')
190else: 224else:
191 do_query(query, 'CREATE TABLE samples (' 225 do_query(query, 'CREATE TABLE samples ('
192 'id integer NOT NULL PRIMARY KEY,' 226 'id integer NOT NULL PRIMARY KEY,'
@@ -210,7 +244,9 @@ else:
210 'data_src bigint,' 244 'data_src bigint,'
211 'branch_type integer,' 245 'branch_type integer,'
212 'in_tx boolean,' 246 'in_tx boolean,'
213 'call_path_id bigint)') 247 'call_path_id bigint,'
248 'insn_count bigint,'
249 'cyc_count bigint)')
214 250
215if perf_db_export_calls or perf_db_export_callchains: 251if perf_db_export_calls or perf_db_export_callchains:
216 do_query(query, 'CREATE TABLE call_paths (' 252 do_query(query, 'CREATE TABLE call_paths ('
@@ -231,7 +267,41 @@ if perf_db_export_calls:
231 'return_id bigint,' 267 'return_id bigint,'
232 'parent_call_path_id bigint,' 268 'parent_call_path_id bigint,'
233 'flags integer,' 269 'flags integer,'
234 'parent_id bigint)') 270 'parent_id bigint,'
271 'insn_count bigint,'
272 'cyc_count bigint)')
273
274do_query(query, 'CREATE TABLE ptwrite ('
275 'id integer NOT NULL PRIMARY KEY,'
276 'payload bigint,'
277 'exact_ip integer)')
278
279do_query(query, 'CREATE TABLE cbr ('
280 'id integer NOT NULL PRIMARY KEY,'
281 'cbr integer,'
282 'mhz integer,'
283 'percent integer)')
284
285do_query(query, 'CREATE TABLE mwait ('
286 'id integer NOT NULL PRIMARY KEY,'
287 'hints integer,'
288 'extensions integer)')
289
290do_query(query, 'CREATE TABLE pwre ('
291 'id integer NOT NULL PRIMARY KEY,'
292 'cstate integer,'
293 'subcstate integer,'
294 'hw integer)')
295
296do_query(query, 'CREATE TABLE exstop ('
297 'id integer NOT NULL PRIMARY KEY,'
298 'exact_ip integer)')
299
300do_query(query, 'CREATE TABLE pwrx ('
301 'id integer NOT NULL PRIMARY KEY,'
302 'deepest_cstate integer,'
303 'last_cstate integer,'
304 'wake_reason integer)')
235 305
236# printf was added to sqlite in version 3.8.3 306# printf was added to sqlite in version 3.8.3
237sqlite_has_printf = False 307sqlite_has_printf = False
@@ -327,6 +397,9 @@ if perf_db_export_calls:
327 'return_time,' 397 'return_time,'
328 'return_time - call_time AS elapsed_time,' 398 'return_time - call_time AS elapsed_time,'
329 'branch_count,' 399 'branch_count,'
400 'insn_count,'
401 'cyc_count,'
402 'CASE WHEN cyc_count=0 THEN CAST(0 AS FLOAT) ELSE ROUND(CAST(insn_count AS FLOAT) / cyc_count, 2) END AS IPC,'
330 'call_id,' 403 'call_id,'
331 'return_id,' 404 'return_id,'
332 'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE flags END AS flags,' 405 'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE flags END AS flags,'
@@ -352,9 +425,108 @@ do_query(query, 'CREATE VIEW samples_view AS '
352 'to_sym_offset,' 425 'to_sym_offset,'
353 '(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name,' 426 '(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name,'
354 '(SELECT name FROM branch_types WHERE id = branch_type) AS branch_type_name,' 427 '(SELECT name FROM branch_types WHERE id = branch_type) AS branch_type_name,'
355 'in_tx' 428 'in_tx,'
429 'insn_count,'
430 'cyc_count,'
431 'CASE WHEN cyc_count=0 THEN CAST(0 AS FLOAT) ELSE ROUND(CAST(insn_count AS FLOAT) / cyc_count, 2) END AS IPC'
356 ' FROM samples') 432 ' FROM samples')
357 433
434do_query(query, 'CREATE VIEW ptwrite_view AS '
435 'SELECT '
436 'ptwrite.id,'
437 'time,'
438 'cpu,'
439 + emit_to_hex('payload') + ' AS payload_hex,'
440 'CASE WHEN exact_ip=0 THEN \'False\' ELSE \'True\' END AS exact_ip'
441 ' FROM ptwrite'
442 ' INNER JOIN samples ON samples.id = ptwrite.id')
443
444do_query(query, 'CREATE VIEW cbr_view AS '
445 'SELECT '
446 'cbr.id,'
447 'time,'
448 'cpu,'
449 'cbr,'
450 'mhz,'
451 'percent'
452 ' FROM cbr'
453 ' INNER JOIN samples ON samples.id = cbr.id')
454
455do_query(query, 'CREATE VIEW mwait_view AS '
456 'SELECT '
457 'mwait.id,'
458 'time,'
459 'cpu,'
460 + emit_to_hex('hints') + ' AS hints_hex,'
461 + emit_to_hex('extensions') + ' AS extensions_hex'
462 ' FROM mwait'
463 ' INNER JOIN samples ON samples.id = mwait.id')
464
465do_query(query, 'CREATE VIEW pwre_view AS '
466 'SELECT '
467 'pwre.id,'
468 'time,'
469 'cpu,'
470 'cstate,'
471 'subcstate,'
472 'CASE WHEN hw=0 THEN \'False\' ELSE \'True\' END AS hw'
473 ' FROM pwre'
474 ' INNER JOIN samples ON samples.id = pwre.id')
475
476do_query(query, 'CREATE VIEW exstop_view AS '
477 'SELECT '
478 'exstop.id,'
479 'time,'
480 'cpu,'
481 'CASE WHEN exact_ip=0 THEN \'False\' ELSE \'True\' END AS exact_ip'
482 ' FROM exstop'
483 ' INNER JOIN samples ON samples.id = exstop.id')
484
485do_query(query, 'CREATE VIEW pwrx_view AS '
486 'SELECT '
487 'pwrx.id,'
488 'time,'
489 'cpu,'
490 'deepest_cstate,'
491 'last_cstate,'
492 'CASE WHEN wake_reason=1 THEN \'Interrupt\''
493 ' WHEN wake_reason=2 THEN \'Timer Deadline\''
494 ' WHEN wake_reason=4 THEN \'Monitored Address\''
495 ' WHEN wake_reason=8 THEN \'HW\''
496 ' ELSE wake_reason '
497 'END AS wake_reason'
498 ' FROM pwrx'
499 ' INNER JOIN samples ON samples.id = pwrx.id')
500
501do_query(query, 'CREATE VIEW power_events_view AS '
502 'SELECT '
503 'samples.id,'
504 'time,'
505 'cpu,'
506 'selected_events.name AS event,'
507 'CASE WHEN selected_events.name=\'cbr\' THEN (SELECT cbr FROM cbr WHERE cbr.id = samples.id) ELSE "" END AS cbr,'
508 'CASE WHEN selected_events.name=\'cbr\' THEN (SELECT mhz FROM cbr WHERE cbr.id = samples.id) ELSE "" END AS mhz,'
509 'CASE WHEN selected_events.name=\'cbr\' THEN (SELECT percent FROM cbr WHERE cbr.id = samples.id) ELSE "" END AS percent,'
510 'CASE WHEN selected_events.name=\'mwait\' THEN (SELECT ' + emit_to_hex('hints') + ' FROM mwait WHERE mwait.id = samples.id) ELSE "" END AS hints_hex,'
511 'CASE WHEN selected_events.name=\'mwait\' THEN (SELECT ' + emit_to_hex('extensions') + ' FROM mwait WHERE mwait.id = samples.id) ELSE "" END AS extensions_hex,'
512 'CASE WHEN selected_events.name=\'pwre\' THEN (SELECT cstate FROM pwre WHERE pwre.id = samples.id) ELSE "" END AS cstate,'
513 'CASE WHEN selected_events.name=\'pwre\' THEN (SELECT subcstate FROM pwre WHERE pwre.id = samples.id) ELSE "" END AS subcstate,'
514 'CASE WHEN selected_events.name=\'pwre\' THEN (SELECT hw FROM pwre WHERE pwre.id = samples.id) ELSE "" END AS hw,'
515 'CASE WHEN selected_events.name=\'exstop\' THEN (SELECT exact_ip FROM exstop WHERE exstop.id = samples.id) ELSE "" END AS exact_ip,'
516 'CASE WHEN selected_events.name=\'pwrx\' THEN (SELECT deepest_cstate FROM pwrx WHERE pwrx.id = samples.id) ELSE "" END AS deepest_cstate,'
517 'CASE WHEN selected_events.name=\'pwrx\' THEN (SELECT last_cstate FROM pwrx WHERE pwrx.id = samples.id) ELSE "" END AS last_cstate,'
518 'CASE WHEN selected_events.name=\'pwrx\' THEN (SELECT '
519 'CASE WHEN wake_reason=1 THEN \'Interrupt\''
520 ' WHEN wake_reason=2 THEN \'Timer Deadline\''
521 ' WHEN wake_reason=4 THEN \'Monitored Address\''
522 ' WHEN wake_reason=8 THEN \'HW\''
523 ' ELSE wake_reason '
524 'END'
525 ' FROM pwrx WHERE pwrx.id = samples.id) ELSE "" END AS wake_reason'
526 ' FROM samples'
527 ' INNER JOIN selected_events ON selected_events.id = evsel_id'
528 ' WHERE selected_events.name IN (\'cbr\',\'mwait\',\'exstop\',\'pwre\',\'pwrx\')')
529
358do_query(query, 'END TRANSACTION') 530do_query(query, 'END TRANSACTION')
359 531
360evsel_query = QSqlQuery(db) 532evsel_query = QSqlQuery(db)
@@ -375,15 +547,27 @@ branch_type_query = QSqlQuery(db)
375branch_type_query.prepare("INSERT INTO branch_types VALUES (?, ?)") 547branch_type_query.prepare("INSERT INTO branch_types VALUES (?, ?)")
376sample_query = QSqlQuery(db) 548sample_query = QSqlQuery(db)
377if branches: 549if branches:
378 sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") 550 sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
379else: 551else:
380 sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") 552 sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
381if perf_db_export_calls or perf_db_export_callchains: 553if perf_db_export_calls or perf_db_export_callchains:
382 call_path_query = QSqlQuery(db) 554 call_path_query = QSqlQuery(db)
383 call_path_query.prepare("INSERT INTO call_paths VALUES (?, ?, ?, ?)") 555 call_path_query.prepare("INSERT INTO call_paths VALUES (?, ?, ?, ?)")
384if perf_db_export_calls: 556if perf_db_export_calls:
385 call_query = QSqlQuery(db) 557 call_query = QSqlQuery(db)
386 call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") 558 call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
559ptwrite_query = QSqlQuery(db)
560ptwrite_query.prepare("INSERT INTO ptwrite VALUES (?, ?, ?)")
561cbr_query = QSqlQuery(db)
562cbr_query.prepare("INSERT INTO cbr VALUES (?, ?, ?, ?)")
563mwait_query = QSqlQuery(db)
564mwait_query.prepare("INSERT INTO mwait VALUES (?, ?, ?)")
565pwre_query = QSqlQuery(db)
566pwre_query.prepare("INSERT INTO pwre VALUES (?, ?, ?, ?)")
567exstop_query = QSqlQuery(db)
568exstop_query.prepare("INSERT INTO exstop VALUES (?, ?)")
569pwrx_query = QSqlQuery(db)
570pwrx_query.prepare("INSERT INTO pwrx VALUES (?, ?, ?, ?)")
387 571
388def trace_begin(): 572def trace_begin():
389 printdate("Writing records...") 573 printdate("Writing records...")
@@ -395,13 +579,23 @@ def trace_begin():
395 comm_table(0, "unknown") 579 comm_table(0, "unknown")
396 dso_table(0, 0, "unknown", "unknown", "") 580 dso_table(0, 0, "unknown", "unknown", "")
397 symbol_table(0, 0, 0, 0, 0, "unknown") 581 symbol_table(0, 0, 0, 0, 0, "unknown")
398 sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 582 sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
399 if perf_db_export_calls or perf_db_export_callchains: 583 if perf_db_export_calls or perf_db_export_callchains:
400 call_path_table(0, 0, 0, 0) 584 call_path_table(0, 0, 0, 0)
401 call_return_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 585 call_return_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
402 586
403unhandled_count = 0 587unhandled_count = 0
404 588
589def is_table_empty(table_name):
590 do_query(query, 'SELECT * FROM ' + table_name + ' LIMIT 1');
591 if query.next():
592 return False
593 return True
594
595def drop(table_name):
596 do_query(query, 'DROP VIEW ' + table_name + '_view');
597 do_query(query, 'DROP TABLE ' + table_name);
598
405def trace_end(): 599def trace_end():
406 do_query(query, 'END TRANSACTION') 600 do_query(query, 'END TRANSACTION')
407 601
@@ -410,6 +604,18 @@ def trace_end():
410 do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)') 604 do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
411 do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)') 605 do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)')
412 606
607 printdate("Dropping unused tables")
608 if is_table_empty("ptwrite"):
609 drop("ptwrite")
610 if is_table_empty("mwait") and is_table_empty("pwre") and is_table_empty("exstop") and is_table_empty("pwrx"):
611 drop("mwait")
612 drop("pwre")
613 drop("exstop")
614 drop("pwrx")
615 do_query(query, 'DROP VIEW power_events_view');
616 if is_table_empty("cbr"):
617 drop("cbr")
618
413 if (unhandled_count): 619 if (unhandled_count):
414 printdate("Warning: ", unhandled_count, " unhandled events") 620 printdate("Warning: ", unhandled_count, " unhandled events")
415 printdate("Done") 621 printdate("Done")
@@ -454,14 +660,91 @@ def sample_table(*x):
454 if branches: 660 if branches:
455 for xx in x[0:15]: 661 for xx in x[0:15]:
456 sample_query.addBindValue(str(xx)) 662 sample_query.addBindValue(str(xx))
457 for xx in x[19:22]: 663 for xx in x[19:24]:
458 sample_query.addBindValue(str(xx)) 664 sample_query.addBindValue(str(xx))
459 do_query_(sample_query) 665 do_query_(sample_query)
460 else: 666 else:
461 bind_exec(sample_query, 22, x) 667 bind_exec(sample_query, 24, x)
462 668
463def call_path_table(*x): 669def call_path_table(*x):
464 bind_exec(call_path_query, 4, x) 670 bind_exec(call_path_query, 4, x)
465 671
466def call_return_table(*x): 672def call_return_table(*x):
467 bind_exec(call_query, 12, x) 673 bind_exec(call_query, 14, x)
674
675def ptwrite(id, raw_buf):
676 data = struct.unpack_from("<IQ", raw_buf)
677 flags = data[0]
678 payload = data[1]
679 exact_ip = flags & 1
680 ptwrite_query.addBindValue(str(id))
681 ptwrite_query.addBindValue(str(payload))
682 ptwrite_query.addBindValue(str(exact_ip))
683 do_query_(ptwrite_query)
684
685def cbr(id, raw_buf):
686 data = struct.unpack_from("<BBBBII", raw_buf)
687 cbr = data[0]
688 MHz = (data[4] + 500) / 1000
689 percent = ((cbr * 1000 / data[2]) + 5) / 10
690 cbr_query.addBindValue(str(id))
691 cbr_query.addBindValue(str(cbr))
692 cbr_query.addBindValue(str(MHz))
693 cbr_query.addBindValue(str(percent))
694 do_query_(cbr_query)
695
696def mwait(id, raw_buf):
697 data = struct.unpack_from("<IQ", raw_buf)
698 payload = data[1]
699 hints = payload & 0xff
700 extensions = (payload >> 32) & 0x3
701 mwait_query.addBindValue(str(id))
702 mwait_query.addBindValue(str(hints))
703 mwait_query.addBindValue(str(extensions))
704 do_query_(mwait_query)
705
706def pwre(id, raw_buf):
707 data = struct.unpack_from("<IQ", raw_buf)
708 payload = data[1]
709 hw = (payload >> 7) & 1
710 cstate = (payload >> 12) & 0xf
711 subcstate = (payload >> 8) & 0xf
712 pwre_query.addBindValue(str(id))
713 pwre_query.addBindValue(str(cstate))
714 pwre_query.addBindValue(str(subcstate))
715 pwre_query.addBindValue(str(hw))
716 do_query_(pwre_query)
717
718def exstop(id, raw_buf):
719 data = struct.unpack_from("<I", raw_buf)
720 flags = data[0]
721 exact_ip = flags & 1
722 exstop_query.addBindValue(str(id))
723 exstop_query.addBindValue(str(exact_ip))
724 do_query_(exstop_query)
725
726def pwrx(id, raw_buf):
727 data = struct.unpack_from("<IQ", raw_buf)
728 payload = data[1]
729 deepest_cstate = payload & 0xf
730 last_cstate = (payload >> 4) & 0xf
731 wake_reason = (payload >> 8) & 0xf
732 pwrx_query.addBindValue(str(id))
733 pwrx_query.addBindValue(str(deepest_cstate))
734 pwrx_query.addBindValue(str(last_cstate))
735 pwrx_query.addBindValue(str(wake_reason))
736 do_query_(pwrx_query)
737
738def synth_data(id, config, raw_buf, *x):
739 if config == 0:
740 ptwrite(id, raw_buf)
741 elif config == 1:
742 mwait(id, raw_buf)
743 elif config == 2:
744 pwre(id, raw_buf)
745 elif config == 3:
746 exstop(id, raw_buf)
747 elif config == 4:
748 pwrx(id, raw_buf)
749 elif config == 5:
750 cbr(id, raw_buf)
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py
index affed7d149be..6e7934f2ac9a 100755
--- a/tools/perf/scripts/python/exported-sql-viewer.py
+++ b/tools/perf/scripts/python/exported-sql-viewer.py
@@ -1,4 +1,4 @@
1#!/usr/bin/env python2 1#!/usr/bin/env python
2# SPDX-License-Identifier: GPL-2.0 2# SPDX-License-Identifier: GPL-2.0
3# exported-sql-viewer.py: view data from sql database 3# exported-sql-viewer.py: view data from sql database
4# Copyright (c) 2014-2018, Intel Corporation. 4# Copyright (c) 2014-2018, Intel Corporation.
@@ -91,6 +91,7 @@
91from __future__ import print_function 91from __future__ import print_function
92 92
93import sys 93import sys
94import argparse
94import weakref 95import weakref
95import threading 96import threading
96import string 97import string
@@ -104,10 +105,23 @@ except ImportError:
104 glb_nsz = 16 105 glb_nsz = 16
105import re 106import re
106import os 107import os
107from PySide.QtCore import * 108
108from PySide.QtGui import *
109from PySide.QtSql import *
110pyside_version_1 = True 109pyside_version_1 = True
110if not "--pyside-version-1" in sys.argv:
111 try:
112 from PySide2.QtCore import *
113 from PySide2.QtGui import *
114 from PySide2.QtSql import *
115 from PySide2.QtWidgets import *
116 pyside_version_1 = False
117 except:
118 pass
119
120if pyside_version_1:
121 from PySide.QtCore import *
122 from PySide.QtGui import *
123 from PySide.QtSql import *
124
111from decimal import * 125from decimal import *
112from ctypes import * 126from ctypes import *
113from multiprocessing import Process, Array, Value, Event 127from multiprocessing import Process, Array, Value, Event
@@ -186,9 +200,10 @@ class Thread(QThread):
186 200
187class TreeModel(QAbstractItemModel): 201class TreeModel(QAbstractItemModel):
188 202
189 def __init__(self, glb, parent=None): 203 def __init__(self, glb, params, parent=None):
190 super(TreeModel, self).__init__(parent) 204 super(TreeModel, self).__init__(parent)
191 self.glb = glb 205 self.glb = glb
206 self.params = params
192 self.root = self.GetRoot() 207 self.root = self.GetRoot()
193 self.last_row_read = 0 208 self.last_row_read = 0
194 209
@@ -385,6 +400,7 @@ class FindBar():
385 400
386 def Activate(self): 401 def Activate(self):
387 self.bar.show() 402 self.bar.show()
403 self.textbox.lineEdit().selectAll()
388 self.textbox.setFocus() 404 self.textbox.setFocus()
389 405
390 def Deactivate(self): 406 def Deactivate(self):
@@ -449,8 +465,9 @@ class FindBar():
449 465
450class CallGraphLevelItemBase(object): 466class CallGraphLevelItemBase(object):
451 467
452 def __init__(self, glb, row, parent_item): 468 def __init__(self, glb, params, row, parent_item):
453 self.glb = glb 469 self.glb = glb
470 self.params = params
454 self.row = row 471 self.row = row
455 self.parent_item = parent_item 472 self.parent_item = parent_item
456 self.query_done = False; 473 self.query_done = False;
@@ -489,18 +506,24 @@ class CallGraphLevelItemBase(object):
489 506
490class CallGraphLevelTwoPlusItemBase(CallGraphLevelItemBase): 507class CallGraphLevelTwoPlusItemBase(CallGraphLevelItemBase):
491 508
492 def __init__(self, glb, row, comm_id, thread_id, call_path_id, time, branch_count, parent_item): 509 def __init__(self, glb, params, row, comm_id, thread_id, call_path_id, time, insn_cnt, cyc_cnt, branch_count, parent_item):
493 super(CallGraphLevelTwoPlusItemBase, self).__init__(glb, row, parent_item) 510 super(CallGraphLevelTwoPlusItemBase, self).__init__(glb, params, row, parent_item)
494 self.comm_id = comm_id 511 self.comm_id = comm_id
495 self.thread_id = thread_id 512 self.thread_id = thread_id
496 self.call_path_id = call_path_id 513 self.call_path_id = call_path_id
514 self.insn_cnt = insn_cnt
515 self.cyc_cnt = cyc_cnt
497 self.branch_count = branch_count 516 self.branch_count = branch_count
498 self.time = time 517 self.time = time
499 518
500 def Select(self): 519 def Select(self):
501 self.query_done = True; 520 self.query_done = True;
502 query = QSqlQuery(self.glb.db) 521 query = QSqlQuery(self.glb.db)
503 QueryExec(query, "SELECT call_path_id, name, short_name, COUNT(calls.id), SUM(return_time - call_time), SUM(branch_count)" 522 if self.params.have_ipc:
523 ipc_str = ", SUM(insn_count), SUM(cyc_count)"
524 else:
525 ipc_str = ""
526 QueryExec(query, "SELECT call_path_id, name, short_name, COUNT(calls.id), SUM(return_time - call_time)" + ipc_str + ", SUM(branch_count)"
504 " FROM calls" 527 " FROM calls"
505 " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" 528 " INNER JOIN call_paths ON calls.call_path_id = call_paths.id"
506 " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" 529 " INNER JOIN symbols ON call_paths.symbol_id = symbols.id"
@@ -511,7 +534,15 @@ class CallGraphLevelTwoPlusItemBase(CallGraphLevelItemBase):
511 " GROUP BY call_path_id, name, short_name" 534 " GROUP BY call_path_id, name, short_name"
512 " ORDER BY call_path_id") 535 " ORDER BY call_path_id")
513 while query.next(): 536 while query.next():
514 child_item = CallGraphLevelThreeItem(self.glb, self.child_count, self.comm_id, self.thread_id, query.value(0), query.value(1), query.value(2), query.value(3), int(query.value(4)), int(query.value(5)), self) 537 if self.params.have_ipc:
538 insn_cnt = int(query.value(5))
539 cyc_cnt = int(query.value(6))
540 branch_count = int(query.value(7))
541 else:
542 insn_cnt = 0
543 cyc_cnt = 0
544 branch_count = int(query.value(5))
545 child_item = CallGraphLevelThreeItem(self.glb, self.params, self.child_count, self.comm_id, self.thread_id, query.value(0), query.value(1), query.value(2), query.value(3), int(query.value(4)), insn_cnt, cyc_cnt, branch_count, self)
515 self.child_items.append(child_item) 546 self.child_items.append(child_item)
516 self.child_count += 1 547 self.child_count += 1
517 548
@@ -519,37 +550,57 @@ class CallGraphLevelTwoPlusItemBase(CallGraphLevelItemBase):
519 550
520class CallGraphLevelThreeItem(CallGraphLevelTwoPlusItemBase): 551class CallGraphLevelThreeItem(CallGraphLevelTwoPlusItemBase):
521 552
522 def __init__(self, glb, row, comm_id, thread_id, call_path_id, name, dso, count, time, branch_count, parent_item): 553 def __init__(self, glb, params, row, comm_id, thread_id, call_path_id, name, dso, count, time, insn_cnt, cyc_cnt, branch_count, parent_item):
523 super(CallGraphLevelThreeItem, self).__init__(glb, row, comm_id, thread_id, call_path_id, time, branch_count, parent_item) 554 super(CallGraphLevelThreeItem, self).__init__(glb, params, row, comm_id, thread_id, call_path_id, time, insn_cnt, cyc_cnt, branch_count, parent_item)
524 dso = dsoname(dso) 555 dso = dsoname(dso)
525 self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ] 556 if self.params.have_ipc:
557 insn_pcnt = PercentToOneDP(insn_cnt, parent_item.insn_cnt)
558 cyc_pcnt = PercentToOneDP(cyc_cnt, parent_item.cyc_cnt)
559 br_pcnt = PercentToOneDP(branch_count, parent_item.branch_count)
560 ipc = CalcIPC(cyc_cnt, insn_cnt)
561 self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(insn_cnt), insn_pcnt, str(cyc_cnt), cyc_pcnt, ipc, str(branch_count), br_pcnt ]
562 else:
563 self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ]
526 self.dbid = call_path_id 564 self.dbid = call_path_id
527 565
528# Context-sensitive call graph data model level two item 566# Context-sensitive call graph data model level two item
529 567
530class CallGraphLevelTwoItem(CallGraphLevelTwoPlusItemBase): 568class CallGraphLevelTwoItem(CallGraphLevelTwoPlusItemBase):
531 569
532 def __init__(self, glb, row, comm_id, thread_id, pid, tid, parent_item): 570 def __init__(self, glb, params, row, comm_id, thread_id, pid, tid, parent_item):
533 super(CallGraphLevelTwoItem, self).__init__(glb, row, comm_id, thread_id, 1, 0, 0, parent_item) 571 super(CallGraphLevelTwoItem, self).__init__(glb, params, row, comm_id, thread_id, 1, 0, 0, 0, 0, parent_item)
534 self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""] 572 if self.params.have_ipc:
573 self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", "", "", "", "", "", ""]
574 else:
575 self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""]
535 self.dbid = thread_id 576 self.dbid = thread_id
536 577
537 def Select(self): 578 def Select(self):
538 super(CallGraphLevelTwoItem, self).Select() 579 super(CallGraphLevelTwoItem, self).Select()
539 for child_item in self.child_items: 580 for child_item in self.child_items:
540 self.time += child_item.time 581 self.time += child_item.time
582 self.insn_cnt += child_item.insn_cnt
583 self.cyc_cnt += child_item.cyc_cnt
541 self.branch_count += child_item.branch_count 584 self.branch_count += child_item.branch_count
542 for child_item in self.child_items: 585 for child_item in self.child_items:
543 child_item.data[4] = PercentToOneDP(child_item.time, self.time) 586 child_item.data[4] = PercentToOneDP(child_item.time, self.time)
544 child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count) 587 if self.params.have_ipc:
588 child_item.data[6] = PercentToOneDP(child_item.insn_cnt, self.insn_cnt)
589 child_item.data[8] = PercentToOneDP(child_item.cyc_cnt, self.cyc_cnt)
590 child_item.data[11] = PercentToOneDP(child_item.branch_count, self.branch_count)
591 else:
592 child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count)
545 593
546# Context-sensitive call graph data model level one item 594# Context-sensitive call graph data model level one item
547 595
548class CallGraphLevelOneItem(CallGraphLevelItemBase): 596class CallGraphLevelOneItem(CallGraphLevelItemBase):
549 597
550 def __init__(self, glb, row, comm_id, comm, parent_item): 598 def __init__(self, glb, params, row, comm_id, comm, parent_item):
551 super(CallGraphLevelOneItem, self).__init__(glb, row, parent_item) 599 super(CallGraphLevelOneItem, self).__init__(glb, params, row, parent_item)
552 self.data = [comm, "", "", "", "", "", ""] 600 if self.params.have_ipc:
601 self.data = [comm, "", "", "", "", "", "", "", "", "", "", ""]
602 else:
603 self.data = [comm, "", "", "", "", "", ""]
553 self.dbid = comm_id 604 self.dbid = comm_id
554 605
555 def Select(self): 606 def Select(self):
@@ -560,7 +611,7 @@ class CallGraphLevelOneItem(CallGraphLevelItemBase):
560 " INNER JOIN threads ON thread_id = threads.id" 611 " INNER JOIN threads ON thread_id = threads.id"
561 " WHERE comm_id = " + str(self.dbid)) 612 " WHERE comm_id = " + str(self.dbid))
562 while query.next(): 613 while query.next():
563 child_item = CallGraphLevelTwoItem(self.glb, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self) 614 child_item = CallGraphLevelTwoItem(self.glb, self.params, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self)
564 self.child_items.append(child_item) 615 self.child_items.append(child_item)
565 self.child_count += 1 616 self.child_count += 1
566 617
@@ -568,8 +619,8 @@ class CallGraphLevelOneItem(CallGraphLevelItemBase):
568 619
569class CallGraphRootItem(CallGraphLevelItemBase): 620class CallGraphRootItem(CallGraphLevelItemBase):
570 621
571 def __init__(self, glb): 622 def __init__(self, glb, params):
572 super(CallGraphRootItem, self).__init__(glb, 0, None) 623 super(CallGraphRootItem, self).__init__(glb, params, 0, None)
573 self.dbid = 0 624 self.dbid = 0
574 self.query_done = True; 625 self.query_done = True;
575 query = QSqlQuery(glb.db) 626 query = QSqlQuery(glb.db)
@@ -577,16 +628,23 @@ class CallGraphRootItem(CallGraphLevelItemBase):
577 while query.next(): 628 while query.next():
578 if not query.value(0): 629 if not query.value(0):
579 continue 630 continue
580 child_item = CallGraphLevelOneItem(glb, self.child_count, query.value(0), query.value(1), self) 631 child_item = CallGraphLevelOneItem(glb, params, self.child_count, query.value(0), query.value(1), self)
581 self.child_items.append(child_item) 632 self.child_items.append(child_item)
582 self.child_count += 1 633 self.child_count += 1
583 634
635# Call graph model parameters
636
637class CallGraphModelParams():
638
639 def __init__(self, glb, parent=None):
640 self.have_ipc = IsSelectable(glb.db, "calls", columns = "insn_count, cyc_count")
641
584# Context-sensitive call graph data model base 642# Context-sensitive call graph data model base
585 643
586class CallGraphModelBase(TreeModel): 644class CallGraphModelBase(TreeModel):
587 645
588 def __init__(self, glb, parent=None): 646 def __init__(self, glb, parent=None):
589 super(CallGraphModelBase, self).__init__(glb, parent) 647 super(CallGraphModelBase, self).__init__(glb, CallGraphModelParams(glb), parent)
590 648
591 def FindSelect(self, value, pattern, query): 649 def FindSelect(self, value, pattern, query):
592 if pattern: 650 if pattern:
@@ -668,17 +726,26 @@ class CallGraphModel(CallGraphModelBase):
668 super(CallGraphModel, self).__init__(glb, parent) 726 super(CallGraphModel, self).__init__(glb, parent)
669 727
670 def GetRoot(self): 728 def GetRoot(self):
671 return CallGraphRootItem(self.glb) 729 return CallGraphRootItem(self.glb, self.params)
672 730
673 def columnCount(self, parent=None): 731 def columnCount(self, parent=None):
674 return 7 732 if self.params.have_ipc:
733 return 12
734 else:
735 return 7
675 736
676 def columnHeader(self, column): 737 def columnHeader(self, column):
677 headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] 738 if self.params.have_ipc:
739 headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Insn Cnt", "Insn Cnt (%)", "Cyc Cnt", "Cyc Cnt (%)", "IPC", "Branch Count ", "Branch Count (%) "]
740 else:
741 headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "]
678 return headers[column] 742 return headers[column]
679 743
680 def columnAlignment(self, column): 744 def columnAlignment(self, column):
681 alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] 745 if self.params.have_ipc:
746 alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ]
747 else:
748 alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ]
682 return alignment[column] 749 return alignment[column]
683 750
684 def DoFindSelect(self, query, match): 751 def DoFindSelect(self, query, match):
@@ -715,11 +782,13 @@ class CallGraphModel(CallGraphModelBase):
715 782
716class CallTreeLevelTwoPlusItemBase(CallGraphLevelItemBase): 783class CallTreeLevelTwoPlusItemBase(CallGraphLevelItemBase):
717 784
718 def __init__(self, glb, row, comm_id, thread_id, calls_id, time, branch_count, parent_item): 785 def __init__(self, glb, params, row, comm_id, thread_id, calls_id, time, insn_cnt, cyc_cnt, branch_count, parent_item):
719 super(CallTreeLevelTwoPlusItemBase, self).__init__(glb, row, parent_item) 786 super(CallTreeLevelTwoPlusItemBase, self).__init__(glb, params, row, parent_item)
720 self.comm_id = comm_id 787 self.comm_id = comm_id
721 self.thread_id = thread_id 788 self.thread_id = thread_id
722 self.calls_id = calls_id 789 self.calls_id = calls_id
790 self.insn_cnt = insn_cnt
791 self.cyc_cnt = cyc_cnt
723 self.branch_count = branch_count 792 self.branch_count = branch_count
724 self.time = time 793 self.time = time
725 794
@@ -729,8 +798,12 @@ class CallTreeLevelTwoPlusItemBase(CallGraphLevelItemBase):
729 comm_thread = " AND comm_id = " + str(self.comm_id) + " AND thread_id = " + str(self.thread_id) 798 comm_thread = " AND comm_id = " + str(self.comm_id) + " AND thread_id = " + str(self.thread_id)
730 else: 799 else:
731 comm_thread = "" 800 comm_thread = ""
801 if self.params.have_ipc:
802 ipc_str = ", insn_count, cyc_count"
803 else:
804 ipc_str = ""
732 query = QSqlQuery(self.glb.db) 805 query = QSqlQuery(self.glb.db)
733 QueryExec(query, "SELECT calls.id, name, short_name, call_time, return_time - call_time, branch_count" 806 QueryExec(query, "SELECT calls.id, name, short_name, call_time, return_time - call_time" + ipc_str + ", branch_count"
734 " FROM calls" 807 " FROM calls"
735 " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" 808 " INNER JOIN call_paths ON calls.call_path_id = call_paths.id"
736 " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" 809 " INNER JOIN symbols ON call_paths.symbol_id = symbols.id"
@@ -738,7 +811,15 @@ class CallTreeLevelTwoPlusItemBase(CallGraphLevelItemBase):
738 " WHERE calls.parent_id = " + str(self.calls_id) + comm_thread + 811 " WHERE calls.parent_id = " + str(self.calls_id) + comm_thread +
739 " ORDER BY call_time, calls.id") 812 " ORDER BY call_time, calls.id")
740 while query.next(): 813 while query.next():
741 child_item = CallTreeLevelThreeItem(self.glb, self.child_count, self.comm_id, self.thread_id, query.value(0), query.value(1), query.value(2), query.value(3), int(query.value(4)), int(query.value(5)), self) 814 if self.params.have_ipc:
815 insn_cnt = int(query.value(5))
816 cyc_cnt = int(query.value(6))
817 branch_count = int(query.value(7))
818 else:
819 insn_cnt = 0
820 cyc_cnt = 0
821 branch_count = int(query.value(5))
822 child_item = CallTreeLevelThreeItem(self.glb, self.params, self.child_count, self.comm_id, self.thread_id, query.value(0), query.value(1), query.value(2), query.value(3), int(query.value(4)), insn_cnt, cyc_cnt, branch_count, self)
742 self.child_items.append(child_item) 823 self.child_items.append(child_item)
743 self.child_count += 1 824 self.child_count += 1
744 825
@@ -746,37 +827,57 @@ class CallTreeLevelTwoPlusItemBase(CallGraphLevelItemBase):
746 827
747class CallTreeLevelThreeItem(CallTreeLevelTwoPlusItemBase): 828class CallTreeLevelThreeItem(CallTreeLevelTwoPlusItemBase):
748 829
749 def __init__(self, glb, row, comm_id, thread_id, calls_id, name, dso, count, time, branch_count, parent_item): 830 def __init__(self, glb, params, row, comm_id, thread_id, calls_id, name, dso, count, time, insn_cnt, cyc_cnt, branch_count, parent_item):
750 super(CallTreeLevelThreeItem, self).__init__(glb, row, comm_id, thread_id, calls_id, time, branch_count, parent_item) 831 super(CallTreeLevelThreeItem, self).__init__(glb, params, row, comm_id, thread_id, calls_id, time, insn_cnt, cyc_cnt, branch_count, parent_item)
751 dso = dsoname(dso) 832 dso = dsoname(dso)
752 self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ] 833 if self.params.have_ipc:
834 insn_pcnt = PercentToOneDP(insn_cnt, parent_item.insn_cnt)
835 cyc_pcnt = PercentToOneDP(cyc_cnt, parent_item.cyc_cnt)
836 br_pcnt = PercentToOneDP(branch_count, parent_item.branch_count)
837 ipc = CalcIPC(cyc_cnt, insn_cnt)
838 self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(insn_cnt), insn_pcnt, str(cyc_cnt), cyc_pcnt, ipc, str(branch_count), br_pcnt ]
839 else:
840 self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ]
753 self.dbid = calls_id 841 self.dbid = calls_id
754 842
755# Call tree data model level two item 843# Call tree data model level two item
756 844
757class CallTreeLevelTwoItem(CallTreeLevelTwoPlusItemBase): 845class CallTreeLevelTwoItem(CallTreeLevelTwoPlusItemBase):
758 846
759 def __init__(self, glb, row, comm_id, thread_id, pid, tid, parent_item): 847 def __init__(self, glb, params, row, comm_id, thread_id, pid, tid, parent_item):
760 super(CallTreeLevelTwoItem, self).__init__(glb, row, comm_id, thread_id, 0, 0, 0, parent_item) 848 super(CallTreeLevelTwoItem, self).__init__(glb, params, row, comm_id, thread_id, 0, 0, 0, 0, 0, parent_item)
761 self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""] 849 if self.params.have_ipc:
850 self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", "", "", "", "", "", ""]
851 else:
852 self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""]
762 self.dbid = thread_id 853 self.dbid = thread_id
763 854
764 def Select(self): 855 def Select(self):
765 super(CallTreeLevelTwoItem, self).Select() 856 super(CallTreeLevelTwoItem, self).Select()
766 for child_item in self.child_items: 857 for child_item in self.child_items:
767 self.time += child_item.time 858 self.time += child_item.time
859 self.insn_cnt += child_item.insn_cnt
860 self.cyc_cnt += child_item.cyc_cnt
768 self.branch_count += child_item.branch_count 861 self.branch_count += child_item.branch_count
769 for child_item in self.child_items: 862 for child_item in self.child_items:
770 child_item.data[4] = PercentToOneDP(child_item.time, self.time) 863 child_item.data[4] = PercentToOneDP(child_item.time, self.time)
771 child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count) 864 if self.params.have_ipc:
865 child_item.data[6] = PercentToOneDP(child_item.insn_cnt, self.insn_cnt)
866 child_item.data[8] = PercentToOneDP(child_item.cyc_cnt, self.cyc_cnt)
867 child_item.data[11] = PercentToOneDP(child_item.branch_count, self.branch_count)
868 else:
869 child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count)
772 870
773# Call tree data model level one item 871# Call tree data model level one item
774 872
775class CallTreeLevelOneItem(CallGraphLevelItemBase): 873class CallTreeLevelOneItem(CallGraphLevelItemBase):
776 874
777 def __init__(self, glb, row, comm_id, comm, parent_item): 875 def __init__(self, glb, params, row, comm_id, comm, parent_item):
778 super(CallTreeLevelOneItem, self).__init__(glb, row, parent_item) 876 super(CallTreeLevelOneItem, self).__init__(glb, params, row, parent_item)
779 self.data = [comm, "", "", "", "", "", ""] 877 if self.params.have_ipc:
878 self.data = [comm, "", "", "", "", "", "", "", "", "", "", ""]
879 else:
880 self.data = [comm, "", "", "", "", "", ""]
780 self.dbid = comm_id 881 self.dbid = comm_id
781 882
782 def Select(self): 883 def Select(self):
@@ -787,7 +888,7 @@ class CallTreeLevelOneItem(CallGraphLevelItemBase):
787 " INNER JOIN threads ON thread_id = threads.id" 888 " INNER JOIN threads ON thread_id = threads.id"
788 " WHERE comm_id = " + str(self.dbid)) 889 " WHERE comm_id = " + str(self.dbid))
789 while query.next(): 890 while query.next():
790 child_item = CallTreeLevelTwoItem(self.glb, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self) 891 child_item = CallTreeLevelTwoItem(self.glb, self.params, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self)
791 self.child_items.append(child_item) 892 self.child_items.append(child_item)
792 self.child_count += 1 893 self.child_count += 1
793 894
@@ -795,8 +896,8 @@ class CallTreeLevelOneItem(CallGraphLevelItemBase):
795 896
796class CallTreeRootItem(CallGraphLevelItemBase): 897class CallTreeRootItem(CallGraphLevelItemBase):
797 898
798 def __init__(self, glb): 899 def __init__(self, glb, params):
799 super(CallTreeRootItem, self).__init__(glb, 0, None) 900 super(CallTreeRootItem, self).__init__(glb, params, 0, None)
800 self.dbid = 0 901 self.dbid = 0
801 self.query_done = True; 902 self.query_done = True;
802 query = QSqlQuery(glb.db) 903 query = QSqlQuery(glb.db)
@@ -804,7 +905,7 @@ class CallTreeRootItem(CallGraphLevelItemBase):
804 while query.next(): 905 while query.next():
805 if not query.value(0): 906 if not query.value(0):
806 continue 907 continue
807 child_item = CallTreeLevelOneItem(glb, self.child_count, query.value(0), query.value(1), self) 908 child_item = CallTreeLevelOneItem(glb, params, self.child_count, query.value(0), query.value(1), self)
808 self.child_items.append(child_item) 909 self.child_items.append(child_item)
809 self.child_count += 1 910 self.child_count += 1
810 911
@@ -816,17 +917,26 @@ class CallTreeModel(CallGraphModelBase):
816 super(CallTreeModel, self).__init__(glb, parent) 917 super(CallTreeModel, self).__init__(glb, parent)
817 918
818 def GetRoot(self): 919 def GetRoot(self):
819 return CallTreeRootItem(self.glb) 920 return CallTreeRootItem(self.glb, self.params)
820 921
821 def columnCount(self, parent=None): 922 def columnCount(self, parent=None):
822 return 7 923 if self.params.have_ipc:
924 return 12
925 else:
926 return 7
823 927
824 def columnHeader(self, column): 928 def columnHeader(self, column):
825 headers = ["Call Path", "Object", "Call Time", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] 929 if self.params.have_ipc:
930 headers = ["Call Path", "Object", "Call Time", "Time (ns) ", "Time (%) ", "Insn Cnt", "Insn Cnt (%)", "Cyc Cnt", "Cyc Cnt (%)", "IPC", "Branch Count ", "Branch Count (%) "]
931 else:
932 headers = ["Call Path", "Object", "Call Time", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "]
826 return headers[column] 933 return headers[column]
827 934
828 def columnAlignment(self, column): 935 def columnAlignment(self, column):
829 alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] 936 if self.params.have_ipc:
937 alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ]
938 else:
939 alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ]
830 return alignment[column] 940 return alignment[column]
831 941
832 def DoFindSelect(self, query, match): 942 def DoFindSelect(self, query, match):
@@ -1355,11 +1465,11 @@ class FetchMoreRecordsBar():
1355 1465
1356class BranchLevelTwoItem(): 1466class BranchLevelTwoItem():
1357 1467
1358 def __init__(self, row, text, parent_item): 1468 def __init__(self, row, col, text, parent_item):
1359 self.row = row 1469 self.row = row
1360 self.parent_item = parent_item 1470 self.parent_item = parent_item
1361 self.data = [""] * 8 1471 self.data = [""] * (col + 1)
1362 self.data[7] = text 1472 self.data[col] = text
1363 self.level = 2 1473 self.level = 2
1364 1474
1365 def getParentItem(self): 1475 def getParentItem(self):
@@ -1391,6 +1501,7 @@ class BranchLevelOneItem():
1391 self.dbid = data[0] 1501 self.dbid = data[0]
1392 self.level = 1 1502 self.level = 1
1393 self.query_done = False 1503 self.query_done = False
1504 self.br_col = len(self.data) - 1
1394 1505
1395 def getChildItem(self, row): 1506 def getChildItem(self, row):
1396 return self.child_items[row] 1507 return self.child_items[row]
@@ -1471,7 +1582,7 @@ class BranchLevelOneItem():
1471 while k < 15: 1582 while k < 15:
1472 byte_str += " " 1583 byte_str += " "
1473 k += 1 1584 k += 1
1474 self.child_items.append(BranchLevelTwoItem(0, byte_str + " " + text, self)) 1585 self.child_items.append(BranchLevelTwoItem(0, self.br_col, byte_str + " " + text, self))
1475 self.child_count += 1 1586 self.child_count += 1
1476 else: 1587 else:
1477 return 1588 return
@@ -1522,16 +1633,37 @@ class BranchRootItem():
1522 def getData(self, column): 1633 def getData(self, column):
1523 return "" 1634 return ""
1524 1635
1636# Calculate instructions per cycle
1637
1638def CalcIPC(cyc_cnt, insn_cnt):
1639 if cyc_cnt and insn_cnt:
1640 ipc = Decimal(float(insn_cnt) / cyc_cnt)
1641 ipc = str(ipc.quantize(Decimal(".01"), rounding=ROUND_HALF_UP))
1642 else:
1643 ipc = "0"
1644 return ipc
1645
1525# Branch data preparation 1646# Branch data preparation
1526 1647
1527def BranchDataPrep(query): 1648def BranchDataPrepBr(query, data):
1528 data = []
1529 for i in xrange(0, 8):
1530 data.append(query.value(i))
1531 data.append(tohex(query.value(8)).rjust(16) + " " + query.value(9) + offstr(query.value(10)) + 1649 data.append(tohex(query.value(8)).rjust(16) + " " + query.value(9) + offstr(query.value(10)) +
1532 " (" + dsoname(query.value(11)) + ")" + " -> " + 1650 " (" + dsoname(query.value(11)) + ")" + " -> " +
1533 tohex(query.value(12)) + " " + query.value(13) + offstr(query.value(14)) + 1651 tohex(query.value(12)) + " " + query.value(13) + offstr(query.value(14)) +
1534 " (" + dsoname(query.value(15)) + ")") 1652 " (" + dsoname(query.value(15)) + ")")
1653
1654def BranchDataPrepIPC(query, data):
1655 insn_cnt = query.value(16)
1656 cyc_cnt = query.value(17)
1657 ipc = CalcIPC(cyc_cnt, insn_cnt)
1658 data.append(insn_cnt)
1659 data.append(cyc_cnt)
1660 data.append(ipc)
1661
1662def BranchDataPrep(query):
1663 data = []
1664 for i in xrange(0, 8):
1665 data.append(query.value(i))
1666 BranchDataPrepBr(query, data)
1535 return data 1667 return data
1536 1668
1537def BranchDataPrepWA(query): 1669def BranchDataPrepWA(query):
@@ -1541,10 +1673,26 @@ def BranchDataPrepWA(query):
1541 data.append("{:>19}".format(query.value(1))) 1673 data.append("{:>19}".format(query.value(1)))
1542 for i in xrange(2, 8): 1674 for i in xrange(2, 8):
1543 data.append(query.value(i)) 1675 data.append(query.value(i))
1544 data.append(tohex(query.value(8)).rjust(16) + " " + query.value(9) + offstr(query.value(10)) + 1676 BranchDataPrepBr(query, data)
1545 " (" + dsoname(query.value(11)) + ")" + " -> " + 1677 return data
1546 tohex(query.value(12)) + " " + query.value(13) + offstr(query.value(14)) + 1678
1547 " (" + dsoname(query.value(15)) + ")") 1679def BranchDataWithIPCPrep(query):
1680 data = []
1681 for i in xrange(0, 8):
1682 data.append(query.value(i))
1683 BranchDataPrepIPC(query, data)
1684 BranchDataPrepBr(query, data)
1685 return data
1686
1687def BranchDataWithIPCPrepWA(query):
1688 data = []
1689 data.append(query.value(0))
1690 # Workaround pyside failing to handle large integers (i.e. time) in python3 by converting to a string
1691 data.append("{:>19}".format(query.value(1)))
1692 for i in xrange(2, 8):
1693 data.append(query.value(i))
1694 BranchDataPrepIPC(query, data)
1695 BranchDataPrepBr(query, data)
1548 return data 1696 return data
1549 1697
1550# Branch data model 1698# Branch data model
@@ -1554,14 +1702,24 @@ class BranchModel(TreeModel):
1554 progress = Signal(object) 1702 progress = Signal(object)
1555 1703
1556 def __init__(self, glb, event_id, where_clause, parent=None): 1704 def __init__(self, glb, event_id, where_clause, parent=None):
1557 super(BranchModel, self).__init__(glb, parent) 1705 super(BranchModel, self).__init__(glb, None, parent)
1558 self.event_id = event_id 1706 self.event_id = event_id
1559 self.more = True 1707 self.more = True
1560 self.populated = 0 1708 self.populated = 0
1709 self.have_ipc = IsSelectable(glb.db, "samples", columns = "insn_count, cyc_count")
1710 if self.have_ipc:
1711 select_ipc = ", insn_count, cyc_count"
1712 prep_fn = BranchDataWithIPCPrep
1713 prep_wa_fn = BranchDataWithIPCPrepWA
1714 else:
1715 select_ipc = ""
1716 prep_fn = BranchDataPrep
1717 prep_wa_fn = BranchDataPrepWA
1561 sql = ("SELECT samples.id, time, cpu, comm, pid, tid, branch_types.name," 1718 sql = ("SELECT samples.id, time, cpu, comm, pid, tid, branch_types.name,"
1562 " CASE WHEN in_tx = '0' THEN 'No' ELSE 'Yes' END," 1719 " CASE WHEN in_tx = '0' THEN 'No' ELSE 'Yes' END,"
1563 " ip, symbols.name, sym_offset, dsos.short_name," 1720 " ip, symbols.name, sym_offset, dsos.short_name,"
1564 " to_ip, to_symbols.name, to_sym_offset, to_dsos.short_name" 1721 " to_ip, to_symbols.name, to_sym_offset, to_dsos.short_name"
1722 + select_ipc +
1565 " FROM samples" 1723 " FROM samples"
1566 " INNER JOIN comms ON comm_id = comms.id" 1724 " INNER JOIN comms ON comm_id = comms.id"
1567 " INNER JOIN threads ON thread_id = threads.id" 1725 " INNER JOIN threads ON thread_id = threads.id"
@@ -1575,9 +1733,9 @@ class BranchModel(TreeModel):
1575 " ORDER BY samples.id" 1733 " ORDER BY samples.id"
1576 " LIMIT " + str(glb_chunk_sz)) 1734 " LIMIT " + str(glb_chunk_sz))
1577 if pyside_version_1 and sys.version_info[0] == 3: 1735 if pyside_version_1 and sys.version_info[0] == 3:
1578 prep = BranchDataPrepWA 1736 prep = prep_fn
1579 else: 1737 else:
1580 prep = BranchDataPrep 1738 prep = prep_wa_fn
1581 self.fetcher = SQLFetcher(glb, sql, prep, self.AddSample) 1739 self.fetcher = SQLFetcher(glb, sql, prep, self.AddSample)
1582 self.fetcher.done.connect(self.Update) 1740 self.fetcher.done.connect(self.Update)
1583 self.fetcher.Fetch(glb_chunk_sz) 1741 self.fetcher.Fetch(glb_chunk_sz)
@@ -1586,13 +1744,23 @@ class BranchModel(TreeModel):
1586 return BranchRootItem() 1744 return BranchRootItem()
1587 1745
1588 def columnCount(self, parent=None): 1746 def columnCount(self, parent=None):
1589 return 8 1747 if self.have_ipc:
1748 return 11
1749 else:
1750 return 8
1590 1751
1591 def columnHeader(self, column): 1752 def columnHeader(self, column):
1592 return ("Time", "CPU", "Command", "PID", "TID", "Branch Type", "In Tx", "Branch")[column] 1753 if self.have_ipc:
1754 return ("Time", "CPU", "Command", "PID", "TID", "Branch Type", "In Tx", "Insn Cnt", "Cyc Cnt", "IPC", "Branch")[column]
1755 else:
1756 return ("Time", "CPU", "Command", "PID", "TID", "Branch Type", "In Tx", "Branch")[column]
1593 1757
1594 def columnFont(self, column): 1758 def columnFont(self, column):
1595 if column != 7: 1759 if self.have_ipc:
1760 br_col = 10
1761 else:
1762 br_col = 7
1763 if column != br_col:
1596 return None 1764 return None
1597 return QFont("Monospace") 1765 return QFont("Monospace")
1598 1766
@@ -2100,10 +2268,10 @@ def GetEventList(db):
2100 2268
2101# Is a table selectable 2269# Is a table selectable
2102 2270
2103def IsSelectable(db, table, sql = ""): 2271def IsSelectable(db, table, sql = "", columns = "*"):
2104 query = QSqlQuery(db) 2272 query = QSqlQuery(db)
2105 try: 2273 try:
2106 QueryExec(query, "SELECT * FROM " + table + " " + sql + " LIMIT 1") 2274 QueryExec(query, "SELECT " + columns + " FROM " + table + " " + sql + " LIMIT 1")
2107 except: 2275 except:
2108 return False 2276 return False
2109 return True 2277 return True
@@ -2754,7 +2922,7 @@ class WindowMenu():
2754 action = self.window_menu.addAction(label) 2922 action = self.window_menu.addAction(label)
2755 action.setCheckable(True) 2923 action.setCheckable(True)
2756 action.setChecked(sub_window == self.mdi_area.activeSubWindow()) 2924 action.setChecked(sub_window == self.mdi_area.activeSubWindow())
2757 action.triggered.connect(lambda x=nr: self.setActiveSubWindow(x)) 2925 action.triggered.connect(lambda a=None,x=nr: self.setActiveSubWindow(x))
2758 self.window_menu.addAction(action) 2926 self.window_menu.addAction(action)
2759 nr += 1 2927 nr += 1
2760 2928
@@ -2840,6 +3008,12 @@ cd xed
2840sudo ./mfile.py --prefix=/usr/local install 3008sudo ./mfile.py --prefix=/usr/local install
2841sudo ldconfig 3009sudo ldconfig
2842</pre> 3010</pre>
3011<h3>Instructions per Cycle (IPC)</h3>
3012If available, IPC information is displayed in columns 'insn_cnt', 'cyc_cnt' and 'IPC'.
3013<p><b>Intel PT note:</b> The information applies to the blocks of code ending with, and including, that branch.
3014Due to the granularity of timing information, the number of cycles for some code blocks will not be known.
3015In that case, 'insn_cnt', 'cyc_cnt' and 'IPC' are zero, but when 'IPC' is displayed it covers the period
3016since the previous displayed 'IPC'.
2843<h3>Find</h3> 3017<h3>Find</h3>
2844Ctrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match. 3018Ctrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match.
2845Refer to Python documentation for the regular expression syntax. 3019Refer to Python documentation for the regular expression syntax.
@@ -3114,14 +3288,14 @@ class MainWindow(QMainWindow):
3114 event = event.split(":")[0] 3288 event = event.split(":")[0]
3115 if event == "branches": 3289 if event == "branches":
3116 label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")" 3290 label = "All branches" if branches_events == 1 else "All branches " + "(id=" + dbid + ")"
3117 reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewBranchView(x), self)) 3291 reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda a=None,x=dbid: self.NewBranchView(x), self))
3118 label = "Selected branches" if branches_events == 1 else "Selected branches " + "(id=" + dbid + ")" 3292 label = "Selected branches" if branches_events == 1 else "Selected branches " + "(id=" + dbid + ")"
3119 reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda x=dbid: self.NewSelectedBranchView(x), self)) 3293 reports_menu.addAction(CreateAction(label, "Create a new window displaying branch events", lambda a=None,x=dbid: self.NewSelectedBranchView(x), self))
3120 3294
3121 def TableMenu(self, tables, menu): 3295 def TableMenu(self, tables, menu):
3122 table_menu = menu.addMenu("&Tables") 3296 table_menu = menu.addMenu("&Tables")
3123 for table in tables: 3297 for table in tables:
3124 table_menu.addAction(CreateAction(table, "Create a new window containing a table view", lambda t=table: self.NewTableView(t), self)) 3298 table_menu.addAction(CreateAction(table, "Create a new window containing a table view", lambda a=None,t=table: self.NewTableView(t), self))
3125 3299
3126 def NewCallGraph(self): 3300 def NewCallGraph(self):
3127 CallGraphWindow(self.glb, self) 3301 CallGraphWindow(self.glb, self)
@@ -3361,18 +3535,27 @@ class DBRef():
3361# Main 3535# Main
3362 3536
3363def Main(): 3537def Main():
3364 if (len(sys.argv) < 2): 3538 usage_str = "exported-sql-viewer.py [--pyside-version-1] <database name>\n" \
3365 printerr("Usage is: exported-sql-viewer.py {<database name> | --help-only}"); 3539 " or: exported-sql-viewer.py --help-only"
3366 raise Exception("Too few arguments") 3540 ap = argparse.ArgumentParser(usage = usage_str, add_help = False)
3367 3541 ap.add_argument("--pyside-version-1", action='store_true')
3368 dbname = sys.argv[1] 3542 ap.add_argument("dbname", nargs="?")
3369 if dbname == "--help-only": 3543 ap.add_argument("--help-only", action='store_true')
3544 args = ap.parse_args()
3545
3546 if args.help_only:
3370 app = QApplication(sys.argv) 3547 app = QApplication(sys.argv)
3371 mainwindow = HelpOnlyWindow() 3548 mainwindow = HelpOnlyWindow()
3372 mainwindow.show() 3549 mainwindow.show()
3373 err = app.exec_() 3550 err = app.exec_()
3374 sys.exit(err) 3551 sys.exit(err)
3375 3552
3553 dbname = args.dbname
3554 if dbname is None:
3555 ap.print_usage()
3556 print("Too few arguments")
3557 sys.exit(1)
3558
3376 is_sqlite3 = False 3559 is_sqlite3 = False
3377 try: 3560 try:
3378 f = open(dbname, "rb") 3561 f = open(dbname, "rb")