diff options
Diffstat (limited to 'tools/perf/builtin-diff.c')
-rw-r--r-- | tools/perf/builtin-diff.c | 148 |
1 files changed, 134 insertions, 14 deletions
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 58fe0e88215c..17cd898074c8 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -19,12 +19,21 @@ | |||
19 | #include "util/util.h" | 19 | #include "util/util.h" |
20 | #include "util/data.h" | 20 | #include "util/data.h" |
21 | #include "util/config.h" | 21 | #include "util/config.h" |
22 | #include "util/time-utils.h" | ||
22 | 23 | ||
23 | #include <errno.h> | 24 | #include <errno.h> |
24 | #include <inttypes.h> | 25 | #include <inttypes.h> |
25 | #include <stdlib.h> | 26 | #include <stdlib.h> |
26 | #include <math.h> | 27 | #include <math.h> |
27 | 28 | ||
29 | struct perf_diff { | ||
30 | struct perf_tool tool; | ||
31 | const char *time_str; | ||
32 | struct perf_time_interval *ptime_range; | ||
33 | int range_size; | ||
34 | int range_num; | ||
35 | }; | ||
36 | |||
28 | /* Diff command specific HPP columns. */ | 37 | /* Diff command specific HPP columns. */ |
29 | enum { | 38 | enum { |
30 | PERF_HPP_DIFF__BASELINE, | 39 | PERF_HPP_DIFF__BASELINE, |
@@ -323,16 +332,22 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair, | |||
323 | return -1; | 332 | return -1; |
324 | } | 333 | } |
325 | 334 | ||
326 | static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, | 335 | static int diff__process_sample_event(struct perf_tool *tool, |
327 | union perf_event *event, | 336 | union perf_event *event, |
328 | struct perf_sample *sample, | 337 | struct perf_sample *sample, |
329 | struct perf_evsel *evsel, | 338 | struct perf_evsel *evsel, |
330 | struct machine *machine) | 339 | struct machine *machine) |
331 | { | 340 | { |
341 | struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool); | ||
332 | struct addr_location al; | 342 | struct addr_location al; |
333 | struct hists *hists = evsel__hists(evsel); | 343 | struct hists *hists = evsel__hists(evsel); |
334 | int ret = -1; | 344 | int ret = -1; |
335 | 345 | ||
346 | if (perf_time__ranges_skip_sample(pdiff->ptime_range, pdiff->range_num, | ||
347 | sample->time)) { | ||
348 | return 0; | ||
349 | } | ||
350 | |||
336 | if (machine__resolve(machine, &al, sample) < 0) { | 351 | if (machine__resolve(machine, &al, sample) < 0) { |
337 | pr_warning("problem processing %d event, skipping it.\n", | 352 | pr_warning("problem processing %d event, skipping it.\n", |
338 | event->header.type); | 353 | event->header.type); |
@@ -359,17 +374,19 @@ out_put: | |||
359 | return ret; | 374 | return ret; |
360 | } | 375 | } |
361 | 376 | ||
362 | static struct perf_tool tool = { | 377 | static struct perf_diff pdiff = { |
363 | .sample = diff__process_sample_event, | 378 | .tool = { |
364 | .mmap = perf_event__process_mmap, | 379 | .sample = diff__process_sample_event, |
365 | .mmap2 = perf_event__process_mmap2, | 380 | .mmap = perf_event__process_mmap, |
366 | .comm = perf_event__process_comm, | 381 | .mmap2 = perf_event__process_mmap2, |
367 | .exit = perf_event__process_exit, | 382 | .comm = perf_event__process_comm, |
368 | .fork = perf_event__process_fork, | 383 | .exit = perf_event__process_exit, |
369 | .lost = perf_event__process_lost, | 384 | .fork = perf_event__process_fork, |
370 | .namespaces = perf_event__process_namespaces, | 385 | .lost = perf_event__process_lost, |
371 | .ordered_events = true, | 386 | .namespaces = perf_event__process_namespaces, |
372 | .ordering_requires_timestamps = true, | 387 | .ordered_events = true, |
388 | .ordering_requires_timestamps = true, | ||
389 | }, | ||
373 | }; | 390 | }; |
374 | 391 | ||
375 | static struct perf_evsel *evsel_match(struct perf_evsel *evsel, | 392 | static struct perf_evsel *evsel_match(struct perf_evsel *evsel, |
@@ -771,19 +788,110 @@ static void data__free(struct data__file *d) | |||
771 | } | 788 | } |
772 | } | 789 | } |
773 | 790 | ||
791 | static int abstime_str_dup(char **pstr) | ||
792 | { | ||
793 | char *str = NULL; | ||
794 | |||
795 | if (pdiff.time_str && strchr(pdiff.time_str, ':')) { | ||
796 | str = strdup(pdiff.time_str); | ||
797 | if (!str) | ||
798 | return -ENOMEM; | ||
799 | } | ||
800 | |||
801 | *pstr = str; | ||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | static int parse_absolute_time(struct data__file *d, char **pstr) | ||
806 | { | ||
807 | char *p = *pstr; | ||
808 | int ret; | ||
809 | |||
810 | /* | ||
811 | * Absolute timestamp for one file has the format: a.b,c.d | ||
812 | * For multiple files, the format is: a.b,c.d:a.b,c.d | ||
813 | */ | ||
814 | p = strchr(*pstr, ':'); | ||
815 | if (p) { | ||
816 | if (p == *pstr) { | ||
817 | pr_err("Invalid time string\n"); | ||
818 | return -EINVAL; | ||
819 | } | ||
820 | |||
821 | *p = 0; | ||
822 | p++; | ||
823 | if (*p == 0) { | ||
824 | pr_err("Invalid time string\n"); | ||
825 | return -EINVAL; | ||
826 | } | ||
827 | } | ||
828 | |||
829 | ret = perf_time__parse_for_ranges(*pstr, d->session, | ||
830 | &pdiff.ptime_range, | ||
831 | &pdiff.range_size, | ||
832 | &pdiff.range_num); | ||
833 | if (ret < 0) | ||
834 | return ret; | ||
835 | |||
836 | if (!p || *p == 0) | ||
837 | *pstr = NULL; | ||
838 | else | ||
839 | *pstr = p; | ||
840 | |||
841 | return ret; | ||
842 | } | ||
843 | |||
844 | static int parse_percent_time(struct data__file *d) | ||
845 | { | ||
846 | int ret; | ||
847 | |||
848 | ret = perf_time__parse_for_ranges(pdiff.time_str, d->session, | ||
849 | &pdiff.ptime_range, | ||
850 | &pdiff.range_size, | ||
851 | &pdiff.range_num); | ||
852 | return ret; | ||
853 | } | ||
854 | |||
855 | static int parse_time_str(struct data__file *d, char *abstime_ostr, | ||
856 | char **pabstime_tmp) | ||
857 | { | ||
858 | int ret = 0; | ||
859 | |||
860 | if (abstime_ostr) | ||
861 | ret = parse_absolute_time(d, pabstime_tmp); | ||
862 | else if (pdiff.time_str) | ||
863 | ret = parse_percent_time(d); | ||
864 | |||
865 | return ret; | ||
866 | } | ||
867 | |||
774 | static int __cmd_diff(void) | 868 | static int __cmd_diff(void) |
775 | { | 869 | { |
776 | struct data__file *d; | 870 | struct data__file *d; |
777 | int ret = -EINVAL, i; | 871 | int ret, i; |
872 | char *abstime_ostr, *abstime_tmp; | ||
873 | |||
874 | ret = abstime_str_dup(&abstime_ostr); | ||
875 | if (ret) | ||
876 | return ret; | ||
877 | |||
878 | abstime_tmp = abstime_ostr; | ||
879 | ret = -EINVAL; | ||
778 | 880 | ||
779 | data__for_each_file(i, d) { | 881 | data__for_each_file(i, d) { |
780 | d->session = perf_session__new(&d->data, false, &tool); | 882 | d->session = perf_session__new(&d->data, false, &pdiff.tool); |
781 | if (!d->session) { | 883 | if (!d->session) { |
782 | pr_err("Failed to open %s\n", d->data.path); | 884 | pr_err("Failed to open %s\n", d->data.path); |
783 | ret = -1; | 885 | ret = -1; |
784 | goto out_delete; | 886 | goto out_delete; |
785 | } | 887 | } |
786 | 888 | ||
889 | if (pdiff.time_str) { | ||
890 | ret = parse_time_str(d, abstime_ostr, &abstime_tmp); | ||
891 | if (ret < 0) | ||
892 | goto out_delete; | ||
893 | } | ||
894 | |||
787 | ret = perf_session__process_events(d->session); | 895 | ret = perf_session__process_events(d->session); |
788 | if (ret) { | 896 | if (ret) { |
789 | pr_err("Failed to process %s\n", d->data.path); | 897 | pr_err("Failed to process %s\n", d->data.path); |
@@ -791,6 +899,9 @@ static int __cmd_diff(void) | |||
791 | } | 899 | } |
792 | 900 | ||
793 | perf_evlist__collapse_resort(d->session->evlist); | 901 | perf_evlist__collapse_resort(d->session->evlist); |
902 | |||
903 | if (pdiff.ptime_range) | ||
904 | zfree(&pdiff.ptime_range); | ||
794 | } | 905 | } |
795 | 906 | ||
796 | data_process(); | 907 | data_process(); |
@@ -802,6 +913,13 @@ static int __cmd_diff(void) | |||
802 | } | 913 | } |
803 | 914 | ||
804 | free(data__files); | 915 | free(data__files); |
916 | |||
917 | if (pdiff.ptime_range) | ||
918 | zfree(&pdiff.ptime_range); | ||
919 | |||
920 | if (abstime_ostr) | ||
921 | free(abstime_ostr); | ||
922 | |||
805 | return ret; | 923 | return ret; |
806 | } | 924 | } |
807 | 925 | ||
@@ -849,6 +967,8 @@ static const struct option options[] = { | |||
849 | OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), | 967 | OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), |
850 | OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", | 968 | OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", |
851 | "How to display percentage of filtered entries", parse_filter_percentage), | 969 | "How to display percentage of filtered entries", parse_filter_percentage), |
970 | OPT_STRING(0, "time", &pdiff.time_str, "str", | ||
971 | "Time span (time percent or absolute timestamp)"), | ||
852 | OPT_END() | 972 | OPT_END() |
853 | }; | 973 | }; |
854 | 974 | ||