Merge tag 'perf-core-for-mingo-20160615' of git://git.kernel.org/pub/scm/linux/kernel...
authorIngo Molnar <mingo@kernel.org>
Thu, 16 Jun 2016 08:27:35 +0000 (10:27 +0200)
committerIngo Molnar <mingo@kernel.org>
Thu, 16 Jun 2016 08:27:35 +0000 (10:27 +0200)
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>
25 files changed:
tools/perf/Documentation/perf-mem.txt
tools/perf/Documentation/perf-probe.txt
tools/perf/builtin-diff.c
tools/perf/builtin-mem.c
tools/perf/builtin-probe.c
tools/perf/builtin-report.c
tools/perf/builtin-top.c
tools/perf/config/Makefile
tools/perf/ui/browsers/hists.c
tools/perf/ui/gtk/hists.c
tools/perf/ui/hist.c
tools/perf/ui/stdio/hist.c
tools/perf/util/build-id.c
tools/perf/util/build-id.h
tools/perf/util/config.c
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/mem-events.c
tools/perf/util/mem-events.h
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h
tools/perf/util/probe-file.c
tools/perf/util/probe-file.h
tools/perf/util/sort.c
tools/perf/util/util.c

index 1d6092c460dd085401cbe084fed2166d84de105c..73496320fca3f871ac50024aff4a5e1b7def582b 100644 (file)
@@ -56,6 +56,9 @@ OPTIONS
 --all-user::
        Configure all used events to run in user space.
 
+--ldload::
+       Specify desired latency for loads event.
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-report[1]
index 3a8a9ba2b0412aba28f1796e283106f84ec63266..947db6fe512c81990b4bfa519f885f76af55d554 100644 (file)
@@ -109,6 +109,10 @@ OPTIONS
        Dry run. With this option, --add and --del doesn't execute actual
        adding and removal operations.
 
+--cache::
+       Cache the probes (with --add option). Any events which successfully added
+       are also stored in the cache file.
+
 --max-probes=NUM::
        Set the maximum number of probe points for an event. Default is 128.
 
index f7645a42708eb2223069b3555df0a325c2c635d8..7f628f9c2fb43f7084a360444805c217053f1ffc 100644 (file)
@@ -666,7 +666,8 @@ static void hists__process(struct hists *hists)
        hists__precompute(hists);
        hists__output_resort(hists, NULL);
 
-       hists__fprintf(hists, true, 0, 0, 0, stdout);
+       hists__fprintf(hists, true, 0, 0, 0, stdout,
+                      symbol_conf.use_callchain);
 }
 
 static void data__fprintf(void)
@@ -1044,7 +1045,7 @@ static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
 }
 
 static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
-                      struct perf_evsel *evsel __maybe_unused)
+                      struct hists *hists __maybe_unused)
 {
        struct diff_hpp_fmt *dfmt =
                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,
 
 static int hpp__width(struct perf_hpp_fmt *fmt,
                      struct perf_hpp *hpp __maybe_unused,
-                     struct perf_evsel *evsel __maybe_unused)
+                     struct hists *hists __maybe_unused)
 {
        struct diff_hpp_fmt *dfmt =
                container_of(fmt, struct diff_hpp_fmt, fmt);
index 1dc140c5481d61a1639de2fb5bcb2e1021b0dfc5..d608a2c9e48cd219e82697bdfa9331a477e9eeed 100644 (file)
@@ -67,6 +67,7 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
        OPT_CALLBACK('e', "event", &mem, "event",
                     "event selector. use 'perf mem record -e list' to list available events",
                     parse_record_events),
+       OPT_UINTEGER(0, "ldlat", &perf_mem_events__loads_ldlat, "mem-loads latency"),
        OPT_INCR('v', "verbose", &verbose,
                 "be more verbose (show counter open errors, etc)"),
        OPT_BOOLEAN('U', "--all-user", &all_user, "collect only user level data"),
index 9af859b28b15cc74edbf8041278ec2ee9e47104e..6d7ab43164495714f129b40c24d02b019bd22106 100644 (file)
@@ -512,6 +512,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                    "Enable symbol demangling"),
        OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
                    "Enable kernel symbol demangling"),
+       OPT_BOOLEAN(0, "cache", &probe_conf.cache, "Manipulate probe cache"),
        OPT_END()
        };
        int ret;
index a87cb338bdf14b2d49c19b840fb99b3265e68997..9f36b236f0f9b883e07dfbc6eca33a95f8abfe2d 100644 (file)
@@ -370,7 +370,8 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
                        continue;
 
                hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
-               hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
+               hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout,
+                              symbol_conf.use_callchain);
                fprintf(stdout, "\n\n");
        }
 
index 2a6cc254ad0c3e09f65f49b5b0169890a5579ac0..81dba80a42b55f0a476b106fd9056e02f2d40e8c 100644 (file)
@@ -295,7 +295,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
        hists__output_recalc_col_len(hists, top->print_entries - printed);
        putchar('\n');
        hists__fprintf(hists, false, top->print_entries - printed, win_width,
-                      top->min_percent, stdout);
+                      top->min_percent, stdout, symbol_conf.use_callchain);
 }
 
 static void prompt_integer(int *target, const char *msg)
index 098874b999819dedc9c1107fabbb2381f839d6e5..80018feb99c0095603d6bf4fb7b2132c8c7ac353 100644 (file)
@@ -365,6 +365,7 @@ ifndef NO_LIBUNWIND
     $(call detected,CONFIG_LIBUNWIND_X86)
     CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT
     LDFLAGS += -lunwind-x86
+    EXTLIBS_LIBUNWIND += -lunwind-x86
     have_libunwind = 1
   endif
 
