diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-06-16 04:27:35 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-06-16 04:27:35 -0400 |
commit | 02469a95096a549508c5adf61d84a1d72851c85b (patch) | |
tree | 130c83a2f6937ffa81d00ec661d223cab7a37715 | |
parent | 2c95afc1e83d93fac3be6923465e1753c2c53b0a (diff) | |
parent | 2fd457a34525ea3bc609e377b46af759af8a7934 (diff) |
Merge tag 'perf-core-for-mingo-20160615' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
User visible changes:
- Add --ldlat option to 'perf mem' to specify load latency for loads
event (e.g. cpu/mem-loads/ ) (Jiri Olsa)
Build fixes:
- Fix libunwind related compile error for static cross build (He Kuang)
Infrastructure changes:
- UI refactorings to support headers with multiple lines, non-evsel
hists browsers, toggle showing callchains, etc (Jiri Olsa)
- More prep work for caching probe definitions, paving the way
for supporting SDT (Statically Defined Traces) userspace probes (Masami Hiramatsu)
- Handle NULL at perf_config_set__delete() (Taeung Song)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/perf/Documentation/perf-mem.txt | 3 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-probe.txt | 4 | ||||
-rw-r--r-- | tools/perf/builtin-diff.c | 7 | ||||
-rw-r--r-- | tools/perf/builtin-mem.c | 1 | ||||
-rw-r--r-- | tools/perf/builtin-probe.c | 1 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 3 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 2 | ||||
-rw-r--r-- | tools/perf/config/Makefile | 3 | ||||
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 39 | ||||
-rw-r--r-- | tools/perf/ui/gtk/hists.c | 2 | ||||
-rw-r--r-- | tools/perf/ui/hist.c | 11 | ||||
-rw-r--r-- | tools/perf/ui/stdio/hist.c | 133 | ||||
-rw-r--r-- | tools/perf/util/build-id.c | 12 | ||||
-rw-r--r-- | tools/perf/util/build-id.h | 2 | ||||
-rw-r--r-- | tools/perf/util/config.c | 3 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 7 | ||||
-rw-r--r-- | tools/perf/util/mem-events.c | 17 | ||||
-rw-r--r-- | tools/perf/util/mem-events.h | 1 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 128 | ||||
-rw-r--r-- | tools/perf/util/probe-event.h | 5 | ||||
-rw-r--r-- | tools/perf/util/probe-file.c | 331 | ||||
-rw-r--r-- | tools/perf/util/probe-file.h | 20 | ||||
-rw-r--r-- | tools/perf/util/sort.c | 14 | ||||
-rw-r--r-- | tools/perf/util/util.c | 13 |
25 files changed, 640 insertions, 124 deletions
diff --git a/tools/perf/Documentation/perf-mem.txt b/tools/perf/Documentation/perf-mem.txt index 1d6092c460dd..73496320fca3 100644 --- a/tools/perf/Documentation/perf-mem.txt +++ b/tools/perf/Documentation/perf-mem.txt | |||
@@ -56,6 +56,9 @@ OPTIONS | |||
56 | --all-user:: | 56 | --all-user:: |
57 | Configure all used events to run in user space. | 57 | Configure all used events to run in user space. |
58 | 58 | ||
59 | --ldload:: | ||
60 | Specify desired latency for loads event. | ||
61 | |||
59 | SEE ALSO | 62 | SEE ALSO |
60 | -------- | 63 | -------- |
61 | linkperf:perf-record[1], linkperf:perf-report[1] | 64 | linkperf:perf-record[1], linkperf:perf-report[1] |
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 3a8a9ba2b041..947db6fe512c 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
@@ -109,6 +109,10 @@ OPTIONS | |||
109 | Dry run. With this option, --add and --del doesn't execute actual | 109 | Dry run. With this option, --add and --del doesn't execute actual |
110 | adding and removal operations. | 110 | adding and removal operations. |
111 | 111 | ||
112 | --cache:: | ||
113 | Cache the probes (with --add option). Any events which successfully added | ||
114 | are also stored in the cache file. | ||
115 | |||
112 | --max-probes=NUM:: | 116 | --max-probes=NUM:: |
113 | Set the maximum number of probe points for an event. Default is 128. | 117 | Set the maximum number of probe points for an event. Default is 128. |
114 | 118 | ||
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index f7645a42708e..7f628f9c2fb4 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -666,7 +666,8 @@ static void hists__process(struct hists *hists) | |||
666 | hists__precompute(hists); | 666 | hists__precompute(hists); |
667 | hists__output_resort(hists, NULL); | 667 | hists__output_resort(hists, NULL); |
668 | 668 | ||
669 | hists__fprintf(hists, true, 0, 0, 0, stdout); | 669 | hists__fprintf(hists, true, 0, 0, 0, stdout, |
670 | symbol_conf.use_callchain); | ||
670 | } | 671 | } |
671 | 672 | ||
672 | static void data__fprintf(void) | 673 | static void data__fprintf(void) |
@@ -1044,7 +1045,7 @@ static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp, | |||
1044 | } | 1045 | } |
1045 | 1046 | ||
1046 | static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | 1047 | static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
1047 | struct perf_evsel *evsel __maybe_unused) | 1048 | struct hists *hists __maybe_unused) |
1048 | { | 1049 | { |
1049 | struct diff_hpp_fmt *dfmt = | 1050 | struct diff_hpp_fmt *dfmt = |
1050 | container_of(fmt, struct diff_hpp_fmt, fmt); | 1051 | container_of(fmt, struct diff_hpp_fmt, fmt); |
@@ -1055,7 +1056,7 @@ static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | |||
1055 | 1056 | ||
1056 | static int hpp__width(struct perf_hpp_fmt *fmt, | 1057 | static int hpp__width(struct perf_hpp_fmt *fmt, |
1057 | struct perf_hpp *hpp __maybe_unused, | 1058 | struct perf_hpp *hpp __maybe_unused, |
1058 | struct perf_evsel *evsel __maybe_unused) | 1059 | struct hists *hists __maybe_unused) |
1059 | { | 1060 | { |
1060 | struct diff_hpp_fmt *dfmt = | 1061 | struct diff_hpp_fmt *dfmt = |
1061 | container_of(fmt, struct diff_hpp_fmt, fmt); | 1062 | container_of(fmt, struct diff_hpp_fmt, fmt); |
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 1dc140c5481d..d608a2c9e48c 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c | |||
@@ -67,6 +67,7 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) | |||
67 | OPT_CALLBACK('e', "event", &mem, "event", | 67 | OPT_CALLBACK('e', "event", &mem, "event", |
68 | "event selector. use 'perf mem record -e list' to list available events", | 68 | "event selector. use 'perf mem record -e list' to list available events", |
69 | parse_record_events), | 69 | parse_record_events), |
70 | OPT_UINTEGER(0, "ldlat", &perf_mem_events__loads_ldlat, "mem-loads latency"), | ||
70 | OPT_INCR('v', "verbose", &verbose, | 71 | OPT_INCR('v', "verbose", &verbose, |
71 | "be more verbose (show counter open errors, etc)"), | 72 | "be more verbose (show counter open errors, etc)"), |
72 | OPT_BOOLEAN('U', "--all-user", &all_user, "collect only user level data"), | 73 | OPT_BOOLEAN('U', "--all-user", &all_user, "collect only user level data"), |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 9af859b28b15..6d7ab4316449 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -512,6 +512,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | |||
512 | "Enable symbol demangling"), | 512 | "Enable symbol demangling"), |
513 | OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, | 513 | OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, |
514 | "Enable kernel symbol demangling"), | 514 | "Enable kernel symbol demangling"), |
515 | OPT_BOOLEAN(0, "cache", &probe_conf.cache, "Manipulate probe cache"), | ||
515 | OPT_END() | 516 | OPT_END() |
516 | }; | 517 | }; |
517 | int ret; | 518 | int ret; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index a87cb338bdf1..9f36b236f0f9 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -370,7 +370,8 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
370 | continue; | 370 | continue; |
371 | 371 | ||
372 | hists__fprintf_nr_sample_events(hists, rep, evname, stdout); | 372 | hists__fprintf_nr_sample_events(hists, rep, evname, stdout); |
373 | hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout); | 373 | hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout, |
374 | symbol_conf.use_callchain); | ||
374 | fprintf(stdout, "\n\n"); | 375 | fprintf(stdout, "\n\n"); |
375 | } | 376 | } |
376 | 377 | ||
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 2a6cc254ad0c..81dba80a42b5 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -295,7 +295,7 @@ static void perf_top__print_sym_table(struct perf_top *top) | |||
295 | hists__output_recalc_col_len(hists, top->print_entries - printed); | 295 | hists__output_recalc_col_len(hists, top->print_entries - printed); |
296 | putchar('\n'); | 296 | putchar('\n'); |
297 | hists__fprintf(hists, false, top->print_entries - printed, win_width, | 297 | hists__fprintf(hists, false, top->print_entries - printed, win_width, |
298 | top->min_percent, stdout); | 298 | top->min_percent, stdout, symbol_conf.use_callchain); |
299 | } | 299 | } |
300 | 300 | ||
301 | static void prompt_integer(int *target, const char *msg) | 301 | static void prompt_integer(int *target, const char *msg) |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 098874b99981..80018feb99c0 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -365,6 +365,7 @@ ifndef NO_LIBUNWIND | |||
365 | $(call detected,CONFIG_LIBUNWIND_X86) | 365 | $(call detected,CONFIG_LIBUNWIND_X86) |
366 | CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT | 366 | CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT |
367 | LDFLAGS += -lunwind-x86 | 367 | LDFLAGS += -lunwind-x86 |
368 | EXTLIBS_LIBUNWIND += -lunwind-x86 | ||
368 | have_libunwind = 1 | 369 | have_libunwind = 1 |
369 | endif | 370 | endif |
370 | 371 | ||
@@ -372,6 +373,7 @@ ifndef NO_LIBUNWIND | |||
372 | $(call detected,CONFIG_LIBUNWIND_AARCH64) | 373 | $(call detected,CONFIG_LIBUNWIND_AARCH64) |
373 | CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT | 374 | CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT |
374 | LDFLAGS += -lunwind-aarch64 | 375 | LDFLAGS += -lunwind-aarch64 |
376 | EXTLIBS_LIBUNWIND += -lunwind-aarch64 | ||
375 | have_libunwind = 1 | 377 | have_libunwind = 1 |
376 | $(call feature_check,libunwind-debug-frame-aarch64) | 378 | $(call feature_check,libunwind-debug-frame-aarch64) |
377 | ifneq ($(feature-libunwind-debug-frame-aarch64), 1) | 379 | ifneq ($(feature-libunwind-debug-frame-aarch64), 1) |
@@ -449,6 +451,7 @@ ifndef NO_LIBUNWIND | |||
449 | CFLAGS += -DHAVE_LIBUNWIND_SUPPORT | 451 | CFLAGS += -DHAVE_LIBUNWIND_SUPPORT |
450 | CFLAGS += $(LIBUNWIND_CFLAGS) | 452 | CFLAGS += $(LIBUNWIND_CFLAGS) |
451 | LDFLAGS += $(LIBUNWIND_LDFLAGS) | 453 | LDFLAGS += $(LIBUNWIND_LDFLAGS) |
454 | EXTLIBS += $(EXTLIBS_LIBUNWIND) | ||
452 | endif | 455 | endif |
453 | 456 | ||
454 | ifndef NO_LIBAUDIT | 457 | ifndef NO_LIBAUDIT |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 538bae880bfe..b1b60544a545 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -1470,7 +1470,7 @@ static int hist_browser__show_no_entry(struct hist_browser *browser, | |||
1470 | column++ < browser->b.horiz_scroll) | 1470 | column++ < browser->b.horiz_scroll) |
1471 | continue; | 1471 | continue; |
1472 | 1472 | ||
1473 | ret = fmt->width(fmt, NULL, hists_to_evsel(browser->hists)); | 1473 | ret = fmt->width(fmt, NULL, browser->hists); |
1474 | 1474 | ||
1475 | if (first) { | 1475 | if (first) { |
1476 | /* for folded sign */ | 1476 | /* for folded sign */ |
@@ -1531,7 +1531,7 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char * | |||
1531 | if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll) | 1531 | if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll) |
1532 | continue; | 1532 | continue; |
1533 | 1533 | ||
1534 | ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); | 1534 | ret = fmt->header(fmt, &dummy_hpp, hists); |
1535 | if (advance_hpp_check(&dummy_hpp, ret)) | 1535 | if (advance_hpp_check(&dummy_hpp, ret)) |
1536 | break; | 1536 | break; |
1537 | 1537 | ||
@@ -1568,7 +1568,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows | |||
1568 | if (column++ < browser->b.horiz_scroll) | 1568 | if (column++ < browser->b.horiz_scroll) |
1569 | continue; | 1569 | continue; |
1570 | 1570 | ||
1571 | ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); | 1571 | ret = fmt->header(fmt, &dummy_hpp, hists); |
1572 | if (advance_hpp_check(&dummy_hpp, ret)) | 1572 | if (advance_hpp_check(&dummy_hpp, ret)) |
1573 | break; | 1573 | break; |
1574 | 1574 | ||
@@ -1605,7 +1605,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows | |||
1605 | } | 1605 | } |
1606 | first_col = false; | 1606 | first_col = false; |
1607 | 1607 | ||
1608 | ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); | 1608 | ret = fmt->header(fmt, &dummy_hpp, hists); |
1609 | dummy_hpp.buf[ret] = '\0'; | 1609 | dummy_hpp.buf[ret] = '\0'; |
1610 | 1610 | ||
1611 | start = trim(dummy_hpp.buf); | 1611 | start = trim(dummy_hpp.buf); |
@@ -1622,21 +1622,38 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows | |||
1622 | return ret; | 1622 | return ret; |
1623 | } | 1623 | } |
1624 | 1624 | ||
1625 | static void hist_browser__show_headers(struct hist_browser *browser) | 1625 | static void hists_browser__hierarchy_headers(struct hist_browser *browser) |
1626 | { | 1626 | { |
1627 | char headers[1024]; | 1627 | char headers[1024]; |
1628 | 1628 | ||
1629 | if (symbol_conf.report_hierarchy) | 1629 | hists_browser__scnprintf_hierarchy_headers(browser, headers, |
1630 | hists_browser__scnprintf_hierarchy_headers(browser, headers, | 1630 | sizeof(headers)); |
1631 | sizeof(headers)); | 1631 | |
1632 | else | ||
1633 | hists_browser__scnprintf_headers(browser, headers, | ||
1634 | sizeof(headers)); | ||
1635 | ui_browser__gotorc(&browser->b, 0, 0); | 1632 | ui_browser__gotorc(&browser->b, 0, 0); |
1636 | ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); | 1633 | ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); |
1637 | ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); | 1634 | ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); |
1638 | } | 1635 | } |
1639 | 1636 | ||
1637 | static void hists_browser__headers(struct hist_browser *browser) | ||
1638 | { | ||
1639 | char headers[1024]; | ||
1640 | |||
1641 | hists_browser__scnprintf_headers(browser, headers, | ||
1642 | sizeof(headers)); | ||
1643 | |||
1644 | ui_browser__gotorc(&browser->b, 0, 0); | ||
1645 | ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); | ||
1646 | ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); | ||
1647 | } | ||
1648 | |||
1649 | static void hist_browser__show_headers(struct hist_browser *browser) | ||
1650 | { | ||
1651 | if (symbol_conf.report_hierarchy) | ||
1652 | hists_browser__hierarchy_headers(browser); | ||
1653 | else | ||
1654 | hists_browser__headers(browser); | ||
1655 | } | ||
1656 | |||
1640 | static void ui_browser__hists_init_top(struct ui_browser *browser) | 1657 | static void ui_browser__hists_init_top(struct ui_browser *browser) |
1641 | { | 1658 | { |
1642 | if (browser->top == NULL) { | 1659 | if (browser->top == NULL) { |
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 932adfaa05af..e5c1325b0340 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c | |||
@@ -549,7 +549,7 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists, | |||
549 | strcat(buf, "+"); | 549 | strcat(buf, "+"); |
550 | first_col = false; | 550 | first_col = false; |
551 | 551 | ||
552 | fmt->header(fmt, &hpp, hists_to_evsel(hists)); | 552 | fmt->header(fmt, &hpp, hists); |
553 | strcat(buf, ltrim(rtrim(hpp.buf))); | 553 | strcat(buf, ltrim(rtrim(hpp.buf))); |
554 | } | 554 | } |
555 | } | 555 | } |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index af07ffb129ca..6940745aa77c 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -215,9 +215,10 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b, | |||
215 | 215 | ||
216 | static int hpp__width_fn(struct perf_hpp_fmt *fmt, | 216 | static int hpp__width_fn(struct perf_hpp_fmt *fmt, |
217 | struct perf_hpp *hpp __maybe_unused, | 217 | struct perf_hpp *hpp __maybe_unused, |
218 | struct perf_evsel *evsel) | 218 | struct hists *hists) |
219 | { | 219 | { |
220 | int len = fmt->user_len ?: fmt->len; | 220 | int len = fmt->user_len ?: fmt->len; |
221 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
221 | 222 | ||
222 | if (symbol_conf.event_group) | 223 | if (symbol_conf.event_group) |
223 | len = max(len, evsel->nr_members * fmt->len); | 224 | len = max(len, evsel->nr_members * fmt->len); |
@@ -229,9 +230,9 @@ static int hpp__width_fn(struct perf_hpp_fmt *fmt, | |||
229 | } | 230 | } |
230 | 231 | ||
231 | static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | 232 | static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
232 | struct perf_evsel *evsel) | 233 | struct hists *hists) |
233 | { | 234 | { |
234 | int len = hpp__width_fn(fmt, hpp, evsel); | 235 | int len = hpp__width_fn(fmt, hpp, hists); |
235 | return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name); | 236 | return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name); |
236 | } | 237 | } |
237 | 238 | ||
@@ -632,7 +633,7 @@ unsigned int hists__sort_list_width(struct hists *hists) | |||
632 | else | 633 | else |
633 | ret += 2; | 634 | ret += 2; |
634 | 635 | ||
635 | ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); | 636 | ret += fmt->width(fmt, &dummy_hpp, hists); |
636 | } | 637 | } |
637 | 638 | ||
638 | if (verbose && hists__has(hists, sym)) /* Addr + origin */ | 639 | if (verbose && hists__has(hists, sym)) /* Addr + origin */ |
@@ -657,7 +658,7 @@ unsigned int hists__overhead_width(struct hists *hists) | |||
657 | else | 658 | else |
658 | ret += 2; | 659 | ret += 2; |
659 | 660 | ||
660 | ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); | 661 | ret += fmt->width(fmt, &dummy_hpp, hists); |
661 | } | 662 | } |
662 | 663 | ||
663 | return ret; | 664 | return ret; |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 560eb47d56f9..f04a63112079 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -492,14 +492,15 @@ out: | |||
492 | } | 492 | } |
493 | 493 | ||
494 | static int hist_entry__fprintf(struct hist_entry *he, size_t size, | 494 | static int hist_entry__fprintf(struct hist_entry *he, size_t size, |
495 | struct hists *hists, | 495 | char *bf, size_t bfsz, FILE *fp, |
496 | char *bf, size_t bfsz, FILE *fp) | 496 | bool use_callchain) |
497 | { | 497 | { |
498 | int ret; | 498 | int ret; |
499 | struct perf_hpp hpp = { | 499 | struct perf_hpp hpp = { |
500 | .buf = bf, | 500 | .buf = bf, |
501 | .size = size, | 501 | .size = size, |
502 | }; | 502 | }; |
503 | struct hists *hists = he->hists; | ||
503 | u64 total_period = hists->stats.total_period; | 504 | u64 total_period = hists->stats.total_period; |
504 | 505 | ||
505 | if (size == 0 || size > bfsz) | 506 | if (size == 0 || size > bfsz) |
@@ -512,7 +513,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, | |||
512 | 513 | ||
513 | ret = fprintf(fp, "%s\n", bf); | 514 | ret = fprintf(fp, "%s\n", bf); |
514 | 515 | ||
515 | if (symbol_conf.use_callchain) | 516 | if (use_callchain) |
516 | ret += hist_entry_callchain__fprintf(he, total_period, 0, fp); | 517 | ret += hist_entry_callchain__fprintf(he, total_period, 0, fp); |
517 | 518 | ||
518 | return ret; | 519 | return ret; |
@@ -548,7 +549,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, | |||
548 | struct perf_hpp_list_node, list); | 549 | struct perf_hpp_list_node, list); |
549 | 550 | ||
550 | perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { | 551 | perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { |
551 | fmt->header(fmt, hpp, hists_to_evsel(hists)); | 552 | fmt->header(fmt, hpp, hists); |
552 | fprintf(fp, "%s%s", hpp->buf, sep ?: " "); | 553 | fprintf(fp, "%s%s", hpp->buf, sep ?: " "); |
553 | } | 554 | } |
554 | 555 | ||
@@ -568,7 +569,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, | |||
568 | header_width += fprintf(fp, "+"); | 569 | header_width += fprintf(fp, "+"); |
569 | first_col = false; | 570 | first_col = false; |
570 | 571 | ||
571 | fmt->header(fmt, hpp, hists_to_evsel(hists)); | 572 | fmt->header(fmt, hpp, hists); |
572 | 573 | ||
573 | header_width += fprintf(fp, "%s", trim(hpp->buf)); | 574 | header_width += fprintf(fp, "%s", trim(hpp->buf)); |
574 | } | 575 | } |
@@ -589,7 +590,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, | |||
589 | fprintf(fp, "%s", sep ?: ".."); | 590 | fprintf(fp, "%s", sep ?: ".."); |
590 | first_col = false; | 591 | first_col = false; |
591 | 592 | ||
592 | width = fmt->width(fmt, hpp, hists_to_evsel(hists)); | 593 | width = fmt->width(fmt, hpp, hists); |
593 | fprintf(fp, "%.*s", width, dots); | 594 | fprintf(fp, "%.*s", width, dots); |
594 | } | 595 | } |
595 | 596 | ||
@@ -606,7 +607,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, | |||
606 | width++; /* for '+' sign between column header */ | 607 | width++; /* for '+' sign between column header */ |
607 | first_col = false; | 608 | first_col = false; |
608 | 609 | ||
609 | width += fmt->width(fmt, hpp, hists_to_evsel(hists)); | 610 | width += fmt->width(fmt, hpp, hists); |
610 | } | 611 | } |
611 | 612 | ||
612 | if (width > header_width) | 613 | if (width > header_width) |
@@ -622,47 +623,31 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, | |||
622 | return 2; | 623 | return 2; |
623 | } | 624 | } |
624 | 625 | ||
625 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | 626 | static int |
626 | int max_cols, float min_pcnt, FILE *fp) | 627 | hists__fprintf_hierarchy_headers(struct hists *hists, |
628 | struct perf_hpp *hpp, | ||
629 | FILE *fp) | ||
627 | { | 630 | { |
628 | struct perf_hpp_fmt *fmt; | ||
629 | struct perf_hpp_list_node *fmt_node; | 631 | struct perf_hpp_list_node *fmt_node; |
630 | struct rb_node *nd; | 632 | struct perf_hpp_fmt *fmt; |
631 | size_t ret = 0; | ||
632 | unsigned int width; | ||
633 | const char *sep = symbol_conf.field_sep; | ||
634 | int nr_rows = 0; | ||
635 | char bf[96]; | ||
636 | struct perf_hpp dummy_hpp = { | ||
637 | .buf = bf, | ||
638 | .size = sizeof(bf), | ||
639 | }; | ||
640 | bool first = true; | ||
641 | size_t linesz; | ||
642 | char *line = NULL; | ||
643 | unsigned indent; | ||
644 | |||
645 | init_rem_hits(); | ||
646 | |||
647 | hists__for_each_format(hists, fmt) | ||
648 | perf_hpp__reset_width(fmt, hists); | ||
649 | |||
650 | if (symbol_conf.col_width_list_str) | ||
651 | perf_hpp__set_user_width(symbol_conf.col_width_list_str); | ||
652 | 633 | ||
653 | if (!show_header) | 634 | list_for_each_entry(fmt_node, &hists->hpp_formats, list) { |
654 | goto print_entries; | 635 | perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) |
636 | perf_hpp__reset_width(fmt, hists); | ||
637 | } | ||
655 | 638 | ||
656 | fprintf(fp, "# "); | 639 | return print_hierarchy_header(hists, hpp, symbol_conf.field_sep, fp); |
640 | } | ||
657 | 641 | ||
658 | if (symbol_conf.report_hierarchy) { | 642 | static int |
659 | list_for_each_entry(fmt_node, &hists->hpp_formats, list) { | 643 | hists__fprintf_standard_headers(struct hists *hists, |
660 | perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) | 644 | struct perf_hpp *hpp, |
661 | perf_hpp__reset_width(fmt, hists); | 645 | FILE *fp) |
662 | } | 646 | { |
663 | nr_rows += print_hierarchy_header(hists, &dummy_hpp, sep, fp); | 647 | struct perf_hpp_fmt *fmt; |
664 | goto print_entries; | 648 | unsigned int width; |
665 | } | 649 | const char *sep = symbol_conf.field_sep; |
650 | bool first = true; | ||
666 | 651 | ||
667 | hists__for_each_format(hists, fmt) { | 652 | hists__for_each_format(hists, fmt) { |
668 | if (perf_hpp__should_skip(fmt, hists)) | 653 | if (perf_hpp__should_skip(fmt, hists)) |
@@ -673,16 +658,14 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
673 | else | 658 | else |
674 | first = false; | 659 | first = false; |
675 | 660 | ||
676 | fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); | 661 | fmt->header(fmt, hpp, hists); |
677 | fprintf(fp, "%s", bf); | 662 | fprintf(fp, "%s", hpp->buf); |
678 | } | 663 | } |
679 | 664 | ||
680 | fprintf(fp, "\n"); | 665 | fprintf(fp, "\n"); |
681 | if (max_rows && ++nr_rows >= max_rows) | ||
682 | goto out; | ||
683 | 666 | ||
684 | if (sep) | 667 | if (sep) |
685 | goto print_entries; | 668 | return 1; |
686 | 669 | ||
687 | first = true; | 670 | first = true; |
688 | 671 | ||
@@ -699,20 +682,60 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
699 | else | 682 | else |
700 | first = false; | 683 | first = false; |
701 | 684 | ||
702 | width = fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); | 685 | width = fmt->width(fmt, hpp, hists); |
703 | for (i = 0; i < width; i++) | 686 | for (i = 0; i < width; i++) |
704 | fprintf(fp, "."); | 687 | fprintf(fp, "."); |
705 | } | 688 | } |
706 | 689 | ||
707 | fprintf(fp, "\n"); | 690 | fprintf(fp, "\n"); |
708 | if (max_rows && ++nr_rows >= max_rows) | ||
709 | goto out; | ||
710 | |||
711 | fprintf(fp, "#\n"); | 691 | fprintf(fp, "#\n"); |
712 | if (max_rows && ++nr_rows >= max_rows) | 692 | return 3; |
693 | } | ||
694 | |||
695 | static int hists__fprintf_headers(struct hists *hists, FILE *fp) | ||
696 | { | ||
697 | char bf[96]; | ||
698 | struct perf_hpp dummy_hpp = { | ||
699 | .buf = bf, | ||
700 | .size = sizeof(bf), | ||
701 | }; | ||
702 | |||
703 | fprintf(fp, "# "); | ||
704 | |||
705 | if (symbol_conf.report_hierarchy) | ||
706 | return hists__fprintf_hierarchy_headers(hists, &dummy_hpp, fp); | ||
707 | else | ||
708 | return hists__fprintf_standard_headers(hists, &dummy_hpp, fp); | ||
709 | |||
710 | } | ||
711 | |||
712 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | ||
713 | int max_cols, float min_pcnt, FILE *fp, | ||
714 | bool use_callchain) | ||
715 | { | ||
716 | struct perf_hpp_fmt *fmt; | ||
717 | struct rb_node *nd; | ||
718 | size_t ret = 0; | ||
719 | const char *sep = symbol_conf.field_sep; | ||
720 | int nr_rows = 0; | ||
721 | size_t linesz; | ||
722 | char *line = NULL; | ||
723 | unsigned indent; | ||
724 | |||
725 | init_rem_hits(); | ||
726 | |||
727 | hists__for_each_format(hists, fmt) | ||
728 | perf_hpp__reset_width(fmt, hists); | ||
729 | |||
730 | if (symbol_conf.col_width_list_str) | ||
731 | perf_hpp__set_user_width(symbol_conf.col_width_list_str); | ||
732 | |||
733 | if (show_header) | ||
734 | nr_rows += hists__fprintf_headers(hists, fp); | ||
735 | |||
736 | if (max_rows && nr_rows >= max_rows) | ||
713 | goto out; | 737 | goto out; |
714 | 738 | ||
715 | print_entries: | ||
716 | linesz = hists__sort_list_width(hists) + 3 + 1; | 739 | linesz = hists__sort_list_width(hists) + 3 + 1; |
717 | linesz += perf_hpp__color_overhead(); | 740 | linesz += perf_hpp__color_overhead(); |
718 | line = malloc(linesz); | 741 | line = malloc(linesz); |
@@ -734,7 +757,7 @@ print_entries: | |||
734 | if (percent < min_pcnt) | 757 | if (percent < min_pcnt) |
735 | continue; | 758 | continue; |
736 | 759 | ||
737 | ret += hist_entry__fprintf(h, max_cols, hists, line, linesz, fp); | 760 | ret += hist_entry__fprintf(h, max_cols, line, linesz, fp, use_callchain); |
738 | 761 | ||
739 | if (max_rows && ++nr_rows >= max_rows) | 762 | if (max_rows && ++nr_rows >= max_rows) |
740 | break; | 763 | break; |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 20aef90bf194..62b147366d01 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -387,9 +387,8 @@ void disable_buildid_cache(void) | |||
387 | no_buildid_cache = true; | 387 | no_buildid_cache = true; |
388 | } | 388 | } |
389 | 389 | ||
390 | static char *build_id_cache__dirname_from_path(const char *name, | 390 | char *build_id_cache__cachedir(const char *sbuild_id, const char *name, |
391 | bool is_kallsyms, bool is_vdso, | 391 | bool is_kallsyms, bool is_vdso) |
392 | const char *sbuild_id) | ||
393 | { | 392 | { |
394 | char *realname = (char *)name, *filename; | 393 | char *realname = (char *)name, *filename; |
395 | bool slash = is_kallsyms || is_vdso; | 394 | bool slash = is_kallsyms || is_vdso; |
@@ -417,8 +416,7 @@ int build_id_cache__list_build_ids(const char *pathname, | |||
417 | char *dir_name; | 416 | char *dir_name; |
418 | int ret = 0; | 417 | int ret = 0; |
419 | 418 | ||
420 | dir_name = build_id_cache__dirname_from_path(pathname, false, false, | 419 | dir_name = build_id_cache__cachedir(NULL, pathname, false, false); |
421 | NULL); | ||
422 | if (!dir_name) | 420 | if (!dir_name) |
423 | return -ENOMEM; | 421 | return -ENOMEM; |
424 | 422 | ||
@@ -444,8 +442,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, | |||
444 | goto out_free; | 442 | goto out_free; |
445 | } | 443 | } |
446 | 444 | ||
447 | dir_name = build_id_cache__dirname_from_path(name, is_kallsyms, | 445 | dir_name = build_id_cache__cachedir(sbuild_id, name, |
448 | is_vdso, sbuild_id); | 446 | is_kallsyms, is_vdso); |
449 | if (!dir_name) | 447 | if (!dir_name) |
450 | goto out_free; | 448 | goto out_free; |
451 | 449 | ||
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index e5435f46e48e..d8c7f2fc6a87 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h | |||
@@ -30,6 +30,8 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits); | |||
30 | int perf_session__write_buildid_table(struct perf_session *session, int fd); | 30 | int perf_session__write_buildid_table(struct perf_session *session, int fd); |
31 | int perf_session__cache_build_ids(struct perf_session *session); | 31 | int perf_session__cache_build_ids(struct perf_session *session); |
32 | 32 | ||
33 | char *build_id_cache__cachedir(const char *sbuild_id, const char *name, | ||
34 | bool is_kallsyms, bool is_vdso); | ||
33 | int build_id_cache__list_build_ids(const char *pathname, | 35 | int build_id_cache__list_build_ids(const char *pathname, |
34 | struct strlist **result); | 36 | struct strlist **result); |
35 | bool build_id_cache__cached(const char *sbuild_id); | 37 | bool build_id_cache__cached(const char *sbuild_id); |
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 8749eca3055f..31e09a4e8862 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c | |||
@@ -742,6 +742,9 @@ static void perf_config_set__purge(struct perf_config_set *set) | |||
742 | 742 | ||
743 | void perf_config_set__delete(struct perf_config_set *set) | 743 | void perf_config_set__delete(struct perf_config_set *set) |
744 | { | 744 | { |
745 | if (set == NULL) | ||
746 | return; | ||
747 | |||
745 | perf_config_set__purge(set); | 748 | perf_config_set__purge(set); |
746 | free(set); | 749 | free(set); |
747 | } | 750 | } |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index d1f19e0012d4..2515cfdb7365 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -1081,7 +1081,7 @@ int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp, | |||
1081 | struct perf_hpp_fmt *fmt, int printed) | 1081 | struct perf_hpp_fmt *fmt, int printed) |
1082 | { | 1082 | { |
1083 | if (!list_is_last(&fmt->list, &he->hists->hpp_list->fields)) { | 1083 | if (!list_is_last(&fmt->list, &he->hists->hpp_list->fields)) { |
1084 | const int width = fmt->width(fmt, hpp, hists_to_evsel(he->hists)); | 1084 | const int width = fmt->width(fmt, hpp, he->hists); |
1085 | if (printed < width) { | 1085 | if (printed < width) { |
1086 | advance_hpp(hpp, printed); | 1086 | advance_hpp(hpp, printed); |
1087 | printed = scnprintf(hpp->buf, hpp->size, "%-*s", width - printed, " "); | 1087 | printed = scnprintf(hpp->buf, hpp->size, "%-*s", width - printed, " "); |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 7b54ccf1b737..a19112872ff9 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -159,7 +159,8 @@ void events_stats__inc(struct events_stats *stats, u32 type); | |||
159 | size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); | 159 | size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); |
160 | 160 | ||
161 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | 161 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, |
162 | int max_cols, float min_pcnt, FILE *fp); | 162 | int max_cols, float min_pcnt, FILE *fp, |
163 | bool use_callchain); | ||
163 | size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp); | 164 | size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp); |
164 | 165 | ||
165 | void hists__filter_by_dso(struct hists *hists); | 166 | void hists__filter_by_dso(struct hists *hists); |
@@ -214,9 +215,9 @@ struct perf_hpp { | |||
214 | struct perf_hpp_fmt { | 215 | struct perf_hpp_fmt { |
215 | const char *name; | 216 | const char *name; |
216 | int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | 217 | int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
217 | struct perf_evsel *evsel); | 218 | struct hists *hists); |
218 | int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | 219 | int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
219 | struct perf_evsel *evsel); | 220 | struct hists *hists); |
220 | int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | 221 | int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
221 | struct hist_entry *he); | 222 | struct hist_entry *he); |
222 | int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | 223 | int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c index 75465f89a413..bbc368e7d1e4 100644 --- a/tools/perf/util/mem-events.c +++ b/tools/perf/util/mem-events.c | |||
@@ -10,18 +10,33 @@ | |||
10 | #include "debug.h" | 10 | #include "debug.h" |
11 | #include "symbol.h" | 11 | #include "symbol.h" |
12 | 12 | ||
13 | unsigned int perf_mem_events__loads_ldlat = 30; | ||
14 | |||
13 | #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s } | 15 | #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s } |
14 | 16 | ||
15 | struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = { | 17 | struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = { |
16 | E("ldlat-loads", "cpu/mem-loads,ldlat=30/P", "mem-loads"), | 18 | E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"), |
17 | E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"), | 19 | E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"), |
18 | }; | 20 | }; |
19 | #undef E | 21 | #undef E |
20 | 22 | ||
21 | #undef E | 23 | #undef E |
22 | 24 | ||
25 | static char mem_loads_name[100]; | ||
26 | static bool mem_loads_name__init; | ||
27 | |||
23 | char *perf_mem_events__name(int i) | 28 | char *perf_mem_events__name(int i) |
24 | { | 29 | { |
30 | if (i == PERF_MEM_EVENTS__LOAD) { | ||
31 | if (!mem_loads_name__init) { | ||
32 | mem_loads_name__init = true; | ||
33 | scnprintf(mem_loads_name, sizeof(mem_loads_name), | ||
34 | perf_mem_events[i].name, | ||
35 | perf_mem_events__loads_ldlat); | ||
36 | } | ||
37 | return mem_loads_name; | ||
38 | } | ||
39 | |||
25 | return (char *)perf_mem_events[i].name; | 40 | return (char *)perf_mem_events[i].name; |
26 | } | 41 | } |
27 | 42 | ||
diff --git a/tools/perf/util/mem-events.h b/tools/perf/util/mem-events.h index 5d6d93066a6e..7f69bf9d789d 100644 --- a/tools/perf/util/mem-events.h +++ b/tools/perf/util/mem-events.h | |||
@@ -18,6 +18,7 @@ enum { | |||
18 | }; | 18 | }; |
19 | 19 | ||
20 | extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX]; | 20 | extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX]; |
21 | extern unsigned int perf_mem_events__loads_ldlat; | ||
21 | 22 | ||
22 | int perf_mem_events__parse(const char *str); | 23 | int perf_mem_events__parse(const char *str); |
23 | int perf_mem_events__init(void); | 24 | int perf_mem_events__init(void); |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 74401a20106d..084756c17309 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -67,7 +67,6 @@ int e_snprintf(char *str, size_t size, const char *format, ...) | |||
67 | return ret; | 67 | return ret; |
68 | } | 68 | } |
69 | 69 | ||
70 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); | ||
71 | static struct machine *host_machine; | 70 | static struct machine *host_machine; |
72 | 71 | ||
73 | /* Initialize symbol maps and path of vmlinux/modules */ | 72 | /* Initialize symbol maps and path of vmlinux/modules */ |
@@ -1603,6 +1602,10 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev) | |||
1603 | p = strchr(argv[1], ':'); | 1602 | p = strchr(argv[1], ':'); |
1604 | if (p) { | 1603 | if (p) { |
1605 | tp->module = strndup(argv[1], p - argv[1]); | 1604 | tp->module = strndup(argv[1], p - argv[1]); |
1605 | if (!tp->module) { | ||
1606 | ret = -ENOMEM; | ||
1607 | goto out; | ||
1608 | } | ||
1606 | p++; | 1609 | p++; |
1607 | } else | 1610 | } else |
1608 | p = argv[1]; | 1611 | p = argv[1]; |
@@ -1712,7 +1715,7 @@ out: | |||
1712 | } | 1715 | } |
1713 | 1716 | ||
1714 | /* Compose only probe point (not argument) */ | 1717 | /* Compose only probe point (not argument) */ |
1715 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | 1718 | char *synthesize_perf_probe_point(struct perf_probe_point *pp) |
1716 | { | 1719 | { |
1717 | struct strbuf buf; | 1720 | struct strbuf buf; |
1718 | char *tmp, *ret = NULL; | 1721 | char *tmp, *ret = NULL; |
@@ -1751,30 +1754,36 @@ out: | |||
1751 | return ret; | 1754 | return ret; |
1752 | } | 1755 | } |
1753 | 1756 | ||
1754 | #if 0 | ||
1755 | char *synthesize_perf_probe_command(struct perf_probe_event *pev) | 1757 | char *synthesize_perf_probe_command(struct perf_probe_event *pev) |
1756 | { | 1758 | { |
1757 | char *buf; | 1759 | struct strbuf buf; |
1758 | int i, len, ret; | 1760 | char *tmp, *ret = NULL; |
1761 | int i; | ||
1759 | 1762 | ||
1760 | buf = synthesize_perf_probe_point(&pev->point); | 1763 | if (strbuf_init(&buf, 64)) |
1761 | if (!buf) | ||
1762 | return NULL; | 1764 | return NULL; |
1765 | if (pev->event) | ||
1766 | if (strbuf_addf(&buf, "%s:%s=", pev->group ?: PERFPROBE_GROUP, | ||
1767 | pev->event) < 0) | ||
1768 | goto out; | ||
1769 | |||
1770 | tmp = synthesize_perf_probe_point(&pev->point); | ||
1771 | if (!tmp || strbuf_addstr(&buf, tmp) < 0) | ||
1772 | goto out; | ||
1773 | free(tmp); | ||
1763 | 1774 | ||
1764 | len = strlen(buf); | ||
1765 | for (i = 0; i < pev->nargs; i++) { | 1775 | for (i = 0; i < pev->nargs; i++) { |
1766 | ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", | 1776 | tmp = synthesize_perf_probe_arg(pev->args + i); |
1767 | pev->args[i].name); | 1777 | if (!tmp || strbuf_addf(&buf, " %s", tmp) < 0) |
1768 | if (ret <= 0) { | 1778 | goto out; |
1769 | free(buf); | 1779 | free(tmp); |
1770 | return NULL; | ||
1771 | } | ||
1772 | len += ret; | ||
1773 | } | 1780 | } |
1774 | 1781 | ||
1775 | return buf; | 1782 | ret = strbuf_detach(&buf, NULL); |
1783 | out: | ||
1784 | strbuf_release(&buf); | ||
1785 | return ret; | ||
1776 | } | 1786 | } |
1777 | #endif | ||
1778 | 1787 | ||
1779 | static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, | 1788 | static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, |
1780 | struct strbuf *buf, int depth) | 1789 | struct strbuf *buf, int depth) |
@@ -2026,6 +2035,79 @@ void clear_perf_probe_event(struct perf_probe_event *pev) | |||
2026 | memset(pev, 0, sizeof(*pev)); | 2035 | memset(pev, 0, sizeof(*pev)); |
2027 | } | 2036 | } |
2028 | 2037 | ||
2038 | #define strdup_or_goto(str, label) \ | ||
2039 | ({ char *__p = NULL; if (str && !(__p = strdup(str))) goto label; __p; }) | ||
2040 | |||
2041 | static int perf_probe_point__copy(struct perf_probe_point *dst, | ||
2042 | struct perf_probe_point *src) | ||
2043 | { | ||
2044 | dst->file = strdup_or_goto(src->file, out_err); | ||
2045 | dst->function = strdup_or_goto(src->function, out_err); | ||
2046 | dst->lazy_line = strdup_or_goto(src->lazy_line, out_err); | ||
2047 | dst->line = src->line; | ||
2048 | dst->retprobe = src->retprobe; | ||
2049 | dst->offset = src->offset; | ||
2050 | return 0; | ||
2051 | |||
2052 | out_err: | ||
2053 | clear_perf_probe_point(dst); | ||
2054 | return -ENOMEM; | ||
2055 | } | ||
2056 | |||
2057 | static int perf_probe_arg__copy(struct perf_probe_arg *dst, | ||
2058 | struct perf_probe_arg *src) | ||
2059 | { | ||
2060 | struct perf_probe_arg_field *field, **ppfield; | ||
2061 | |||
2062 | dst->name = strdup_or_goto(src->name, out_err); | ||
2063 | dst->var = strdup_or_goto(src->var, out_err); | ||
2064 | dst->type = strdup_or_goto(src->type, out_err); | ||
2065 | |||
2066 | field = src->field; | ||
2067 | ppfield = &(dst->field); | ||
2068 | while (field) { | ||
2069 | *ppfield = zalloc(sizeof(*field)); | ||
2070 | if (!*ppfield) | ||
2071 | goto out_err; | ||
2072 | (*ppfield)->name = strdup_or_goto(field->name, out_err); | ||
2073 | (*ppfield)->index = field->index; | ||
2074 | (*ppfield)->ref = field->ref; | ||
2075 | field = field->next; | ||
2076 | ppfield = &((*ppfield)->next); | ||
2077 | } | ||
2078 | return 0; | ||
2079 | out_err: | ||
2080 | return -ENOMEM; | ||
2081 | } | ||
2082 | |||
2083 | int perf_probe_event__copy(struct perf_probe_event *dst, | ||
2084 | struct perf_probe_event *src) | ||
2085 | { | ||
2086 | int i; | ||
2087 | |||
2088 | dst->event = strdup_or_goto(src->event, out_err); | ||
2089 | dst->group = strdup_or_goto(src->group, out_err); | ||
2090 | dst->target = strdup_or_goto(src->target, out_err); | ||
2091 | dst->uprobes = src->uprobes; | ||
2092 | |||
2093 | if (perf_probe_point__copy(&dst->point, &src->point) < 0) | ||
2094 | goto out_err; | ||
2095 | |||
2096 | dst->args = zalloc(sizeof(struct perf_probe_arg) * src->nargs); | ||
2097 | if (!dst->args) | ||
2098 | goto out_err; | ||
2099 | dst->nargs = src->nargs; | ||
2100 | |||
2101 | for (i = 0; i < src->nargs; i++) | ||
2102 | if (perf_probe_arg__copy(&dst->args[i], &src->args[i]) < 0) | ||
2103 | goto out_err; | ||
2104 | return 0; | ||
2105 | |||
2106 | out_err: | ||
2107 | clear_perf_probe_event(dst); | ||
2108 | return -ENOMEM; | ||
2109 | } | ||
2110 | |||
2029 | void clear_probe_trace_event(struct probe_trace_event *tev) | 2111 | void clear_probe_trace_event(struct probe_trace_event *tev) |
2030 | { | 2112 | { |
2031 | struct probe_trace_arg_ref *ref, *next; | 2113 | struct probe_trace_arg_ref *ref, *next; |
@@ -2432,6 +2514,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
2432 | { | 2514 | { |
2433 | int i, fd, ret; | 2515 | int i, fd, ret; |
2434 | struct probe_trace_event *tev = NULL; | 2516 | struct probe_trace_event *tev = NULL; |
2517 | struct probe_cache *cache = NULL; | ||
2435 | struct strlist *namelist; | 2518 | struct strlist *namelist; |
2436 | 2519 | ||
2437 | fd = probe_file__open(PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0)); | 2520 | fd = probe_file__open(PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0)); |
@@ -2473,6 +2556,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
2473 | } | 2556 | } |
2474 | if (ret == -EINVAL && pev->uprobes) | 2557 | if (ret == -EINVAL && pev->uprobes) |
2475 | warn_uprobe_event_compat(tev); | 2558 | warn_uprobe_event_compat(tev); |
2559 | if (ret == 0 && probe_conf.cache) { | ||
2560 | cache = probe_cache__new(pev->target); | ||
2561 | if (!cache || | ||
2562 | probe_cache__add_entry(cache, pev, tevs, ntevs) < 0 || | ||
2563 | probe_cache__commit(cache) < 0) | ||
2564 | pr_warning("Failed to add event to probe cache\n"); | ||
2565 | probe_cache__delete(cache); | ||
2566 | } | ||
2476 | 2567 | ||
2477 | strlist__delete(namelist); | 2568 | strlist__delete(namelist); |
2478 | close_out: | 2569 | close_out: |
@@ -2501,9 +2592,6 @@ static int find_probe_functions(struct map *map, char *name, | |||
2501 | return found; | 2592 | return found; |
2502 | } | 2593 | } |
2503 | 2594 | ||
2504 | #define strdup_or_goto(str, label) \ | ||
2505 | ({ char *__p = strdup(str); if (!__p) goto label; __p; }) | ||
2506 | |||
2507 | void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused, | 2595 | void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused, |
2508 | struct probe_trace_event *tev __maybe_unused, | 2596 | struct probe_trace_event *tev __maybe_unused, |
2509 | struct map *map __maybe_unused, | 2597 | struct map *map __maybe_unused, |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 5a27eb4fad05..432b690d3f17 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -12,6 +12,7 @@ struct probe_conf { | |||
12 | bool show_location_range; | 12 | bool show_location_range; |
13 | bool force_add; | 13 | bool force_add; |
14 | bool no_inlines; | 14 | bool no_inlines; |
15 | bool cache; | ||
15 | int max_probes; | 16 | int max_probes; |
16 | }; | 17 | }; |
17 | extern struct probe_conf probe_conf; | 18 | extern struct probe_conf probe_conf; |
@@ -121,6 +122,10 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev); | |||
121 | char *synthesize_perf_probe_command(struct perf_probe_event *pev); | 122 | char *synthesize_perf_probe_command(struct perf_probe_event *pev); |
122 | char *synthesize_probe_trace_command(struct probe_trace_event *tev); | 123 | char *synthesize_probe_trace_command(struct probe_trace_event *tev); |
123 | char *synthesize_perf_probe_arg(struct perf_probe_arg *pa); | 124 | char *synthesize_perf_probe_arg(struct perf_probe_arg *pa); |
125 | char *synthesize_perf_probe_point(struct perf_probe_point *pp); | ||
126 | |||
127 | int perf_probe_event__copy(struct perf_probe_event *dst, | ||
128 | struct perf_probe_event *src); | ||
124 | 129 | ||
125 | /* Check the perf_probe_event needs debuginfo */ | 130 | /* Check the perf_probe_event needs debuginfo */ |
126 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); | 131 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); |
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 3fe6214970e6..25a40427003e 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c | |||
@@ -14,6 +14,7 @@ | |||
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | #include <sys/uio.h> | ||
17 | #include "util.h" | 18 | #include "util.h" |
18 | #include "event.h" | 19 | #include "event.h" |
19 | #include "strlist.h" | 20 | #include "strlist.h" |
@@ -324,3 +325,333 @@ int probe_file__del_events(int fd, struct strfilter *filter) | |||
324 | 325 | ||
325 | return ret; | 326 | return ret; |
326 | } | 327 | } |
328 | |||
329 | /* Caller must ensure to remove this entry from list */ | ||
330 | static void probe_cache_entry__delete(struct probe_cache_entry *entry) | ||
331 | { | ||
332 | if (entry) { | ||
333 | BUG_ON(!list_empty(&entry->node)); | ||
334 | |||
335 | strlist__delete(entry->tevlist); | ||
336 | clear_perf_probe_event(&entry->pev); | ||
337 | zfree(&entry->spev); | ||
338 | free(entry); | ||
339 | } | ||
340 | } | ||
341 | |||
342 | static struct probe_cache_entry * | ||
343 | probe_cache_entry__new(struct perf_probe_event *pev) | ||
344 | { | ||
345 | struct probe_cache_entry *entry = zalloc(sizeof(*entry)); | ||
346 | |||
347 | if (entry) { | ||
348 | INIT_LIST_HEAD(&entry->node); | ||
349 | entry->tevlist = strlist__new(NULL, NULL); | ||
350 | if (!entry->tevlist) | ||
351 | zfree(&entry); | ||
352 | else if (pev) { | ||
353 | entry->spev = synthesize_perf_probe_command(pev); | ||
354 | if (!entry->spev || | ||
355 | perf_probe_event__copy(&entry->pev, pev) < 0) { | ||
356 | probe_cache_entry__delete(entry); | ||
357 | return NULL; | ||
358 | } | ||
359 | } | ||
360 | } | ||
361 | |||
362 | return entry; | ||
363 | } | ||
364 | |||
365 | /* For the kernel probe caches, pass target = NULL */ | ||
366 | static int probe_cache__open(struct probe_cache *pcache, const char *target) | ||
367 | { | ||
368 | char cpath[PATH_MAX]; | ||
369 | char sbuildid[SBUILD_ID_SIZE]; | ||
370 | char *dir_name; | ||
371 | bool is_kallsyms = !target; | ||
372 | int ret, fd; | ||
373 | |||
374 | if (target) | ||
375 | ret = filename__sprintf_build_id(target, sbuildid); | ||
376 | else { | ||
377 | target = DSO__NAME_KALLSYMS; | ||
378 | ret = sysfs__sprintf_build_id("/", sbuildid); | ||
379 | } | ||
380 | if (ret < 0) { | ||
381 | pr_debug("Failed to get build-id from %s.\n", target); | ||
382 | return ret; | ||
383 | } | ||
384 | |||
385 | /* If we have no buildid cache, make it */ | ||
386 | if (!build_id_cache__cached(sbuildid)) { | ||
387 | ret = build_id_cache__add_s(sbuildid, target, | ||
388 | is_kallsyms, NULL); | ||
389 | if (ret < 0) { | ||
390 | pr_debug("Failed to add build-id cache: %s\n", target); | ||
391 | return ret; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | dir_name = build_id_cache__cachedir(sbuildid, target, is_kallsyms, | ||
396 | false); | ||
397 | if (!dir_name) | ||
398 | return -ENOMEM; | ||
399 | |||
400 | snprintf(cpath, PATH_MAX, "%s/probes", dir_name); | ||
401 | fd = open(cpath, O_CREAT | O_RDWR, 0644); | ||
402 | if (fd < 0) | ||
403 | pr_debug("Failed to open cache(%d): %s\n", fd, cpath); | ||
404 | free(dir_name); | ||
405 | pcache->fd = fd; | ||
406 | |||
407 | return fd; | ||
408 | } | ||
409 | |||
410 | static int probe_cache__load(struct probe_cache *pcache) | ||
411 | { | ||
412 | struct probe_cache_entry *entry = NULL; | ||
413 | char buf[MAX_CMDLEN], *p; | ||
414 | int ret = 0; | ||
415 | FILE *fp; | ||
416 | |||
417 | fp = fdopen(dup(pcache->fd), "r"); | ||
418 | if (!fp) | ||
419 | return -EINVAL; | ||
420 | |||
421 | while (!feof(fp)) { | ||
422 | if (!fgets(buf, MAX_CMDLEN, fp)) | ||
423 | break; | ||
424 | p = strchr(buf, '\n'); | ||
425 | if (p) | ||
426 | *p = '\0'; | ||
427 | if (buf[0] == '#') { /* #perf_probe_event */ | ||
428 | entry = probe_cache_entry__new(NULL); | ||
429 | if (!entry) { | ||
430 | ret = -ENOMEM; | ||
431 | goto out; | ||
432 | } | ||
433 | entry->spev = strdup(buf + 1); | ||
434 | if (entry->spev) | ||
435 | ret = parse_perf_probe_command(buf + 1, | ||
436 | &entry->pev); | ||
437 | else | ||
438 | ret = -ENOMEM; | ||
439 | if (ret < 0) { | ||
440 | probe_cache_entry__delete(entry); | ||
441 | goto out; | ||
442 | } | ||
443 | list_add_tail(&entry->node, &pcache->entries); | ||
444 | } else { /* trace_probe_event */ | ||
445 | if (!entry) { | ||
446 | ret = -EINVAL; | ||
447 | goto out; | ||
448 | } | ||
449 | strlist__add(entry->tevlist, buf); | ||
450 | } | ||
451 | } | ||
452 | out: | ||
453 | fclose(fp); | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | static struct probe_cache *probe_cache__alloc(void) | ||
458 | { | ||
459 | struct probe_cache *pcache = zalloc(sizeof(*pcache)); | ||
460 | |||
461 | if (pcache) { | ||
462 | INIT_LIST_HEAD(&pcache->entries); | ||
463 | pcache->fd = -EINVAL; | ||
464 | } | ||
465 | return pcache; | ||
466 | } | ||
467 | |||
468 | void probe_cache__purge(struct probe_cache *pcache) | ||
469 | { | ||
470 | struct probe_cache_entry *entry, *n; | ||
471 | |||
472 | list_for_each_entry_safe(entry, n, &pcache->entries, node) { | ||
473 | list_del_init(&entry->node); | ||
474 | probe_cache_entry__delete(entry); | ||
475 | } | ||
476 | } | ||
477 | |||
478 | void probe_cache__delete(struct probe_cache *pcache) | ||
479 | { | ||
480 | if (!pcache) | ||
481 | return; | ||
482 | |||
483 | probe_cache__purge(pcache); | ||
484 | if (pcache->fd > 0) | ||
485 | close(pcache->fd); | ||
486 | free(pcache); | ||
487 | } | ||
488 | |||
489 | struct probe_cache *probe_cache__new(const char *target) | ||
490 | { | ||
491 | struct probe_cache *pcache = probe_cache__alloc(); | ||
492 | int ret; | ||
493 | |||
494 | if (!pcache) | ||
495 | return NULL; | ||
496 | |||
497 | ret = probe_cache__open(pcache, target); | ||
498 | if (ret < 0) { | ||
499 | pr_debug("Cache open error: %d\n", ret); | ||
500 | goto out_err; | ||
501 | } | ||
502 | |||
503 | ret = probe_cache__load(pcache); | ||
504 | if (ret < 0) { | ||
505 | pr_debug("Cache read error: %d\n", ret); | ||
506 | goto out_err; | ||
507 | } | ||
508 | |||
509 | return pcache; | ||
510 | |||
511 | out_err: | ||
512 | probe_cache__delete(pcache); | ||
513 | return NULL; | ||
514 | } | ||
515 | |||
516 | static bool streql(const char *a, const char *b) | ||
517 | { | ||
518 | if (a == b) | ||
519 | return true; | ||
520 | |||
521 | if (!a || !b) | ||
522 | return false; | ||
523 | |||
524 | return !strcmp(a, b); | ||
525 | } | ||
526 | |||
527 | static struct probe_cache_entry * | ||
528 | probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev) | ||
529 | { | ||
530 | struct probe_cache_entry *entry = NULL; | ||
531 | char *cmd = synthesize_perf_probe_command(pev); | ||
532 | |||
533 | if (!cmd) | ||
534 | return NULL; | ||
535 | |||
536 | list_for_each_entry(entry, &pcache->entries, node) { | ||
537 | /* Hit if same event name or same command-string */ | ||
538 | if ((pev->event && | ||
539 | (streql(entry->pev.group, pev->group) && | ||
540 | streql(entry->pev.event, pev->event))) || | ||
541 | (!strcmp(entry->spev, cmd))) | ||
542 | goto found; | ||
543 | } | ||
544 | entry = NULL; | ||
545 | |||
546 | found: | ||
547 | free(cmd); | ||
548 | return entry; | ||
549 | } | ||
550 | |||
551 | int probe_cache__add_entry(struct probe_cache *pcache, | ||
552 | struct perf_probe_event *pev, | ||
553 | struct probe_trace_event *tevs, int ntevs) | ||
554 | { | ||
555 | struct probe_cache_entry *entry = NULL; | ||
556 | char *command; | ||
557 | int i, ret = 0; | ||
558 | |||
559 | if (!pcache || !pev || !tevs || ntevs <= 0) { | ||
560 | ret = -EINVAL; | ||
561 | goto out_err; | ||
562 | } | ||
563 | |||
564 | /* Remove old cache entry */ | ||
565 | entry = probe_cache__find(pcache, pev); | ||
566 | if (entry) { | ||
567 | list_del_init(&entry->node); | ||
568 | probe_cache_entry__delete(entry); | ||
569 | } | ||
570 | |||
571 | ret = -ENOMEM; | ||
572 | entry = probe_cache_entry__new(pev); | ||
573 | if (!entry) | ||
574 | goto out_err; | ||
575 | |||
576 | for (i = 0; i < ntevs; i++) { | ||
577 | if (!tevs[i].point.symbol) | ||
578 | continue; | ||
579 | |||
580 | command = synthesize_probe_trace_command(&tevs[i]); | ||
581 | if (!command) | ||
582 | goto out_err; | ||
583 | strlist__add(entry->tevlist, command); | ||
584 | free(command); | ||
585 | } | ||
586 | list_add_tail(&entry->node, &pcache->entries); | ||
587 | pr_debug("Added probe cache: %d\n", ntevs); | ||
588 | return 0; | ||
589 | |||
590 | out_err: | ||
591 | pr_debug("Failed to add probe caches\n"); | ||
592 | probe_cache_entry__delete(entry); | ||
593 | return ret; | ||
594 | } | ||
595 | |||
596 | static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd) | ||
597 | { | ||
598 | struct str_node *snode; | ||
599 | struct stat st; | ||
600 | struct iovec iov[3]; | ||
601 | int ret; | ||
602 | /* Save stat for rollback */ | ||
603 | ret = fstat(fd, &st); | ||
604 | if (ret < 0) | ||
605 | return ret; | ||
606 | |||
607 | pr_debug("Writing cache: #%s\n", entry->spev); | ||
608 | iov[0].iov_base = (void *)"#"; iov[0].iov_len = 1; | ||
609 | iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev); | ||
610 | iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1; | ||
611 | ret = writev(fd, iov, 3); | ||
612 | if (ret < (int)iov[1].iov_len + 2) | ||
613 | goto rollback; | ||
614 | |||
615 | strlist__for_each(snode, entry->tevlist) { | ||
616 | iov[0].iov_base = (void *)snode->s; | ||
617 | iov[0].iov_len = strlen(snode->s); | ||
618 | iov[1].iov_base = (void *)"\n"; iov[1].iov_len = 1; | ||
619 | ret = writev(fd, iov, 2); | ||
620 | if (ret < (int)iov[0].iov_len + 1) | ||
621 | goto rollback; | ||
622 | } | ||
623 | return 0; | ||
624 | |||
625 | rollback: | ||
626 | /* Rollback to avoid cache file corruption */ | ||
627 | if (ret > 0) | ||
628 | ret = -1; | ||
629 | if (ftruncate(fd, st.st_size) < 0) | ||
630 | ret = -2; | ||
631 | |||
632 | return ret; | ||
633 | } | ||
634 | |||
635 | int probe_cache__commit(struct probe_cache *pcache) | ||
636 | { | ||
637 | struct probe_cache_entry *entry; | ||
638 | int ret = 0; | ||
639 | |||
640 | /* TBD: if we do not update existing entries, skip it */ | ||
641 | ret = lseek(pcache->fd, 0, SEEK_SET); | ||
642 | if (ret < 0) | ||
643 | goto out; | ||
644 | |||
645 | ret = ftruncate(pcache->fd, 0); | ||
646 | if (ret < 0) | ||
647 | goto out; | ||
648 | |||
649 | list_for_each_entry(entry, &pcache->entries, node) { | ||
650 | ret = probe_cache_entry__write(entry, pcache->fd); | ||
651 | pr_debug("Cache committed: %d\n", ret); | ||
652 | if (ret < 0) | ||
653 | break; | ||
654 | } | ||
655 | out: | ||
656 | return ret; | ||
657 | } | ||
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index 18ac9cf51c34..d872e3df7e59 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h | |||
@@ -5,6 +5,19 @@ | |||
5 | #include "strfilter.h" | 5 | #include "strfilter.h" |
6 | #include "probe-event.h" | 6 | #include "probe-event.h" |
7 | 7 | ||
8 | /* Cache of probe definitions */ | ||
9 | struct probe_cache_entry { | ||
10 | struct list_head node; | ||
11 | struct perf_probe_event pev; | ||
12 | char *spev; | ||
13 | struct strlist *tevlist; | ||
14 | }; | ||
15 | |||
16 | struct probe_cache { | ||
17 | int fd; | ||
18 | struct list_head entries; | ||
19 | }; | ||
20 | |||
8 | #define PF_FL_UPROBE 1 | 21 | #define PF_FL_UPROBE 1 |
9 | #define PF_FL_RW 2 | 22 | #define PF_FL_RW 2 |
10 | 23 | ||
@@ -18,5 +31,12 @@ int probe_file__get_events(int fd, struct strfilter *filter, | |||
18 | struct strlist *plist); | 31 | struct strlist *plist); |
19 | int probe_file__del_strlist(int fd, struct strlist *namelist); | 32 | int probe_file__del_strlist(int fd, struct strlist *namelist); |
20 | 33 | ||
34 | struct probe_cache *probe_cache__new(const char *target); | ||
35 | int probe_cache__add_entry(struct probe_cache *pcache, | ||
36 | struct perf_probe_event *pev, | ||
37 | struct probe_trace_event *tevs, int ntevs); | ||
38 | int probe_cache__commit(struct probe_cache *pcache); | ||
39 | void probe_cache__purge(struct probe_cache *pcache); | ||
40 | void probe_cache__delete(struct probe_cache *pcache); | ||
21 | 41 | ||
22 | #endif | 42 | #endif |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index c4e9bd70723c..896d34ebcc1e 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -1218,7 +1218,7 @@ struct sort_entry sort_mem_daddr_dso = { | |||
1218 | .se_header = "Data Object", | 1218 | .se_header = "Data Object", |
1219 | .se_cmp = sort__dso_daddr_cmp, | 1219 | .se_cmp = sort__dso_daddr_cmp, |
1220 | .se_snprintf = hist_entry__dso_daddr_snprintf, | 1220 | .se_snprintf = hist_entry__dso_daddr_snprintf, |
1221 | .se_width_idx = HISTC_MEM_DADDR_SYMBOL, | 1221 | .se_width_idx = HISTC_MEM_DADDR_DSO, |
1222 | }; | 1222 | }; |
1223 | 1223 | ||
1224 | struct sort_entry sort_mem_locked = { | 1224 | struct sort_entry sort_mem_locked = { |
@@ -1488,7 +1488,7 @@ void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) | |||
1488 | } | 1488 | } |
1489 | 1489 | ||
1490 | static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | 1490 | static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
1491 | struct perf_evsel *evsel) | 1491 | struct hists *hists) |
1492 | { | 1492 | { |
1493 | struct hpp_sort_entry *hse; | 1493 | struct hpp_sort_entry *hse; |
1494 | size_t len = fmt->user_len; | 1494 | size_t len = fmt->user_len; |
@@ -1496,14 +1496,14 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | |||
1496 | hse = container_of(fmt, struct hpp_sort_entry, hpp); | 1496 | hse = container_of(fmt, struct hpp_sort_entry, hpp); |
1497 | 1497 | ||
1498 | if (!len) | 1498 | if (!len) |
1499 | len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx); | 1499 | len = hists__col_len(hists, hse->se->se_width_idx); |
1500 | 1500 | ||
1501 | return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name); | 1501 | return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name); |
1502 | } | 1502 | } |
1503 | 1503 | ||
1504 | static int __sort__hpp_width(struct perf_hpp_fmt *fmt, | 1504 | static int __sort__hpp_width(struct perf_hpp_fmt *fmt, |
1505 | struct perf_hpp *hpp __maybe_unused, | 1505 | struct perf_hpp *hpp __maybe_unused, |
1506 | struct perf_evsel *evsel) | 1506 | struct hists *hists) |
1507 | { | 1507 | { |
1508 | struct hpp_sort_entry *hse; | 1508 | struct hpp_sort_entry *hse; |
1509 | size_t len = fmt->user_len; | 1509 | size_t len = fmt->user_len; |
@@ -1511,7 +1511,7 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt, | |||
1511 | hse = container_of(fmt, struct hpp_sort_entry, hpp); | 1511 | hse = container_of(fmt, struct hpp_sort_entry, hpp); |
1512 | 1512 | ||
1513 | if (!len) | 1513 | if (!len) |
1514 | len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx); | 1514 | len = hists__col_len(hists, hse->se->se_width_idx); |
1515 | 1515 | ||
1516 | return len; | 1516 | return len; |
1517 | } | 1517 | } |
@@ -1793,7 +1793,7 @@ static void update_dynamic_len(struct hpp_dynamic_entry *hde, | |||
1793 | } | 1793 | } |
1794 | 1794 | ||
1795 | static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | 1795 | static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
1796 | struct perf_evsel *evsel __maybe_unused) | 1796 | struct hists *hists __maybe_unused) |
1797 | { | 1797 | { |
1798 | struct hpp_dynamic_entry *hde; | 1798 | struct hpp_dynamic_entry *hde; |
1799 | size_t len = fmt->user_len; | 1799 | size_t len = fmt->user_len; |
@@ -1808,7 +1808,7 @@ static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | |||
1808 | 1808 | ||
1809 | static int __sort__hde_width(struct perf_hpp_fmt *fmt, | 1809 | static int __sort__hde_width(struct perf_hpp_fmt *fmt, |
1810 | struct perf_hpp *hpp __maybe_unused, | 1810 | struct perf_hpp *hpp __maybe_unused, |
1811 | struct perf_evsel *evsel __maybe_unused) | 1811 | struct hists *hists __maybe_unused) |
1812 | { | 1812 | { |
1813 | struct hpp_dynamic_entry *hde; | 1813 | struct hpp_dynamic_entry *hde; |
1814 | size_t len = fmt->user_len; | 1814 | size_t len = fmt->user_len; |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 23504ad5d6dd..e08b9a092a23 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -97,20 +97,17 @@ int rm_rf(char *path) | |||
97 | scnprintf(namebuf, sizeof(namebuf), "%s/%s", | 97 | scnprintf(namebuf, sizeof(namebuf), "%s/%s", |
98 | path, d->d_name); | 98 | path, d->d_name); |
99 | 99 | ||
100 | ret = stat(namebuf, &statbuf); | 100 | /* We have to check symbolic link itself */ |
101 | ret = lstat(namebuf, &statbuf); | ||
101 | if (ret < 0) { | 102 | if (ret < 0) { |
102 | pr_debug("stat failed: %s\n", namebuf); | 103 | pr_debug("stat failed: %s\n", namebuf); |
103 | break; | 104 | break; |
104 | } | 105 | } |
105 | 106 | ||
106 | if (S_ISREG(statbuf.st_mode)) | 107 | if (S_ISDIR(statbuf.st_mode)) |
107 | ret = unlink(namebuf); | ||
108 | else if (S_ISDIR(statbuf.st_mode)) | ||
109 | ret = rm_rf(namebuf); | 108 | ret = rm_rf(namebuf); |
110 | else { | 109 | else |
111 | pr_debug("unknown file: %s\n", namebuf); | 110 | ret = unlink(namebuf); |
112 | ret = -1; | ||
113 | } | ||
114 | } | 111 | } |
115 | closedir(dir); | 112 | closedir(dir); |
116 | 113 | ||