Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Jin Yao and committed by
Arnaldo Carvalho de Melo
4802138d 15325938

+179 -14
+45
tools/perf/Documentation/perf-diff.txt
··· 118 118 sum of shown entries will be always 100%. "absolute" means it retains 119 119 the original value before and after the filter is applied. 120 120 121 + --time:: 122 + Analyze samples within given time window. It supports time 123 + percent with multiple time ranges. Time string is 'a%/n,b%/m,...' 124 + or 'a%-b%,c%-%d,...'. 125 + 126 + For example: 127 + 128 + Select the second 10% time slice to diff: 129 + 130 + perf diff --time 10%/2 131 + 132 + Select from 0% to 10% time slice to diff: 133 + 134 + perf diff --time 0%-10% 135 + 136 + Select the first and the second 10% time slices to diff: 137 + 138 + perf diff --time 10%/1,10%/2 139 + 140 + Select from 0% to 10% and 30% to 40% slices to diff: 141 + 142 + perf diff --time 0%-10%,30%-40% 143 + 144 + It also supports analyzing samples within a given time window 145 + <start>,<stop>. Times have the format seconds.microseconds. If 'start' 146 + is not given (i.e., time string is ',x.y') then analysis starts at 147 + the beginning of the file. If stop time is not given (i.e, time 148 + string is 'x.y,') then analysis goes to the end of the file. Time string is 149 + 'a1.b1,c1.d1:a2.b2,c2.d2'. Use ':' to separate timestamps for different 150 + perf.data files. 151 + 152 + For example, we get the timestamp information from 'perf script'. 153 + 154 + perf script -i perf.data.old 155 + mgen 13940 [000] 3946.361400: ... 156 + 157 + perf script -i perf.data 158 + mgen 13940 [000] 3971.150589 ... 159 + 160 + perf diff --time 3946.361400,:3971.150589, 161 + 162 + It analyzes the perf.data.old from the timestamp 3946.361400 to 163 + the end of perf.data.old and analyzes the perf.data from the 164 + timestamp 3971.150589 to the end of perf.data. 165 + 121 166 COMPARISON 122 167 ---------- 123 168 The comparison is governed by the baseline file. The baseline perf.data
+134 -14
tools/perf/builtin-diff.c
··· 19 19 #include "util/util.h" 20 20 #include "util/data.h" 21 21 #include "util/config.h" 22 + #include "util/time-utils.h" 22 23 23 24 #include <errno.h> 24 25 #include <inttypes.h> 25 26 #include <stdlib.h> 26 27 #include <math.h> 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 + }; 27 36 28 37 /* Diff command specific HPP columns. */ 29 38 enum { ··· 332 323 return -1; 333 324 } 334 325 335 - static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, 326 + static int diff__process_sample_event(struct perf_tool *tool, 336 327 union perf_event *event, 337 328 struct perf_sample *sample, 338 329 struct perf_evsel *evsel, 339 330 struct machine *machine) 340 331 { 332 + struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool); 341 333 struct addr_location al; 342 334 struct hists *hists = evsel__hists(evsel); 343 335 int ret = -1; 336 + 337 + if (perf_time__ranges_skip_sample(pdiff->ptime_range, pdiff->range_num, 338 + sample->time)) { 339 + return 0; 340 + } 344 341 345 342 if (machine__resolve(machine, &al, sample) < 0) { 346 343 pr_warning("problem processing %d event, skipping it.\n", ··· 374 359 return ret; 375 360 } 376 361 377 - static struct perf_tool tool = { 378 - .sample = diff__process_sample_event, 379 - .mmap = perf_event__process_mmap, 380 - .mmap2 = perf_event__process_mmap2, 381 - .comm = perf_event__process_comm, 382 - .exit = perf_event__process_exit, 383 - .fork = perf_event__process_fork, 384 - .lost = perf_event__process_lost, 385 - .namespaces = perf_event__process_namespaces, 386 - .ordered_events = true, 387 - .ordering_requires_timestamps = true, 362 + static struct perf_diff pdiff = { 363 + .tool = { 364 + .sample = diff__process_sample_event, 365 + .mmap = perf_event__process_mmap, 366 + .mmap2 = perf_event__process_mmap2, 367 + .comm = perf_event__process_comm, 368 + .exit = perf_event__process_exit, 369 + .fork = perf_event__process_fork, 370 + .lost = perf_event__process_lost, 371 + .namespaces = perf_event__process_namespaces, 372 + .ordered_events = true, 373 + .ordering_requires_timestamps = true, 374 + }, 388 375 }; 389 376 390 377 static struct perf_evsel *evsel_match(struct perf_evsel *evsel, ··· 788 771 } 789 772 } 790 773 774 + static int abstime_str_dup(char **pstr) 775 + { 776 + char *str = NULL; 777 + 778 + if (pdiff.time_str && strchr(pdiff.time_str, ':')) { 779 + str = strdup(pdiff.time_str); 780 + if (!str) 781 + return -ENOMEM; 782 + } 783 + 784 + *pstr = str; 785 + return 0; 786 + } 787 + 788 + static int parse_absolute_time(struct data__file *d, char **pstr) 789 + { 790 + char *p = *pstr; 791 + int ret; 792 + 793 + /* 794 + * Absolute timestamp for one file has the format: a.b,c.d 795 + * For multiple files, the format is: a.b,c.d:a.b,c.d 796 + */ 797 + p = strchr(*pstr, ':'); 798 + if (p) { 799 + if (p == *pstr) { 800 + pr_err("Invalid time string\n"); 801 + return -EINVAL; 802 + } 803 + 804 + *p = 0; 805 + p++; 806 + if (*p == 0) { 807 + pr_err("Invalid time string\n"); 808 + return -EINVAL; 809 + } 810 + } 811 + 812 + ret = perf_time__parse_for_ranges(*pstr, d->session, 813 + &pdiff.ptime_range, 814 + &pdiff.range_size, 815 + &pdiff.range_num); 816 + if (ret < 0) 817 + return ret; 818 + 819 + if (!p || *p == 0) 820 + *pstr = NULL; 821 + else 822 + *pstr = p; 823 + 824 + return ret; 825 + } 826 + 827 + static int parse_percent_time(struct data__file *d) 828 + { 829 + int ret; 830 + 831 + ret = perf_time__parse_for_ranges(pdiff.time_str, d->session, 832 + &pdiff.ptime_range, 833 + &pdiff.range_size, 834 + &pdiff.range_num); 835 + return ret; 836 + } 837 + 838 + static int parse_time_str(struct data__file *d, char *abstime_ostr, 839 + char **pabstime_tmp) 840 + { 841 + int ret = 0; 842 + 843 + if (abstime_ostr) 844 + ret = parse_absolute_time(d, pabstime_tmp); 845 + else if (pdiff.time_str) 846 + ret = parse_percent_time(d); 847 + 848 + return ret; 849 + } 850 + 791 851 static int __cmd_diff(void) 792 852 { 793 853 struct data__file *d; 794 - int ret = -EINVAL, i; 854 + int ret, i; 855 + char *abstime_ostr, *abstime_tmp; 856 + 857 + ret = abstime_str_dup(&abstime_ostr); 858 + if (ret) 859 + return ret; 860 + 861 + abstime_tmp = abstime_ostr; 862 + ret = -EINVAL; 795 863 796 864 data__for_each_file(i, d) { 797 - d->session = perf_session__new(&d->data, false, &tool); 865 + d->session = perf_session__new(&d->data, false, &pdiff.tool); 798 866 if (!d->session) { 799 867 pr_err("Failed to open %s\n", d->data.path); 800 868 ret = -1; 801 869 goto out_delete; 870 + } 871 + 872 + if (pdiff.time_str) { 873 + ret = parse_time_str(d, abstime_ostr, &abstime_tmp); 874 + if (ret < 0) 875 + goto out_delete; 802 876 } 803 877 804 878 ret = perf_session__process_events(d->session); ··· 899 791 } 900 792 901 793 perf_evlist__collapse_resort(d->session->evlist); 794 + 795 + if (pdiff.ptime_range) 796 + zfree(&pdiff.ptime_range); 902 797 } 903 798 904 799 data_process(); ··· 913 802 } 914 803 915 804 free(data__files); 805 + 806 + if (pdiff.ptime_range) 807 + zfree(&pdiff.ptime_range); 808 + 809 + if (abstime_ostr) 810 + free(abstime_ostr); 811 + 916 812 return ret; 917 813 } 918 814 ··· 967 849 OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), 968 850 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", 969 851 "How to display percentage of filtered entries", parse_filter_percentage), 852 + OPT_STRING(0, "time", &pdiff.time_str, "str", 853 + "Time span (time percent or absolute timestamp)"), 970 854 OPT_END() 971 855 }; 972 856