diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2019-07-08 12:06:57 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2019-07-08 12:06:57 -0400 |
commit | e3b22a65348ab54261a98b6bc90ecf8977ff8ebf (patch) | |
tree | 81c517d6f0e5585be7af5ffa1a4d4136b1f4a9c6 /tools/perf/scripts/python | |
parent | 05c78468a60f2fd961cd0a0c01c27f288bf81204 (diff) | |
parent | 552a031ba12a4236be107a5b082a399237758a5d (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.py | 330 | ||||
-rw-r--r-- | tools/perf/scripts/python/export-to-sqlite.py | 319 | ||||
-rwxr-xr-x | tools/perf/scripts/python/exported-sql-viewer.py | 345 |
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 | ||
202 | from PySide.QtSql import * | 215 | pyside_version_1 = True |
216 | if not "pyside-version-1" in sys.argv: | ||
217 | try: | ||
218 | from PySide2.QtSql import * | ||
219 | pyside_version_1 = False | ||
220 | except: | ||
221 | pass | ||
222 | |||
223 | if pyside_version_1: | ||
224 | from PySide.QtSql import * | ||
203 | 225 | ||
204 | if sys.version_info < (3, 0): | 226 | if 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 | ||
257 | def usage(): | 279 | def 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 | ||
264 | if (len(sys.argv) < 2): | 287 | if (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)') | ||
373 | else: | 400 | else: |
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 | ||
398 | if perf_db_export_calls or perf_db_export_callchains: | 427 | if 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 | |||
450 | do_query(query, 'CREATE TABLE ptwrite (' | ||
451 | 'id bigint NOT NULL,' | ||
452 | 'payload bigint,' | ||
453 | 'exact_ip boolean)') | ||
454 | |||
455 | do_query(query, 'CREATE TABLE cbr (' | ||
456 | 'id bigint NOT NULL,' | ||
457 | 'cbr integer,' | ||
458 | 'mhz integer,' | ||
459 | 'percent integer)') | ||
460 | |||
461 | do_query(query, 'CREATE TABLE mwait (' | ||
462 | 'id bigint NOT NULL,' | ||
463 | 'hints integer,' | ||
464 | 'extensions integer)') | ||
465 | |||
466 | do_query(query, 'CREATE TABLE pwre (' | ||
467 | 'id bigint NOT NULL,' | ||
468 | 'cstate integer,' | ||
469 | 'subcstate integer,' | ||
470 | 'hw boolean)') | ||
471 | |||
472 | do_query(query, 'CREATE TABLE exstop (' | ||
473 | 'id bigint NOT NULL,' | ||
474 | 'exact_ip boolean)') | ||
475 | |||
476 | do_query(query, 'CREATE TABLE pwrx (' | ||
477 | 'id bigint NOT NULL,' | ||
478 | 'deepest_cstate integer,' | ||
479 | 'last_cstate integer,' | ||
480 | 'wake_reason integer)') | ||
418 | 481 | ||
419 | do_query(query, 'CREATE VIEW machines_view AS ' | 482 | do_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 | ||
596 | do_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 | |||
606 | do_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 | |||
617 | do_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 | |||
627 | do_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 | |||
638 | do_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 | |||
647 | do_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 | |||
663 | do_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 | ||
528 | file_header = struct.pack("!11sii", b"PGCOPY\n\377\r\n\0", 0, 0) | 695 | file_header = struct.pack("!11sii", b"PGCOPY\n\377\r\n\0", 0, 0) |
529 | file_trailer = b"\377\377" | 696 | file_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") |
584 | if perf_db_export_calls: | 751 | if perf_db_export_calls: |
585 | call_file = open_output_file("call_table.bin") | 752 | call_file = open_output_file("call_table.bin") |
753 | ptwrite_file = open_output_file("ptwrite_table.bin") | ||
754 | cbr_file = open_output_file("cbr_table.bin") | ||
755 | mwait_file = open_output_file("mwait_table.bin") | ||
756 | pwre_file = open_output_file("pwre_table.bin") | ||
757 | exstop_file = open_output_file("exstop_table.bin") | ||
758 | pwrx_file = open_output_file("pwrx_table.bin") | ||
586 | 759 | ||
587 | def trace_begin(): | 760 | def 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 | ||
601 | unhandled_count = 0 | 774 | unhandled_count = 0 |
602 | 775 | ||
776 | def 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 | |||
782 | def drop(table_name): | ||
783 | do_query(query, 'DROP VIEW ' + table_name + '_view'); | ||
784 | do_query(query, 'DROP TABLE ' + table_name); | ||
785 | |||
603 | def trace_end(): | 786 | def 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 | ||
750 | def 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): | 975 | def 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 | ||
757 | def call_path_table(cp_id, parent_id, symbol_id, ip, *x): | 982 | def 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 | ||
762 | def 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): | 987 | def 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 | |||
992 | def 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 | |||
1000 | def 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 | |||
1008 | def 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 | |||
1016 | def 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 | |||
1025 | def 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 | |||
1032 | def 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 | |||
1041 | def 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 | ||
52 | from PySide.QtSql import * | 72 | pyside_version_1 = True |
73 | if not "pyside-version-1" in sys.argv: | ||
74 | try: | ||
75 | from PySide2.QtSql import * | ||
76 | pyside_version_1 = False | ||
77 | except: | ||
78 | pass | ||
79 | |||
80 | if pyside_version_1: | ||
81 | from PySide.QtSql import * | ||
53 | 82 | ||
54 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | 83 | sys.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 | ||
71 | def usage(): | 100 | def 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 | ||
78 | if (len(sys.argv) < 2): | 108 | if (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)') | ||
190 | else: | 224 | else: |
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 | ||
215 | if perf_db_export_calls or perf_db_export_callchains: | 251 | if 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 | |||
274 | do_query(query, 'CREATE TABLE ptwrite (' | ||
275 | 'id integer NOT NULL PRIMARY KEY,' | ||
276 | 'payload bigint,' | ||
277 | 'exact_ip integer)') | ||
278 | |||
279 | do_query(query, 'CREATE TABLE cbr (' | ||
280 | 'id integer NOT NULL PRIMARY KEY,' | ||
281 | 'cbr integer,' | ||
282 | 'mhz integer,' | ||
283 | 'percent integer)') | ||
284 | |||
285 | do_query(query, 'CREATE TABLE mwait (' | ||
286 | 'id integer NOT NULL PRIMARY KEY,' | ||
287 | 'hints integer,' | ||
288 | 'extensions integer)') | ||
289 | |||
290 | do_query(query, 'CREATE TABLE pwre (' | ||
291 | 'id integer NOT NULL PRIMARY KEY,' | ||
292 | 'cstate integer,' | ||
293 | 'subcstate integer,' | ||
294 | 'hw integer)') | ||
295 | |||
296 | do_query(query, 'CREATE TABLE exstop (' | ||
297 | 'id integer NOT NULL PRIMARY KEY,' | ||
298 | 'exact_ip integer)') | ||
299 | |||
300 | do_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 |
237 | sqlite_has_printf = False | 307 | sqlite_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 | ||
434 | do_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 | |||
444 | do_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 | |||
455 | do_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 | |||
465 | do_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 | |||
476 | do_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 | |||
485 | do_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 | |||
501 | do_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 | |||
358 | do_query(query, 'END TRANSACTION') | 530 | do_query(query, 'END TRANSACTION') |
359 | 531 | ||
360 | evsel_query = QSqlQuery(db) | 532 | evsel_query = QSqlQuery(db) |
@@ -375,15 +547,27 @@ branch_type_query = QSqlQuery(db) | |||
375 | branch_type_query.prepare("INSERT INTO branch_types VALUES (?, ?)") | 547 | branch_type_query.prepare("INSERT INTO branch_types VALUES (?, ?)") |
376 | sample_query = QSqlQuery(db) | 548 | sample_query = QSqlQuery(db) |
377 | if branches: | 549 | if branches: |
378 | sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") | 550 | sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") |
379 | else: | 551 | else: |
380 | sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") | 552 | sample_query.prepare("INSERT INTO samples VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") |
381 | if perf_db_export_calls or perf_db_export_callchains: | 553 | if 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 (?, ?, ?, ?)") |
384 | if perf_db_export_calls: | 556 | if 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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") |
559 | ptwrite_query = QSqlQuery(db) | ||
560 | ptwrite_query.prepare("INSERT INTO ptwrite VALUES (?, ?, ?)") | ||
561 | cbr_query = QSqlQuery(db) | ||
562 | cbr_query.prepare("INSERT INTO cbr VALUES (?, ?, ?, ?)") | ||
563 | mwait_query = QSqlQuery(db) | ||
564 | mwait_query.prepare("INSERT INTO mwait VALUES (?, ?, ?)") | ||
565 | pwre_query = QSqlQuery(db) | ||
566 | pwre_query.prepare("INSERT INTO pwre VALUES (?, ?, ?, ?)") | ||
567 | exstop_query = QSqlQuery(db) | ||
568 | exstop_query.prepare("INSERT INTO exstop VALUES (?, ?)") | ||
569 | pwrx_query = QSqlQuery(db) | ||
570 | pwrx_query.prepare("INSERT INTO pwrx VALUES (?, ?, ?, ?)") | ||
387 | 571 | ||
388 | def trace_begin(): | 572 | def 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 | ||
403 | unhandled_count = 0 | 587 | unhandled_count = 0 |
404 | 588 | ||
589 | def 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 | |||
595 | def drop(table_name): | ||
596 | do_query(query, 'DROP VIEW ' + table_name + '_view'); | ||
597 | do_query(query, 'DROP TABLE ' + table_name); | ||
598 | |||
405 | def trace_end(): | 599 | def 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 | ||
463 | def call_path_table(*x): | 669 | def call_path_table(*x): |
464 | bind_exec(call_path_query, 4, x) | 670 | bind_exec(call_path_query, 4, x) |
465 | 671 | ||
466 | def call_return_table(*x): | 672 | def call_return_table(*x): |
467 | bind_exec(call_query, 12, x) | 673 | bind_exec(call_query, 14, x) |
674 | |||
675 | def 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 | |||
685 | def 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 | |||
696 | def 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 | |||
706 | def 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 | |||
718 | def 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 | |||
726 | def 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 | |||
738 | def 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 @@ | |||
91 | from __future__ import print_function | 91 | from __future__ import print_function |
92 | 92 | ||
93 | import sys | 93 | import sys |
94 | import argparse | ||
94 | import weakref | 95 | import weakref |
95 | import threading | 96 | import threading |
96 | import string | 97 | import string |
@@ -104,10 +105,23 @@ except ImportError: | |||
104 | glb_nsz = 16 | 105 | glb_nsz = 16 |
105 | import re | 106 | import re |
106 | import os | 107 | import os |
107 | from PySide.QtCore import * | 108 | |
108 | from PySide.QtGui import * | ||
109 | from PySide.QtSql import * | ||
110 | pyside_version_1 = True | 109 | pyside_version_1 = True |
110 | if 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 | |||
120 | if pyside_version_1: | ||
121 | from PySide.QtCore import * | ||
122 | from PySide.QtGui import * | ||
123 | from PySide.QtSql import * | ||
124 | |||
111 | from decimal import * | 125 | from decimal import * |
112 | from ctypes import * | 126 | from ctypes import * |
113 | from multiprocessing import Process, Array, Value, Event | 127 | from multiprocessing import Process, Array, Value, Event |
@@ -186,9 +200,10 @@ class Thread(QThread): | |||
186 | 200 | ||
187 | class TreeModel(QAbstractItemModel): | 201 | class 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 | ||
450 | class CallGraphLevelItemBase(object): | 466 | class 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 | ||
490 | class CallGraphLevelTwoPlusItemBase(CallGraphLevelItemBase): | 507 | class 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 | ||
520 | class CallGraphLevelThreeItem(CallGraphLevelTwoPlusItemBase): | 551 | class 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 | ||
530 | class CallGraphLevelTwoItem(CallGraphLevelTwoPlusItemBase): | 568 | class 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 | ||
548 | class CallGraphLevelOneItem(CallGraphLevelItemBase): | 596 | class 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 | ||
569 | class CallGraphRootItem(CallGraphLevelItemBase): | 620 | class 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 | |||
637 | class 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 | ||
586 | class CallGraphModelBase(TreeModel): | 644 | class 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 | ||
716 | class CallTreeLevelTwoPlusItemBase(CallGraphLevelItemBase): | 783 | class 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 | ||
747 | class CallTreeLevelThreeItem(CallTreeLevelTwoPlusItemBase): | 828 | class 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 | ||
757 | class CallTreeLevelTwoItem(CallTreeLevelTwoPlusItemBase): | 845 | class 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 | ||
775 | class CallTreeLevelOneItem(CallGraphLevelItemBase): | 873 | class 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 | ||
796 | class CallTreeRootItem(CallGraphLevelItemBase): | 897 | class 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 | ||
1356 | class BranchLevelTwoItem(): | 1466 | class 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 | |||
1638 | def 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 | ||
1527 | def BranchDataPrep(query): | 1648 | def 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 | |||
1654 | def 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 | |||
1662 | def 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 | ||
1537 | def BranchDataPrepWA(query): | 1669 | def 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)) + ")") | 1679 | def 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 | |||
1687 | def 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 | ||
2103 | def IsSelectable(db, table, sql = ""): | 2271 | def 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 | |||
2840 | sudo ./mfile.py --prefix=/usr/local install | 3008 | sudo ./mfile.py --prefix=/usr/local install |
2841 | sudo ldconfig | 3009 | sudo ldconfig |
2842 | </pre> | 3010 | </pre> |
3011 | <h3>Instructions per Cycle (IPC)</h3> | ||
3012 | If 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. | ||
3014 | Due to the granularity of timing information, the number of cycles for some code blocks will not be known. | ||
3015 | In that case, 'insn_cnt', 'cyc_cnt' and 'IPC' are zero, but when 'IPC' is displayed it covers the period | ||
3016 | since the previous displayed 'IPC'. | ||
2843 | <h3>Find</h3> | 3017 | <h3>Find</h3> |
2844 | Ctrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match. | 3018 | Ctrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match. |
2845 | Refer to Python documentation for the regular expression syntax. | 3019 | Refer 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 | ||
3363 | def Main(): | 3537 | def 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") |