aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-06-16 04:27:35 -0400
committerIngo Molnar <mingo@kernel.org>2016-06-16 04:27:35 -0400
commit02469a95096a549508c5adf61d84a1d72851c85b (patch)
tree130c83a2f6937ffa81d00ec661d223cab7a37715
parent2c95afc1e83d93fac3be6923465e1753c2c53b0a (diff)
parent2fd457a34525ea3bc609e377b46af759af8a7934 (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.txt3
-rw-r--r--tools/perf/Documentation/perf-probe.txt4
-rw-r--r--tools/perf/builtin-diff.c7
-rw-r--r--tools/perf/builtin-mem.c1
-rw-r--r--tools/perf/builtin-probe.c1
-rw-r--r--tools/perf/builtin-report.c3
-rw-r--r--tools/perf/builtin-top.c2
-rw-r--r--tools/perf/config/Makefile3
-rw-r--r--tools/perf/ui/browsers/hists.c39
-rw-r--r--tools/perf/ui/gtk/hists.c2
-rw-r--r--tools/perf/ui/hist.c11
-rw-r--r--tools/perf/ui/stdio/hist.c133
-rw-r--r--tools/perf/util/build-id.c12
-rw-r--r--tools/perf/util/build-id.h2
-rw-r--r--tools/perf/util/config.c3
-rw-r--r--tools/perf/util/hist.c2
-rw-r--r--tools/perf/util/hist.h7
-rw-r--r--tools/perf/util/mem-events.c17
-rw-r--r--tools/perf/util/mem-events.h1
-rw-r--r--tools/perf/util/probe-event.c128
-rw-r--r--tools/perf/util/probe-event.h5
-rw-r--r--tools/perf/util/probe-file.c331
-rw-r--r--tools/perf/util/probe-file.h20
-rw-r--r--tools/perf/util/sort.c14
-rw-r--r--tools/perf/util/util.c13
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
59SEE ALSO 62SEE ALSO
60-------- 63--------
61linkperf:perf-record[1], linkperf:perf-report[1] 64linkperf: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
672static void data__fprintf(void) 673static 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
1046static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 1047static 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
1056static int hpp__width(struct perf_hpp_fmt *fmt, 1057static 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
301static void prompt_integer(int *target, const char *msg) 301static 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)
452endif 455endif
453 456
454ifndef NO_LIBAUDIT 457ifndef 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
1625static void hist_browser__show_headers(struct hist_browser *browser) 1625static 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
1637static 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
1649static 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
1640static void ui_browser__hists_init_top(struct ui_browser *browser) 1657static 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
216static int hpp__width_fn(struct perf_hpp_fmt *fmt, 216static 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
231static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 232static 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
494static int hist_entry__fprintf(struct hist_entry *he, size_t size, 494static 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
625size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 626static int
626 int max_cols, float min_pcnt, FILE *fp) 627hists__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) { 642static int
659 list_for_each_entry(fmt_node, &hists->hpp_formats, list) { 643hists__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
695static 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
712size_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
715print_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
390static char *build_id_cache__dirname_from_path(const char *name, 390char *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);
30int perf_session__write_buildid_table(struct perf_session *session, int fd); 30int perf_session__write_buildid_table(struct perf_session *session, int fd);
31int perf_session__cache_build_ids(struct perf_session *session); 31int perf_session__cache_build_ids(struct perf_session *session);
32 32
33char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
34 bool is_kallsyms, bool is_vdso);
33int build_id_cache__list_build_ids(const char *pathname, 35int build_id_cache__list_build_ids(const char *pathname,
34 struct strlist **result); 36 struct strlist **result);
35bool build_id_cache__cached(const char *sbuild_id); 37bool 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
743void perf_config_set__delete(struct perf_config_set *set) 743void 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);
159size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); 159size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
160 160
161size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 161size_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);
163size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp); 164size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp);
164 165
165void hists__filter_by_dso(struct hists *hists); 166void hists__filter_by_dso(struct hists *hists);
@@ -214,9 +215,9 @@ struct perf_hpp {
214struct perf_hpp_fmt { 215struct 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
13unsigned 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
15struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = { 17struct 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
25static char mem_loads_name[100];
26static bool mem_loads_name__init;
27
23char *perf_mem_events__name(int i) 28char *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
20extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX]; 20extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX];
21extern unsigned int perf_mem_events__loads_ldlat;
21 22
22int perf_mem_events__parse(const char *str); 23int perf_mem_events__parse(const char *str);
23int perf_mem_events__init(void); 24int 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
70static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
71static struct machine *host_machine; 70static 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) */
1715static char *synthesize_perf_probe_point(struct perf_probe_point *pp) 1718char *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
1755char *synthesize_perf_probe_command(struct perf_probe_event *pev) 1757char *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);
1783out:
1784 strbuf_release(&buf);
1785 return ret;
1776} 1786}
1777#endif
1778 1787
1779static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, 1788static 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
2041static 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
2052out_err:
2053 clear_perf_probe_point(dst);
2054 return -ENOMEM;
2055}
2056
2057static 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;
2079out_err:
2080 return -ENOMEM;
2081}
2082
2083int 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
2106out_err:
2107 clear_perf_probe_event(dst);
2108 return -ENOMEM;
2109}
2110
2029void clear_probe_trace_event(struct probe_trace_event *tev) 2111void 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);
2478close_out: 2569close_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
2507void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused, 2595void __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};
17extern struct probe_conf probe_conf; 18extern struct probe_conf probe_conf;
@@ -121,6 +122,10 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev);
121char *synthesize_perf_probe_command(struct perf_probe_event *pev); 122char *synthesize_perf_probe_command(struct perf_probe_event *pev);
122char *synthesize_probe_trace_command(struct probe_trace_event *tev); 123char *synthesize_probe_trace_command(struct probe_trace_event *tev);
123char *synthesize_perf_probe_arg(struct perf_probe_arg *pa); 124char *synthesize_perf_probe_arg(struct perf_probe_arg *pa);
125char *synthesize_perf_probe_point(struct perf_probe_point *pp);
126
127int 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 */
126bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); 131bool 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 */
330static 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
342static struct probe_cache_entry *
343probe_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 */
366static 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
410static 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 }
452out:
453 fclose(fp);
454 return ret;
455}
456
457static 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
468void 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
478void 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
489struct 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
511out_err:
512 probe_cache__delete(pcache);
513 return NULL;
514}
515
516static 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
527static struct probe_cache_entry *
528probe_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
546found:
547 free(cmd);
548 return entry;
549}
550
551int 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
590out_err:
591 pr_debug("Failed to add probe caches\n");
592 probe_cache_entry__delete(entry);
593 return ret;
594}
595
596static 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
625rollback:
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
635int 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 }
655out:
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 */
9struct probe_cache_entry {
10 struct list_head node;
11 struct perf_probe_event pev;
12 char *spev;
13 struct strlist *tevlist;
14};
15
16struct 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);
19int probe_file__del_strlist(int fd, struct strlist *namelist); 32int probe_file__del_strlist(int fd, struct strlist *namelist);
20 33
34struct probe_cache *probe_cache__new(const char *target);
35int probe_cache__add_entry(struct probe_cache *pcache,
36 struct perf_probe_event *pev,
37 struct probe_trace_event *tevs, int ntevs);
38int probe_cache__commit(struct probe_cache *pcache);
39void probe_cache__purge(struct probe_cache *pcache);
40void 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
1224struct sort_entry sort_mem_locked = { 1224struct 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
1490static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 1490static 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
1504static int __sort__hpp_width(struct perf_hpp_fmt *fmt, 1504static 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
1795static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 1795static 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
1809static int __sort__hde_width(struct perf_hpp_fmt *fmt, 1809static 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