@@ -372,6 +373,7 @@ ifndef NO_LIBUNWIND
     $(call detected,CONFIG_LIBUNWIND_AARCH64)
     CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT
     LDFLAGS += -lunwind-aarch64
+    EXTLIBS_LIBUNWIND += -lunwind-aarch64
     have_libunwind = 1
     $(call feature_check,libunwind-debug-frame-aarch64)
     ifneq ($(feature-libunwind-debug-frame-aarch64), 1)
@@ -449,6 +451,7 @@ ifndef NO_LIBUNWIND
   CFLAGS  += -DHAVE_LIBUNWIND_SUPPORT
   CFLAGS  += $(LIBUNWIND_CFLAGS)
   LDFLAGS += $(LIBUNWIND_LDFLAGS)
+  EXTLIBS += $(EXTLIBS_LIBUNWIND)
 endif
 
 ifndef NO_LIBAUDIT
index 538bae880bfee592f9ed962a4b99b7a19027c7a8..b1b60544a545941e149fb089ef8b19802fb6dfce 100644 (file)
@@ -1470,7 +1470,7 @@ static int hist_browser__show_no_entry(struct hist_browser *browser,
                    column++ < browser->b.horiz_scroll)
                        continue;
 
-               ret = fmt->width(fmt, NULL, hists_to_evsel(browser->hists));
+               ret = fmt->width(fmt, NULL, browser->hists);
 
                if (first) {
                        /* for folded sign */
@@ -1531,7 +1531,7 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *
                if (perf_hpp__should_skip(fmt, hists)  || column++ < browser->b.horiz_scroll)
                        continue;
 
-               ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
+               ret = fmt->header(fmt, &dummy_hpp, hists);
                if (advance_hpp_check(&dummy_hpp, ret))
                        break;
 
@@ -1568,7 +1568,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
                if (column++ < browser->b.horiz_scroll)
                        continue;
 
-               ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
+               ret = fmt->header(fmt, &dummy_hpp, hists);
                if (advance_hpp_check(&dummy_hpp, ret))
                        break;
 
@@ -1605,7 +1605,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
                        }
                        first_col = false;
 
-                       ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
+                       ret = fmt->header(fmt, &dummy_hpp, hists);
                        dummy_hpp.buf[ret] = '\0';
 
                        start = trim(dummy_hpp.buf);
@@ -1622,21 +1622,38 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
        return ret;
 }
 
-static void hist_browser__show_headers(struct hist_browser *browser)
+static void hists_browser__hierarchy_headers(struct hist_browser *browser)
 {
        char headers[1024];
 
-       if (symbol_conf.report_hierarchy)
-               hists_browser__scnprintf_hierarchy_headers(browser, headers,
-                                                          sizeof(headers));
-       else
-               hists_browser__scnprintf_headers(browser, headers,
-                                                sizeof(headers));
+       hists_browser__scnprintf_hierarchy_headers(browser, headers,
+                                                  sizeof(headers));
+
        ui_browser__gotorc(&browser->b, 0, 0);
        ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
        ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
 }
 
+static void hists_browser__headers(struct hist_browser *browser)
+{
+       char headers[1024];
+
+       hists_browser__scnprintf_headers(browser, headers,
+                                        sizeof(headers));
+
+       ui_browser__gotorc(&browser->b, 0, 0);
+       ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
+       ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
+}
+
+static void hist_browser__show_headers(struct hist_browser *browser)
+{
+       if (symbol_conf.report_hierarchy)
+               hists_browser__hierarchy_headers(browser);
+       else
+               hists_browser__headers(browser);
+}
+
 static void ui_browser__hists_init_top(struct ui_browser *browser)
 {
        if (browser->top == NULL) {
index 932adfaa05af2cf2ea8860f712244d4d647adea3..e5c1325b03407af8008f51c1d891dd60c452f06d 100644 (file)
@@ -549,7 +549,7 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
                                strcat(buf, "+");
                        first_col = false;
 
-                       fmt->header(fmt, &hpp, hists_to_evsel(hists));
+                       fmt->header(fmt, &hpp, hists);
                        strcat(buf, ltrim(rtrim(hpp.buf)));
                }
        }
index af07ffb129ca5ba24b2459fee6ee659d8c71e97f..6940745aa77c65a25f5beb07242093192fcbee7f 100644 (file)
@@ -215,9 +215,10 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,
 
 static int hpp__width_fn(struct perf_hpp_fmt *fmt,
                         struct perf_hpp *hpp __maybe_unused,
-                        struct perf_evsel *evsel)
+                        struct hists *hists)
 {
        int len = fmt->user_len ?: fmt->len;
+       struct perf_evsel *evsel = hists_to_evsel(hists);
 
        if (symbol_conf.event_group)
                len = max(len, evsel->nr_members * fmt->len);
@@ -229,9 +230,9 @@ static int hpp__width_fn(struct perf_hpp_fmt *fmt,
 }
 
 static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
-                         struct perf_evsel *evsel)
+                         struct hists *hists)
 {
-       int len = hpp__width_fn(fmt, hpp, evsel);
+       int len = hpp__width_fn(fmt, hpp, hists);
        return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
 }
 
@@ -632,7 +633,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
                else
                        ret += 2;
 
-               ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
+               ret += fmt->width(fmt, &dummy_hpp, hists);
        }
 
        if (verbose && hists__has(hists, sym)) /* Addr + origin */
@@ -657,7 +658,7 @@ unsigned int hists__overhead_width(struct hists *hists)
                else
                        ret += 2;
 
-               ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
+               ret += fmt->width(fmt, &dummy_hpp, hists);
        }
 
        return ret;
