diff options
author | Ingo Molnar <mingo@kernel.org> | 2019-02-28 02:29:50 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2019-02-28 02:29:50 -0500 |
commit | c978b9460fe1d4a1e1effa0abd6bd69b18a098a8 (patch) | |
tree | eecc4c6179dea191c55ac8ef50467573b29a0b06 /tools | |
parent | 0a1571243d3f150fa99c6f41f1b8e17a307a2b8b (diff) | |
parent | de667cce7f4f96b6e22da8fd9c065b961f355080 (diff) |
Merge tag 'perf-core-for-mingo-5.1-20190225' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
perf annotate:
Wei Li:
- Fix getting source line failure
perf script:
Andi Kleen:
- Handle missing fields with -F +...
perf data:
Jiri Olsa:
- Prep work to support per-cpu files in a directory.
Intel PT:
Adrian Hunter:
- Improve thread_stack__no_call_return()
- Hide x86 retpolines in thread stacks.
- exported SQL viewer refactorings, new 'top calls' report..
Alexander Shishkin:
- Copy parent's address filter offsets on clone
- Fix address filters for vmas with non-zero offset. Applies to
ARM's CoreSight as well.
python scripts:
Tony Jones:
- Python3 support for several 'perf script' python scripts.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
37 files changed, 945 insertions, 390 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 7f3c3fea67b4..67f9d9ffacfb 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -441,7 +441,7 @@ static int __cmd_annotate(struct perf_annotate *ann) | |||
441 | } | 441 | } |
442 | 442 | ||
443 | if (total_nr_samples == 0) { | 443 | if (total_nr_samples == 0) { |
444 | ui__error("The %s file has no samples!\n", session->data->file.path); | 444 | ui__error("The %s data has no samples!\n", session->data->path); |
445 | goto out; | 445 | goto out; |
446 | } | 446 | } |
447 | 447 | ||
@@ -578,7 +578,7 @@ int cmd_annotate(int argc, const char **argv) | |||
578 | if (quiet) | 578 | if (quiet) |
579 | perf_quiet_option(); | 579 | perf_quiet_option(); |
580 | 580 | ||
581 | data.file.path = input_name; | 581 | data.path = input_name; |
582 | 582 | ||
583 | annotate.session = perf_session__new(&data, false, &annotate.tool); | 583 | annotate.session = perf_session__new(&data, false, &annotate.tool); |
584 | if (annotate.session == NULL) | 584 | if (annotate.session == NULL) |
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index 115110a4796a..10457b10e568 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c | |||
@@ -416,8 +416,8 @@ int cmd_buildid_cache(int argc, const char **argv) | |||
416 | nsi = nsinfo__new(ns_id); | 416 | nsi = nsinfo__new(ns_id); |
417 | 417 | ||
418 | if (missing_filename) { | 418 | if (missing_filename) { |
419 | data.file.path = missing_filename; | 419 | data.path = missing_filename; |
420 | data.force = force; | 420 | data.force = force; |
421 | 421 | ||
422 | session = perf_session__new(&data, false, NULL); | 422 | session = perf_session__new(&data, false, NULL); |
423 | if (session == NULL) | 423 | if (session == NULL) |
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 78abbe8d9d5f..f403e19488b5 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c | |||
@@ -52,11 +52,9 @@ static int perf_session__list_build_ids(bool force, bool with_hits) | |||
52 | { | 52 | { |
53 | struct perf_session *session; | 53 | struct perf_session *session; |
54 | struct perf_data data = { | 54 | struct perf_data data = { |
55 | .file = { | 55 | .path = input_name, |
56 | .path = input_name, | 56 | .mode = PERF_DATA_MODE_READ, |
57 | }, | 57 | .force = force, |
58 | .mode = PERF_DATA_MODE_READ, | ||
59 | .force = force, | ||
60 | }; | 58 | }; |
61 | 59 | ||
62 | symbol__elf_init(); | 60 | symbol__elf_init(); |
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index efaaab23c6fd..4272763a5e96 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c | |||
@@ -2750,8 +2750,8 @@ static int perf_c2c__report(int argc, const char **argv) | |||
2750 | if (!input_name || !strlen(input_name)) | 2750 | if (!input_name || !strlen(input_name)) |
2751 | input_name = "perf.data"; | 2751 | input_name = "perf.data"; |
2752 | 2752 | ||
2753 | data.file.path = input_name; | 2753 | data.path = input_name; |
2754 | data.force = symbol_conf.force; | 2754 | data.force = symbol_conf.force; |
2755 | 2755 | ||
2756 | err = setup_display(display); | 2756 | err = setup_display(display); |
2757 | if (err) | 2757 | if (err) |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 751e1971456b..58fe0e88215c 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -708,7 +708,7 @@ static void data__fprintf(void) | |||
708 | 708 | ||
709 | data__for_each_file(i, d) | 709 | data__for_each_file(i, d) |
710 | fprintf(stdout, "# [%d] %s %s\n", | 710 | fprintf(stdout, "# [%d] %s %s\n", |
711 | d->idx, d->data.file.path, | 711 | d->idx, d->data.path, |
712 | !d->idx ? "(Baseline)" : ""); | 712 | !d->idx ? "(Baseline)" : ""); |
713 | 713 | ||
714 | fprintf(stdout, "#\n"); | 714 | fprintf(stdout, "#\n"); |
@@ -779,14 +779,14 @@ static int __cmd_diff(void) | |||
779 | data__for_each_file(i, d) { | 779 | data__for_each_file(i, d) { |
780 | d->session = perf_session__new(&d->data, false, &tool); | 780 | d->session = perf_session__new(&d->data, false, &tool); |
781 | if (!d->session) { | 781 | if (!d->session) { |
782 | pr_err("Failed to open %s\n", d->data.file.path); | 782 | pr_err("Failed to open %s\n", d->data.path); |
783 | ret = -1; | 783 | ret = -1; |
784 | goto out_delete; | 784 | goto out_delete; |
785 | } | 785 | } |
786 | 786 | ||
787 | ret = perf_session__process_events(d->session); | 787 | ret = perf_session__process_events(d->session); |
788 | if (ret) { | 788 | if (ret) { |
789 | pr_err("Failed to process %s\n", d->data.file.path); | 789 | pr_err("Failed to process %s\n", d->data.path); |
790 | goto out_delete; | 790 | goto out_delete; |
791 | } | 791 | } |
792 | 792 | ||
@@ -1289,9 +1289,9 @@ static int data_init(int argc, const char **argv) | |||
1289 | data__for_each_file(i, d) { | 1289 | data__for_each_file(i, d) { |
1290 | struct perf_data *data = &d->data; | 1290 | struct perf_data *data = &d->data; |
1291 | 1291 | ||
1292 | data->file.path = use_default ? defaults[i] : argv[i]; | 1292 | data->path = use_default ? defaults[i] : argv[i]; |
1293 | data->mode = PERF_DATA_MODE_READ, | 1293 | data->mode = PERF_DATA_MODE_READ, |
1294 | data->force = force, | 1294 | data->force = force, |
1295 | 1295 | ||
1296 | d->idx = i; | 1296 | d->idx = i; |
1297 | } | 1297 | } |
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index e06e822ce634..6e4f63b0da4a 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c | |||
@@ -23,9 +23,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details | |||
23 | struct perf_session *session; | 23 | struct perf_session *session; |
24 | struct perf_evsel *pos; | 24 | struct perf_evsel *pos; |
25 | struct perf_data data = { | 25 | struct perf_data data = { |
26 | .file = { | 26 | .path = file_name, |
27 | .path = file_name, | ||
28 | }, | ||
29 | .mode = PERF_DATA_MODE_READ, | 27 | .mode = PERF_DATA_MODE_READ, |
30 | .force = details->force, | 28 | .force = details->force, |
31 | }; | 29 | }; |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 9bb1f35d5cb7..24086b7f1b14 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -770,10 +770,8 @@ int cmd_inject(int argc, const char **argv) | |||
770 | .input_name = "-", | 770 | .input_name = "-", |
771 | .samples = LIST_HEAD_INIT(inject.samples), | 771 | .samples = LIST_HEAD_INIT(inject.samples), |
772 | .output = { | 772 | .output = { |
773 | .file = { | 773 | .path = "-", |
774 | .path = "-", | 774 | .mode = PERF_DATA_MODE_WRITE, |
775 | }, | ||
776 | .mode = PERF_DATA_MODE_WRITE, | ||
777 | }, | 775 | }, |
778 | }; | 776 | }; |
779 | struct perf_data data = { | 777 | struct perf_data data = { |
@@ -786,7 +784,7 @@ int cmd_inject(int argc, const char **argv) | |||
786 | "Inject build-ids into the output stream"), | 784 | "Inject build-ids into the output stream"), |
787 | OPT_STRING('i', "input", &inject.input_name, "file", | 785 | OPT_STRING('i', "input", &inject.input_name, "file", |
788 | "input file name"), | 786 | "input file name"), |
789 | OPT_STRING('o', "output", &inject.output.file.path, "file", | 787 | OPT_STRING('o', "output", &inject.output.path, "file", |
790 | "output file name"), | 788 | "output file name"), |
791 | OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, | 789 | OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, |
792 | "Merge sched-stat and sched-switch for getting events " | 790 | "Merge sched-stat and sched-switch for getting events " |
@@ -834,7 +832,7 @@ int cmd_inject(int argc, const char **argv) | |||
834 | 832 | ||
835 | inject.tool.ordered_events = inject.sched_stat; | 833 | inject.tool.ordered_events = inject.sched_stat; |
836 | 834 | ||
837 | data.file.path = inject.input_name; | 835 | data.path = inject.input_name; |
838 | inject.session = perf_session__new(&data, true, &inject.tool); | 836 | inject.session = perf_session__new(&data, true, &inject.tool); |
839 | if (inject.session == NULL) | 837 | if (inject.session == NULL) |
840 | return -1; | 838 | return -1; |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index b80ec0883537..fa520f4b8095 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -1949,7 +1949,7 @@ int cmd_kmem(int argc, const char **argv) | |||
1949 | return __cmd_record(argc, argv); | 1949 | return __cmd_record(argc, argv); |
1950 | } | 1950 | } |
1951 | 1951 | ||
1952 | data.file.path = input_name; | 1952 | data.path = input_name; |
1953 | 1953 | ||
1954 | kmem_session = session = perf_session__new(&data, false, &perf_kmem); | 1954 | kmem_session = session = perf_session__new(&data, false, &perf_kmem); |
1955 | if (session == NULL) | 1955 | if (session == NULL) |
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 3d4cbc4e87c7..dbb6f737a3e2 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
@@ -1080,11 +1080,9 @@ static int read_events(struct perf_kvm_stat *kvm) | |||
1080 | .ordered_events = true, | 1080 | .ordered_events = true, |
1081 | }; | 1081 | }; |
1082 | struct perf_data file = { | 1082 | struct perf_data file = { |
1083 | .file = { | 1083 | .path = kvm->file_name, |
1084 | .path = kvm->file_name, | 1084 | .mode = PERF_DATA_MODE_READ, |
1085 | }, | 1085 | .force = kvm->force, |
1086 | .mode = PERF_DATA_MODE_READ, | ||
1087 | .force = kvm->force, | ||
1088 | }; | 1086 | }; |
1089 | 1087 | ||
1090 | kvm->tool = eops; | 1088 | kvm->tool = eops; |
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 6e0189df2b3b..b9810a8d350a 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c | |||
@@ -866,11 +866,9 @@ static int __cmd_report(bool display_info) | |||
866 | .ordered_events = true, | 866 | .ordered_events = true, |
867 | }; | 867 | }; |
868 | struct perf_data data = { | 868 | struct perf_data data = { |
869 | .file = { | 869 | .path = input_name, |
870 | .path = input_name, | 870 | .mode = PERF_DATA_MODE_READ, |
871 | }, | 871 | .force = force, |
872 | .mode = PERF_DATA_MODE_READ, | ||
873 | .force = force, | ||
874 | }; | 872 | }; |
875 | 873 | ||
876 | session = perf_session__new(&data, false, &eops); | 874 | session = perf_session__new(&data, false, &eops); |
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index ba7e8d87dec3..f45c8b502f63 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c | |||
@@ -239,11 +239,9 @@ static int process_sample_event(struct perf_tool *tool, | |||
239 | static int report_raw_events(struct perf_mem *mem) | 239 | static int report_raw_events(struct perf_mem *mem) |
240 | { | 240 | { |
241 | struct perf_data data = { | 241 | struct perf_data data = { |
242 | .file = { | 242 | .path = input_name, |
243 | .path = input_name, | 243 | .mode = PERF_DATA_MODE_READ, |
244 | }, | 244 | .force = mem->force, |
245 | .mode = PERF_DATA_MODE_READ, | ||
246 | .force = mem->force, | ||
247 | }; | 245 | }; |
248 | int ret; | 246 | int ret; |
249 | struct perf_session *session = perf_session__new(&data, false, | 247 | struct perf_session *session = perf_session__new(&data, false, |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 6c3719ac901d..f3f7f3100336 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -660,10 +660,9 @@ static int process_sample_event(struct perf_tool *tool, | |||
660 | 660 | ||
661 | static int process_buildids(struct record *rec) | 661 | static int process_buildids(struct record *rec) |
662 | { | 662 | { |
663 | struct perf_data *data = &rec->data; | ||
664 | struct perf_session *session = rec->session; | 663 | struct perf_session *session = rec->session; |
665 | 664 | ||
666 | if (data->size == 0) | 665 | if (perf_data__size(&rec->data) == 0) |
667 | return 0; | 666 | return 0; |
668 | 667 | ||
669 | /* | 668 | /* |
@@ -851,7 +850,7 @@ record__finish_output(struct record *rec) | |||
851 | return; | 850 | return; |
852 | 851 | ||
853 | rec->session->header.data_size += rec->bytes_written; | 852 | rec->session->header.data_size += rec->bytes_written; |
854 | data->size = lseek(perf_data__fd(data), 0, SEEK_CUR); | 853 | data->file.size = lseek(perf_data__fd(data), 0, SEEK_CUR); |
855 | 854 | ||
856 | if (!rec->no_buildid) { | 855 | if (!rec->no_buildid) { |
857 | process_buildids(rec); | 856 | process_buildids(rec); |
@@ -919,7 +918,7 @@ record__switch_output(struct record *rec, bool at_exit) | |||
919 | 918 | ||
920 | if (!quiet) | 919 | if (!quiet) |
921 | fprintf(stderr, "[ perf record: Dump %s.%s ]\n", | 920 | fprintf(stderr, "[ perf record: Dump %s.%s ]\n", |
922 | data->file.path, timestamp); | 921 | data->path, timestamp); |
923 | 922 | ||
924 | /* Output tracking events */ | 923 | /* Output tracking events */ |
925 | if (!at_exit) { | 924 | if (!at_exit) { |
@@ -1462,7 +1461,7 @@ out_child: | |||
1462 | 1461 | ||
1463 | fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s%s ]\n", | 1462 | fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s%s ]\n", |
1464 | perf_data__size(data) / 1024.0 / 1024.0, | 1463 | perf_data__size(data) / 1024.0 / 1024.0, |
1465 | data->file.path, postfix, samples); | 1464 | data->path, postfix, samples); |
1466 | } | 1465 | } |
1467 | 1466 | ||
1468 | out_delete_session: | 1467 | out_delete_session: |
@@ -1863,7 +1862,7 @@ static struct option __record_options[] = { | |||
1863 | OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu", | 1862 | OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu", |
1864 | "list of cpus to monitor"), | 1863 | "list of cpus to monitor"), |
1865 | OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), | 1864 | OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), |
1866 | OPT_STRING('o', "output", &record.data.file.path, "file", | 1865 | OPT_STRING('o', "output", &record.data.path, "file", |
1867 | "output file name"), | 1866 | "output file name"), |
1868 | OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit, | 1867 | OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit, |
1869 | &record.opts.no_inherit_set, | 1868 | &record.opts.no_inherit_set, |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 2e8c74d6430c..1532ebde6c4b 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -899,7 +899,7 @@ static int __cmd_report(struct report *rep) | |||
899 | rep->nr_entries += evsel__hists(pos)->nr_entries; | 899 | rep->nr_entries += evsel__hists(pos)->nr_entries; |
900 | 900 | ||
901 | if (rep->nr_entries == 0) { | 901 | if (rep->nr_entries == 0) { |
902 | ui__error("The %s file has no samples!\n", data->file.path); | 902 | ui__error("The %s data has no samples!\n", data->path); |
903 | return 0; | 903 | return 0; |
904 | } | 904 | } |
905 | 905 | ||
@@ -1207,8 +1207,8 @@ int cmd_report(int argc, const char **argv) | |||
1207 | input_name = "perf.data"; | 1207 | input_name = "perf.data"; |
1208 | } | 1208 | } |
1209 | 1209 | ||
1210 | data.file.path = input_name; | 1210 | data.path = input_name; |
1211 | data.force = symbol_conf.force; | 1211 | data.force = symbol_conf.force; |
1212 | 1212 | ||
1213 | repeat: | 1213 | repeat: |
1214 | session = perf_session__new(&data, false, &report.tool); | 1214 | session = perf_session__new(&data, false, &report.tool); |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 640558e9352e..275f2d92a7bf 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -1785,11 +1785,9 @@ static int perf_sched__read_events(struct perf_sched *sched) | |||
1785 | }; | 1785 | }; |
1786 | struct perf_session *session; | 1786 | struct perf_session *session; |
1787 | struct perf_data data = { | 1787 | struct perf_data data = { |
1788 | .file = { | 1788 | .path = input_name, |
1789 | .path = input_name, | 1789 | .mode = PERF_DATA_MODE_READ, |
1790 | }, | 1790 | .force = sched->force, |
1791 | .mode = PERF_DATA_MODE_READ, | ||
1792 | .force = sched->force, | ||
1793 | }; | 1791 | }; |
1794 | int rc = -1; | 1792 | int rc = -1; |
1795 | 1793 | ||
@@ -2958,11 +2956,9 @@ static int perf_sched__timehist(struct perf_sched *sched) | |||
2958 | { "sched:sched_migrate_task", timehist_migrate_task_event, }, | 2956 | { "sched:sched_migrate_task", timehist_migrate_task_event, }, |
2959 | }; | 2957 | }; |
2960 | struct perf_data data = { | 2958 | struct perf_data data = { |
2961 | .file = { | 2959 | .path = input_name, |
2962 | .path = input_name, | 2960 | .mode = PERF_DATA_MODE_READ, |
2963 | }, | 2961 | .force = sched->force, |
2964 | .mode = PERF_DATA_MODE_READ, | ||
2965 | .force = sched->force, | ||
2966 | }; | 2962 | }; |
2967 | 2963 | ||
2968 | struct perf_session *session; | 2964 | struct perf_session *session; |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 373ea151dc60..2d8cb1d1682c 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -149,6 +149,7 @@ static struct { | |||
149 | unsigned int print_ip_opts; | 149 | unsigned int print_ip_opts; |
150 | u64 fields; | 150 | u64 fields; |
151 | u64 invalid_fields; | 151 | u64 invalid_fields; |
152 | u64 user_set_fields; | ||
152 | } output[OUTPUT_TYPE_MAX] = { | 153 | } output[OUTPUT_TYPE_MAX] = { |
153 | 154 | ||
154 | [PERF_TYPE_HARDWARE] = { | 155 | [PERF_TYPE_HARDWARE] = { |
@@ -345,7 +346,7 @@ static int perf_evsel__do_check_stype(struct perf_evsel *evsel, | |||
345 | if (attr->sample_type & sample_type) | 346 | if (attr->sample_type & sample_type) |
346 | return 0; | 347 | return 0; |
347 | 348 | ||
348 | if (output[type].user_set) { | 349 | if (output[type].user_set_fields & field) { |
349 | if (allow_user_set) | 350 | if (allow_user_set) |
350 | return 0; | 351 | return 0; |
351 | evname = perf_evsel__name(evsel); | 352 | evname = perf_evsel__name(evsel); |
@@ -2632,10 +2633,13 @@ parse: | |||
2632 | pr_warning("\'%s\' not valid for %s events. Ignoring.\n", | 2633 | pr_warning("\'%s\' not valid for %s events. Ignoring.\n", |
2633 | all_output_options[i].str, event_type(j)); | 2634 | all_output_options[i].str, event_type(j)); |
2634 | } else { | 2635 | } else { |
2635 | if (change == REMOVE) | 2636 | if (change == REMOVE) { |
2636 | output[j].fields &= ~all_output_options[i].field; | 2637 | output[j].fields &= ~all_output_options[i].field; |
2637 | else | 2638 | output[j].user_set_fields &= ~all_output_options[i].field; |
2639 | } else { | ||
2638 | output[j].fields |= all_output_options[i].field; | 2640 | output[j].fields |= all_output_options[i].field; |
2641 | output[j].user_set_fields |= all_output_options[i].field; | ||
2642 | } | ||
2639 | output[j].user_set = true; | 2643 | output[j].user_set = true; |
2640 | output[j].wildcard_set = true; | 2644 | output[j].wildcard_set = true; |
2641 | } | 2645 | } |
@@ -2951,10 +2955,8 @@ int find_scripts(char **scripts_array, char **scripts_path_array) | |||
2951 | DIR *scripts_dir, *lang_dir; | 2955 | DIR *scripts_dir, *lang_dir; |
2952 | struct perf_session *session; | 2956 | struct perf_session *session; |
2953 | struct perf_data data = { | 2957 | struct perf_data data = { |
2954 | .file = { | 2958 | .path = input_name, |
2955 | .path = input_name, | 2959 | .mode = PERF_DATA_MODE_READ, |
2956 | }, | ||
2957 | .mode = PERF_DATA_MODE_READ, | ||
2958 | }; | 2960 | }; |
2959 | char *temp; | 2961 | char *temp; |
2960 | int i = 0; | 2962 | int i = 0; |
@@ -3427,8 +3429,8 @@ int cmd_script(int argc, const char **argv) | |||
3427 | argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, | 3429 | argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, |
3428 | PARSE_OPT_STOP_AT_NON_OPTION); | 3430 | PARSE_OPT_STOP_AT_NON_OPTION); |
3429 | 3431 | ||
3430 | data.file.path = input_name; | 3432 | data.path = input_name; |
3431 | data.force = symbol_conf.force; | 3433 | data.force = symbol_conf.force; |
3432 | 3434 | ||
3433 | if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { | 3435 | if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { |
3434 | rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); | 3436 | rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); |
@@ -3654,7 +3656,7 @@ int cmd_script(int argc, const char **argv) | |||
3654 | goto out_delete; | 3656 | goto out_delete; |
3655 | } | 3657 | } |
3656 | 3658 | ||
3657 | input = open(data.file.path, O_RDONLY); /* input_name */ | 3659 | input = open(data.path, O_RDONLY); /* input_name */ |
3658 | if (input < 0) { | 3660 | if (input < 0) { |
3659 | err = -errno; | 3661 | err = -errno; |
3660 | perror("failed to open file"); | 3662 | perror("failed to open file"); |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index bb24f9c17f9a..7b8f09b0b8bf 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -1322,7 +1322,7 @@ static int __cmd_record(int argc, const char **argv) | |||
1322 | PARSE_OPT_STOP_AT_NON_OPTION); | 1322 | PARSE_OPT_STOP_AT_NON_OPTION); |
1323 | 1323 | ||
1324 | if (output_name) | 1324 | if (output_name) |
1325 | data->file.path = output_name; | 1325 | data->path = output_name; |
1326 | 1326 | ||
1327 | if (stat_config.run_count != 1 || forever) { | 1327 | if (stat_config.run_count != 1 || forever) { |
1328 | pr_err("Cannot use -r option with perf stat record.\n"); | 1328 | pr_err("Cannot use -r option with perf stat record.\n"); |
@@ -1523,8 +1523,8 @@ static int __cmd_report(int argc, const char **argv) | |||
1523 | input_name = "perf.data"; | 1523 | input_name = "perf.data"; |
1524 | } | 1524 | } |
1525 | 1525 | ||
1526 | perf_stat.data.file.path = input_name; | 1526 | perf_stat.data.path = input_name; |
1527 | perf_stat.data.mode = PERF_DATA_MODE_READ; | 1527 | perf_stat.data.mode = PERF_DATA_MODE_READ; |
1528 | 1528 | ||
1529 | session = perf_session__new(&perf_stat.data, false, &perf_stat.tool); | 1529 | session = perf_session__new(&perf_stat.data, false, &perf_stat.tool); |
1530 | if (session == NULL) | 1530 | if (session == NULL) |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 775b99833e51..9b98687a27b9 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -1602,11 +1602,9 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) | |||
1602 | { "syscalls:sys_exit_select", process_exit_poll }, | 1602 | { "syscalls:sys_exit_select", process_exit_poll }, |
1603 | }; | 1603 | }; |
1604 | struct perf_data data = { | 1604 | struct perf_data data = { |
1605 | .file = { | 1605 | .path = input_name, |
1606 | .path = input_name, | 1606 | .mode = PERF_DATA_MODE_READ, |
1607 | }, | 1607 | .force = tchart->force, |
1608 | .mode = PERF_DATA_MODE_READ, | ||
1609 | .force = tchart->force, | ||
1610 | }; | 1608 | }; |
1611 | 1609 | ||
1612 | struct perf_session *session = perf_session__new(&data, false, | 1610 | struct perf_session *session = perf_session__new(&data, false, |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 1a11fe656afc..f5b3a1e9c1dd 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -3154,11 +3154,9 @@ static int trace__replay(struct trace *trace) | |||
3154 | { "probe:vfs_getname", trace__vfs_getname, }, | 3154 | { "probe:vfs_getname", trace__vfs_getname, }, |
3155 | }; | 3155 | }; |
3156 | struct perf_data data = { | 3156 | struct perf_data data = { |
3157 | .file = { | 3157 | .path = input_name, |
3158 | .path = input_name, | 3158 | .mode = PERF_DATA_MODE_READ, |
3159 | }, | 3159 | .force = trace->force, |
3160 | .mode = PERF_DATA_MODE_READ, | ||
3161 | .force = trace->force, | ||
3162 | }; | 3160 | }; |
3163 | struct perf_session *session; | 3161 | struct perf_session *session; |
3164 | struct perf_evsel *evsel; | 3162 | struct perf_evsel *evsel; |
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index c3091401df91..09ce73b07d35 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py | |||
@@ -1,3 +1,4 @@ | |||
1 | #!/usr/bin/env python2 | ||
1 | # SPDX-License-Identifier: GPL-2.0 | 2 | # SPDX-License-Identifier: GPL-2.0 |
2 | # exported-sql-viewer.py: view data from sql database | 3 | # exported-sql-viewer.py: view data from sql database |
3 | # Copyright (c) 2014-2018, Intel Corporation. | 4 | # Copyright (c) 2014-2018, Intel Corporation. |
@@ -1397,18 +1398,28 @@ class BranchModel(TreeModel): | |||
1397 | def HasMoreRecords(self): | 1398 | def HasMoreRecords(self): |
1398 | return self.more | 1399 | return self.more |
1399 | 1400 | ||
1401 | # Report Variables | ||
1402 | |||
1403 | class ReportVars(): | ||
1404 | |||
1405 | def __init__(self, name = "", where_clause = "", limit = ""): | ||
1406 | self.name = name | ||
1407 | self.where_clause = where_clause | ||
1408 | self.limit = limit | ||
1409 | |||
1410 | def UniqueId(self): | ||
1411 | return str(self.where_clause + ";" + self.limit) | ||
1412 | |||
1400 | # Branch window | 1413 | # Branch window |
1401 | 1414 | ||
1402 | class BranchWindow(QMdiSubWindow): | 1415 | class BranchWindow(QMdiSubWindow): |
1403 | 1416 | ||
1404 | def __init__(self, glb, event_id, name, where_clause, parent=None): | 1417 | def __init__(self, glb, event_id, report_vars, parent=None): |
1405 | super(BranchWindow, self).__init__(parent) | 1418 | super(BranchWindow, self).__init__(parent) |
1406 | 1419 | ||
1407 | model_name = "Branch Events " + str(event_id) | 1420 | model_name = "Branch Events " + str(event_id) + " " + report_vars.UniqueId() |
1408 | if len(where_clause): | ||
1409 | model_name = where_clause + " " + model_name | ||
1410 | 1421 | ||
1411 | self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, where_clause)) | 1422 | self.model = LookupCreateModel(model_name, lambda: BranchModel(glb, event_id, report_vars.where_clause)) |
1412 | 1423 | ||
1413 | self.view = QTreeView() | 1424 | self.view = QTreeView() |
1414 | self.view.setUniformRowHeights(True) | 1425 | self.view.setUniformRowHeights(True) |
@@ -1426,7 +1437,7 @@ class BranchWindow(QMdiSubWindow): | |||
1426 | 1437 | ||
1427 | self.setWidget(self.vbox.Widget()) | 1438 | self.setWidget(self.vbox.Widget()) |
1428 | 1439 | ||
1429 | AddSubWindow(glb.mainwindow.mdi_area, self, name + " Branch Events") | 1440 | AddSubWindow(glb.mainwindow.mdi_area, self, report_vars.name + " Branch Events") |
1430 | 1441 | ||
1431 | def ResizeColumnToContents(self, column, n): | 1442 | def ResizeColumnToContents(self, column, n): |
1432 | # Using the view's resizeColumnToContents() here is extrememly slow | 1443 | # Using the view's resizeColumnToContents() here is extrememly slow |
@@ -1471,47 +1482,134 @@ class BranchWindow(QMdiSubWindow): | |||
1471 | else: | 1482 | else: |
1472 | self.find_bar.NotFound() | 1483 | self.find_bar.NotFound() |
1473 | 1484 | ||
1474 | # Dialog data item converted and validated using a SQL table | 1485 | # Line edit data item |
1475 | 1486 | ||
1476 | class SQLTableDialogDataItem(): | 1487 | class LineEditDataItem(object): |
1477 | 1488 | ||
1478 | def __init__(self, glb, label, placeholder_text, table_name, match_column, column_name1, column_name2, parent): | 1489 | def __init__(self, glb, label, placeholder_text, parent, id = "", default = ""): |
1479 | self.glb = glb | 1490 | self.glb = glb |
1480 | self.label = label | 1491 | self.label = label |
1481 | self.placeholder_text = placeholder_text | 1492 | self.placeholder_text = placeholder_text |
1482 | self.table_name = table_name | ||
1483 | self.match_column = match_column | ||
1484 | self.column_name1 = column_name1 | ||
1485 | self.column_name2 = column_name2 | ||
1486 | self.parent = parent | 1493 | self.parent = parent |
1494 | self.id = id | ||
1487 | 1495 | ||
1488 | self.value = "" | 1496 | self.value = default |
1489 | 1497 | ||
1490 | self.widget = QLineEdit() | 1498 | self.widget = QLineEdit(default) |
1491 | self.widget.editingFinished.connect(self.Validate) | 1499 | self.widget.editingFinished.connect(self.Validate) |
1492 | self.widget.textChanged.connect(self.Invalidate) | 1500 | self.widget.textChanged.connect(self.Invalidate) |
1493 | self.red = False | 1501 | self.red = False |
1494 | self.error = "" | 1502 | self.error = "" |
1495 | self.validated = True | 1503 | self.validated = True |
1496 | 1504 | ||
1497 | self.last_id = 0 | ||
1498 | self.first_time = 0 | ||
1499 | self.last_time = 2 ** 64 | ||
1500 | if self.table_name == "<timeranges>": | ||
1501 | query = QSqlQuery(self.glb.db) | ||
1502 | QueryExec(query, "SELECT id, time FROM samples ORDER BY id DESC LIMIT 1") | ||
1503 | if query.next(): | ||
1504 | self.last_id = int(query.value(0)) | ||
1505 | self.last_time = int(query.value(1)) | ||
1506 | QueryExec(query, "SELECT time FROM samples WHERE time != 0 ORDER BY id LIMIT 1") | ||
1507 | if query.next(): | ||
1508 | self.first_time = int(query.value(0)) | ||
1509 | if placeholder_text: | ||
1510 | placeholder_text += ", between " + str(self.first_time) + " and " + str(self.last_time) | ||
1511 | |||
1512 | if placeholder_text: | 1505 | if placeholder_text: |
1513 | self.widget.setPlaceholderText(placeholder_text) | 1506 | self.widget.setPlaceholderText(placeholder_text) |
1514 | 1507 | ||
1508 | def TurnTextRed(self): | ||
1509 | if not self.red: | ||
1510 | palette = QPalette() | ||
1511 | palette.setColor(QPalette.Text,Qt.red) | ||
1512 | self.widget.setPalette(palette) | ||
1513 | self.red = True | ||
1514 | |||
1515 | def TurnTextNormal(self): | ||
1516 | if self.red: | ||
1517 | palette = QPalette() | ||
1518 | self.widget.setPalette(palette) | ||
1519 | self.red = False | ||
1520 | |||
1521 | def InvalidValue(self, value): | ||
1522 | self.value = "" | ||
1523 | self.TurnTextRed() | ||
1524 | self.error = self.label + " invalid value '" + value + "'" | ||
1525 | self.parent.ShowMessage(self.error) | ||
1526 | |||
1527 | def Invalidate(self): | ||
1528 | self.validated = False | ||
1529 | |||
1530 | def DoValidate(self, input_string): | ||
1531 | self.value = input_string.strip() | ||
1532 | |||
1533 | def Validate(self): | ||
1534 | self.validated = True | ||
1535 | self.error = "" | ||
1536 | self.TurnTextNormal() | ||
1537 | self.parent.ClearMessage() | ||
1538 | input_string = self.widget.text() | ||
1539 | if not len(input_string.strip()): | ||
1540 | self.value = "" | ||
1541 | return | ||
1542 | self.DoValidate(input_string) | ||
1543 | |||
1544 | def IsValid(self): | ||
1545 | if not self.validated: | ||
1546 | self.Validate() | ||
1547 | if len(self.error): | ||
1548 | self.parent.ShowMessage(self.error) | ||
1549 | return False | ||
1550 | return True | ||
1551 | |||
1552 | def IsNumber(self, value): | ||
1553 | try: | ||
1554 | x = int(value) | ||
1555 | except: | ||
1556 | x = 0 | ||
1557 | return str(x) == value | ||
1558 | |||
1559 | # Non-negative integer ranges dialog data item | ||
1560 | |||
1561 | class NonNegativeIntegerRangesDataItem(LineEditDataItem): | ||
1562 | |||
1563 | def __init__(self, glb, label, placeholder_text, column_name, parent): | ||
1564 | super(NonNegativeIntegerRangesDataItem, self).__init__(glb, label, placeholder_text, parent) | ||
1565 | |||
1566 | self.column_name = column_name | ||
1567 | |||
1568 | def DoValidate(self, input_string): | ||
1569 | singles = [] | ||
1570 | ranges = [] | ||
1571 | for value in [x.strip() for x in input_string.split(",")]: | ||
1572 | if "-" in value: | ||
1573 | vrange = value.split("-") | ||
1574 | if len(vrange) != 2 or not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]): | ||
1575 | return self.InvalidValue(value) | ||
1576 | ranges.append(vrange) | ||
1577 | else: | ||
1578 | if not self.IsNumber(value): | ||
1579 | return self.InvalidValue(value) | ||
1580 | singles.append(value) | ||
1581 | ranges = [("(" + self.column_name + " >= " + r[0] + " AND " + self.column_name + " <= " + r[1] + ")") for r in ranges] | ||
1582 | if len(singles): | ||
1583 | ranges.append(self.column_name + " IN (" + ",".join(singles) + ")") | ||
1584 | self.value = " OR ".join(ranges) | ||
1585 | |||
1586 | # Positive integer dialog data item | ||
1587 | |||
1588 | class PositiveIntegerDataItem(LineEditDataItem): | ||
1589 | |||
1590 | def __init__(self, glb, label, placeholder_text, parent, id = "", default = ""): | ||
1591 | super(PositiveIntegerDataItem, self).__init__(glb, label, placeholder_text, parent, id, default) | ||
1592 | |||
1593 | def DoValidate(self, input_string): | ||
1594 | if not self.IsNumber(input_string.strip()): | ||
1595 | return self.InvalidValue(input_string) | ||
1596 | value = int(input_string.strip()) | ||
1597 | if value <= 0: | ||
1598 | return self.InvalidValue(input_string) | ||
1599 | self.value = str(value) | ||
1600 | |||
1601 | # Dialog data item converted and validated using a SQL table | ||
1602 | |||
1603 | class SQLTableDataItem(LineEditDataItem): | ||
1604 | |||
1605 | def __init__(self, glb, label, placeholder_text, table_name, match_column, column_name1, column_name2, parent): | ||
1606 | super(SQLTableDataItem, self).__init__(glb, label, placeholder_text, parent) | ||
1607 | |||
1608 | self.table_name = table_name | ||
1609 | self.match_column = match_column | ||
1610 | self.column_name1 = column_name1 | ||
1611 | self.column_name2 = column_name2 | ||
1612 | |||
1515 | def ValueToIds(self, value): | 1613 | def ValueToIds(self, value): |
1516 | ids = [] | 1614 | ids = [] |
1517 | query = QSqlQuery(self.glb.db) | 1615 | query = QSqlQuery(self.glb.db) |
@@ -1522,6 +1620,42 @@ class SQLTableDialogDataItem(): | |||
1522 | ids.append(str(query.value(0))) | 1620 | ids.append(str(query.value(0))) |
1523 | return ids | 1621 | return ids |
1524 | 1622 | ||
1623 | def DoValidate(self, input_string): | ||
1624 | all_ids = [] | ||
1625 | for value in [x.strip() for x in input_string.split(",")]: | ||
1626 | ids = self.ValueToIds(value) | ||
1627 | if len(ids): | ||
1628 | all_ids.extend(ids) | ||
1629 | else: | ||
1630 | return self.InvalidValue(value) | ||
1631 | self.value = self.column_name1 + " IN (" + ",".join(all_ids) + ")" | ||
1632 | if self.column_name2: | ||
1633 | self.value = "( " + self.value + " OR " + self.column_name2 + " IN (" + ",".join(all_ids) + ") )" | ||
1634 | |||
1635 | # Sample time ranges dialog data item converted and validated using 'samples' SQL table | ||
1636 | |||
1637 | class SampleTimeRangesDataItem(LineEditDataItem): | ||
1638 | |||
1639 | def __init__(self, glb, label, placeholder_text, column_name, parent): | ||
1640 | self.column_name = column_name | ||
1641 | |||
1642 | self.last_id = 0 | ||
1643 | self.first_time = 0 | ||
1644 | self.last_time = 2 ** 64 | ||
1645 | |||
1646 | query = QSqlQuery(glb.db) | ||
1647 | QueryExec(query, "SELECT id, time FROM samples ORDER BY id DESC LIMIT 1") | ||
1648 | if query.next(): | ||
1649 | self.last_id = int(query.value(0)) | ||
1650 | self.last_time = int(query.value(1)) | ||
1651 | QueryExec(query, "SELECT time FROM samples WHERE time != 0 ORDER BY id LIMIT 1") | ||
1652 | if query.next(): | ||
1653 | self.first_time = int(query.value(0)) | ||
1654 | if placeholder_text: | ||
1655 | placeholder_text += ", between " + str(self.first_time) + " and " + str(self.last_time) | ||
1656 | |||
1657 | super(SampleTimeRangesDataItem, self).__init__(glb, label, placeholder_text, parent) | ||
1658 | |||
1525 | def IdBetween(self, query, lower_id, higher_id, order): | 1659 | def IdBetween(self, query, lower_id, higher_id, order): |
1526 | QueryExec(query, "SELECT id FROM samples WHERE id > " + str(lower_id) + " AND id < " + str(higher_id) + " ORDER BY id " + order + " LIMIT 1") | 1660 | QueryExec(query, "SELECT id FROM samples WHERE id > " + str(lower_id) + " AND id < " + str(higher_id) + " ORDER BY id " + order + " LIMIT 1") |
1527 | if query.next(): | 1661 | if query.next(): |
@@ -1559,7 +1693,6 @@ class SQLTableDialogDataItem(): | |||
1559 | return str(lower_id) | 1693 | return str(lower_id) |
1560 | 1694 | ||
1561 | def ConvertRelativeTime(self, val): | 1695 | def ConvertRelativeTime(self, val): |
1562 | print "val ", val | ||
1563 | mult = 1 | 1696 | mult = 1 |
1564 | suffix = val[-2:] | 1697 | suffix = val[-2:] |
1565 | if suffix == "ms": | 1698 | if suffix == "ms": |
@@ -1581,29 +1714,23 @@ class SQLTableDialogDataItem(): | |||
1581 | return str(val) | 1714 | return str(val) |
1582 | 1715 | ||
1583 | def ConvertTimeRange(self, vrange): | 1716 | def ConvertTimeRange(self, vrange): |
1584 | print "vrange ", vrange | ||
1585 | if vrange[0] == "": | 1717 | if vrange[0] == "": |
1586 | vrange[0] = str(self.first_time) | 1718 | vrange[0] = str(self.first_time) |
1587 | if vrange[1] == "": | 1719 | if vrange[1] == "": |
1588 | vrange[1] = str(self.last_time) | 1720 | vrange[1] = str(self.last_time) |
1589 | vrange[0] = self.ConvertRelativeTime(vrange[0]) | 1721 | vrange[0] = self.ConvertRelativeTime(vrange[0]) |
1590 | vrange[1] = self.ConvertRelativeTime(vrange[1]) | 1722 | vrange[1] = self.ConvertRelativeTime(vrange[1]) |
1591 | print "vrange2 ", vrange | ||
1592 | if not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]): | 1723 | if not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]): |
1593 | return False | 1724 | return False |
1594 | print "ok1" | ||
1595 | beg_range = max(int(vrange[0]), self.first_time) | 1725 | beg_range = max(int(vrange[0]), self.first_time) |
1596 | end_range = min(int(vrange[1]), self.last_time) | 1726 | end_range = min(int(vrange[1]), self.last_time) |
1597 | if beg_range > self.last_time or end_range < self.first_time: | 1727 | if beg_range > self.last_time or end_range < self.first_time: |
1598 | return False | 1728 | return False |
1599 | print "ok2" | ||
1600 | vrange[0] = self.BinarySearchTime(0, self.last_id, beg_range, True) | 1729 | vrange[0] = self.BinarySearchTime(0, self.last_id, beg_range, True) |
1601 | vrange[1] = self.BinarySearchTime(1, self.last_id + 1, end_range, False) | 1730 | vrange[1] = self.BinarySearchTime(1, self.last_id + 1, end_range, False) |
1602 | print "vrange3 ", vrange | ||
1603 | return True | 1731 | return True |
1604 | 1732 | ||
1605 | def AddTimeRange(self, value, ranges): | 1733 | def AddTimeRange(self, value, ranges): |
1606 | print "value ", value | ||
1607 | n = value.count("-") | 1734 | n = value.count("-") |
1608 | if n == 1: | 1735 | if n == 1: |
1609 | pass | 1736 | pass |
@@ -1621,111 +1748,31 @@ class SQLTableDialogDataItem(): | |||
1621 | return True | 1748 | return True |
1622 | return False | 1749 | return False |
1623 | 1750 | ||
1624 | def InvalidValue(self, value): | 1751 | def DoValidate(self, input_string): |
1625 | self.value = "" | 1752 | ranges = [] |
1626 | palette = QPalette() | 1753 | for value in [x.strip() for x in input_string.split(",")]: |
1627 | palette.setColor(QPalette.Text,Qt.red) | 1754 | if not self.AddTimeRange(value, ranges): |
1628 | self.widget.setPalette(palette) | 1755 | return self.InvalidValue(value) |
1629 | self.red = True | 1756 | ranges = [("(" + self.column_name + " >= " + r[0] + " AND " + self.column_name + " <= " + r[1] + ")") for r in ranges] |
1630 | self.error = self.label + " invalid value '" + value + "'" | 1757 | self.value = " OR ".join(ranges) |
1631 | self.parent.ShowMessage(self.error) | ||
1632 | 1758 | ||
1633 | def IsNumber(self, value): | 1759 | # Report Dialog Base |
1634 | try: | ||
1635 | x = int(value) | ||
1636 | except: | ||
1637 | x = 0 | ||
1638 | return str(x) == value | ||
1639 | 1760 | ||
1640 | def Invalidate(self): | 1761 | class ReportDialogBase(QDialog): |
1641 | self.validated = False | ||
1642 | 1762 | ||
1643 | def Validate(self): | 1763 | def __init__(self, glb, title, items, partial, parent=None): |
1644 | input_string = self.widget.text() | 1764 | super(ReportDialogBase, self).__init__(parent) |
1645 | self.validated = True | ||
1646 | if self.red: | ||
1647 | palette = QPalette() | ||
1648 | self.widget.setPalette(palette) | ||
1649 | self.red = False | ||
1650 | if not len(input_string.strip()): | ||
1651 | self.error = "" | ||
1652 | self.value = "" | ||
1653 | return | ||
1654 | if self.table_name == "<timeranges>": | ||
1655 | ranges = [] | ||
1656 | for value in [x.strip() for x in input_string.split(",")]: | ||
1657 | if not self.AddTimeRange(value, ranges): | ||
1658 | return self.InvalidValue(value) | ||
1659 | ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges] | ||
1660 | self.value = " OR ".join(ranges) | ||
1661 | elif self.table_name == "<ranges>": | ||
1662 | singles = [] | ||
1663 | ranges = [] | ||
1664 | for value in [x.strip() for x in input_string.split(",")]: | ||
1665 | if "-" in value: | ||
1666 | vrange = value.split("-") | ||
1667 | if len(vrange) != 2 or not self.IsNumber(vrange[0]) or not self.IsNumber(vrange[1]): | ||
1668 | return self.InvalidValue(value) | ||
1669 | ranges.append(vrange) | ||
1670 | else: | ||
1671 | if not self.IsNumber(value): | ||
1672 | return self.InvalidValue(value) | ||
1673 | singles.append(value) | ||
1674 | ranges = [("(" + self.column_name1 + " >= " + r[0] + " AND " + self.column_name1 + " <= " + r[1] + ")") for r in ranges] | ||
1675 | if len(singles): | ||
1676 | ranges.append(self.column_name1 + " IN (" + ",".join(singles) + ")") | ||
1677 | self.value = " OR ".join(ranges) | ||
1678 | elif self.table_name: | ||
1679 | all_ids = [] | ||
1680 | for value in [x.strip() for x in input_string.split(",")]: | ||
1681 | ids = self.ValueToIds(value) | ||
1682 | if len(ids): | ||
1683 | all_ids.extend(ids) | ||
1684 | else: | ||
1685 | return self.InvalidValue(value) | ||
1686 | self.value = self.column_name1 + " IN (" + ",".join(all_ids) + ")" | ||
1687 | if self.column_name2: | ||
1688 | self.value = "( " + self.value + " OR " + self.column_name2 + " IN (" + ",".join(all_ids) + ") )" | ||
1689 | else: | ||
1690 | self.value = input_string.strip() | ||
1691 | self.error = "" | ||
1692 | self.parent.ClearMessage() | ||
1693 | |||
1694 | def IsValid(self): | ||
1695 | if not self.validated: | ||
1696 | self.Validate() | ||
1697 | if len(self.error): | ||
1698 | self.parent.ShowMessage(self.error) | ||
1699 | return False | ||
1700 | return True | ||
1701 | |||
1702 | # Selected branch report creation dialog | ||
1703 | |||
1704 | class SelectedBranchDialog(QDialog): | ||
1705 | |||
1706 | def __init__(self, glb, parent=None): | ||
1707 | super(SelectedBranchDialog, self).__init__(parent) | ||
1708 | 1765 | ||
1709 | self.glb = glb | 1766 | self.glb = glb |
1710 | 1767 | ||
1711 | self.name = "" | 1768 | self.report_vars = ReportVars() |
1712 | self.where_clause = "" | ||
1713 | 1769 | ||
1714 | self.setWindowTitle("Selected Branches") | 1770 | self.setWindowTitle(title) |
1715 | self.setMinimumWidth(600) | 1771 | self.setMinimumWidth(600) |
1716 | 1772 | ||
1717 | items = ( | 1773 | self.data_items = [x(glb, self) for x in items] |
1718 | ("Report name:", "Enter a name to appear in the window title bar", "", "", "", ""), | 1774 | |
1719 | ("Time ranges:", "Enter time ranges", "<timeranges>", "", "samples.id", ""), | 1775 | self.partial = partial |
1720 | ("CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "<ranges>", "", "cpu", ""), | ||
1721 | ("Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", ""), | ||
1722 | ("PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", ""), | ||
1723 | ("TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", ""), | ||
1724 | ("DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id"), | ||
1725 | ("Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id"), | ||
1726 | ("Raw SQL clause: ", "Enter a raw SQL WHERE clause", "", "", "", ""), | ||
1727 | ) | ||
1728 | self.data_items = [SQLTableDialogDataItem(glb, *x, parent=self) for x in items] | ||
1729 | 1776 | ||
1730 | self.grid = QGridLayout() | 1777 | self.grid = QGridLayout() |
1731 | 1778 | ||
@@ -1757,23 +1804,28 @@ class SelectedBranchDialog(QDialog): | |||
1757 | self.setLayout(self.vbox); | 1804 | self.setLayout(self.vbox); |
1758 | 1805 | ||
1759 | def Ok(self): | 1806 | def Ok(self): |
1760 | self.name = self.data_items[0].value | 1807 | vars = self.report_vars |
1761 | if not self.name: | 1808 | for d in self.data_items: |
1809 | if d.id == "REPORTNAME": | ||
1810 | vars.name = d.value | ||
1811 | if not vars.name: | ||
1762 | self.ShowMessage("Report name is required") | 1812 | self.ShowMessage("Report name is required") |
1763 | return | 1813 | return |
1764 | for d in self.data_items: | 1814 | for d in self.data_items: |
1765 | if not d.IsValid(): | 1815 | if not d.IsValid(): |
1766 | return | 1816 | return |
1767 | for d in self.data_items[1:]: | 1817 | for d in self.data_items[1:]: |
1768 | if len(d.value): | 1818 | if d.id == "LIMIT": |
1769 | if len(self.where_clause): | 1819 | vars.limit = d.value |
1770 | self.where_clause += " AND " | 1820 | elif len(d.value): |
1771 | self.where_clause += d.value | 1821 | if len(vars.where_clause): |
1772 | if len(self.where_clause): | 1822 | vars.where_clause += " AND " |
1773 | self.where_clause = " AND ( " + self.where_clause + " ) " | 1823 | vars.where_clause += d.value |
1774 | else: | 1824 | if len(vars.where_clause): |
1775 | self.ShowMessage("No selection") | 1825 | if self.partial: |
1776 | return | 1826 | vars.where_clause = " AND ( " + vars.where_clause + " ) " |
1827 | else: | ||
1828 | vars.where_clause = " WHERE " + vars.where_clause + " " | ||
1777 | self.accept() | 1829 | self.accept() |
1778 | 1830 | ||
1779 | def ShowMessage(self, msg): | 1831 | def ShowMessage(self, msg): |
@@ -1782,6 +1834,23 @@ class SelectedBranchDialog(QDialog): | |||
1782 | def ClearMessage(self): | 1834 | def ClearMessage(self): |
1783 | self.status.setText("") | 1835 | self.status.setText("") |
1784 | 1836 | ||
1837 | # Selected branch report creation dialog | ||
1838 | |||
1839 | class SelectedBranchDialog(ReportDialogBase): | ||
1840 | |||
1841 | def __init__(self, glb, parent=None): | ||
1842 | title = "Selected Branches" | ||
1843 | items = (lambda g, p: LineEditDataItem(g, "Report name:", "Enter a name to appear in the window title bar", p, "REPORTNAME"), | ||
1844 | lambda g, p: SampleTimeRangesDataItem(g, "Time ranges:", "Enter time ranges", "samples.id", p), | ||
1845 | lambda g, p: NonNegativeIntegerRangesDataItem(g, "CPUs:", "Enter CPUs or ranges e.g. 0,5-6", "cpu", p), | ||
1846 | lambda g, p: SQLTableDataItem(g, "Commands:", "Only branches with these commands will be included", "comms", "comm", "comm_id", "", p), | ||
1847 | lambda g, p: SQLTableDataItem(g, "PIDs:", "Only branches with these process IDs will be included", "threads", "pid", "thread_id", "", p), | ||
1848 | lambda g, p: SQLTableDataItem(g, "TIDs:", "Only branches with these thread IDs will be included", "threads", "tid", "thread_id", "", p), | ||
1849 | lambda g, p: SQLTableDataItem(g, "DSOs:", "Only branches with these DSOs will be included", "dsos", "short_name", "samples.dso_id", "to_dso_id", p), | ||
1850 | lambda g, p: SQLTableDataItem(g, "Symbols:", "Only branches with these symbols will be included", "symbols", "name", "symbol_id", "to_symbol_id", p), | ||
1851 | lambda g, p: LineEditDataItem(g, "Raw SQL clause: ", "Enter a raw SQL WHERE clause", p)) | ||
1852 | super(SelectedBranchDialog, self).__init__(glb, title, items, True, parent) | ||
1853 | |||
1785 | # Event list | 1854 | # Event list |
1786 | 1855 | ||
1787 | def GetEventList(db): | 1856 | def GetEventList(db): |
@@ -1792,6 +1861,16 @@ def GetEventList(db): | |||
1792 | events.append(query.value(0)) | 1861 | events.append(query.value(0)) |
1793 | return events | 1862 | return events |
1794 | 1863 | ||
1864 | # Is a table selectable | ||
1865 | |||
1866 | def IsSelectable(db, table): | ||
1867 | query = QSqlQuery(db) | ||
1868 | try: | ||
1869 | QueryExec(query, "SELECT * FROM " + table + " LIMIT 1") | ||
1870 | except: | ||
1871 | return False | ||
1872 | return True | ||
1873 | |||
1795 | # SQL data preparation | 1874 | # SQL data preparation |
1796 | 1875 | ||
1797 | def SQLTableDataPrep(query, count): | 1876 | def SQLTableDataPrep(query, count): |
@@ -1817,12 +1896,13 @@ class SQLTableModel(TableModel): | |||
1817 | 1896 | ||
1818 | progress = Signal(object) | 1897 | progress = Signal(object) |
1819 | 1898 | ||
1820 | def __init__(self, glb, sql, column_count, parent=None): | 1899 | def __init__(self, glb, sql, column_headers, parent=None): |
1821 | super(SQLTableModel, self).__init__(parent) | 1900 | super(SQLTableModel, self).__init__(parent) |
1822 | self.glb = glb | 1901 | self.glb = glb |
1823 | self.more = True | 1902 | self.more = True |
1824 | self.populated = 0 | 1903 | self.populated = 0 |
1825 | self.fetcher = SQLFetcher(glb, sql, lambda x, y=column_count: SQLTableDataPrep(x, y), self.AddSample) | 1904 | self.column_headers = column_headers |
1905 | self.fetcher = SQLFetcher(glb, sql, lambda x, y=len(column_headers): SQLTableDataPrep(x, y), self.AddSample) | ||
1826 | self.fetcher.done.connect(self.Update) | 1906 | self.fetcher.done.connect(self.Update) |
1827 | self.fetcher.Fetch(glb_chunk_sz) | 1907 | self.fetcher.Fetch(glb_chunk_sz) |
1828 | 1908 | ||
@@ -1860,6 +1940,12 @@ class SQLTableModel(TableModel): | |||
1860 | def HasMoreRecords(self): | 1940 | def HasMoreRecords(self): |
1861 | return self.more | 1941 | return self.more |
1862 | 1942 | ||
1943 | def columnCount(self, parent=None): | ||
1944 | return len(self.column_headers) | ||
1945 | |||
1946 | def columnHeader(self, column): | ||
1947 | return self.column_headers[column] | ||
1948 | |||
1863 | # SQL automatic table data model | 1949 | # SQL automatic table data model |
1864 | 1950 | ||
1865 | class SQLAutoTableModel(SQLTableModel): | 1951 | class SQLAutoTableModel(SQLTableModel): |
@@ -1869,12 +1955,12 @@ class SQLAutoTableModel(SQLTableModel): | |||
1869 | if table_name == "comm_threads_view": | 1955 | if table_name == "comm_threads_view": |
1870 | # For now, comm_threads_view has no id column | 1956 | # For now, comm_threads_view has no id column |
1871 | sql = "SELECT * FROM " + table_name + " WHERE comm_id > $$last_id$$ ORDER BY comm_id LIMIT " + str(glb_chunk_sz) | 1957 | sql = "SELECT * FROM " + table_name + " WHERE comm_id > $$last_id$$ ORDER BY comm_id LIMIT " + str(glb_chunk_sz) |
1872 | self.column_headers = [] | 1958 | column_headers = [] |
1873 | query = QSqlQuery(glb.db) | 1959 | query = QSqlQuery(glb.db) |
1874 | if glb.dbref.is_sqlite3: | 1960 | if glb.dbref.is_sqlite3: |
1875 | QueryExec(query, "PRAGMA table_info(" + table_name + ")") | 1961 | QueryExec(query, "PRAGMA table_info(" + table_name + ")") |
1876 | while query.next(): | 1962 | while query.next(): |
1877 | self.column_headers.append(query.value(1)) | 1963 | column_headers.append(query.value(1)) |
1878 | if table_name == "sqlite_master": | 1964 | if table_name == "sqlite_master": |
1879 | sql = "SELECT * FROM " + table_name | 1965 | sql = "SELECT * FROM " + table_name |
1880 | else: | 1966 | else: |
@@ -1887,14 +1973,8 @@ class SQLAutoTableModel(SQLTableModel): | |||
1887 | schema = "public" | 1973 | schema = "public" |
1888 | QueryExec(query, "SELECT column_name FROM information_schema.columns WHERE table_schema = '" + schema + "' and table_name = '" + select_table_name + "'") | 1974 | QueryExec(query, "SELECT column_name FROM information_schema.columns WHERE table_schema = '" + schema + "' and table_name = '" + select_table_name + "'") |
1889 | while query.next(): | 1975 | while query.next(): |
1890 | self.column_headers.append(query.value(0)) | 1976 | column_headers.append(query.value(0)) |
1891 | super(SQLAutoTableModel, self).__init__(glb, sql, len(self.column_headers), parent) | 1977 | super(SQLAutoTableModel, self).__init__(glb, sql, column_headers, parent) |
1892 | |||
1893 | def columnCount(self, parent=None): | ||
1894 | return len(self.column_headers) | ||
1895 | |||
1896 | def columnHeader(self, column): | ||
1897 | return self.column_headers[column] | ||
1898 | 1978 | ||
1899 | # Base class for custom ResizeColumnsToContents | 1979 | # Base class for custom ResizeColumnsToContents |
1900 | 1980 | ||
@@ -1997,6 +2077,103 @@ def GetTableList(glb): | |||
1997 | tables.append("information_schema.columns") | 2077 | tables.append("information_schema.columns") |
1998 | return tables | 2078 | return tables |
1999 | 2079 | ||
2080 | # Top Calls data model | ||
2081 | |||
2082 | class TopCallsModel(SQLTableModel): | ||
2083 | |||
2084 | def __init__(self, glb, report_vars, parent=None): | ||
2085 | text = "" | ||
2086 | if not glb.dbref.is_sqlite3: | ||
2087 | text = "::text" | ||
2088 | limit = "" | ||
2089 | if len(report_vars.limit): | ||
2090 | limit = " LIMIT " + report_vars.limit | ||
2091 | sql = ("SELECT comm, pid, tid, name," | ||
2092 | " CASE" | ||
2093 | " WHEN (short_name = '[kernel.kallsyms]') THEN '[kernel]'" + text + | ||
2094 | " ELSE short_name" | ||
2095 | " END AS dso," | ||
2096 | " call_time, return_time, (return_time - call_time) AS elapsed_time, branch_count, " | ||
2097 | " CASE" | ||
2098 | " WHEN (calls.flags = 1) THEN 'no call'" + text + | ||
2099 | " WHEN (calls.flags = 2) THEN 'no return'" + text + | ||
2100 | " WHEN (calls.flags = 3) THEN 'no call/return'" + text + | ||
2101 | " ELSE ''" + text + | ||
2102 | " END AS flags" | ||
2103 | " FROM calls" | ||
2104 | " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" | ||
2105 | " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" | ||
2106 | " INNER JOIN dsos ON symbols.dso_id = dsos.id" | ||
2107 | " INNER JOIN comms ON calls.comm_id = comms.id" | ||
2108 | " INNER JOIN threads ON calls.thread_id = threads.id" + | ||
2109 | report_vars.where_clause + | ||
2110 | " ORDER BY elapsed_time DESC" + | ||
2111 | limit | ||
2112 | ) | ||
2113 | column_headers = ("Command", "PID", "TID", "Symbol", "Object", "Call Time", "Return Time", "Elapsed Time (ns)", "Branch Count", "Flags") | ||
2114 | self.alignment = (Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignLeft) | ||
2115 | super(TopCallsModel, self).__init__(glb, sql, column_headers, parent) | ||
2116 | |||
2117 | def columnAlignment(self, column): | ||
2118 | return self.alignment[column] | ||
2119 | |||
2120 | # Top Calls report creation dialog | ||
2121 | |||
2122 | class TopCallsDialog(ReportDialogBase): | ||
2123 | |||
2124 | def __init__(self, glb, parent=None): | ||
2125 | title = "Top Calls by Elapsed Time" | ||
2126 | items = (lambda g, p: LineEditDataItem(g, "Report name:", "Enter a name to appear in the window title bar", p, "REPORTNAME"), | ||
2127 | lambda g, p: SQLTableDataItem(g, "Commands:", "Only calls with these commands will be included", "comms", "comm", "comm_id", "", p), | ||
2128 | lambda g, p: SQLTableDataItem(g, "PIDs:", "Only calls with these process IDs will be included", "threads", "pid", "thread_id", "", p), | ||
2129 | lambda g, p: SQLTableDataItem(g, "TIDs:", "Only calls with these thread IDs will be included", "threads", "tid", "thread_id", "", p), | ||
2130 | lambda g, p: SQLTableDataItem(g, "DSOs:", "Only calls with these DSOs will be included", "dsos", "short_name", "dso_id", "", p), | ||
2131 | lambda g, p: SQLTableDataItem(g, "Symbols:", "Only calls with these symbols will be included", "symbols", "name", "symbol_id", "", p), | ||
2132 | lambda g, p: LineEditDataItem(g, "Raw SQL clause: ", "Enter a raw SQL WHERE clause", p), | ||
2133 | lambda g, p: PositiveIntegerDataItem(g, "Record limit:", "Limit selection to this number of records", p, "LIMIT", "100")) | ||
2134 | super(TopCallsDialog, self).__init__(glb, title, items, False, parent) | ||
2135 | |||
2136 | # Top Calls window | ||
2137 | |||
2138 | class TopCallsWindow(QMdiSubWindow, ResizeColumnsToContentsBase): | ||
2139 | |||
2140 | def __init__(self, glb, report_vars, parent=None): | ||
2141 | super(TopCallsWindow, self).__init__(parent) | ||
2142 | |||
2143 | self.data_model = LookupCreateModel("Top Calls " + report_vars.UniqueId(), lambda: TopCallsModel(glb, report_vars)) | ||
2144 | self.model = self.data_model | ||
2145 | |||
2146 | self.view = QTableView() | ||
2147 | self.view.setModel(self.model) | ||
2148 | self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) | ||
2149 | self.view.verticalHeader().setVisible(False) | ||
2150 | |||
2151 | self.ResizeColumnsToContents() | ||
2152 | |||
2153 | self.find_bar = FindBar(self, self, True) | ||
2154 | |||
2155 | self.finder = ChildDataItemFinder(self.model) | ||
2156 | |||
2157 | self.fetch_bar = FetchMoreRecordsBar(self.data_model, self) | ||
2158 | |||
2159 | self.vbox = VBox(self.view, self.find_bar.Widget(), self.fetch_bar.Widget()) | ||
2160 | |||
2161 | self.setWidget(self.vbox.Widget()) | ||
2162 | |||
2163 | AddSubWindow(glb.mainwindow.mdi_area, self, report_vars.name) | ||
2164 | |||
2165 | def Find(self, value, direction, pattern, context): | ||
2166 | self.view.setFocus() | ||
2167 | self.find_bar.Busy() | ||
2168 | self.finder.Find(value, direction, pattern, context, self.FindDone) | ||
2169 | |||
2170 | def FindDone(self, row): | ||
2171 | self.find_bar.Idle() | ||
2172 | if row >= 0: | ||
2173 | self.view.setCurrentIndex(self.model.index(row, 0, QModelIndex())) | ||
2174 | else: | ||
2175 | self.find_bar.NotFound() | ||
2176 | |||
2000 | # Action Definition | 2177 | # Action Definition |
2001 | 2178 | ||
2002 | def CreateAction(label, tip, callback, parent=None, shortcut=None): | 2179 | def CreateAction(label, tip, callback, parent=None, shortcut=None): |
@@ -2100,6 +2277,7 @@ p.c2 { | |||
2100 | <p class=c2><a href=#callgraph>1.1 Context-Sensitive Call Graph</a></p> | 2277 | <p class=c2><a href=#callgraph>1.1 Context-Sensitive Call Graph</a></p> |
2101 | <p class=c2><a href=#allbranches>1.2 All branches</a></p> | 2278 | <p class=c2><a href=#allbranches>1.2 All branches</a></p> |
2102 | <p class=c2><a href=#selectedbranches>1.3 Selected branches</a></p> | 2279 | <p class=c2><a href=#selectedbranches>1.3 Selected branches</a></p> |
2280 | <p class=c2><a href=#topcallsbyelapsedtime>1.4 Top calls by elapsed time</a></p> | ||
2103 | <p class=c1><a href=#tables>2. Tables</a></p> | 2281 | <p class=c1><a href=#tables>2. Tables</a></p> |
2104 | <h1 id=reports>1. Reports</h1> | 2282 | <h1 id=reports>1. Reports</h1> |
2105 | <h2 id=callgraph>1.1 Context-Sensitive Call Graph</h2> | 2283 | <h2 id=callgraph>1.1 Context-Sensitive Call Graph</h2> |
@@ -2175,6 +2353,10 @@ ms, us or ns. Also, negative values are relative to the end of trace. Examples: | |||
2175 | -10ms- The last 10ms | 2353 | -10ms- The last 10ms |
2176 | </pre> | 2354 | </pre> |
2177 | N.B. Due to the granularity of timestamps, there could be no branches in any given time range. | 2355 | N.B. Due to the granularity of timestamps, there could be no branches in any given time range. |
2356 | <h2 id=topcallsbyelapsedtime>1.4 Top calls by elapsed time</h2> | ||
2357 | The Top calls by elapsed time report displays calls in descending order of time elapsed between when the function was called and when it returned. | ||
2358 | The data is reduced by various selection criteria. A dialog box displays available criteria which are AND'ed together. | ||
2359 | If not all data is fetched, a Fetch bar is provided. Ctrl-F displays a Find bar. | ||
2178 | <h1 id=tables>2. Tables</h1> | 2360 | <h1 id=tables>2. Tables</h1> |
2179 | The Tables menu shows all tables and views in the database. Most tables have an associated view | 2361 | The Tables menu shows all tables and views in the database. Most tables have an associated view |
2180 | which displays the information in a more friendly way. Not all data for large tables is fetched | 2362 | which displays the information in a more friendly way. Not all data for large tables is fetched |
@@ -2304,10 +2486,14 @@ class MainWindow(QMainWindow): | |||
2304 | edit_menu.addAction(CreateAction("&Enlarge Font", "Make text bigger", self.EnlargeFont, self, [QKeySequence("Ctrl++")])) | 2486 | edit_menu.addAction(CreateAction("&Enlarge Font", "Make text bigger", self.EnlargeFont, self, [QKeySequence("Ctrl++")])) |
2305 | 2487 | ||
2306 | reports_menu = menu.addMenu("&Reports") | 2488 | reports_menu = menu.addMenu("&Reports") |
2307 | reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self)) | 2489 | if IsSelectable(glb.db, "calls"): |
2490 | reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self)) | ||
2308 | 2491 | ||
2309 | self.EventMenu(GetEventList(glb.db), reports_menu) | 2492 | self.EventMenu(GetEventList(glb.db), reports_menu) |
2310 | 2493 | ||
2494 | if IsSelectable(glb.db, "calls"): | ||
2495 | reports_menu.addAction(CreateAction("&Top calls by elapsed time", "Create a new window displaying top calls by elapsed time", self.NewTopCalls, self)) | ||
2496 | |||
2311 | self.TableMenu(GetTableList(glb), menu) | 2497 | self.TableMenu(GetTableList(glb), menu) |
2312 | 2498 | ||
2313 | self.window_menu = WindowMenu(self.mdi_area, menu) | 2499 | self.window_menu = WindowMenu(self.mdi_area, menu) |
@@ -2363,14 +2549,20 @@ class MainWindow(QMainWindow): | |||
2363 | def NewCallGraph(self): | 2549 | def NewCallGraph(self): |
2364 | CallGraphWindow(self.glb, self) | 2550 | CallGraphWindow(self.glb, self) |
2365 | 2551 | ||
2552 | def NewTopCalls(self): | ||
2553 | dialog = TopCallsDialog(self.glb, self) | ||
2554 | ret = dialog.exec_() | ||
2555 | if ret: | ||
2556 | TopCallsWindow(self.glb, dialog.report_vars, self) | ||
2557 | |||
2366 | def NewBranchView(self, event_id): | 2558 | def NewBranchView(self, event_id): |
2367 | BranchWindow(self.glb, event_id, "", "", self) | 2559 | BranchWindow(self.glb, event_id, ReportVars(), self) |
2368 | 2560 | ||
2369 | def NewSelectedBranchView(self, event_id): | 2561 | def NewSelectedBranchView(self, event_id): |
2370 | dialog = SelectedBranchDialog(self.glb, self) | 2562 | dialog = SelectedBranchDialog(self.glb, self) |
2371 | ret = dialog.exec_() | 2563 | ret = dialog.exec_() |
2372 | if ret: | 2564 | if ret: |
2373 | BranchWindow(self.glb, event_id, dialog.name, dialog.where_clause, self) | 2565 | BranchWindow(self.glb, event_id, dialog.report_vars, self) |
2374 | 2566 | ||
2375 | def NewTableView(self, table_name): | 2567 | def NewTableView(self, table_name): |
2376 | TableWindow(self.glb, table_name, self) | 2568 | TableWindow(self.glb, table_name, self) |
diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py index cafeff3d74db..3648e8b986ec 100644 --- a/tools/perf/scripts/python/failed-syscalls-by-pid.py +++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py | |||
@@ -5,6 +5,8 @@ | |||
5 | # Displays system-wide failed system call totals, broken down by pid. | 5 | # Displays system-wide failed system call totals, broken down by pid. |
6 | # If a [comm] arg is specified, only syscalls called by [comm] are displayed. | 6 | # If a [comm] arg is specified, only syscalls called by [comm] are displayed. |
7 | 7 | ||
8 | from __future__ import print_function | ||
9 | |||
8 | import os | 10 | import os |
9 | import sys | 11 | import sys |
10 | 12 | ||
@@ -32,7 +34,7 @@ if len(sys.argv) > 1: | |||
32 | syscalls = autodict() | 34 | syscalls = autodict() |
33 | 35 | ||
34 | def trace_begin(): | 36 | def trace_begin(): |
35 | print "Press control+C to stop and show the summary" | 37 | print("Press control+C to stop and show the summary") |
36 | 38 | ||
37 | def trace_end(): | 39 | def trace_end(): |
38 | print_error_totals() | 40 | print_error_totals() |
@@ -57,22 +59,21 @@ def syscalls__sys_exit(event_name, context, common_cpu, | |||
57 | 59 | ||
58 | def print_error_totals(): | 60 | def print_error_totals(): |
59 | if for_comm is not None: | 61 | if for_comm is not None: |
60 | print "\nsyscall errors for %s:\n\n" % (for_comm), | 62 | print("\nsyscall errors for %s:\n" % (for_comm)) |
61 | else: | 63 | else: |
62 | print "\nsyscall errors:\n\n", | 64 | print("\nsyscall errors:\n") |
63 | 65 | ||
64 | print "%-30s %10s\n" % ("comm [pid]", "count"), | 66 | print("%-30s %10s" % ("comm [pid]", "count")) |
65 | print "%-30s %10s\n" % ("------------------------------", \ | 67 | print("%-30s %10s" % ("------------------------------", "----------")) |
66 | "----------"), | ||
67 | 68 | ||
68 | comm_keys = syscalls.keys() | 69 | comm_keys = syscalls.keys() |
69 | for comm in comm_keys: | 70 | for comm in comm_keys: |
70 | pid_keys = syscalls[comm].keys() | 71 | pid_keys = syscalls[comm].keys() |
71 | for pid in pid_keys: | 72 | for pid in pid_keys: |
72 | print "\n%s [%d]\n" % (comm, pid), | 73 | print("\n%s [%d]" % (comm, pid)) |
73 | id_keys = syscalls[comm][pid].keys() | 74 | id_keys = syscalls[comm][pid].keys() |
74 | for id in id_keys: | 75 | for id in id_keys: |
75 | print " syscall: %-16s\n" % syscall_name(id), | 76 | print(" syscall: %-16s" % syscall_name(id)) |
76 | ret_keys = syscalls[comm][pid][id].keys() | 77 | ret_keys = syscalls[comm][pid][id].keys() |
77 | for ret, val in sorted(syscalls[comm][pid][id].iteritems(), key = lambda(k, v): (v, k), reverse = True): | 78 | for ret, val in sorted(syscalls[comm][pid][id].items(), key = lambda kv: (kv[1], kv[0]), reverse = True): |
78 | print " err = %-20s %10d\n" % (strerror(ret), val), | 79 | print(" err = %-20s %10d" % (strerror(ret), val)) |
diff --git a/tools/perf/scripts/python/mem-phys-addr.py b/tools/perf/scripts/python/mem-phys-addr.py index ebee2c5ae496..fb0bbcbfa0f0 100644 --- a/tools/perf/scripts/python/mem-phys-addr.py +++ b/tools/perf/scripts/python/mem-phys-addr.py | |||
@@ -4,6 +4,8 @@ | |||
4 | # Copyright (c) 2018, Intel Corporation. | 4 | # Copyright (c) 2018, Intel Corporation. |
5 | 5 | ||
6 | from __future__ import division | 6 | from __future__ import division |
7 | from __future__ import print_function | ||
8 | |||
7 | import os | 9 | import os |
8 | import sys | 10 | import sys |
9 | import struct | 11 | import struct |
@@ -31,21 +33,23 @@ def parse_iomem(): | |||
31 | for i, j in enumerate(f): | 33 | for i, j in enumerate(f): |
32 | m = re.split('-|:',j,2) | 34 | m = re.split('-|:',j,2) |
33 | if m[2].strip() == 'System RAM': | 35 | if m[2].strip() == 'System RAM': |
34 | system_ram.append(long(m[0], 16)) | 36 | system_ram.append(int(m[0], 16)) |
35 | system_ram.append(long(m[1], 16)) | 37 | system_ram.append(int(m[1], 16)) |
36 | if m[2].strip() == 'Persistent Memory': | 38 | if m[2].strip() == 'Persistent Memory': |
37 | pmem.append(long(m[0], 16)) | 39 | pmem.append(int(m[0], 16)) |
38 | pmem.append(long(m[1], 16)) | 40 | pmem.append(int(m[1], 16)) |
39 | 41 | ||
40 | def print_memory_type(): | 42 | def print_memory_type(): |
41 | print "Event: %s" % (event_name) | 43 | print("Event: %s" % (event_name)) |
42 | print "%-40s %10s %10s\n" % ("Memory type", "count", "percentage"), | 44 | print("%-40s %10s %10s\n" % ("Memory type", "count", "percentage"), end='') |
43 | print "%-40s %10s %10s\n" % ("----------------------------------------", \ | 45 | print("%-40s %10s %10s\n" % ("----------------------------------------", |
44 | "-----------", "-----------"), | 46 | "-----------", "-----------"), |
47 | end=''); | ||
45 | total = sum(load_mem_type_cnt.values()) | 48 | total = sum(load_mem_type_cnt.values()) |
46 | for mem_type, count in sorted(load_mem_type_cnt.most_common(), \ | 49 | for mem_type, count in sorted(load_mem_type_cnt.most_common(), \ |
47 | key = lambda(k, v): (v, k), reverse = True): | 50 | key = lambda kv: (kv[1], kv[0]), reverse = True): |
48 | print "%-40s %10d %10.1f%%\n" % (mem_type, count, 100 * count / total), | 51 | print("%-40s %10d %10.1f%%\n" % (mem_type, count, 100 * count / total), |
52 | end='') | ||
49 | 53 | ||
50 | def trace_begin(): | 54 | def trace_begin(): |
51 | parse_iomem() | 55 | parse_iomem() |
@@ -80,7 +84,7 @@ def find_memory_type(phys_addr): | |||
80 | f.seek(0, 0) | 84 | f.seek(0, 0) |
81 | for j in f: | 85 | for j in f: |
82 | m = re.split('-|:',j,2) | 86 | m = re.split('-|:',j,2) |
83 | if long(m[0], 16) <= phys_addr <= long(m[1], 16): | 87 | if int(m[0], 16) <= phys_addr <= int(m[1], 16): |
84 | return m[2] | 88 | return m[2] |
85 | return "N/A" | 89 | return "N/A" |
86 | 90 | ||
diff --git a/tools/perf/scripts/python/net_dropmonitor.py b/tools/perf/scripts/python/net_dropmonitor.py index a150164b44a3..212557a02c50 100755 --- a/tools/perf/scripts/python/net_dropmonitor.py +++ b/tools/perf/scripts/python/net_dropmonitor.py | |||
@@ -1,6 +1,8 @@ | |||
1 | # Monitor the system for dropped packets and proudce a report of drop locations and counts | 1 | # Monitor the system for dropped packets and proudce a report of drop locations and counts |
2 | # SPDX-License-Identifier: GPL-2.0 | 2 | # SPDX-License-Identifier: GPL-2.0 |
3 | 3 | ||
4 | from __future__ import print_function | ||
5 | |||
4 | import os | 6 | import os |
5 | import sys | 7 | import sys |
6 | 8 | ||
@@ -50,19 +52,19 @@ def get_sym(sloc): | |||
50 | return (None, 0) | 52 | return (None, 0) |
51 | 53 | ||
52 | def print_drop_table(): | 54 | def print_drop_table(): |
53 | print "%25s %25s %25s" % ("LOCATION", "OFFSET", "COUNT") | 55 | print("%25s %25s %25s" % ("LOCATION", "OFFSET", "COUNT")) |
54 | for i in drop_log.keys(): | 56 | for i in drop_log.keys(): |
55 | (sym, off) = get_sym(i) | 57 | (sym, off) = get_sym(i) |
56 | if sym == None: | 58 | if sym == None: |
57 | sym = i | 59 | sym = i |
58 | print "%25s %25s %25s" % (sym, off, drop_log[i]) | 60 | print("%25s %25s %25s" % (sym, off, drop_log[i])) |
59 | 61 | ||
60 | 62 | ||
61 | def trace_begin(): | 63 | def trace_begin(): |
62 | print "Starting trace (Ctrl-C to dump results)" | 64 | print("Starting trace (Ctrl-C to dump results)") |
63 | 65 | ||
64 | def trace_end(): | 66 | def trace_end(): |
65 | print "Gathering kallsyms data" | 67 | print("Gathering kallsyms data") |
66 | get_kallsyms_table() | 68 | get_kallsyms_table() |
67 | print_drop_table() | 69 | print_drop_table() |
68 | 70 | ||
diff --git a/tools/perf/scripts/python/netdev-times.py b/tools/perf/scripts/python/netdev-times.py index 9b2050f778f1..267bda49325d 100644 --- a/tools/perf/scripts/python/netdev-times.py +++ b/tools/perf/scripts/python/netdev-times.py | |||
@@ -8,6 +8,8 @@ | |||
8 | # dev=: show only thing related to specified device | 8 | # dev=: show only thing related to specified device |
9 | # debug: work with debug mode. It shows buffer status. | 9 | # debug: work with debug mode. It shows buffer status. |
10 | 10 | ||
11 | from __future__ import print_function | ||
12 | |||
11 | import os | 13 | import os |
12 | import sys | 14 | import sys |
13 | 15 | ||
@@ -17,6 +19,7 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | |||
17 | from perf_trace_context import * | 19 | from perf_trace_context import * |
18 | from Core import * | 20 | from Core import * |
19 | from Util import * | 21 | from Util import * |
22 | from functools import cmp_to_key | ||
20 | 23 | ||
21 | all_event_list = []; # insert all tracepoint event related with this script | 24 | all_event_list = []; # insert all tracepoint event related with this script |
22 | irq_dic = {}; # key is cpu and value is a list which stacks irqs | 25 | irq_dic = {}; # key is cpu and value is a list which stacks irqs |
@@ -61,12 +64,12 @@ def diff_msec(src, dst): | |||
61 | def print_transmit(hunk): | 64 | def print_transmit(hunk): |
62 | if dev != 0 and hunk['dev'].find(dev) < 0: | 65 | if dev != 0 and hunk['dev'].find(dev) < 0: |
63 | return | 66 | return |
64 | print "%7s %5d %6d.%06dsec %12.3fmsec %12.3fmsec" % \ | 67 | print("%7s %5d %6d.%06dsec %12.3fmsec %12.3fmsec" % |
65 | (hunk['dev'], hunk['len'], | 68 | (hunk['dev'], hunk['len'], |
66 | nsecs_secs(hunk['queue_t']), | 69 | nsecs_secs(hunk['queue_t']), |
67 | nsecs_nsecs(hunk['queue_t'])/1000, | 70 | nsecs_nsecs(hunk['queue_t'])/1000, |
68 | diff_msec(hunk['queue_t'], hunk['xmit_t']), | 71 | diff_msec(hunk['queue_t'], hunk['xmit_t']), |
69 | diff_msec(hunk['xmit_t'], hunk['free_t'])) | 72 | diff_msec(hunk['xmit_t'], hunk['free_t']))) |
70 | 73 | ||
71 | # Format for displaying rx packet processing | 74 | # Format for displaying rx packet processing |
72 | PF_IRQ_ENTRY= " irq_entry(+%.3fmsec irq=%d:%s)" | 75 | PF_IRQ_ENTRY= " irq_entry(+%.3fmsec irq=%d:%s)" |
@@ -98,55 +101,55 @@ def print_receive(hunk): | |||
98 | if show_hunk == 0: | 101 | if show_hunk == 0: |
99 | return | 102 | return |
100 | 103 | ||
101 | print "%d.%06dsec cpu=%d" % \ | 104 | print("%d.%06dsec cpu=%d" % |
102 | (nsecs_secs(base_t), nsecs_nsecs(base_t)/1000, cpu) | 105 | (nsecs_secs(base_t), nsecs_nsecs(base_t)/1000, cpu)) |
103 | for i in range(len(irq_list)): | 106 | for i in range(len(irq_list)): |
104 | print PF_IRQ_ENTRY % \ | 107 | print(PF_IRQ_ENTRY % |
105 | (diff_msec(base_t, irq_list[i]['irq_ent_t']), | 108 | (diff_msec(base_t, irq_list[i]['irq_ent_t']), |
106 | irq_list[i]['irq'], irq_list[i]['name']) | 109 | irq_list[i]['irq'], irq_list[i]['name'])) |
107 | print PF_JOINT | 110 | print(PF_JOINT) |
108 | irq_event_list = irq_list[i]['event_list'] | 111 | irq_event_list = irq_list[i]['event_list'] |
109 | for j in range(len(irq_event_list)): | 112 | for j in range(len(irq_event_list)): |
110 | irq_event = irq_event_list[j] | 113 | irq_event = irq_event_list[j] |
111 | if irq_event['event'] == 'netif_rx': | 114 | if irq_event['event'] == 'netif_rx': |
112 | print PF_NET_RX % \ | 115 | print(PF_NET_RX % |
113 | (diff_msec(base_t, irq_event['time']), | 116 | (diff_msec(base_t, irq_event['time']), |
114 | irq_event['skbaddr']) | 117 | irq_event['skbaddr'])) |
115 | print PF_JOINT | 118 | print(PF_JOINT) |
116 | print PF_SOFT_ENTRY % \ | 119 | print(PF_SOFT_ENTRY % |
117 | diff_msec(base_t, hunk['sirq_ent_t']) | 120 | diff_msec(base_t, hunk['sirq_ent_t'])) |
118 | print PF_JOINT | 121 | print(PF_JOINT) |
119 | event_list = hunk['event_list'] | 122 | event_list = hunk['event_list'] |
120 | for i in range(len(event_list)): | 123 | for i in range(len(event_list)): |
121 | event = event_list[i] | 124 | event = event_list[i] |
122 | if event['event_name'] == 'napi_poll': | 125 | if event['event_name'] == 'napi_poll': |
123 | print PF_NAPI_POLL % \ | 126 | print(PF_NAPI_POLL % |
124 | (diff_msec(base_t, event['event_t']), event['dev']) | 127 | (diff_msec(base_t, event['event_t']), event['dev'])) |
125 | if i == len(event_list) - 1: | 128 | if i == len(event_list) - 1: |
126 | print "" | 129 | print("") |
127 | else: | 130 | else: |
128 | print PF_JOINT | 131 | print(PF_JOINT) |
129 | else: | 132 | else: |
130 | print PF_NET_RECV % \ | 133 | print(PF_NET_RECV % |
131 | (diff_msec(base_t, event['event_t']), event['skbaddr'], | 134 | (diff_msec(base_t, event['event_t']), event['skbaddr'], |
132 | event['len']) | 135 | event['len'])) |
133 | if 'comm' in event.keys(): | 136 | if 'comm' in event.keys(): |
134 | print PF_WJOINT | 137 | print(PF_WJOINT) |
135 | print PF_CPY_DGRAM % \ | 138 | print(PF_CPY_DGRAM % |
136 | (diff_msec(base_t, event['comm_t']), | 139 | (diff_msec(base_t, event['comm_t']), |
137 | event['pid'], event['comm']) | 140 | event['pid'], event['comm'])) |
138 | elif 'handle' in event.keys(): | 141 | elif 'handle' in event.keys(): |
139 | print PF_WJOINT | 142 | print(PF_WJOINT) |
140 | if event['handle'] == "kfree_skb": | 143 | if event['handle'] == "kfree_skb": |
141 | print PF_KFREE_SKB % \ | 144 | print(PF_KFREE_SKB % |
142 | (diff_msec(base_t, | 145 | (diff_msec(base_t, |
143 | event['comm_t']), | 146 | event['comm_t']), |
144 | event['location']) | 147 | event['location'])) |
145 | elif event['handle'] == "consume_skb": | 148 | elif event['handle'] == "consume_skb": |
146 | print PF_CONS_SKB % \ | 149 | print(PF_CONS_SKB % |
147 | diff_msec(base_t, | 150 | diff_msec(base_t, |
148 | event['comm_t']) | 151 | event['comm_t'])) |
149 | print PF_JOINT | 152 | print(PF_JOINT) |
150 | 153 | ||
151 | def trace_begin(): | 154 | def trace_begin(): |
152 | global show_tx | 155 | global show_tx |
@@ -172,8 +175,7 @@ def trace_begin(): | |||
172 | 175 | ||
173 | def trace_end(): | 176 | def trace_end(): |
174 | # order all events in time | 177 | # order all events in time |
175 | all_event_list.sort(lambda a,b :cmp(a[EINFO_IDX_TIME], | 178 | all_event_list.sort(key=cmp_to_key(lambda a,b :a[EINFO_IDX_TIME] < b[EINFO_IDX_TIME])) |
176 | b[EINFO_IDX_TIME])) | ||
177 | # process all events | 179 | # process all events |
178 | for i in range(len(all_event_list)): | 180 | for i in range(len(all_event_list)): |
179 | event_info = all_event_list[i] | 181 | event_info = all_event_list[i] |
@@ -210,19 +212,19 @@ def trace_end(): | |||
210 | print_receive(receive_hunk_list[i]) | 212 | print_receive(receive_hunk_list[i]) |
211 | # display transmit hunks | 213 | # display transmit hunks |
212 | if show_tx: | 214 | if show_tx: |
213 | print " dev len Qdisc " \ | 215 | print(" dev len Qdisc " |
214 | " netdevice free" | 216 | " netdevice free") |
215 | for i in range(len(tx_free_list)): | 217 | for i in range(len(tx_free_list)): |
216 | print_transmit(tx_free_list[i]) | 218 | print_transmit(tx_free_list[i]) |
217 | if debug: | 219 | if debug: |
218 | print "debug buffer status" | 220 | print("debug buffer status") |
219 | print "----------------------------" | 221 | print("----------------------------") |
220 | print "xmit Qdisc:remain:%d overflow:%d" % \ | 222 | print("xmit Qdisc:remain:%d overflow:%d" % |
221 | (len(tx_queue_list), of_count_tx_queue_list) | 223 | (len(tx_queue_list), of_count_tx_queue_list)) |
222 | print "xmit netdevice:remain:%d overflow:%d" % \ | 224 | print("xmit netdevice:remain:%d overflow:%d" % |
223 | (len(tx_xmit_list), of_count_tx_xmit_list) | 225 | (len(tx_xmit_list), of_count_tx_xmit_list)) |
224 | print "receive:remain:%d overflow:%d" % \ | 226 | print("receive:remain:%d overflow:%d" % |
225 | (len(rx_skb_list), of_count_rx_skb_list) | 227 | (len(rx_skb_list), of_count_rx_skb_list)) |
226 | 228 | ||
227 | # called from perf, when it finds a correspoinding event | 229 | # called from perf, when it finds a correspoinding event |
228 | def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, callchain, vec): | 230 | def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, callchain, vec): |
diff --git a/tools/perf/scripts/python/powerpc-hcalls.py b/tools/perf/scripts/python/powerpc-hcalls.py index 00e0e7476e55..8b78dc790adb 100644 --- a/tools/perf/scripts/python/powerpc-hcalls.py +++ b/tools/perf/scripts/python/powerpc-hcalls.py | |||
@@ -4,6 +4,8 @@ | |||
4 | # | 4 | # |
5 | # Hypervisor call statisics | 5 | # Hypervisor call statisics |
6 | 6 | ||
7 | from __future__ import print_function | ||
8 | |||
7 | import os | 9 | import os |
8 | import sys | 10 | import sys |
9 | 11 | ||
@@ -149,7 +151,7 @@ hcall_table = { | |||
149 | } | 151 | } |
150 | 152 | ||
151 | def hcall_table_lookup(opcode): | 153 | def hcall_table_lookup(opcode): |
152 | if (hcall_table.has_key(opcode)): | 154 | if (opcode in hcall_table): |
153 | return hcall_table[opcode] | 155 | return hcall_table[opcode] |
154 | else: | 156 | else: |
155 | return opcode | 157 | return opcode |
@@ -157,8 +159,8 @@ def hcall_table_lookup(opcode): | |||
157 | print_ptrn = '%-28s%10s%10s%10s%10s' | 159 | print_ptrn = '%-28s%10s%10s%10s%10s' |
158 | 160 | ||
159 | def trace_end(): | 161 | def trace_end(): |
160 | print print_ptrn % ('hcall', 'count', 'min(ns)', 'max(ns)', 'avg(ns)') | 162 | print(print_ptrn % ('hcall', 'count', 'min(ns)', 'max(ns)', 'avg(ns)')) |
161 | print '-' * 68 | 163 | print('-' * 68) |
162 | for opcode in output: | 164 | for opcode in output: |
163 | h_name = hcall_table_lookup(opcode) | 165 | h_name = hcall_table_lookup(opcode) |
164 | time = output[opcode]['time'] | 166 | time = output[opcode]['time'] |
@@ -166,14 +168,14 @@ def trace_end(): | |||
166 | min_t = output[opcode]['min'] | 168 | min_t = output[opcode]['min'] |
167 | max_t = output[opcode]['max'] | 169 | max_t = output[opcode]['max'] |
168 | 170 | ||
169 | print print_ptrn % (h_name, cnt, min_t, max_t, time/cnt) | 171 | print(print_ptrn % (h_name, cnt, min_t, max_t, time//cnt)) |
170 | 172 | ||
171 | def powerpc__hcall_exit(name, context, cpu, sec, nsec, pid, comm, callchain, | 173 | def powerpc__hcall_exit(name, context, cpu, sec, nsec, pid, comm, callchain, |
172 | opcode, retval): | 174 | opcode, retval): |
173 | if (d_enter.has_key(cpu) and d_enter[cpu].has_key(opcode)): | 175 | if (cpu in d_enter and opcode in d_enter[cpu]): |
174 | diff = nsecs(sec, nsec) - d_enter[cpu][opcode] | 176 | diff = nsecs(sec, nsec) - d_enter[cpu][opcode] |
175 | 177 | ||
176 | if (output.has_key(opcode)): | 178 | if (opcode in output): |
177 | output[opcode]['time'] += diff | 179 | output[opcode]['time'] += diff |
178 | output[opcode]['cnt'] += 1 | 180 | output[opcode]['cnt'] += 1 |
179 | if (output[opcode]['min'] > diff): | 181 | if (output[opcode]['min'] > diff): |
@@ -190,11 +192,11 @@ def powerpc__hcall_exit(name, context, cpu, sec, nsec, pid, comm, callchain, | |||
190 | 192 | ||
191 | del d_enter[cpu][opcode] | 193 | del d_enter[cpu][opcode] |
192 | # else: | 194 | # else: |
193 | # print "Can't find matching hcall_enter event. Ignoring sample" | 195 | # print("Can't find matching hcall_enter event. Ignoring sample") |
194 | 196 | ||
195 | def powerpc__hcall_entry(event_name, context, cpu, sec, nsec, pid, comm, | 197 | def powerpc__hcall_entry(event_name, context, cpu, sec, nsec, pid, comm, |
196 | callchain, opcode): | 198 | callchain, opcode): |
197 | if (d_enter.has_key(cpu)): | 199 | if (cpu in d_enter): |
198 | d_enter[cpu][opcode] = nsecs(sec, nsec) | 200 | d_enter[cpu][opcode] = nsecs(sec, nsec) |
199 | else: | 201 | else: |
200 | d_enter[cpu] = {opcode: nsecs(sec, nsec)} | 202 | d_enter[cpu] = {opcode: nsecs(sec, nsec)} |
diff --git a/tools/perf/scripts/python/sctop.py b/tools/perf/scripts/python/sctop.py index 61621b93affb..987ffae7c8ca 100644 --- a/tools/perf/scripts/python/sctop.py +++ b/tools/perf/scripts/python/sctop.py | |||
@@ -8,7 +8,14 @@ | |||
8 | # will be refreshed every [interval] seconds. The default interval is | 8 | # will be refreshed every [interval] seconds. The default interval is |
9 | # 3 seconds. | 9 | # 3 seconds. |
10 | 10 | ||
11 | import os, sys, thread, time | 11 | from __future__ import print_function |
12 | |||
13 | import os, sys, time | ||
14 | |||
15 | try: | ||
16 | import thread | ||
17 | except ImportError: | ||
18 | import _thread as thread | ||
12 | 19 | ||
13 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | 20 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ |
14 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | 21 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') |
@@ -62,18 +69,19 @@ def print_syscall_totals(interval): | |||
62 | while 1: | 69 | while 1: |
63 | clear_term() | 70 | clear_term() |
64 | if for_comm is not None: | 71 | if for_comm is not None: |
65 | print "\nsyscall events for %s:\n\n" % (for_comm), | 72 | print("\nsyscall events for %s:\n" % (for_comm)) |
66 | else: | 73 | else: |
67 | print "\nsyscall events:\n\n", | 74 | print("\nsyscall events:\n") |
68 | 75 | ||
69 | print "%-40s %10s\n" % ("event", "count"), | 76 | print("%-40s %10s" % ("event", "count")) |
70 | print "%-40s %10s\n" % ("----------------------------------------", \ | 77 | print("%-40s %10s" % |
71 | "----------"), | 78 | ("----------------------------------------", |
79 | "----------")) | ||
72 | 80 | ||
73 | for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \ | 81 | for id, val in sorted(syscalls.items(), key = lambda kv: (kv[1], kv[0]), \ |
74 | reverse = True): | 82 | reverse = True): |
75 | try: | 83 | try: |
76 | print "%-40s %10d\n" % (syscall_name(id), val), | 84 | print("%-40s %10d" % (syscall_name(id), val)) |
77 | except TypeError: | 85 | except TypeError: |
78 | pass | 86 | pass |
79 | syscalls.clear() | 87 | syscalls.clear() |
diff --git a/tools/perf/scripts/python/stackcollapse.py b/tools/perf/scripts/python/stackcollapse.py index 1697b5e18c96..5e703efaddcc 100755 --- a/tools/perf/scripts/python/stackcollapse.py +++ b/tools/perf/scripts/python/stackcollapse.py | |||
@@ -19,6 +19,8 @@ | |||
19 | # Written by Paolo Bonzini <pbonzini@redhat.com> | 19 | # Written by Paolo Bonzini <pbonzini@redhat.com> |
20 | # Based on Brendan Gregg's stackcollapse-perf.pl script. | 20 | # Based on Brendan Gregg's stackcollapse-perf.pl script. |
21 | 21 | ||
22 | from __future__ import print_function | ||
23 | |||
22 | import os | 24 | import os |
23 | import sys | 25 | import sys |
24 | from collections import defaultdict | 26 | from collections import defaultdict |
@@ -120,7 +122,6 @@ def process_event(param_dict): | |||
120 | lines[stack_string] = lines[stack_string] + 1 | 122 | lines[stack_string] = lines[stack_string] + 1 |
121 | 123 | ||
122 | def trace_end(): | 124 | def trace_end(): |
123 | list = lines.keys() | 125 | list = sorted(lines) |
124 | list.sort() | ||
125 | for stack in list: | 126 | for stack in list: |
126 | print "%s %d" % (stack, lines[stack]) | 127 | print("%s %d" % (stack, lines[stack])) |
diff --git a/tools/perf/scripts/python/stat-cpi.py b/tools/perf/scripts/python/stat-cpi.py index a81ad8835a74..01fa933ff3cf 100644 --- a/tools/perf/scripts/python/stat-cpi.py +++ b/tools/perf/scripts/python/stat-cpi.py | |||
@@ -1,5 +1,7 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
2 | 2 | ||
3 | from __future__ import print_function | ||
4 | |||
3 | data = {} | 5 | data = {} |
4 | times = [] | 6 | times = [] |
5 | threads = [] | 7 | threads = [] |
@@ -19,8 +21,8 @@ def store_key(time, cpu, thread): | |||
19 | threads.append(thread) | 21 | threads.append(thread) |
20 | 22 | ||
21 | def store(time, event, cpu, thread, val, ena, run): | 23 | def store(time, event, cpu, thread, val, ena, run): |
22 | #print "event %s cpu %d, thread %d, time %d, val %d, ena %d, run %d" % \ | 24 | #print("event %s cpu %d, thread %d, time %d, val %d, ena %d, run %d" % |
23 | # (event, cpu, thread, time, val, ena, run) | 25 | # (event, cpu, thread, time, val, ena, run)) |
24 | 26 | ||
25 | store_key(time, cpu, thread) | 27 | store_key(time, cpu, thread) |
26 | key = get_key(time, event, cpu, thread) | 28 | key = get_key(time, event, cpu, thread) |
@@ -58,7 +60,7 @@ def stat__interval(time): | |||
58 | if ins != 0: | 60 | if ins != 0: |
59 | cpi = cyc/float(ins) | 61 | cpi = cyc/float(ins) |
60 | 62 | ||
61 | print "%15f: cpu %d, thread %d -> cpi %f (%d/%d)" % (time/(float(1000000000)), cpu, thread, cpi, cyc, ins) | 63 | print("%15f: cpu %d, thread %d -> cpi %f (%d/%d)" % (time/(float(1000000000)), cpu, thread, cpi, cyc, ins)) |
62 | 64 | ||
63 | def trace_end(): | 65 | def trace_end(): |
64 | pass | 66 | pass |
@@ -74,4 +76,4 @@ def trace_end(): | |||
74 | # if ins != 0: | 76 | # if ins != 0: |
75 | # cpi = cyc/float(ins) | 77 | # cpi = cyc/float(ins) |
76 | # | 78 | # |
77 | # print "time %.9f, cpu %d, thread %d -> cpi %f" % (time/(float(1000000000)), cpu, thread, cpi) | 79 | # print("time %.9f, cpu %d, thread %d -> cpi %f" % (time/(float(1000000000)), cpu, thread, cpi)) |
diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py index daf314cc5dd3..42782487b0e9 100644 --- a/tools/perf/scripts/python/syscall-counts-by-pid.py +++ b/tools/perf/scripts/python/syscall-counts-by-pid.py | |||
@@ -5,6 +5,8 @@ | |||
5 | # Displays system-wide system call totals, broken down by syscall. | 5 | # Displays system-wide system call totals, broken down by syscall. |
6 | # If a [comm] arg is specified, only syscalls called by [comm] are displayed. | 6 | # If a [comm] arg is specified, only syscalls called by [comm] are displayed. |
7 | 7 | ||
8 | from __future__ import print_function | ||
9 | |||
8 | import os, sys | 10 | import os, sys |
9 | 11 | ||
10 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | 12 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ |
@@ -31,7 +33,7 @@ if len(sys.argv) > 1: | |||
31 | syscalls = autodict() | 33 | syscalls = autodict() |
32 | 34 | ||
33 | def trace_begin(): | 35 | def trace_begin(): |
34 | print "Press control+C to stop and show the summary" | 36 | print("Press control+C to stop and show the summary") |
35 | 37 | ||
36 | def trace_end(): | 38 | def trace_end(): |
37 | print_syscall_totals() | 39 | print_syscall_totals() |
@@ -55,20 +57,20 @@ def syscalls__sys_enter(event_name, context, common_cpu, | |||
55 | 57 | ||
56 | def print_syscall_totals(): | 58 | def print_syscall_totals(): |
57 | if for_comm is not None: | 59 | if for_comm is not None: |
58 | print "\nsyscall events for %s:\n\n" % (for_comm), | 60 | print("\nsyscall events for %s:\n" % (for_comm)) |
59 | else: | 61 | else: |
60 | print "\nsyscall events by comm/pid:\n\n", | 62 | print("\nsyscall events by comm/pid:\n") |
61 | 63 | ||
62 | print "%-40s %10s\n" % ("comm [pid]/syscalls", "count"), | 64 | print("%-40s %10s" % ("comm [pid]/syscalls", "count")) |
63 | print "%-40s %10s\n" % ("----------------------------------------", \ | 65 | print("%-40s %10s" % ("----------------------------------------", |
64 | "----------"), | 66 | "----------")) |
65 | 67 | ||
66 | comm_keys = syscalls.keys() | 68 | comm_keys = syscalls.keys() |
67 | for comm in comm_keys: | 69 | for comm in comm_keys: |
68 | pid_keys = syscalls[comm].keys() | 70 | pid_keys = syscalls[comm].keys() |
69 | for pid in pid_keys: | 71 | for pid in pid_keys: |
70 | print "\n%s [%d]\n" % (comm, pid), | 72 | print("\n%s [%d]" % (comm, pid)) |
71 | id_keys = syscalls[comm][pid].keys() | 73 | id_keys = syscalls[comm][pid].keys() |
72 | for id, val in sorted(syscalls[comm][pid].iteritems(), \ | 74 | for id, val in sorted(syscalls[comm][pid].items(), \ |
73 | key = lambda(k, v): (v, k), reverse = True): | 75 | key = lambda kv: (kv[1], kv[0]), reverse = True): |
74 | print " %-38s %10d\n" % (syscall_name(id), val), | 76 | print(" %-38s %10d" % (syscall_name(id), val)) |
diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py index e66a7730aeb5..0ebd89cfd42c 100644 --- a/tools/perf/scripts/python/syscall-counts.py +++ b/tools/perf/scripts/python/syscall-counts.py | |||
@@ -5,6 +5,8 @@ | |||
5 | # Displays system-wide system call totals, broken down by syscall. | 5 | # Displays system-wide system call totals, broken down by syscall. |
6 | # If a [comm] arg is specified, only syscalls called by [comm] are displayed. | 6 | # If a [comm] arg is specified, only syscalls called by [comm] are displayed. |
7 | 7 | ||
8 | from __future__ import print_function | ||
9 | |||
8 | import os | 10 | import os |
9 | import sys | 11 | import sys |
10 | 12 | ||
@@ -28,7 +30,7 @@ if len(sys.argv) > 1: | |||
28 | syscalls = autodict() | 30 | syscalls = autodict() |
29 | 31 | ||
30 | def trace_begin(): | 32 | def trace_begin(): |
31 | print "Press control+C to stop and show the summary" | 33 | print("Press control+C to stop and show the summary") |
32 | 34 | ||
33 | def trace_end(): | 35 | def trace_end(): |
34 | print_syscall_totals() | 36 | print_syscall_totals() |
@@ -51,14 +53,14 @@ def syscalls__sys_enter(event_name, context, common_cpu, | |||
51 | 53 | ||
52 | def print_syscall_totals(): | 54 | def print_syscall_totals(): |
53 | if for_comm is not None: | 55 | if for_comm is not None: |
54 | print "\nsyscall events for %s:\n\n" % (for_comm), | 56 | print("\nsyscall events for %s:\n" % (for_comm)) |
55 | else: | 57 | else: |
56 | print "\nsyscall events:\n\n", | 58 | print("\nsyscall events:\n") |
57 | 59 | ||
58 | print "%-40s %10s\n" % ("event", "count"), | 60 | print("%-40s %10s" % ("event", "count")) |
59 | print "%-40s %10s\n" % ("----------------------------------------", \ | 61 | print("%-40s %10s" % ("----------------------------------------", |
60 | "-----------"), | 62 | "-----------")) |
61 | 63 | ||
62 | for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \ | 64 | for id, val in sorted(syscalls.items(), key = lambda kv: (kv[1], kv[0]), \ |
63 | reverse = True): | 65 | reverse = True): |
64 | print "%-40s %10d\n" % (syscall_name(id), val), | 66 | print("%-40s %10d" % (syscall_name(id), val)) |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 2468b8aa0b6b..11a8a447a3af 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -1891,6 +1891,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, | |||
1891 | struct annotation_options *options, | 1891 | struct annotation_options *options, |
1892 | struct arch **parch) | 1892 | struct arch **parch) |
1893 | { | 1893 | { |
1894 | struct annotation *notes = symbol__annotation(sym); | ||
1894 | struct annotate_args args = { | 1895 | struct annotate_args args = { |
1895 | .privsize = privsize, | 1896 | .privsize = privsize, |
1896 | .evsel = evsel, | 1897 | .evsel = evsel, |
@@ -1921,6 +1922,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, | |||
1921 | 1922 | ||
1922 | args.ms.map = map; | 1923 | args.ms.map = map; |
1923 | args.ms.sym = sym; | 1924 | args.ms.sym = sym; |
1925 | notes->start = map__rip_2objdump(map, sym->start); | ||
1924 | 1926 | ||
1925 | return symbol__disassemble(sym, &args); | 1927 | return symbol__disassemble(sym, &args); |
1926 | } | 1928 | } |
@@ -2796,8 +2798,6 @@ int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *ev | |||
2796 | 2798 | ||
2797 | symbol__calc_percent(sym, evsel); | 2799 | symbol__calc_percent(sym, evsel); |
2798 | 2800 | ||
2799 | notes->start = map__rip_2objdump(map, sym->start); | ||
2800 | |||
2801 | annotation__set_offsets(notes, size); | 2801 | annotation__set_offsets(notes, size); |
2802 | annotation__mark_jump_targets(notes, sym); | 2802 | annotation__mark_jump_targets(notes, sym); |
2803 | annotation__compute_ipc(notes, size); | 2803 | annotation__compute_ipc(notes, size); |
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 2a36fab76994..26af43ad9ddd 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c | |||
@@ -1578,7 +1578,7 @@ int bt_convert__perf2ctf(const char *input, const char *path, | |||
1578 | { | 1578 | { |
1579 | struct perf_session *session; | 1579 | struct perf_session *session; |
1580 | struct perf_data data = { | 1580 | struct perf_data data = { |
1581 | .file = { .path = input, .fd = -1 }, | 1581 | .path = input, |
1582 | .mode = PERF_DATA_MODE_READ, | 1582 | .mode = PERF_DATA_MODE_READ, |
1583 | .force = opts->force, | 1583 | .force = opts->force, |
1584 | }; | 1584 | }; |
@@ -1650,7 +1650,7 @@ int bt_convert__perf2ctf(const char *input, const char *path, | |||
1650 | 1650 | ||
1651 | fprintf(stderr, | 1651 | fprintf(stderr, |
1652 | "[ perf data convert: Converted '%s' into CTF data '%s' ]\n", | 1652 | "[ perf data convert: Converted '%s' into CTF data '%s' ]\n", |
1653 | data.file.path, path); | 1653 | data.path, path); |
1654 | 1654 | ||
1655 | fprintf(stderr, | 1655 | fprintf(stderr, |
1656 | "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples", | 1656 | "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples", |
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index d8cfc19ddb10..7bd5ddeb7a41 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c | |||
@@ -7,11 +7,117 @@ | |||
7 | #include <fcntl.h> | 7 | #include <fcntl.h> |
8 | #include <unistd.h> | 8 | #include <unistd.h> |
9 | #include <string.h> | 9 | #include <string.h> |
10 | #include <asm/bug.h> | ||
11 | #include <sys/types.h> | ||
12 | #include <dirent.h> | ||
10 | 13 | ||
11 | #include "data.h" | 14 | #include "data.h" |
12 | #include "util.h" | 15 | #include "util.h" |
13 | #include "debug.h" | 16 | #include "debug.h" |
14 | 17 | ||
18 | static void close_dir(struct perf_data_file *files, int nr) | ||
19 | { | ||
20 | while (--nr >= 1) { | ||
21 | close(files[nr].fd); | ||
22 | free(files[nr].path); | ||
23 | } | ||
24 | free(files); | ||
25 | } | ||
26 | |||
27 | void perf_data__close_dir(struct perf_data *data) | ||
28 | { | ||
29 | close_dir(data->dir.files, data->dir.nr); | ||
30 | } | ||
31 | |||
32 | int perf_data__create_dir(struct perf_data *data, int nr) | ||
33 | { | ||
34 | struct perf_data_file *files = NULL; | ||
35 | int i, ret = -1; | ||
36 | |||
37 | files = zalloc(nr * sizeof(*files)); | ||
38 | if (!files) | ||
39 | return -ENOMEM; | ||
40 | |||
41 | data->dir.files = files; | ||
42 | data->dir.nr = nr; | ||
43 | |||
44 | for (i = 0; i < nr; i++) { | ||
45 | struct perf_data_file *file = &files[i]; | ||
46 | |||
47 | if (asprintf(&file->path, "%s/data.%d", data->path, i) < 0) | ||
48 | goto out_err; | ||
49 | |||
50 | ret = open(file->path, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); | ||
51 | if (ret < 0) | ||
52 | goto out_err; | ||
53 | |||
54 | file->fd = ret; | ||
55 | } | ||
56 | |||
57 | return 0; | ||
58 | |||
59 | out_err: | ||
60 | close_dir(files, i); | ||
61 | return ret; | ||
62 | } | ||
63 | |||
64 | int perf_data__open_dir(struct perf_data *data) | ||
65 | { | ||
66 | struct perf_data_file *files = NULL; | ||
67 | struct dirent *dent; | ||
68 | int ret = -1; | ||
69 | DIR *dir; | ||
70 | int nr = 0; | ||
71 | |||
72 | dir = opendir(data->path); | ||
73 | if (!dir) | ||
74 | return -EINVAL; | ||
75 | |||
76 | while ((dent = readdir(dir)) != NULL) { | ||
77 | struct perf_data_file *file; | ||
78 | char path[PATH_MAX]; | ||
79 | struct stat st; | ||
80 | |||
81 | snprintf(path, sizeof(path), "%s/%s", data->path, dent->d_name); | ||
82 | if (stat(path, &st)) | ||
83 | continue; | ||
84 | |||
85 | if (!S_ISREG(st.st_mode) || strncmp(dent->d_name, "data", 4)) | ||
86 | continue; | ||
87 | |||
88 | ret = -ENOMEM; | ||
89 | |||
90 | file = realloc(files, (nr + 1) * sizeof(*files)); | ||
91 | if (!file) | ||
92 | goto out_err; | ||
93 | |||
94 | files = file; | ||
95 | file = &files[nr++]; | ||
96 | |||
97 | file->path = strdup(path); | ||
98 | if (!file->path) | ||
99 | goto out_err; | ||
100 | |||
101 | ret = open(file->path, O_RDONLY); | ||
102 | if (ret < 0) | ||
103 | goto out_err; | ||
104 | |||
105 | file->fd = ret; | ||
106 | file->size = st.st_size; | ||
107 | } | ||
108 | |||
109 | if (!files) | ||
110 | return -EINVAL; | ||
111 | |||
112 | data->dir.files = files; | ||
113 | data->dir.nr = nr; | ||
114 | return 0; | ||
115 | |||
116 | out_err: | ||
117 | close_dir(files, nr); | ||
118 | return ret; | ||
119 | } | ||
120 | |||
15 | static bool check_pipe(struct perf_data *data) | 121 | static bool check_pipe(struct perf_data *data) |
16 | { | 122 | { |
17 | struct stat st; | 123 | struct stat st; |
@@ -19,11 +125,11 @@ static bool check_pipe(struct perf_data *data) | |||
19 | int fd = perf_data__is_read(data) ? | 125 | int fd = perf_data__is_read(data) ? |
20 | STDIN_FILENO : STDOUT_FILENO; | 126 | STDIN_FILENO : STDOUT_FILENO; |
21 | 127 | ||
22 | if (!data->file.path) { | 128 | if (!data->path) { |
23 | if (!fstat(fd, &st) && S_ISFIFO(st.st_mode)) | 129 | if (!fstat(fd, &st) && S_ISFIFO(st.st_mode)) |
24 | is_pipe = true; | 130 | is_pipe = true; |
25 | } else { | 131 | } else { |
26 | if (!strcmp(data->file.path, "-")) | 132 | if (!strcmp(data->path, "-")) |
27 | is_pipe = true; | 133 | is_pipe = true; |
28 | } | 134 | } |
29 | 135 | ||
@@ -37,13 +143,31 @@ static int check_backup(struct perf_data *data) | |||
37 | { | 143 | { |
38 | struct stat st; | 144 | struct stat st; |
39 | 145 | ||
40 | if (!stat(data->file.path, &st) && st.st_size) { | 146 | if (perf_data__is_read(data)) |
41 | /* TODO check errors properly */ | 147 | return 0; |
148 | |||
149 | if (!stat(data->path, &st) && st.st_size) { | ||
42 | char oldname[PATH_MAX]; | 150 | char oldname[PATH_MAX]; |
151 | int ret; | ||
152 | |||
43 | snprintf(oldname, sizeof(oldname), "%s.old", | 153 | snprintf(oldname, sizeof(oldname), "%s.old", |
44 | data->file.path); | 154 | data->path); |
45 | unlink(oldname); | 155 | |
46 | rename(data->file.path, oldname); | 156 | ret = rm_rf_perf_data(oldname); |
157 | if (ret) { | ||
158 | pr_err("Can't remove old data: %s (%s)\n", | ||
159 | ret == -2 ? | ||
160 | "Unknown file found" : strerror(errno), | ||
161 | oldname); | ||
162 | return -1; | ||
163 | } | ||
164 | |||
165 | if (rename(data->path, oldname)) { | ||
166 | pr_err("Can't move data: %s (%s to %s)\n", | ||
167 | strerror(errno), | ||
168 | data->path, oldname); | ||
169 | return -1; | ||
170 | } | ||
47 | } | 171 | } |
48 | 172 | ||
49 | return 0; | 173 | return 0; |
@@ -82,7 +206,7 @@ static int open_file_read(struct perf_data *data) | |||
82 | goto out_close; | 206 | goto out_close; |
83 | } | 207 | } |
84 | 208 | ||
85 | data->size = st.st_size; | 209 | data->file.size = st.st_size; |
86 | return fd; | 210 | return fd; |
87 | 211 | ||
88 | out_close: | 212 | out_close: |
@@ -95,9 +219,6 @@ static int open_file_write(struct perf_data *data) | |||
95 | int fd; | 219 | int fd; |
96 | char sbuf[STRERR_BUFSIZE]; | 220 | char sbuf[STRERR_BUFSIZE]; |
97 | 221 | ||
98 | if (check_backup(data)) | ||
99 | return -1; | ||
100 | |||
101 | fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, | 222 | fd = open(data->file.path, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, |
102 | S_IRUSR|S_IWUSR); | 223 | S_IRUSR|S_IWUSR); |
103 | 224 | ||
@@ -115,8 +236,22 @@ static int open_file(struct perf_data *data) | |||
115 | fd = perf_data__is_read(data) ? | 236 | fd = perf_data__is_read(data) ? |
116 | open_file_read(data) : open_file_write(data); | 237 | open_file_read(data) : open_file_write(data); |
117 | 238 | ||
239 | if (fd < 0) { | ||
240 | free(data->file.path); | ||
241 | return -1; | ||
242 | } | ||
243 | |||
118 | data->file.fd = fd; | 244 | data->file.fd = fd; |
119 | return fd < 0 ? -1 : 0; | 245 | return 0; |
246 | } | ||
247 | |||
248 | static int open_file_dup(struct perf_data *data) | ||
249 | { | ||
250 | data->file.path = strdup(data->path); | ||
251 | if (!data->file.path) | ||
252 | return -ENOMEM; | ||
253 | |||
254 | return open_file(data); | ||
120 | } | 255 | } |
121 | 256 | ||
122 | int perf_data__open(struct perf_data *data) | 257 | int perf_data__open(struct perf_data *data) |
@@ -124,14 +259,18 @@ int perf_data__open(struct perf_data *data) | |||
124 | if (check_pipe(data)) | 259 | if (check_pipe(data)) |
125 | return 0; | 260 | return 0; |
126 | 261 | ||
127 | if (!data->file.path) | 262 | if (!data->path) |
128 | data->file.path = "perf.data"; | 263 | data->path = "perf.data"; |
129 | 264 | ||
130 | return open_file(data); | 265 | if (check_backup(data)) |
266 | return -1; | ||
267 | |||
268 | return open_file_dup(data); | ||
131 | } | 269 | } |
132 | 270 | ||
133 | void perf_data__close(struct perf_data *data) | 271 | void perf_data__close(struct perf_data *data) |
134 | { | 272 | { |
273 | free(data->file.path); | ||
135 | close(data->file.fd); | 274 | close(data->file.fd); |
136 | } | 275 | } |
137 | 276 | ||
@@ -159,15 +298,15 @@ int perf_data__switch(struct perf_data *data, | |||
159 | if (perf_data__is_read(data)) | 298 | if (perf_data__is_read(data)) |
160 | return -EINVAL; | 299 | return -EINVAL; |
161 | 300 | ||
162 | if (asprintf(&new_filepath, "%s.%s", data->file.path, postfix) < 0) | 301 | if (asprintf(&new_filepath, "%s.%s", data->path, postfix) < 0) |
163 | return -ENOMEM; | 302 | return -ENOMEM; |
164 | 303 | ||
165 | /* | 304 | /* |
166 | * Only fire a warning, don't return error, continue fill | 305 | * Only fire a warning, don't return error, continue fill |
167 | * original file. | 306 | * original file. |
168 | */ | 307 | */ |
169 | if (rename(data->file.path, new_filepath)) | 308 | if (rename(data->path, new_filepath)) |
170 | pr_warning("Failed to rename %s to %s\n", data->file.path, new_filepath); | 309 | pr_warning("Failed to rename %s to %s\n", data->path, new_filepath); |
171 | 310 | ||
172 | if (!at_exit) { | 311 | if (!at_exit) { |
173 | close(data->file.fd); | 312 | close(data->file.fd); |
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h index 4828f7feea89..14b47be2bd69 100644 --- a/tools/perf/util/data.h +++ b/tools/perf/util/data.h | |||
@@ -10,16 +10,22 @@ enum perf_data_mode { | |||
10 | }; | 10 | }; |
11 | 11 | ||
12 | struct perf_data_file { | 12 | struct perf_data_file { |
13 | const char *path; | 13 | char *path; |
14 | int fd; | 14 | int fd; |
15 | unsigned long size; | ||
15 | }; | 16 | }; |
16 | 17 | ||
17 | struct perf_data { | 18 | struct perf_data { |
19 | const char *path; | ||
18 | struct perf_data_file file; | 20 | struct perf_data_file file; |
19 | bool is_pipe; | 21 | bool is_pipe; |
20 | bool force; | 22 | bool force; |
21 | unsigned long size; | ||
22 | enum perf_data_mode mode; | 23 | enum perf_data_mode mode; |
24 | |||
25 | struct { | ||
26 | struct perf_data_file *files; | ||
27 | int nr; | ||
28 | } dir; | ||
23 | }; | 29 | }; |
24 | 30 | ||
25 | static inline bool perf_data__is_read(struct perf_data *data) | 31 | static inline bool perf_data__is_read(struct perf_data *data) |
@@ -44,7 +50,7 @@ static inline int perf_data__fd(struct perf_data *data) | |||
44 | 50 | ||
45 | static inline unsigned long perf_data__size(struct perf_data *data) | 51 | static inline unsigned long perf_data__size(struct perf_data *data) |
46 | { | 52 | { |
47 | return data->size; | 53 | return data->file.size; |
48 | } | 54 | } |
49 | 55 | ||
50 | int perf_data__open(struct perf_data *data); | 56 | int perf_data__open(struct perf_data *data); |
@@ -63,4 +69,8 @@ ssize_t perf_data_file__write(struct perf_data_file *file, | |||
63 | int perf_data__switch(struct perf_data *data, | 69 | int perf_data__switch(struct perf_data *data, |
64 | const char *postfix, | 70 | const char *postfix, |
65 | size_t pos, bool at_exit); | 71 | size_t pos, bool at_exit); |
72 | |||
73 | int perf_data__create_dir(struct perf_data *data, int nr); | ||
74 | int perf_data__open_dir(struct perf_data *data); | ||
75 | void perf_data__close_dir(struct perf_data *data); | ||
66 | #endif /* __PERF_DATA_H */ | 76 | #endif /* __PERF_DATA_H */ |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index a2323d777dae..01b324c275b9 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -527,17 +527,11 @@ static int write_event_desc(struct feat_fd *ff, | |||
527 | static int write_cmdline(struct feat_fd *ff, | 527 | static int write_cmdline(struct feat_fd *ff, |
528 | struct perf_evlist *evlist __maybe_unused) | 528 | struct perf_evlist *evlist __maybe_unused) |
529 | { | 529 | { |
530 | char buf[MAXPATHLEN]; | 530 | char pbuf[MAXPATHLEN], *buf; |
531 | u32 n; | 531 | int i, ret, n; |
532 | int i, ret; | ||
533 | 532 | ||
534 | /* actual path to perf binary */ | 533 | /* actual path to perf binary */ |
535 | ret = readlink("/proc/self/exe", buf, sizeof(buf) - 1); | 534 | buf = perf_exe(pbuf, MAXPATHLEN); |
536 | if (ret <= 0) | ||
537 | return -1; | ||
538 | |||
539 | /* readlink() does not add null termination */ | ||
540 | buf[ret] = '\0'; | ||
541 | 535 | ||
542 | /* account for binary path */ | 536 | /* account for binary path */ |
543 | n = perf_env.nr_cmdline + 1; | 537 | n = perf_env.nr_cmdline + 1; |
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c index f52c0f90915d..a8b45168513c 100644 --- a/tools/perf/util/thread-stack.c +++ b/tools/perf/util/thread-stack.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "thread.h" | 20 | #include "thread.h" |
21 | #include "event.h" | 21 | #include "event.h" |
22 | #include "machine.h" | 22 | #include "machine.h" |
23 | #include "env.h" | ||
23 | #include "util.h" | 24 | #include "util.h" |
24 | #include "debug.h" | 25 | #include "debug.h" |
25 | #include "symbol.h" | 26 | #include "symbol.h" |
@@ -29,6 +30,19 @@ | |||
29 | 30 | ||
30 | #define STACK_GROWTH 2048 | 31 | #define STACK_GROWTH 2048 |
31 | 32 | ||
33 | /* | ||
34 | * State of retpoline detection. | ||
35 | * | ||
36 | * RETPOLINE_NONE: no retpoline detection | ||
37 | * X86_RETPOLINE_POSSIBLE: x86 retpoline possible | ||
38 | * X86_RETPOLINE_DETECTED: x86 retpoline detected | ||
39 | */ | ||
40 | enum retpoline_state_t { | ||
41 | RETPOLINE_NONE, | ||
42 | X86_RETPOLINE_POSSIBLE, | ||
43 | X86_RETPOLINE_DETECTED, | ||
44 | }; | ||
45 | |||
32 | /** | 46 | /** |
33 | * struct thread_stack_entry - thread stack entry. | 47 | * struct thread_stack_entry - thread stack entry. |
34 | * @ret_addr: return address | 48 | * @ret_addr: return address |
@@ -64,6 +78,7 @@ struct thread_stack_entry { | |||
64 | * @crp: call/return processor | 78 | * @crp: call/return processor |
65 | * @comm: current comm | 79 | * @comm: current comm |
66 | * @arr_sz: size of array if this is the first element of an array | 80 | * @arr_sz: size of array if this is the first element of an array |
81 | * @rstate: used to detect retpolines | ||
67 | */ | 82 | */ |
68 | struct thread_stack { | 83 | struct thread_stack { |
69 | struct thread_stack_entry *stack; | 84 | struct thread_stack_entry *stack; |
@@ -76,6 +91,7 @@ struct thread_stack { | |||
76 | struct call_return_processor *crp; | 91 | struct call_return_processor *crp; |
77 | struct comm *comm; | 92 | struct comm *comm; |
78 | unsigned int arr_sz; | 93 | unsigned int arr_sz; |
94 | enum retpoline_state_t rstate; | ||
79 | }; | 95 | }; |
80 | 96 | ||
81 | /* | 97 | /* |
@@ -115,10 +131,16 @@ static int thread_stack__init(struct thread_stack *ts, struct thread *thread, | |||
115 | if (err) | 131 | if (err) |
116 | return err; | 132 | return err; |
117 | 133 | ||
118 | if (thread->mg && thread->mg->machine) | 134 | if (thread->mg && thread->mg->machine) { |
119 | ts->kernel_start = machine__kernel_start(thread->mg->machine); | 135 | struct machine *machine = thread->mg->machine; |
120 | else | 136 | const char *arch = perf_env__arch(machine->env); |
137 | |||
138 | ts->kernel_start = machine__kernel_start(machine); | ||
139 | if (!strcmp(arch, "x86")) | ||
140 | ts->rstate = X86_RETPOLINE_POSSIBLE; | ||
141 | } else { | ||
121 | ts->kernel_start = 1ULL << 63; | 142 | ts->kernel_start = 1ULL << 63; |
143 | } | ||
122 | ts->crp = crp; | 144 | ts->crp = crp; |
123 | 145 | ||
124 | return 0; | 146 | return 0; |
@@ -638,14 +660,57 @@ static int thread_stack__no_call_return(struct thread *thread, | |||
638 | else | 660 | else |
639 | parent = root; | 661 | parent = root; |
640 | 662 | ||
641 | /* This 'return' had no 'call', so push and pop top of stack */ | 663 | if (parent->sym == from_al->sym) { |
642 | cp = call_path__findnew(cpr, parent, fsym, ip, ks); | 664 | /* |
665 | * At the bottom of the stack, assume the missing 'call' was | ||
666 | * before the trace started. So, pop the current symbol and push | ||
667 | * the 'to' symbol. | ||
668 | */ | ||
669 | if (ts->cnt == 1) { | ||
670 | err = thread_stack__call_return(thread, ts, --ts->cnt, | ||
671 | tm, ref, false); | ||
672 | if (err) | ||
673 | return err; | ||
674 | } | ||
675 | |||
676 | if (!ts->cnt) { | ||
677 | cp = call_path__findnew(cpr, root, tsym, addr, ks); | ||
678 | |||
679 | return thread_stack__push_cp(ts, addr, tm, ref, cp, | ||
680 | true, false); | ||
681 | } | ||
682 | |||
683 | /* | ||
684 | * Otherwise assume the 'return' is being used as a jump (e.g. | ||
685 | * retpoline) and just push the 'to' symbol. | ||
686 | */ | ||
687 | cp = call_path__findnew(cpr, parent, tsym, addr, ks); | ||
688 | |||
689 | err = thread_stack__push_cp(ts, 0, tm, ref, cp, true, false); | ||
690 | if (!err) | ||
691 | ts->stack[ts->cnt - 1].non_call = true; | ||
692 | |||
693 | return err; | ||
694 | } | ||
695 | |||
696 | /* | ||
697 | * Assume 'parent' has not yet returned, so push 'to', and then push and | ||
698 | * pop 'from'. | ||
699 | */ | ||
700 | |||
701 | cp = call_path__findnew(cpr, parent, tsym, addr, ks); | ||
643 | 702 | ||
644 | err = thread_stack__push_cp(ts, addr, tm, ref, cp, true, false); | 703 | err = thread_stack__push_cp(ts, addr, tm, ref, cp, true, false); |
645 | if (err) | 704 | if (err) |
646 | return err; | 705 | return err; |
647 | 706 | ||
648 | return thread_stack__pop_cp(thread, ts, addr, tm, ref, tsym); | 707 | cp = call_path__findnew(cpr, cp, fsym, ip, ks); |
708 | |||
709 | err = thread_stack__push_cp(ts, ip, tm, ref, cp, true, false); | ||
710 | if (err) | ||
711 | return err; | ||
712 | |||
713 | return thread_stack__call_return(thread, ts, --ts->cnt, tm, ref, false); | ||
649 | } | 714 | } |
650 | 715 | ||
651 | static int thread_stack__trace_begin(struct thread *thread, | 716 | static int thread_stack__trace_begin(struct thread *thread, |
@@ -690,6 +755,70 @@ static int thread_stack__trace_end(struct thread_stack *ts, | |||
690 | false, true); | 755 | false, true); |
691 | } | 756 | } |
692 | 757 | ||
758 | static bool is_x86_retpoline(const char *name) | ||
759 | { | ||
760 | const char *p = strstr(name, "__x86_indirect_thunk_"); | ||
761 | |||
762 | return p == name || !strcmp(name, "__indirect_thunk_start"); | ||
763 | } | ||
764 | |||
765 | /* | ||
766 | * x86 retpoline functions pollute the call graph. This function removes them. | ||
767 | * This does not handle function return thunks, nor is there any improvement | ||
768 | * for the handling of inline thunks or extern thunks. | ||
769 | */ | ||
770 | static int thread_stack__x86_retpoline(struct thread_stack *ts, | ||
771 | struct perf_sample *sample, | ||
772 | struct addr_location *to_al) | ||
773 | { | ||
774 | struct thread_stack_entry *tse = &ts->stack[ts->cnt - 1]; | ||
775 | struct call_path_root *cpr = ts->crp->cpr; | ||
776 | struct symbol *sym = tse->cp->sym; | ||
777 | struct symbol *tsym = to_al->sym; | ||
778 | struct call_path *cp; | ||
779 | |||
780 | if (sym && is_x86_retpoline(sym->name)) { | ||
781 | /* | ||
782 | * This is a x86 retpoline fn. It pollutes the call graph by | ||
783 | * showing up everywhere there is an indirect branch, but does | ||
784 | * not itself mean anything. Here the top-of-stack is removed, | ||
785 | * by decrementing the stack count, and then further down, the | ||
786 | * resulting top-of-stack is replaced with the actual target. | ||
787 | * The result is that the retpoline functions will no longer | ||
788 | * appear in the call graph. Note this only affects the call | ||
789 | * graph, since all the original branches are left unchanged. | ||
790 | */ | ||
791 | ts->cnt -= 1; | ||
792 | sym = ts->stack[ts->cnt - 2].cp->sym; | ||
793 | if (sym && sym == tsym && to_al->addr != tsym->start) { | ||
794 | /* | ||
795 | * Target is back to the middle of the symbol we came | ||
796 | * from so assume it is an indirect jmp and forget it | ||
797 | * altogether. | ||
798 | */ | ||
799 | ts->cnt -= 1; | ||
800 | return 0; | ||
801 | } | ||
802 | } else if (sym && sym == tsym) { | ||
803 | /* | ||
804 | * Target is back to the symbol we came from so assume it is an | ||
805 | * indirect jmp and forget it altogether. | ||
806 | */ | ||
807 | ts->cnt -= 1; | ||
808 | return 0; | ||
809 | } | ||
810 | |||
811 | cp = call_path__findnew(cpr, ts->stack[ts->cnt - 2].cp, tsym, | ||
812 | sample->addr, ts->kernel_start); | ||
813 | if (!cp) | ||
814 | return -ENOMEM; | ||
815 | |||
816 | /* Replace the top-of-stack with the actual target */ | ||
817 | ts->stack[ts->cnt - 1].cp = cp; | ||
818 | |||
819 | return 0; | ||
820 | } | ||
821 | |||
693 | int thread_stack__process(struct thread *thread, struct comm *comm, | 822 | int thread_stack__process(struct thread *thread, struct comm *comm, |
694 | struct perf_sample *sample, | 823 | struct perf_sample *sample, |
695 | struct addr_location *from_al, | 824 | struct addr_location *from_al, |
@@ -697,6 +826,7 @@ int thread_stack__process(struct thread *thread, struct comm *comm, | |||
697 | struct call_return_processor *crp) | 826 | struct call_return_processor *crp) |
698 | { | 827 | { |
699 | struct thread_stack *ts = thread__stack(thread, sample->cpu); | 828 | struct thread_stack *ts = thread__stack(thread, sample->cpu); |
829 | enum retpoline_state_t rstate; | ||
700 | int err = 0; | 830 | int err = 0; |
701 | 831 | ||
702 | if (ts && !ts->crp) { | 832 | if (ts && !ts->crp) { |
@@ -712,6 +842,10 @@ int thread_stack__process(struct thread *thread, struct comm *comm, | |||
712 | ts->comm = comm; | 842 | ts->comm = comm; |
713 | } | 843 | } |
714 | 844 | ||
845 | rstate = ts->rstate; | ||
846 | if (rstate == X86_RETPOLINE_DETECTED) | ||
847 | ts->rstate = X86_RETPOLINE_POSSIBLE; | ||
848 | |||
715 | /* Flush stack on exec */ | 849 | /* Flush stack on exec */ |
716 | if (ts->comm != comm && thread->pid_ == thread->tid) { | 850 | if (ts->comm != comm && thread->pid_ == thread->tid) { |
717 | err = __thread_stack__flush(thread, ts); | 851 | err = __thread_stack__flush(thread, ts); |
@@ -748,10 +882,25 @@ int thread_stack__process(struct thread *thread, struct comm *comm, | |||
748 | ts->kernel_start); | 882 | ts->kernel_start); |
749 | err = thread_stack__push_cp(ts, ret_addr, sample->time, ref, | 883 | err = thread_stack__push_cp(ts, ret_addr, sample->time, ref, |
750 | cp, false, trace_end); | 884 | cp, false, trace_end); |
885 | |||
886 | /* | ||
887 | * A call to the same symbol but not the start of the symbol, | ||
888 | * may be the start of a x86 retpoline. | ||
889 | */ | ||
890 | if (!err && rstate == X86_RETPOLINE_POSSIBLE && to_al->sym && | ||
891 | from_al->sym == to_al->sym && | ||
892 | to_al->addr != to_al->sym->start) | ||
893 | ts->rstate = X86_RETPOLINE_DETECTED; | ||
894 | |||
751 | } else if (sample->flags & PERF_IP_FLAG_RETURN) { | 895 | } else if (sample->flags & PERF_IP_FLAG_RETURN) { |
752 | if (!sample->ip || !sample->addr) | 896 | if (!sample->ip || !sample->addr) |
753 | return 0; | 897 | return 0; |
754 | 898 | ||
899 | /* x86 retpoline 'return' doesn't match the stack */ | ||
900 | if (rstate == X86_RETPOLINE_DETECTED && ts->cnt > 2 && | ||
901 | ts->stack[ts->cnt - 1].ret_addr != sample->addr) | ||
902 | return thread_stack__x86_retpoline(ts, sample, to_al); | ||
903 | |||
755 | err = thread_stack__pop_cp(thread, ts, sample->addr, | 904 | err = thread_stack__pop_cp(thread, ts, sample->addr, |
756 | sample->time, ref, from_al->sym); | 905 | sample->time, ref, from_al->sym); |
757 | if (err) { | 906 | if (err) { |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 3ee410fc047a..d388f80d8703 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/time64.h> | 21 | #include <linux/time64.h> |
22 | #include <unistd.h> | 22 | #include <unistd.h> |
23 | #include "strlist.h" | 23 | #include "strlist.h" |
24 | #include "string2.h" | ||
24 | 25 | ||
25 | /* | 26 | /* |
26 | * XXX We need to find a better place for these things... | 27 | * XXX We need to find a better place for these things... |
@@ -117,7 +118,38 @@ int mkdir_p(char *path, mode_t mode) | |||
117 | return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; | 118 | return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; |
118 | } | 119 | } |
119 | 120 | ||
120 | int rm_rf(const char *path) | 121 | static bool match_pat(char *file, const char **pat) |
122 | { | ||
123 | int i = 0; | ||
124 | |||
125 | if (!pat) | ||
126 | return true; | ||
127 | |||
128 | while (pat[i]) { | ||
129 | if (strglobmatch(file, pat[i])) | ||
130 | return true; | ||
131 | |||
132 | i++; | ||
133 | } | ||
134 | |||
135 | return false; | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * The depth specify how deep the removal will go. | ||
140 | * 0 - will remove only files under the 'path' directory | ||
141 | * 1 .. x - will dive in x-level deep under the 'path' directory | ||
142 | * | ||
143 | * If specified the pat is array of string patterns ended with NULL, | ||
144 | * which are checked upon every file/directory found. Only matching | ||
145 | * ones are removed. | ||
146 | * | ||
147 | * The function returns: | ||
148 | * 0 on success | ||
149 | * -1 on removal failure with errno set | ||
150 | * -2 on pattern failure | ||
151 | */ | ||
152 | static int rm_rf_depth_pat(const char *path, int depth, const char **pat) | ||
121 | { | 153 | { |
122 | DIR *dir; | 154 | DIR *dir; |
123 | int ret; | 155 | int ret; |
@@ -144,6 +176,9 @@ int rm_rf(const char *path) | |||
144 | if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) | 176 | if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) |
145 | continue; | 177 | continue; |
146 | 178 | ||
179 | if (!match_pat(d->d_name, pat)) | ||
180 | return -2; | ||
181 | |||
147 | scnprintf(namebuf, sizeof(namebuf), "%s/%s", | 182 | scnprintf(namebuf, sizeof(namebuf), "%s/%s", |
148 | path, d->d_name); | 183 | path, d->d_name); |
149 | 184 | ||
@@ -155,7 +190,7 @@ int rm_rf(const char *path) | |||
155 | } | 190 | } |
156 | 191 | ||
157 | if (S_ISDIR(statbuf.st_mode)) | 192 | if (S_ISDIR(statbuf.st_mode)) |
158 | ret = rm_rf(namebuf); | 193 | ret = depth ? rm_rf_depth_pat(namebuf, depth - 1, pat) : 0; |
159 | else | 194 | else |
160 | ret = unlink(namebuf); | 195 | ret = unlink(namebuf); |
161 | } | 196 | } |
@@ -167,6 +202,22 @@ int rm_rf(const char *path) | |||
167 | return rmdir(path); | 202 | return rmdir(path); |
168 | } | 203 | } |
169 | 204 | ||
205 | int rm_rf_perf_data(const char *path) | ||
206 | { | ||
207 | const char *pat[] = { | ||
208 | "header", | ||
209 | "data.*", | ||
210 | NULL, | ||
211 | }; | ||
212 | |||
213 | return rm_rf_depth_pat(path, 0, pat); | ||
214 | } | ||
215 | |||
216 | int rm_rf(const char *path) | ||
217 | { | ||
218 | return rm_rf_depth_pat(path, INT_MAX, NULL); | ||
219 | } | ||
220 | |||
170 | /* A filter which removes dot files */ | 221 | /* A filter which removes dot files */ |
171 | bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d) | 222 | bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d) |
172 | { | 223 | { |
@@ -517,3 +568,13 @@ out: | |||
517 | 568 | ||
518 | return tip; | 569 | return tip; |
519 | } | 570 | } |
571 | |||
572 | char *perf_exe(char *buf, int len) | ||
573 | { | ||
574 | int n = readlink("/proc/self/exe", buf, len); | ||
575 | if (n > 0) { | ||
576 | buf[n] = 0; | ||
577 | return buf; | ||
578 | } | ||
579 | return strcpy(buf, "perf"); | ||
580 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index ece040b799f6..09c1b0f91f65 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -31,6 +31,7 @@ struct strlist; | |||
31 | 31 | ||
32 | int mkdir_p(char *path, mode_t mode); | 32 | int mkdir_p(char *path, mode_t mode); |
33 | int rm_rf(const char *path); | 33 | int rm_rf(const char *path); |
34 | int rm_rf_perf_data(const char *path); | ||
34 | struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct dirent *)); | 35 | struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct dirent *)); |
35 | bool lsdir_no_dot_filter(const char *name, struct dirent *d); | 36 | bool lsdir_no_dot_filter(const char *name, struct dirent *d); |
36 | int copyfile(const char *from, const char *to); | 37 | int copyfile(const char *from, const char *to); |
@@ -76,6 +77,8 @@ extern bool perf_singlethreaded; | |||
76 | void perf_set_singlethreaded(void); | 77 | void perf_set_singlethreaded(void); |
77 | void perf_set_multithreaded(void); | 78 | void perf_set_multithreaded(void); |
78 | 79 | ||
80 | char *perf_exe(char *buf, int len); | ||
81 | |||
79 | #ifndef O_CLOEXEC | 82 | #ifndef O_CLOEXEC |
80 | #ifdef __sparc__ | 83 | #ifdef __sparc__ |
81 | #define O_CLOEXEC 0x400000 | 84 | #define O_CLOEXEC 0x400000 |