summaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-diff.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-03-10 18:22:03 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-10 18:22:03 -0400
commit12ad143e1b803e541e48b8ba40f550250259ecdd (patch)
tree5202b407df21e5abaeb294d1ecddcf0a2eca7f8b /tools/perf/builtin-diff.c
parent262d6a9a63a387c8dfa9eb4f7713e159c941e52c (diff)
parentb339da480315505aa28a723a983217ebcff95c86 (diff)
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Thomas Gleixner: "Perf updates and fixes: Kernel: - Handle events which have the bpf_event attribute set as side band events as they carry information about BPF programs. - Add missing switch-case fall-through comments Libraries: - Fix leaks and double frees in error code paths. - Prevent buffer overflows in libtraceevent Tools: - Improvements in handling Intel BT/PTS - Add BTF ELF markers to perf trace BPF programs to improve output - Support --time, --cpu, --pid and --tid filters for perf diff - Calculate the column width in perf annotate as the hardcoded 6 characters for the instruction are not sufficient - Small fixes all over the place" * 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (38 commits) perf/core: Mark expected switch fall-through perf/x86/intel/uncore: Fix client IMC events return huge result perf/ring_buffer: Use high order allocations for AUX buffers optimistically perf data: Force perf_data__open|close zero data->file.path perf session: Fix double free in perf_data__close perf evsel: Probe for precise_ip with simple attr perf tools: Read and store caps/max_precise in perf_pmu perf hist: Fix memory leak of srcline perf hist: Add error path into hist_entry__init perf c2c: Fix c2c report for empty numa node perf script python: Add Python3 support to intel-pt-events.py perf script python: Add Python3 support to event_analyzing_sample.py perf script python: add Python3 support to check-perf-trace.py perf script python: Add Python3 support to futex-contention.py perf script python: Remove mixed indentation perf diff: Support --pid/--tid filter options perf diff: Support --cpu filter option perf diff: Support --time filter option perf thread: Generalize function to copy from thread addr space from intel-bts code perf annotate: Calculate the max instruction name, align column to that ...
Diffstat (limited to 'tools/perf/builtin-diff.c')
-rw-r--r--tools/perf/builtin-diff.c168
1 files changed, 154 insertions, 14 deletions
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 58fe0e88215c..6e7920793729 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,
@@ -74,6 +83,9 @@ static unsigned int sort_compute = 1;
74static s64 compute_wdiff_w1; 83static s64 compute_wdiff_w1;
75static s64 compute_wdiff_w2; 84static s64 compute_wdiff_w2;
76 85
86static const char *cpu_list;
87static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
88
77enum { 89enum {
78 COMPUTE_DELTA, 90 COMPUTE_DELTA,
79 COMPUTE_RATIO, 91 COMPUTE_RATIO,
@@ -323,22 +335,33 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
323 return -1; 335 return -1;
324} 336}
325 337
326static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, 338static int diff__process_sample_event(struct perf_tool *tool,
327 union perf_event *event, 339 union perf_event *event,
328 struct perf_sample *sample, 340 struct perf_sample *sample,
329 struct perf_evsel *evsel, 341 struct perf_evsel *evsel,
330 struct machine *machine) 342 struct machine *machine)
331{ 343{
344 struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool);
332 struct addr_location al; 345 struct addr_location al;
333 struct hists *hists = evsel__hists(evsel); 346 struct hists *hists = evsel__hists(evsel);
334 int ret = -1; 347 int ret = -1;
335 348
349 if (perf_time__ranges_skip_sample(pdiff->ptime_range, pdiff->range_num,
350 sample->time)) {
351 return 0;
352 }
353
336 if (machine__resolve(machine, &al, sample) < 0) { 354 if (machine__resolve(machine, &al, sample) < 0) {
337 pr_warning("problem processing %d event, skipping it.\n", 355 pr_warning("problem processing %d event, skipping it.\n",
338 event->header.type); 356 event->header.type);
339 return -1; 357 return -1;
340 } 358 }
341 359
360 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) {
361 ret = 0;
362 goto out_put;
363 }
364
342 if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample, true)) { 365 if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample, true)) {
343 pr_warning("problem incrementing symbol period, skipping event\n"); 366 pr_warning("problem incrementing symbol period, skipping event\n");
344 goto out_put; 367 goto out_put;
@@ -359,17 +382,19 @@ out_put:
359 return ret; 382 return ret;
360} 383}
361 384
362static struct perf_tool tool = { 385static struct perf_diff pdiff = {
363 .sample = diff__process_sample_event, 386 .tool = {
364 .mmap = perf_event__process_mmap, 387 .sample = diff__process_sample_event,
365 .mmap2 = perf_event__process_mmap2, 388 .mmap = perf_event__process_mmap,
366 .comm = perf_event__process_comm, 389 .mmap2 = perf_event__process_mmap2,
367 .exit = perf_event__process_exit, 390 .comm = perf_event__process_comm,
368 .fork = perf_event__process_fork, 391 .exit = perf_event__process_exit,
369 .lost = perf_event__process_lost, 392 .fork = perf_event__process_fork,
370 .namespaces = perf_event__process_namespaces, 393 .lost = perf_event__process_lost,
371 .ordered_events = true, 394 .namespaces = perf_event__process_namespaces,
372 .ordering_requires_timestamps = true, 395 .ordered_events = true,
396 .ordering_requires_timestamps = true,
397 },
373}; 398};
374 399
375static struct perf_evsel *evsel_match(struct perf_evsel *evsel, 400static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
@@ -771,19 +796,117 @@ static void data__free(struct data__file *d)
771 } 796 }
772} 797}
773 798
799static int abstime_str_dup(char **pstr)
800{
801 char *str = NULL;
802
803 if (pdiff.time_str && strchr(pdiff.time_str, ':')) {
804 str = strdup(pdiff.time_str);
805 if (!str)
806 return -ENOMEM;
807 }
808
809 *pstr = str;
810 return 0;
811}
812
813static int parse_absolute_time(struct data__file *d, char **pstr)
814{
815 char *p = *pstr;
816 int ret;
817
818 /*
819 * Absolute timestamp for one file has the format: a.b,c.d
820 * For multiple files, the format is: a.b,c.d:a.b,c.d
821 */
822 p = strchr(*pstr, ':');
823 if (p) {
824 if (p == *pstr) {
825 pr_err("Invalid time string\n");
826 return -EINVAL;
827 }
828
829 *p = 0;
830 p++;
831 if (*p == 0) {
832 pr_err("Invalid time string\n");
833 return -EINVAL;
834 }
835 }
836
837 ret = perf_time__parse_for_ranges(*pstr, d->session,
838 &pdiff.ptime_range,
839 &pdiff.range_size,
840 &pdiff.range_num);
841 if (ret < 0)
842 return ret;
843
844 if (!p || *p == 0)
845 *pstr = NULL;
846 else
847 *pstr = p;
848
849 return ret;
850}
851
852static int parse_percent_time(struct data__file *d)
853{
854 int ret;
855
856 ret = perf_time__parse_for_ranges(pdiff.time_str, d->session,
857 &pdiff.ptime_range,
858 &pdiff.range_size,
859 &pdiff.range_num);
860 return ret;
861}
862
863static int parse_time_str(struct data__file *d, char *abstime_ostr,
864 char **pabstime_tmp)
865{
866 int ret = 0;
867
868 if (abstime_ostr)
869 ret = parse_absolute_time(d, pabstime_tmp);
870 else if (pdiff.time_str)
871 ret = parse_percent_time(d);
872
873 return ret;
874}
875
774static int __cmd_diff(void) 876static int __cmd_diff(void)
775{ 877{
776 struct data__file *d; 878 struct data__file *d;
777 int ret = -EINVAL, i; 879 int ret, i;
880 char *abstime_ostr, *abstime_tmp;
881
882 ret = abstime_str_dup(&abstime_ostr);
883 if (ret)
884 return ret;
885
886 abstime_tmp = abstime_ostr;
887 ret = -EINVAL;
778 888
779 data__for_each_file(i, d) { 889 data__for_each_file(i, d) {
780 d->session = perf_session__new(&d->data, false, &tool); 890 d->session = perf_session__new(&d->data, false, &pdiff.tool);
781 if (!d->session) { 891 if (!d->session) {
782 pr_err("Failed to open %s\n", d->data.path); 892 pr_err("Failed to open %s\n", d->data.path);
783 ret = -1; 893 ret = -1;
784 goto out_delete; 894 goto out_delete;
785 } 895 }
786 896
897 if (pdiff.time_str) {
898 ret = parse_time_str(d, abstime_ostr, &abstime_tmp);
899 if (ret < 0)
900 goto out_delete;
901 }
902
903 if (cpu_list) {
904 ret = perf_session__cpu_bitmap(d->session, cpu_list,
905 cpu_bitmap);
906 if (ret < 0)
907 goto out_delete;
908 }
909
787 ret = perf_session__process_events(d->session); 910 ret = perf_session__process_events(d->session);
788 if (ret) { 911 if (ret) {
789 pr_err("Failed to process %s\n", d->data.path); 912 pr_err("Failed to process %s\n", d->data.path);
@@ -791,6 +914,9 @@ static int __cmd_diff(void)
791 } 914 }
792 915
793 perf_evlist__collapse_resort(d->session->evlist); 916 perf_evlist__collapse_resort(d->session->evlist);
917
918 if (pdiff.ptime_range)
919 zfree(&pdiff.ptime_range);
794 } 920 }
795 921
796 data_process(); 922 data_process();
@@ -802,6 +928,13 @@ static int __cmd_diff(void)
802 } 928 }
803 929
804 free(data__files); 930 free(data__files);
931
932 if (pdiff.ptime_range)
933 zfree(&pdiff.ptime_range);
934
935 if (abstime_ostr)
936 free(abstime_ostr);
937
805 return ret; 938 return ret;
806} 939}
807 940
@@ -849,6 +982,13 @@ static const struct option options[] = {
849 OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), 982 OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
850 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", 983 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
851 "How to display percentage of filtered entries", parse_filter_percentage), 984 "How to display percentage of filtered entries", parse_filter_percentage),
985 OPT_STRING(0, "time", &pdiff.time_str, "str",
986 "Time span (time percent or absolute timestamp)"),
987 OPT_STRING(0, "cpu", &cpu_list, "cpu", "list of cpus to profile"),
988 OPT_STRING(0, "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
989 "only consider symbols in these pids"),
990 OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
991 "only consider symbols in these tids"),
852 OPT_END() 992 OPT_END()
853}; 993};
854 994