aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-diff.c
diff options
context:
space:
mode:
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