index 560eb47d56f945acbbdc188d6a8fb3e407faf41e..f04a6311207935fc022ca0b9557db8639d6c00a9 100644 (file)
@@ -492,14 +492,15 @@ out:
 }
 
 static int hist_entry__fprintf(struct hist_entry *he, size_t size,
-                              struct hists *hists,
-                              char *bf, size_t bfsz, FILE *fp)
+                              char *bf, size_t bfsz, FILE *fp,
+                              bool use_callchain)
 {
        int ret;
        struct perf_hpp hpp = {
                .buf            = bf,
                .size           = size,
        };
+       struct hists *hists = he->hists;
        u64 total_period = hists->stats.total_period;
 
        if (size == 0 || size > bfsz)
@@ -512,7 +513,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
 
        ret = fprintf(fp, "%s\n", bf);
 
-       if (symbol_conf.use_callchain)
+       if (use_callchain)
                ret += hist_entry_callchain__fprintf(he, total_period, 0, fp);
 
        return ret;
@@ -548,7 +549,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
                                    struct perf_hpp_list_node, list);
 
        perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
-               fmt->header(fmt, hpp, hists_to_evsel(hists));
+               fmt->header(fmt, hpp, hists);
                fprintf(fp, "%s%s", hpp->buf, sep ?: "  ");
        }
 
@@ -568,7 +569,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
                                header_width += fprintf(fp, "+");
                        first_col = false;
 
-                       fmt->header(fmt, hpp, hists_to_evsel(hists));
+                       fmt->header(fmt, hpp, hists);
 
                        header_width += fprintf(fp, "%s", trim(hpp->buf));
                }
@@ -589,7 +590,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
                        fprintf(fp, "%s", sep ?: "..");
                first_col = false;
 
-               width = fmt->width(fmt, hpp, hists_to_evsel(hists));
+               width = fmt->width(fmt, hpp, hists);
                fprintf(fp, "%.*s", width, dots);
        }
 
@@ -606,7 +607,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
                                width++;  /* for '+' sign between column header */
                        first_col = false;
 
-                       width += fmt->width(fmt, hpp, hists_to_evsel(hists));
+                       width += fmt->width(fmt, hpp, hists);
                }
 
                if (width > header_width)
@@ -622,47 +623,31 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
        return 2;
 }
 
-size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
-                     int max_cols, float min_pcnt, FILE *fp)
+static int
+hists__fprintf_hierarchy_headers(struct hists *hists,
+                                struct perf_hpp *hpp,
+                                FILE *fp)
 {
-       struct perf_hpp_fmt *fmt;
        struct perf_hpp_list_node *fmt_node;
-       struct rb_node *nd;
-       size_t ret = 0;
-       unsigned int width;
-       const char *sep = symbol_conf.field_sep;
-       int nr_rows = 0;
-       char bf[96];
-       struct perf_hpp dummy_hpp = {
-               .buf    = bf,
-               .size   = sizeof(bf),
-       };
-       bool first = true;
-       size_t linesz;
-       char *line = NULL;
-       unsigned indent;
-
-       init_rem_hits();
-
-       hists__for_each_format(hists, fmt)
-               perf_hpp__reset_width(fmt, hists);
-
-       if (symbol_conf.col_width_list_str)
-               perf_hpp__set_user_width(symbol_conf.col_width_list_str);
+       struct perf_hpp_fmt *fmt;
 
-       if (!show_header)
-               goto print_entries;
+       list_for_each_entry(fmt_node, &hists->hpp_formats, list) {
+               perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
+                       perf_hpp__reset_width(fmt, hists);
+       }
 
-       fprintf(fp, "# ");
+       return print_hierarchy_header(hists, hpp, symbol_conf.field_sep, fp);
+}
 
-       if (symbol_conf.report_hierarchy) {
-               list_for_each_entry(fmt_node, &hists->hpp_formats, list) {
-                       perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
-                               perf_hpp__reset_width(fmt, hists);
-               }
-               nr_rows += print_hierarchy_header(hists, &dummy_hpp, sep, fp);
-               goto print_entries;
-       }
+static int
+hists__fprintf_standard_headers(struct hists *hists,
+                               struct perf_hpp *hpp,
+                               FILE *fp)
+{
+       struct perf_hpp_fmt *fmt;
+       unsigned int width;
+       const char *sep = symbol_conf.field_sep;
+       bool first = true;
 
        hists__for_each_format(hists, fmt) {
                if (perf_hpp__should_skip(fmt, hists))
@@ -673,16 +658,14 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
                else
                        first = false;
 
-               fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
-               fprintf(fp, "%s", bf);
+               fmt->header(fmt, hpp, hists);
+               fprintf(fp, "%s", hpp->buf);
        }
 
        fprintf(fp, "\n");
-       if (max_rows && ++nr_rows >= max_rows)
-               goto out;
 
        if (sep)
-               goto print_entries;
+               return 1;
 
        first = true;
 
@@ -699,20 +682,60 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
                else
                        first = false;
 
-               width = fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
+               width = fmt->width(fmt, hpp, hists);
                for (i = 0; i < width; i++)
                        fprintf(fp, ".");
        }
 
        fprintf(fp, "\n");
-       if (max_rows && ++nr_rows >= max_rows)
-               goto out;
-
        fprintf(fp, "#\n");
