aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-diff.c
diff options
context:
space:
mode:
authorJin Yao <yao.jin@linux.intel.com>2019-03-05 08:05:41 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2019-03-06 16:03:23 -0500
commit4802138d78caed36cee2a859f77fb2035f230018 (patch)
tree5de7673784647494ff6605fcec6472c26d62f8cf /tools/perf/builtin-diff.c
parent153259382633ecbbc0af4f3f0b6515757ebe2984 (diff)
perf diff: Support --time filter option
To improve 'perf diff', implement a --time filter option to diff the samples within given time window. It supports time percent with multiple time ranges. The time string format is 'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'. For example: Select the second 10% time slice to diff: perf diff --time 10%/2 Select from 0% to 10% time slice to diff: perf diff --time 0%-10% Select the first and the second 10% time slices to diff: perf diff --time 10%/1,10%/2 Select from 0% to 10% and 30% to 40% slices to diff: perf diff --time 0%-10%,30%-40% It also supports analysing samples within a given time window <start>,<stop>. Times have the format seconds.microseconds. If 'start' is not given (i.e., time string is ',x.y') then analysis starts at the beginning of the file. If the stop time is not given (i.e, time string is 'x.y,') then analysis goes to end of file. Time string is 'a1.b1,c1.d1:a2.b2,c2.d2'. Use ':' to separate timestamps for different perf.data files. For example, we get the timestamp information from perf script. perf script -i perf.data.old mgen 13940 [000] 3946.361400: ... perf script -i perf.data mgen 13940 [000] 3971.150589 ... perf diff --time 3946.361400,:3971.150589, It analyzes the perf.data.old from the timestamp 3946.361400 to the end of perf.data.old and analyzes the perf.data from the timestamp 3971.150589 to the end of perf.data. v4: --- Update abstime_str_dup(), let it return error if strdup is failed, and update __cmd_diff() accordingly. Signed-off-by: Jin Yao <yao.jin@linux.intel.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Jin Yao <yao.jin@intel.com> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/1551791143-10334-2-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-diff.c')
-rw-r--r--tools/perf/builtin-diff.c148
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
29struct 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. */
29enum { 38enum {
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
326static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, 335static 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
362static struct perf_tool tool = { 377static 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
375static struct perf_evsel *evsel_match(struct perf_evsel *evsel, 392static 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
791static 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
805static 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
844static 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
855static 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
774static int __cmd_diff(void) 868static 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