sum of shown entries will be always 100%.  "absolute" means it retains
        the original value before and after the filter is applied.
 
+--time::
+       Analyze samples within given time window. It supports time
+       percent with multiple time ranges. Time string 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 analyzing 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 stop time is not given (i.e, time
+       string is 'x.y,') then analysis goes to the end of the 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.
+
 COMPARISON
 ----------
 The comparison is governed by the baseline file. The baseline perf.data
 
 #include "util/util.h"
 #include "util/data.h"
 #include "util/config.h"
+#include "util/time-utils.h"
 
 #include <errno.h>
 #include <inttypes.h>
 #include <stdlib.h>
 #include <math.h>
 
+struct perf_diff {
+       struct perf_tool                 tool;
+       const char                      *time_str;
+       struct perf_time_interval       *ptime_range;
+       int                              range_size;
+       int                              range_num;
+};
+
 /* Diff command specific HPP columns. */
 enum {
        PERF_HPP_DIFF__BASELINE,
        return -1;
 }
 
-static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
+static int diff__process_sample_event(struct perf_tool *tool,
                                      union perf_event *event,
                                      struct perf_sample *sample,
                                      struct perf_evsel *evsel,
                                      struct machine *machine)
 {
+       struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool);
        struct addr_location al;
        struct hists *hists = evsel__hists(evsel);
        int ret = -1;
 
+       if (perf_time__ranges_skip_sample(pdiff->ptime_range, pdiff->range_num,
+                                         sample->time)) {
+               return 0;
+       }
+
        if (machine__resolve(machine, &al, sample) < 0) {
                pr_warning("problem processing %d event, skipping it.\n",
                           event->header.type);
        return ret;
 }
 
-static struct perf_tool tool = {
-       .sample = diff__process_sample_event,
-       .mmap   = perf_event__process_mmap,
-       .mmap2  = perf_event__process_mmap2,
-       .comm   = perf_event__process_comm,
-       .exit   = perf_event__process_exit,
-       .fork   = perf_event__process_fork,
-       .lost   = perf_event__process_lost,
-       .namespaces = perf_event__process_namespaces,
-       .ordered_events = true,
-       .ordering_requires_timestamps = true,
+static struct perf_diff pdiff = {
+       .tool = {
+               .sample = diff__process_sample_event,
+               .mmap   = perf_event__process_mmap,
+               .mmap2  = perf_event__process_mmap2,
+               .comm   = perf_event__process_comm,
+               .exit   = perf_event__process_exit,
+               .fork   = perf_event__process_fork,
+               .lost   = perf_event__process_lost,
+               .namespaces = perf_event__process_namespaces,
+               .ordered_events = true,
+               .ordering_requires_timestamps = true,
+       },
 };
 
 static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
        }
 }
 
+static int abstime_str_dup(char **pstr)
+{
+       char *str = NULL;
+
+       if (pdiff.time_str && strchr(pdiff.time_str, ':')) {
+               str = strdup(pdiff.time_str);
+               if (!str)
+                       return -ENOMEM;
+       }
+
+       *pstr = str;
+       return 0;
+}
+
+static int parse_absolute_time(struct data__file *d, char **pstr)
+{
+       char *p = *pstr;
+       int ret;
+
+       /*
+        * Absolute timestamp for one file has the format: a.b,c.d
+        * For multiple files, the format is: a.b,c.d:a.b,c.d
+        */
+       p = strchr(*pstr, ':');
+       if (p) {
+               if (p == *pstr) {
+                       pr_err("Invalid time string\n");
+                       return -EINVAL;
+               }
+
+               *p = 0;
+               p++;
+               if (*p == 0) {
+                       pr_err("Invalid time string\n");
+                       return -EINVAL;
+               }
+       }
+
+       ret = perf_time__parse_for_ranges(*pstr, d->session,
+                                         &pdiff.ptime_range,
+                                         &pdiff.range_size,
+                                         &pdiff.range_num);
+       if (ret < 0)
+               return ret;
+
+       if (!p || *p == 0)
+               *pstr = NULL;
+       else
+               *pstr = p;
+
+       return ret;
+}
+
+static int parse_percent_time(struct data__file *d)
+{
+       int ret;
+
+       ret = perf_time__parse_for_ranges(pdiff.time_str, d->session,
+                                         &pdiff.ptime_range,
+                                         &pdiff.range_size,
+                                         &pdiff.range_num);
+       return ret;
+}
+
+static int parse_time_str(struct data__file *d, char *abstime_ostr,
+                          char **pabstime_tmp)
+{
+       int ret = 0;
+
+       if (abstime_ostr)
+               ret = parse_absolute_time(d, pabstime_tmp);
+       else if (pdiff.time_str)
+               ret = parse_percent_time(d);
+
+       return ret;
+}
+
 static int __cmd_diff(void)
 {
        struct data__file *d;
-       int ret = -EINVAL, i;
+       int ret, i;
+       char *abstime_ostr, *abstime_tmp;
+
+       ret = abstime_str_dup(&abstime_ostr);
+       if (ret)
+               return ret;
+
+       abstime_tmp = abstime_ostr;
+       ret = -EINVAL;
 
        data__for_each_file(i, d) {
-               d->session = perf_session__new(&d->data, false, &tool);
+               d->session = perf_session__new(&d->data, false, &pdiff.tool);
                if (!d->session) {
                        pr_err("Failed to open %s\n", d->data.path);
                        ret = -1;
                        goto out_delete;
                }
 
+               if (pdiff.time_str) {
+                       ret = parse_time_str(d, abstime_ostr, &abstime_tmp);
+                       if (ret < 0)
+                               goto out_delete;
+               }
+
                ret = perf_session__process_events(d->session);
                if (ret) {
                        pr_err("Failed to process %s\n", d->data.path);
                }
 
                perf_evlist__collapse_resort(d->session->evlist);
+
+               if (pdiff.ptime_range)
+                       zfree(&pdiff.ptime_range);
        }
 
        data_process();
        }
 
        free(data__files);
+
+       if (pdiff.ptime_range)
+               zfree(&pdiff.ptime_range);
+
+       if (abstime_ostr)
+               free(abstime_ostr);
+
        return ret;
 }
 
        OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
        OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
                     "How to display percentage of filtered entries", parse_filter_percentage),
+       OPT_STRING(0, "time", &pdiff.time_str, "str",
+                  "Time span (time percent or absolute timestamp)"),
        OPT_END()
 };