-       if (max_rows && ++nr_rows >= max_rows)
+       return 3;
+}
+
+static int hists__fprintf_headers(struct hists *hists, FILE *fp)
+{
+       char bf[96];
+       struct perf_hpp dummy_hpp = {
+               .buf    = bf,
+               .size   = sizeof(bf),
+       };
+
+       fprintf(fp, "# ");
+
+       if (symbol_conf.report_hierarchy)
+               return hists__fprintf_hierarchy_headers(hists, &dummy_hpp, fp);
+       else
+               return hists__fprintf_standard_headers(hists, &dummy_hpp, fp);
+
+}
+
+size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
+                     int max_cols, float min_pcnt, FILE *fp,
+                     bool use_callchain)
+{
+       struct perf_hpp_fmt *fmt;
+       struct rb_node *nd;
+       size_t ret = 0;
+       const char *sep = symbol_conf.field_sep;
+       int nr_rows = 0;
+       size_t linesz;
+       char *line = NULL;
+       unsigned indent;
+
+       init_rem_hits();
+
+       hists__for_each_format(hists, fmt)
+               perf_hpp__reset_width(fmt, hists);
+
+       if (symbol_conf.col_width_list_str)
+               perf_hpp__set_user_width(symbol_conf.col_width_list_str);
+
+       if (show_header)
+               nr_rows += hists__fprintf_headers(hists, fp);
+
+       if (max_rows && nr_rows >= max_rows)
                goto out;
 
-print_entries:
        linesz = hists__sort_list_width(hists) + 3 + 1;
        linesz += perf_hpp__color_overhead();
        line = malloc(linesz);
@@ -734,7 +757,7 @@ print_entries:
                if (percent < min_pcnt)
                        continue;
 
-               ret += hist_entry__fprintf(h, max_cols, hists, line, linesz, fp);
+               ret += hist_entry__fprintf(h, max_cols, line, linesz, fp, use_callchain);
 
                if (max_rows && ++nr_rows >= max_rows)
                        break;
index 20aef90bf19412fc32a6734b7dec8849922155a1..62b147366d017107675f4881cc06fa410aa572d0 100644 (file)
@@ -387,9 +387,8 @@ void disable_buildid_cache(void)
        no_buildid_cache = true;
 }
 
-static char *build_id_cache__dirname_from_path(const char *name,
-                                              bool is_kallsyms, bool is_vdso,
-                                              const char *sbuild_id)
+char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
+                              bool is_kallsyms, bool is_vdso)
 {
        char *realname = (char *)name, *filename;
        bool slash = is_kallsyms || is_vdso;
@@ -417,8 +416,7 @@ int build_id_cache__list_build_ids(const char *pathname,
        char *dir_name;
        int ret = 0;
 
-       dir_name = build_id_cache__dirname_from_path(pathname, false, false,
-                                                    NULL);
+       dir_name = build_id_cache__cachedir(NULL, pathname, false, false);
        if (!dir_name)
                return -ENOMEM;
 
@@ -444,8 +442,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
                        goto out_free;
        }
 
-       dir_name = build_id_cache__dirname_from_path(name, is_kallsyms,
-                                                    is_vdso, sbuild_id);
+       dir_name = build_id_cache__cachedir(sbuild_id, name,
+                                           is_kallsyms, is_vdso);
        if (!dir_name)
                goto out_free;
 
index e5435f46e48e5e2ee9955a05500c6345fa1775f2..d8c7f2fc6a878bddec7fd8bc7c971b0190ffd8d6 100644 (file)
@@ -30,6 +30,8 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
 int perf_session__write_buildid_table(struct perf_session *session, int fd);
 int perf_session__cache_build_ids(struct perf_session *session);
 
+char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
+                              bool is_kallsyms, bool is_vdso);
 int build_id_cache__list_build_ids(const char *pathname,
                                   struct strlist **result);
 bool build_id_cache__cached(const char *sbuild_id);
index 8749eca3055f6fca7f3ae094cf858bce43e8c487..31e09a4e88621450822178736f21bd070e75a336 100644 (file)
@@ -742,6 +742,9 @@ static void perf_config_set__purge(struct perf_config_set *set)
 
 void perf_config_set__delete(struct perf_config_set *set)
 {
+       if (set == NULL)
+               return;
+
        perf_config_set__purge(set);
        free(set);
 }
index d1f19e0012d44d907a65ac4d1ca281eab38e9b70..2515cfdb7365aecf996d1b69ad21374a2ec30c87 100644 (file)
@@ -1081,7 +1081,7 @@ int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp,
                                   struct perf_hpp_fmt *fmt, int printed)
 {
        if (!list_is_last(&fmt->list, &he->hists->hpp_list->fields)) {
-               const int width = fmt->width(fmt, hpp, hists_to_evsel(he->hists));
+               const int width = fmt->width(fmt, hpp, he->hists);
                if (printed < width) {
                        advance_hpp(hpp, printed);
                        printed = scnprintf(hpp->buf, hpp->size, "%-*s", width - printed, " ");
index 7b54ccf1b7370ab2336bd16a1c18a7c932b7e41d..a19112872ff9d0680d2d3bb7376c9e1b3c05ecce 100644 (file)
@@ -159,7 +159,8 @@ void events_stats__inc(struct events_stats *stats, u32 type);
 size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
 
 size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
-                     int max_cols, float min_pcnt, FILE *fp);
+                     int max_cols, float min_pcnt, FILE *fp,
+                     bool use_callchain);
 size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp);
 
 void hists__filter_by_dso(struct hists *hists);
@@ -214,9 +215,9 @@ struct perf_hpp {
 struct perf_hpp_fmt {
        const char *name;
        int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
-                     struct perf_evsel *evsel);
+                     struct hists *hists);
        int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
-                    struct perf_evsel *evsel);
+                    struct hists *hists);
        int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
                     struct hist_entry *he);
        int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
index 75465f89a4131bca863e389da525e1d51b90aae2..bbc368e7d1e4f7f9a53a329fac26d28785db9efc 100644 (file)
 #include "debug.h"
 #include "symbol.h"
 
+unsigned int perf_mem_events__loads_ldlat = 30;
+
 #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
 
 struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
-       E("ldlat-loads",        "cpu/mem-loads,ldlat=30/P",     "mem-loads"),
+       E("ldlat-loads",        "cpu/mem-loads,ldlat=%u/P",     "mem-loads"),
        E("ldlat-stores",       "cpu/mem-stores/P",             "mem-stores"),
 };
 #undef E
 
 #undef E
 
+static char mem_loads_name[100];
+static bool mem_loads_name__init;
+
 char *perf_mem_events__name(int i)
 {
+       if (i == PERF_MEM_EVENTS__LOAD) {
+               if (!mem_loads_name__init) {
+                       mem_loads_name__init = true;
+                       scnprintf(mem_loads_name, sizeof(mem_loads_name),
+                                 perf_mem_events[i].name,
+                                 perf_mem_events__loads_ldlat);
+               }
+               return mem_loads_name;
+       }
+
        return (char *)perf_mem_events[i].name;
 }
 
index 5d6d93066a6e80e492634d6add9ad85f153211e6..7f69bf9d789da77cecd13e432874ca6e689e2a8a 100644 (file)
@@ -18,6 +18,7 @@ enum {
 };
 
 extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX];
+extern unsigned int perf_mem_events__loads_ldlat;
 
 int perf_mem_events__parse(const char *str);
 int perf_mem_events__init(void);
index 74401a20106d1c4baf9ed495125ede61995835f4..084756c173094c53e393b5f999968f9ade2a13a2 100644 (file)
@@ -67,7 +67,6 @@ int e_snprintf(char *str, size_t size, const char *format, ...)
        return ret;
 }
 
-static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
 static struct machine *host_machine;
 
 /* 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)
        p = strchr(argv[1], ':');
        if (p) {
                tp->module = strndup(argv[1], p - argv[1]);
+               if (!tp->module) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
                p++;
        } else
                p = argv[1];
@@ -1712,7 +1715,7 @@ out:
 }
 
 /* Compose only probe point (not argument) */
-static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
+char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 {
        struct strbuf buf;
        char *tmp, *ret = NULL;
@@ -1751,30 +1754,36 @@ out:
        return ret;
 }
 
-#if 0
 char *synthesize_perf_probe_command(struct perf_probe_event *pev)
 {
-       char *buf;
-       int i, len, ret;
+       struct strbuf buf;
+       char *tmp, *ret = NULL;
+       int i;
 
-       buf = synthesize_perf_probe_point(&pev->point);
-       if (!buf)
+       if (strbuf_init(&buf, 64))
                return NULL;
+       if (pev->event)
+               if (strbuf_addf(&buf, "%s:%s=", pev->group ?: PERFPROBE_GROUP,
+                               pev->event) < 0)
+                       goto out;
+
+       tmp = synthesize_perf_probe_point(&pev->point);
+       if (!tmp || strbuf_addstr(&buf, tmp) < 0)
+               goto out;
+       free(tmp);
 
-       len = strlen(buf);
        for (i = 0; i < pev->nargs; i++) {
-               ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
-                                pev->args[i].name);
-               if (ret <= 0) {
-                       free(buf);
-                       return NULL;
-               }
-               len += ret;
+               tmp = synthesize_perf_probe_arg(pev->args + i);
+               if (!tmp || strbuf_addf(&buf, " %s", tmp) < 0)
+                       goto out;
+               free(tmp);
        }
 
-       return buf;
+       ret = strbuf_detach(&buf, NULL);
+out:
+       strbuf_release(&buf);
+       return ret;
 }
-#endif
 
 static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
                                            struct strbuf *buf, int depth)
@@ -2026,6 +2035,79 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
        memset(pev, 0, sizeof(*pev));
 }
 
+#define strdup_or_goto(str, label)     \
+({ char *__p = NULL; if (str && !(__p = strdup(str))) goto label; __p; })
+
+static int perf_probe_point__copy(struct perf_probe_point *dst,
+                                 struct perf_probe_point *src)
+{
+       dst->file = strdup_or_goto(src->file, out_err);
+       dst->function = strdup_or_goto(src->function, out_err);
+       dst->lazy_line = strdup_or_goto(src->lazy_line, out_err);
+       dst->line = src->line;
+       dst->retprobe = src->retprobe;
+       dst->offset = src->offset;
+       return 0;
+
+out_err:
+       clear_perf_probe_point(dst);
+       return -ENOMEM;
+}
+
+static int perf_probe_arg__copy(struct perf_probe_arg *dst,
+                               struct perf_probe_arg *src)
+{
+       struct perf_probe_arg_field *field, **ppfield;
+
+       dst->name = strdup_or_goto(src->name, out_err);
+       dst->var = strdup_or_goto(src->var, out_err);
+       dst->type = strdup_or_goto(src->type, out_err);
+
+       field = src->field;
+       ppfield = &(dst->field);
+       while (field) {
+               *ppfield = zalloc(sizeof(*field));
+               if (!*ppfield)
+                       goto out_err;
+               (*ppfield)->name = strdup_or_goto(field->name, out_err);
+               (*ppfield)->index = field->index;
+               (*ppfield)->ref = field->ref;
+               field = field->next;
+               ppfield = &((*ppfield)->next);
+       }
+       return 0;
+out_err:
+       return -ENOMEM;
+}
+
+int perf_probe_event__copy(struct perf_probe_event *dst,
+                          struct perf_probe_event *src)
+{
+       int i;
+
+       dst->event = strdup_or_goto(src->event, out_err);
+       dst->group = strdup_or_goto(src->group, out_err);
+       dst->target = strdup_or_goto(src->target, out_err);
+       dst->uprobes = src->uprobes;
+
+       if (perf_probe_point__copy(&dst->point, &src->point) < 0)
+               goto out_err;
+
+       dst->args = zalloc(sizeof(struct perf_probe_arg) * src->nargs);
+       if (!dst->args)
+               goto out_err;
+       dst->nargs = src->nargs;
+
+       for (i = 0; i < src->nargs; i++)
+               if (perf_probe_arg__copy(&dst->args[i], &src->args[i]) < 0)
+                       goto out_err;
+       return 0;
+
+out_err:
+       clear_perf_probe_event(dst);
+       return -ENOMEM;
+}
+
 void clear_probe_trace_event(struct probe_trace_event *tev)
 {
        struct probe_trace_arg_ref *ref, *next;
@@ -2432,6 +2514,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 {
        int i, fd, ret;
        struct probe_trace_event *tev = NULL;
+       struct probe_cache *cache = NULL;
        struct strlist *namelist;
 
        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,
        }
        if (ret == -EINVAL && pev->uprobes)
                warn_uprobe_event_compat(tev);
+       if (ret == 0 && probe_conf.cache) {
+               cache = probe_cache__new(pev->target);
+               if (!cache ||
+                   probe_cache__add_entry(cache, pev, tevs, ntevs) < 0 ||
+                   probe_cache__commit(cache) < 0)
+                       pr_warning("Failed to add event to probe cache\n");
+               probe_cache__delete(cache);
+       }
 
        strlist__delete(namelist);
 close_out:
@@ -2501,9 +2592,6 @@ static int find_probe_functions(struct map *map, char *name,
        return found;
 }
 
-#define strdup_or_goto(str, label)     \
-       ({ char *__p = strdup(str); if (!__p) goto label; __p; })
-
 void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused,
                                struct probe_trace_event *tev __maybe_unused,
                                struct map *map __maybe_unused,
index 5a27eb4fad05a29e518ac7b9ecad4a25fb8f4dd6..432b690d3f177ae73de222b390e472218ea296be 100644 (file)
@@ -12,6 +12,7 @@ struct probe_conf {
        bool    show_location_range;
        bool    force_add;
        bool    no_inlines;
+       bool    cache;
        int     max_probes;
 };
 extern struct probe_conf probe_conf;
@@ -121,6 +122,10 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev);
 char *synthesize_perf_probe_command(struct perf_probe_event *pev);
 char *synthesize_probe_trace_command(struct probe_trace_event *tev);
 char *synthesize_perf_probe_arg(struct perf_probe_arg *pa);
+char *synthesize_perf_probe_point(struct perf_probe_point *pp);
+
+int perf_probe_event__copy(struct perf_probe_event *dst,
+                          struct perf_probe_event *src);
 
 /* Check the perf_probe_event needs debuginfo */
 bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
index 3fe6214970e632932cb3809dea4c36d0aa792029..25a40427003e19c33f074583ff8ddb7e18f2b9b0 100644 (file)
@@ -14,6 +14,7 @@
  * GNU General Public License for more details.
  *
  */
+#include <sys/uio.h>
 #include "util.h"
 #include "event.h"
 #include "strlist.h"
@@ -324,3 +325,333 @@ int probe_file__del_events(int fd, struct strfilter *filter)
 
        return ret;
 }
+
+/* Caller must ensure to remove this entry from list */
+static void probe_cache_entry__delete(struct probe_cache_entry *entry)
+{
+       if (entry) {
+               BUG_ON(!list_empty(&entry->node));
+
+               strlist__delete(entry->tevlist);
+               clear_perf_probe_event(&entry->pev);
+               zfree(&entry->spev);
+               free(entry);
+       }
+}
+
+static struct probe_cache_entry *
+probe_cache_entry__new(struct perf_probe_event *pev)
+{
+       struct probe_cache_entry *entry = zalloc(sizeof(*entry));
+
+       if (entry) {
+               INIT_LIST_HEAD(&entry->node);
+               entry->tevlist = strlist__new(NULL, NULL);
+               if (!entry->tevlist)
+                       zfree(&entry);
+               else if (pev) {
+                       entry->spev = synthesize_perf_probe_command(pev);
+                       if (!entry->spev ||
+                           perf_probe_event__copy(&entry->pev, pev) < 0) {
+                               probe_cache_entry__delete(entry);
+                               return NULL;
+                       }
+               }
+       }
+
+       return entry;
+}
+
+/* For the kernel probe caches, pass target = NULL */
+static int probe_cache__open(struct probe_cache *pcache, const char *target)
+{
+       char cpath[PATH_MAX];
+       char sbuildid[SBUILD_ID_SIZE];
+       char *dir_name;
+       bool is_kallsyms = !target;
+       int ret, fd;
+
+       if (target)
+               ret = filename__sprintf_build_id(target, sbuildid);
+       else {
+               target = DSO__NAME_KALLSYMS;
+               ret = sysfs__sprintf_build_id("/", sbuildid);
+       }
+       if (ret < 0) {
+               pr_debug("Failed to get build-id from %s.\n", target);
+               return ret;
+       }
+
+       /* If we have no buildid cache, make it */
+       if (!build_id_cache__cached(sbuildid)) {
+               ret = build_id_cache__add_s(sbuildid, target,
+                                           is_kallsyms, NULL);
+               if (ret < 0) {
+                       pr_debug("Failed to add build-id cache: %s\n", target);
+                       return ret;
+               }
+       }
+
+       dir_name = build_id_cache__cachedir(sbuildid, target, is_kallsyms,
+                                           false);
+       if (!dir_name)
+               return -ENOMEM;
+
+       snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
+       fd = open(cpath, O_CREAT | O_RDWR, 0644);
+       if (fd < 0)
+               pr_debug("Failed to open cache(%d): %s\n", fd, cpath);
+       free(dir_name);
+       pcache->fd = fd;
+
+       return fd;
+}
+
+static int probe_cache__load(struct probe_cache *pcache)
+{
+       struct probe_cache_entry *entry = NULL;
+       char buf[MAX_CMDLEN], *p;
+       int ret = 0;
+       FILE *fp;
+
+       fp = fdopen(dup(pcache->fd), "r");
+       if (!fp)
+               return -EINVAL;
+
+       while (!feof(fp)) {
+               if (!fgets(buf, MAX_CMDLEN, fp))
+                       break;
+               p = strchr(buf, '\n');
+               if (p)
+                       *p = '\0';
+               if (buf[0] == '#') {    /* #perf_probe_event */
+                       entry = probe_cache_entry__new(NULL);
+                       if (!entry) {
+                               ret = -ENOMEM;
+                               goto out;
+                       }
+                       entry->spev = strdup(buf + 1);
+                       if (entry->spev)
+                               ret = parse_perf_probe_command(buf + 1,
+                                                               &entry->pev);
+                       else
+                               ret = -ENOMEM;
+                       if (ret < 0) {
+                               probe_cache_entry__delete(entry);
+                               goto out;
+                       }
+                       list_add_tail(&entry->node, &pcache->entries);
+               } else {        /* trace_probe_event */
+                       if (!entry) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       strlist__add(entry->tevlist, buf);
+               }
+       }
+out:
+       fclose(fp);
+       return ret;
+}
+
+static struct probe_cache *probe_cache__alloc(void)
+{
+       struct probe_cache *pcache = zalloc(sizeof(*pcache));
+
+       if (pcache) {
+               INIT_LIST_HEAD(&pcache->entries);
+               pcache->fd = -EINVAL;
+       }
+       return pcache;
+}
+
+void probe_cache__purge(struct probe_cache *pcache)
+{
+       struct probe_cache_entry *entry, *n;
+
+       list_for_each_entry_safe(entry, n, &pcache->entries, node) {
+               list_del_init(&entry->node);
+               probe_cache_entry__delete(entry);
+       }
+}
+
+void probe_cache__delete(struct probe_cache *pcache)
+{
+       if (!pcache)
+               return;
+
+       probe_cache__purge(pcache);
+       if (pcache->fd > 0)
+               close(pcache->fd);
+       free(pcache);
+}
+
+struct probe_cache *probe_cache__new(const char *target)
+{
+       struct probe_cache *pcache = probe_cache__alloc();
+       int ret;
+
+       if (!pcache)
+               return NULL;
+
+       ret = probe_cache__open(pcache, target);
+       if (ret < 0) {
+               pr_debug("Cache open error: %d\n", ret);
+               goto out_err;
+       }
+
+       ret = probe_cache__load(pcache);
+       if (ret < 0) {
+               pr_debug("Cache read error: %d\n", ret);
+               goto out_err;
+       }
+
+       return pcache;
+
+out_err:
+       probe_cache__delete(pcache);
+       return NULL;
+}
+
+static bool streql(const char *a, const char *b)
+{
+       if (a == b)
+               return true;
+
+       if (!a || !b)
+               return false;
+
+       return !strcmp(a, b);
+}
+
+static struct probe_cache_entry *
+probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
+{
+       struct probe_cache_entry *entry = NULL;
+       char *cmd = synthesize_perf_probe_command(pev);
+
+       if (!cmd)
+               return NULL;
+
+       list_for_each_entry(entry, &pcache->entries, node) {
+               /* Hit if same event name or same command-string */
+               if ((pev->event &&
+                    (streql(entry->pev.group, pev->group) &&
+                     streql(entry->pev.event, pev->event))) ||
+                   (!strcmp(entry->spev, cmd)))
+                       goto found;
+       }
+       entry = NULL;
+
+found:
+       free(cmd);
+       return entry;
+}
+
+int probe_cache__add_entry(struct probe_cache *pcache,
+                          struct perf_probe_event *pev,
+                          struct probe_trace_event *tevs, int ntevs)
+{
+       struct probe_cache_entry *entry = NULL;
+       char *command;
+       int i, ret = 0;
+
+       if (!pcache || !pev || !tevs || ntevs <= 0) {
+               ret = -EINVAL;
+               goto out_err;
+       }
+
+       /* Remove old cache entry */
+       entry = probe_cache__find(pcache, pev);
+       if (entry) {
+               list_del_init(&entry->node);
+               probe_cache_entry__delete(entry);
+       }
+
+       ret = -ENOMEM;
+       entry = probe_cache_entry__new(pev);
+       if (!entry)
+               goto out_err;
+
+       for (i = 0; i < ntevs; i++) {
+               if (!tevs[i].point.symbol)
+                       continue;
+
+               command = synthesize_probe_trace_command(&tevs[i]);
+               if (!command)
+                       goto out_err;
+               strlist__add(entry->tevlist, command);
+               free(command);
+       }
+       list_add_tail(&entry->node, &pcache->entries);
+       pr_debug("Added probe cache: %d\n", ntevs);
+       return 0;
+
+out_err:
+       pr_debug("Failed to add probe caches\n");
+       probe_cache_entry__delete(entry);
+       return ret;
+}
+
+static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd)
+{
+       struct str_node *snode;
+       struct stat st;
+       struct iovec iov[3];
+       int ret;
+       /* Save stat for rollback */
+       ret = fstat(fd, &st);
+       if (ret < 0)
+               return ret;
+
+       pr_debug("Writing cache: #%s\n", entry->spev);
+       iov[0].iov_base = (void *)"#"; iov[0].iov_len = 1;
+       iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev);
+       iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1;
+       ret = writev(fd, iov, 3);
+       if (ret < (int)iov[1].iov_len + 2)
+               goto rollback;
+
+       strlist__for_each(snode, entry->tevlist) {
+               iov[0].iov_base = (void *)snode->s;
+               iov[0].iov_len = strlen(snode->s);
+               iov[1].iov_base = (void *)"\n"; iov[1].iov_len = 1;
+               ret = writev(fd, iov, 2);
+               if (ret < (int)iov[0].iov_len + 1)
+                       goto rollback;
+       }
+       return 0;
+
+rollback:
+       /* Rollback to avoid cache file corruption */
+       if (ret > 0)
+               ret = -1;
+       if (ftruncate(fd, st.st_size) < 0)
+               ret = -2;
+
+       return ret;
+}
+
+int probe_cache__commit(struct probe_cache *pcache)
+{
+       struct probe_cache_entry *entry;
+       int ret = 0;
+
+       /* TBD: if we do not update existing entries, skip it */
+       ret = lseek(pcache->fd, 0, SEEK_SET);
+       if (ret < 0)
+               goto out;
+
+       ret = ftruncate(pcache->fd, 0);
+       if (ret < 0)
+               goto out;
+
+       list_for_each_entry(entry, &pcache->entries, node) {
+               ret = probe_cache_entry__write(entry, pcache->fd);
+               pr_debug("Cache committed: %d\n", ret);
+               if (ret < 0)
+                       break;
+       }
+out:
+       return ret;
+}
index 18ac9cf51c3433438eb3036d340f34e5975161bc..d872e3df7e59166d00bb51eb696e5df38f8c032d 100644 (file)
@@ -5,6 +5,19 @@
 #include "strfilter.h"
 #include "probe-event.h"
 
+/* Cache of probe definitions */
+struct probe_cache_entry {
+       struct list_head        node;
+       struct perf_probe_event pev;
+       char                    *spev;
+       struct strlist          *tevlist;
+};
+
+struct probe_cache {
+       int     fd;
+       struct list_head entries;
+};
+
 #define PF_FL_UPROBE   1
 #define PF_FL_RW       2
 
@@ -18,5 +31,12 @@ int probe_file__get_events(int fd, struct strfilter *filter,
                                  struct strlist *plist);
 int probe_file__del_strlist(int fd, struct strlist *namelist);
 
+struct probe_cache *probe_cache__new(const char *target);
+int probe_cache__add_entry(struct probe_cache *pcache,
+                          struct perf_probe_event *pev,
+                          struct probe_trace_event *tevs, int ntevs);
+int probe_cache__commit(struct probe_cache *pcache);
+void probe_cache__purge(struct probe_cache *pcache);
+void probe_cache__delete(struct probe_cache *pcache);
 
 #endif
index c4e9bd70723c5b26df4499af5d32afdb86109c31..896d34ebcc1e741d4a41b86717f27a101671a490 100644 (file)
@@ -1218,7 +1218,7 @@ struct sort_entry sort_mem_daddr_dso = {
        .se_header      = "Data Object",
        .se_cmp         = sort__dso_daddr_cmp,
        .se_snprintf    = hist_entry__dso_daddr_snprintf,
-       .se_width_idx   = HISTC_MEM_DADDR_SYMBOL,
+       .se_width_idx   = HISTC_MEM_DADDR_DSO,
 };
 
 struct sort_entry sort_mem_locked = {
@@ -1488,7 +1488,7 @@ void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
 }
 
 static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
-                             struct perf_evsel *evsel)
+                             struct hists *hists)
 {
        struct hpp_sort_entry *hse;
        size_t len = fmt->user_len;
@@ -1496,14 +1496,14 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
 
        if (!len)
-               len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
+               len = hists__col_len(hists, hse->se->se_width_idx);
 
        return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
 }
 
 static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
                             struct perf_hpp *hpp __maybe_unused,
-                            struct perf_evsel *evsel)
+                            struct hists *hists)
 {
        struct hpp_sort_entry *hse;
        size_t len = fmt->user_len;
@@ -1511,7 +1511,7 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
 
        if (!len)
-               len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
+               len = hists__col_len(hists, hse->se->se_width_idx);
 
        return len;
 }
@@ -1793,7 +1793,7 @@ static void update_dynamic_len(struct hpp_dynamic_entry *hde,
 }
 
 static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
-                             struct perf_evsel *evsel __maybe_unused)
+                             struct hists *hists __maybe_unused)
 {
        struct hpp_dynamic_entry *hde;
        size_t len = fmt->user_len;
@@ -1808,7 +1808,7 @@ static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
 
 static int __sort__hde_width(struct perf_hpp_fmt *fmt,
                             struct perf_hpp *hpp __maybe_unused,
-                            struct perf_evsel *evsel __maybe_unused)
+                            struct hists *hists __maybe_unused)
 {
        struct hpp_dynamic_entry *hde;
        size_t len = fmt->user_len;
index 23504ad5d6dd2154ca04d63ab4aa97e764de6692..e08b9a092a239b17096ab2c23932898b1c249fe9 100644 (file)
@@ -97,20 +97,17 @@ int rm_rf(char *path)
                scnprintf(namebuf, sizeof(namebuf), "%s/%s",
                          path, d->d_name);
 
-               ret = stat(namebuf, &statbuf);
+               /* We have to check symbolic link itself */
+               ret = lstat(namebuf, &statbuf);
                if (ret < 0) {
                        pr_debug("stat failed: %s\n", namebuf);
                        break;
                }
 
-               if (S_ISREG(statbuf.st_mode))
-                       ret = unlink(namebuf);
-               else if (S_ISDIR(statbuf.st_mode))
+               if (S_ISDIR(statbuf.st_mode))
                        ret = rm_rf(namebuf);
-               else {
-                       pr_debug("unknown file: %s\n", namebuf);
-                       ret = -1;
-               }
+               else
+                       ret = unlink(namebuf);
        }
        closedir(dir);
 
This page took 0.051018 seconds and 5 git commands to generate.