Browse Source

Merge tag 'perf-core-for-mingo' 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:

  - Do not print trailing spaces in the hists browser (top, report) to
    avoid line wrapping issues when long C++ demangled functions are
    sampled (Arnaldo Carvalho de Melo)

  - Allow 'perf config' to show --system or --user settings (Taeung Song)

  - Add better warning about the need to install the audit-lib-python
    package when using perf python scripts (Taeung Song)

  - Fix symbol resolution when kernel modules files are only in the
    build id cache (~/.debug) (Wang Nan)

Build fixes:

  - Fix 'perf test' build on older systems where 'signal' is reserved (Arnaldo Carvalho de Melo)

Infrastructure changes:

  - Free the terms list_head in parse_events__free_terms(), also unlink the entries
    when deleting them (Wang Nan)

  - Fix releasing event_class in 'perf data' fixing integration with
    libbabeltrace (Wang Nan)

  - Add EXTRA_LDFLAGS option to Makefile (Zubair Lutfullah Kakakhel)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Ingo Molnar 9 years ago
parent
commit
fe7a2eaa71

+ 13 - 1
tools/perf/Documentation/perf-config.txt

@@ -8,7 +8,7 @@ perf-config - Get and set variables in a configuration file.
 SYNOPSIS
 SYNOPSIS
 --------
 --------
 [verse]
 [verse]
-'perf config' -l | --list
+'perf config' [<file-option>] -l | --list
 
 
 DESCRIPTION
 DESCRIPTION
 -----------
 -----------
@@ -21,6 +21,14 @@ OPTIONS
 --list::
 --list::
 	Show current config variables, name and value, for all sections.
 	Show current config variables, name and value, for all sections.
 
 
+--user::
+	For writing and reading options: write to user
+	'$HOME/.perfconfig' file or read it.
+
+--system::
+	For writing and reading options: write to system-wide
+	'$(sysconfdir)/perfconfig' or read it.
+
 CONFIGURATION FILE
 CONFIGURATION FILE
 ------------------
 ------------------
 
 
@@ -30,6 +38,10 @@ The '$HOME/.perfconfig' file is used to store a per-user configuration.
 The file '$(sysconfdir)/perfconfig' can be used to
 The file '$(sysconfdir)/perfconfig' can be used to
 store a system-wide default configuration.
 store a system-wide default configuration.
 
 
+When reading or writing, the values are read from the system and user
+configuration files by default, and options '--system' and '--user'
+can be used to tell the command to read from or write to only that location.
+
 Syntax
 Syntax
 ~~~~~~
 ~~~~~~
 
 

+ 2 - 0
tools/perf/Makefile.perf

@@ -139,6 +139,8 @@ $(call allow-override,CC,$(CROSS_COMPILE)gcc)
 $(call allow-override,AR,$(CROSS_COMPILE)ar)
 $(call allow-override,AR,$(CROSS_COMPILE)ar)
 $(call allow-override,LD,$(CROSS_COMPILE)ld)
 $(call allow-override,LD,$(CROSS_COMPILE)ld)
 
 
+LD += $(EXTRA_LDFLAGS)
+
 PKG_CONFIG = $(CROSS_COMPILE)pkg-config
 PKG_CONFIG = $(CROSS_COMPILE)pkg-config
 
 
 RM      = rm -f
 RM      = rm -f

+ 1 - 1
tools/perf/arch/x86/util/intel-pt.c

@@ -89,7 +89,7 @@ static int intel_pt_parse_terms_with_default(struct list_head *formats,
 
 
 	*config = attr.config;
 	*config = attr.config;
 out_free:
 out_free:
-	parse_events__free_terms(terms);
+	parse_events_terms__delete(terms);
 	return err;
 	return err;
 }
 }
 
 

+ 24 - 3
tools/perf/builtin-config.c

@@ -13,8 +13,10 @@
 #include "util/util.h"
 #include "util/util.h"
 #include "util/debug.h"
 #include "util/debug.h"
 
 
+static bool use_system_config, use_user_config;
+
 static const char * const config_usage[] = {
 static const char * const config_usage[] = {
-	"perf config [options]",
+	"perf config [<file-option>] [options]",
 	NULL
 	NULL
 };
 };
 
 
@@ -25,6 +27,8 @@ enum actions {
 static struct option config_options[] = {
 static struct option config_options[] = {
 	OPT_SET_UINT('l', "list", &actions,
 	OPT_SET_UINT('l', "list", &actions,
 		     "show current config variables", ACTION_LIST),
 		     "show current config variables", ACTION_LIST),
+	OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
+	OPT_BOOLEAN(0, "user", &use_user_config, "use user config file"),
 	OPT_END()
 	OPT_END()
 };
 };
 
 
@@ -42,10 +46,23 @@ static int show_config(const char *key, const char *value,
 int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
 int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 {
 	int ret = 0;
 	int ret = 0;
+	char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
 
 
 	argc = parse_options(argc, argv, config_options, config_usage,
 	argc = parse_options(argc, argv, config_options, config_usage,
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 
 
+	if (use_system_config && use_user_config) {
+		pr_err("Error: only one config file at a time\n");
+		parse_options_usage(config_usage, config_options, "user", 0);
+		parse_options_usage(NULL, config_options, "system", 0);
+		return -1;
+	}
+
+	if (use_system_config)
+		config_exclusive_filename = perf_etc_perfconfig();
+	else if (use_user_config)
+		config_exclusive_filename = user_config;
+
 	switch (actions) {
 	switch (actions) {
 	case ACTION_LIST:
 	case ACTION_LIST:
 		if (argc) {
 		if (argc) {
@@ -53,9 +70,13 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
 			parse_options_usage(config_usage, config_options, "l", 1);
 			parse_options_usage(config_usage, config_options, "l", 1);
 		} else {
 		} else {
 			ret = perf_config(show_config, NULL);
 			ret = perf_config(show_config, NULL);
-			if (ret < 0)
+			if (ret < 0) {
+				const char * config_filename = config_exclusive_filename;
+				if (!config_exclusive_filename)
+					config_filename = user_config;
 				pr_err("Nothing configured, "
 				pr_err("Nothing configured, "
-				       "please check your ~/.perfconfig file\n");
+				       "please check your %s \n", config_filename);
+			}
 		}
 		}
 		break;
 		break;
 	default:
 	default:

+ 4 - 1
tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py

@@ -71,7 +71,10 @@ try:
 except:
 except:
 	if not audit_package_warned:
 	if not audit_package_warned:
 		audit_package_warned = True
 		audit_package_warned = True
-		print "Install the audit-libs-python package to get syscall names"
+		print "Install the audit-libs-python package to get syscall names.\n" \
+                    "For example:\n  # apt-get install python-audit (Ubuntu)" \
+                    "\n  # yum install audit-libs-python (Fedora)" \
+                    "\n  etc.\n"
 
 
 def syscall_name(id):
 def syscall_name(id):
 	try:
 	try:

+ 6 - 6
tools/perf/tests/bp_signal.c

@@ -103,7 +103,7 @@ static void sig_handler(int signum __maybe_unused,
 	}
 	}
 }
 }
 
 
-static int __event(bool is_x, void *addr, int signal)
+static int __event(bool is_x, void *addr, int sig)
 {
 {
 	struct perf_event_attr pe;
 	struct perf_event_attr pe;
 	int fd;
 	int fd;
@@ -133,7 +133,7 @@ static int __event(bool is_x, void *addr, int signal)
 	}
 	}
 
 
 	fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
 	fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
-	fcntl(fd, F_SETSIG, signal);
+	fcntl(fd, F_SETSIG, sig);
 	fcntl(fd, F_SETOWN, getpid());
 	fcntl(fd, F_SETOWN, getpid());
 
 
 	ioctl(fd, PERF_EVENT_IOC_RESET, 0);
 	ioctl(fd, PERF_EVENT_IOC_RESET, 0);
@@ -141,14 +141,14 @@ static int __event(bool is_x, void *addr, int signal)
 	return fd;
 	return fd;
 }
 }
 
 
-static int bp_event(void *addr, int signal)
+static int bp_event(void *addr, int sig)
 {
 {
-	return __event(true, addr, signal);
+	return __event(true, addr, sig);
 }
 }
 
 
-static int wp_event(void *addr, int signal)
+static int wp_event(void *addr, int sig)
 {
 {
-	return __event(false, addr, signal);
+	return __event(false, addr, sig);
 }
 }
 
 
 static long long bp_count(int fd)
 static long long bp_count(int fd)

+ 1 - 1
tools/perf/tests/parse-events.c

@@ -1666,7 +1666,7 @@ static int test_term(struct terms_test *t)
 	}
 	}
 
 
 	ret = t->check(&terms);
 	ret = t->check(&terms);
-	parse_events__free_terms(&terms);
+	parse_events_terms__purge(&terms);
 
 
 	return ret;
 	return ret;
 }
 }

+ 18 - 9
tools/perf/ui/browsers/hists.c

@@ -1061,7 +1061,6 @@ static int hist_browser__show_entry(struct hist_browser *browser,
 				    struct hist_entry *entry,
 				    struct hist_entry *entry,
 				    unsigned short row)
 				    unsigned short row)
 {
 {
-	char s[256];
 	int printed = 0;
 	int printed = 0;
 	int width = browser->b.width;
 	int width = browser->b.width;
 	char folded_sign = ' ';
 	char folded_sign = ' ';
@@ -1086,16 +1085,18 @@ static int hist_browser__show_entry(struct hist_browser *browser,
 			.folded_sign	= folded_sign,
 			.folded_sign	= folded_sign,
 			.current_entry	= current_entry,
 			.current_entry	= current_entry,
 		};
 		};
-		struct perf_hpp hpp = {
-			.buf		= s,
-			.size		= sizeof(s),
-			.ptr		= &arg,
-		};
 		int column = 0;
 		int column = 0;
 
 
 		hist_browser__gotorc(browser, row, 0);
 		hist_browser__gotorc(browser, row, 0);
 
 
 		hists__for_each_format(browser->hists, fmt) {
 		hists__for_each_format(browser->hists, fmt) {
+			char s[2048];
+			struct perf_hpp hpp = {
+				.buf	= s,
+				.size	= sizeof(s),
+				.ptr	= &arg,
+			};
+
 			if (perf_hpp__should_skip(fmt, entry->hists) ||
 			if (perf_hpp__should_skip(fmt, entry->hists) ||
 			    column++ < browser->b.horiz_scroll)
 			    column++ < browser->b.horiz_scroll)
 				continue;
 				continue;
@@ -1120,11 +1121,18 @@ static int hist_browser__show_entry(struct hist_browser *browser,
 			}
 			}
 
 
 			if (fmt->color) {
 			if (fmt->color) {
-				width -= fmt->color(fmt, &hpp, entry);
+				int ret = fmt->color(fmt, &hpp, entry);
+				hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
+				/*
+				 * fmt->color() already used ui_browser to
+				 * print the non alignment bits, skip it (+ret):
+				 */
+				ui_browser__printf(&browser->b, "%s", s + ret);
 			} else {
 			} else {
-				width -= fmt->entry(fmt, &hpp, entry);
+				hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
 				ui_browser__printf(&browser->b, "%s", s);
 				ui_browser__printf(&browser->b, "%s", s);
 			}
 			}
+			width -= hpp.buf - s;
 		}
 		}
 
 
 		/* The scroll bar isn't being used */
 		/* The scroll bar isn't being used */
@@ -1452,9 +1460,10 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
 			first = false;
 			first = false;
 
 
 		ret = fmt->entry(fmt, &hpp, he);
 		ret = fmt->entry(fmt, &hpp, he);
+		ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
 		advance_hpp(&hpp, ret);
 		advance_hpp(&hpp, ret);
 	}
 	}
-	printed += fprintf(fp, "%s\n", rtrim(s));
+	printed += fprintf(fp, "%s\n", s);
 
 
 	if (folded_sign == '-')
 	if (folded_sign == '-')
 		printed += hist_browser__fprintf_callchain(browser, he, fp);
 		printed += hist_browser__fprintf_callchain(browser, he, fp);

+ 1 - 0
tools/perf/ui/stdio/hist.c

@@ -403,6 +403,7 @@ static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
 		else
 		else
 			ret = fmt->entry(fmt, hpp, he);
 			ret = fmt->entry(fmt, hpp, he);
 
 
+		ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
 		advance_hpp(hpp, ret);
 		advance_hpp(hpp, ret);
 	}
 	}
 
 

+ 44 - 0
tools/perf/util/build-id.c

@@ -166,6 +166,50 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
 	return build_id__filename(build_id_hex, bf, size);
 	return build_id__filename(build_id_hex, bf, size);
 }
 }
 
 
+bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
+{
+	char *id_name, *ch;
+	struct stat sb;
+
+	id_name = dso__build_id_filename(dso, bf, size);
+	if (!id_name)
+		goto err;
+	if (access(id_name, F_OK))
+		goto err;
+	if (lstat(id_name, &sb) == -1)
+		goto err;
+	if ((size_t)sb.st_size > size - 1)
+		goto err;
+	if (readlink(id_name, bf, size - 1) < 0)
+		goto err;
+
+	bf[sb.st_size] = '\0';
+
+	/*
+	 * link should be:
+	 * ../../lib/modules/4.4.0-rc4/kernel/net/ipv4/netfilter/nf_nat_ipv4.ko/a09fe3eb3147dafa4e3b31dbd6257e4d696bdc92
+	 */
+	ch = strrchr(bf, '/');
+	if (!ch)
+		goto err;
+	if (ch - 3 < bf)
+		goto err;
+
+	return strncmp(".ko", ch - 3, 3) == 0;
+err:
+	/*
+	 * If dso__build_id_filename work, get id_name again,
+	 * because id_name points to bf and is broken.
+	 */
+	if (id_name)
+		id_name = dso__build_id_filename(dso, bf, size);
+	pr_err("Invalid build id: %s\n", id_name ? :
+					 dso->long_name ? :
+					 dso->short_name ? :
+					 "[unknown]");
+	return false;
+}
+
 #define dsos__for_each_with_build_id(pos, head)	\
 #define dsos__for_each_with_build_id(pos, head)	\
 	list_for_each_entry(pos, head, node)	\
 	list_for_each_entry(pos, head, node)	\
 		if (!pos->has_build_id)		\
 		if (!pos->has_build_id)		\

+ 1 - 0
tools/perf/util/build-id.h

@@ -16,6 +16,7 @@ int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id);
 int filename__sprintf_build_id(const char *pathname, char *sbuild_id);
 int filename__sprintf_build_id(const char *pathname, char *sbuild_id);
 
 
 char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
 char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
+bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size);
 
 
 int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
 int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
 			   struct perf_sample *sample, struct perf_evsel *evsel,
 			   struct perf_sample *sample, struct perf_evsel *evsel,

+ 3 - 0
tools/perf/util/cache.h

@@ -23,6 +23,8 @@
 #define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
 #define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
 #define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
 #define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
 
 
+extern const char *config_exclusive_filename;
+
 typedef int (*config_fn_t)(const char *, const char *, void *);
 typedef int (*config_fn_t)(const char *, const char *, void *);
 extern int perf_default_config(const char *, const char *, void *);
 extern int perf_default_config(const char *, const char *, void *);
 extern int perf_config(config_fn_t fn, void *);
 extern int perf_config(config_fn_t fn, void *);
@@ -31,6 +33,7 @@ extern u64 perf_config_u64(const char *, const char *);
 extern int perf_config_bool(const char *, const char *);
 extern int perf_config_bool(const char *, const char *);
 extern int config_error_nonbool(const char *);
 extern int config_error_nonbool(const char *);
 extern const char *perf_config_dirname(const char *, const char *);
 extern const char *perf_config_dirname(const char *, const char *);
+extern const char *perf_etc_perfconfig(void);
 
 
 char *alias_lookup(const char *alias);
 char *alias_lookup(const char *alias);
 int split_cmdline(char *cmdline, const char ***argv);
 int split_cmdline(char *cmdline, const char ***argv);

+ 2 - 2
tools/perf/util/config.c

@@ -26,7 +26,7 @@ static const char *config_file_name;
 static int config_linenr;
 static int config_linenr;
 static int config_file_eof;
 static int config_file_eof;
 
 
-static const char *config_exclusive_filename;
+const char *config_exclusive_filename;
 
 
 static int get_next_char(void)
 static int get_next_char(void)
 {
 {
@@ -434,7 +434,7 @@ static int perf_config_from_file(config_fn_t fn, const char *filename, void *dat
 	return ret;
 	return ret;
 }
 }
 
 
-static const char *perf_etc_perfconfig(void)
+const char *perf_etc_perfconfig(void)
 {
 {
 	static const char *system_wide;
 	static const char *system_wide;
 	if (!system_wide)
 	if (!system_wide)

+ 18 - 0
tools/perf/util/data-convert-bt.c

@@ -858,6 +858,23 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session)
 	return 0;
 	return 0;
 }
 }
 
 
+static void cleanup_events(struct perf_session *session)
+{
+	struct perf_evlist *evlist = session->evlist;
+	struct perf_evsel *evsel;
+
+	evlist__for_each(evlist, evsel) {
+		struct evsel_priv *priv;
+
+		priv = evsel->priv;
+		bt_ctf_event_class_put(priv->event_class);
+		zfree(&evsel->priv);
+	}
+
+	perf_evlist__delete(evlist);
+	session->evlist = NULL;
+}
+
 static int setup_streams(struct ctf_writer *cw, struct perf_session *session)
 static int setup_streams(struct ctf_writer *cw, struct perf_session *session)
 {
 {
 	struct ctf_stream **stream;
 	struct ctf_stream **stream;
@@ -1171,6 +1188,7 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
 		(double) c.events_size / 1024.0 / 1024.0,
 		(double) c.events_size / 1024.0 / 1024.0,
 		c.events_count);
 		c.events_count);
 
 
+	cleanup_events(session);
 	perf_session__delete(session);
 	perf_session__delete(session);
 	ctf_writer__cleanup(cw);
 	ctf_writer__cleanup(cw);
 
 

+ 21 - 0
tools/perf/util/hist.c

@@ -1014,6 +1014,27 @@ void hist_entry__delete(struct hist_entry *he)
 	free(he);
 	free(he);
 }
 }
 
 
+/*
+ * If this is not the last column, then we need to pad it according to the
+ * pre-calculated max lenght for this column, otherwise don't bother adding
+ * spaces because that would break viewing this with, for instance, 'less',
+ * that would show tons of trailing spaces when a long C++ demangled method
+ * names is sampled.
+*/
+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));
+		if (printed < width) {
+			advance_hpp(hpp, printed);
+			printed = scnprintf(hpp->buf, hpp->size, "%-*s", width - printed, " ");
+		}
+	}
+
+	return printed;
+}
+
 /*
 /*
  * collapse the histogram
  * collapse the histogram
  */
  */

+ 5 - 0
tools/perf/util/hist.h

@@ -122,11 +122,16 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
 int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
 int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
 			 int max_stack_depth, void *arg);
 			 int max_stack_depth, void *arg);
 
 
+struct perf_hpp;
+struct perf_hpp_fmt;
+
 int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
 int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
 int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
 int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
 int hist_entry__transaction_len(void);
 int hist_entry__transaction_len(void);
 int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size,
 int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size,
 			      struct hists *hists);
 			      struct hists *hists);
+int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp,
+				   struct perf_hpp_fmt *fmt, int printed);
 void hist_entry__delete(struct hist_entry *he);
 void hist_entry__delete(struct hist_entry *he);
 
 
 void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog);
 void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog);

+ 13 - 4
tools/perf/util/parse-events.c

@@ -1386,8 +1386,7 @@ int parse_events_terms(struct list_head *terms, const char *str)
 		return 0;
 		return 0;
 	}
 	}
 
 
-	if (data.terms)
-		parse_events__free_terms(data.terms);
+	parse_events_terms__delete(data.terms);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -2068,12 +2067,22 @@ int parse_events_term__clone(struct parse_events_term **new,
 			term->err_term, term->err_val);
 			term->err_term, term->err_val);
 }
 }
 
 
-void parse_events__free_terms(struct list_head *terms)
+void parse_events_terms__purge(struct list_head *terms)
 {
 {
 	struct parse_events_term *term, *h;
 	struct parse_events_term *term, *h;
 
 
-	list_for_each_entry_safe(term, h, terms, list)
+	list_for_each_entry_safe(term, h, terms, list) {
+		list_del_init(&term->list);
 		free(term);
 		free(term);
+	}
+}
+
+void parse_events_terms__delete(struct list_head *terms)
+{
+	if (!terms)
+		return;
+	parse_events_terms__purge(terms);
+	free(terms);
 }
 }
 
 
 void parse_events_evlist_error(struct parse_events_evlist *data,
 void parse_events_evlist_error(struct parse_events_evlist *data,

+ 2 - 1
tools/perf/util/parse-events.h

@@ -115,7 +115,8 @@ int parse_events_term__sym_hw(struct parse_events_term **term,
 			      char *config, unsigned idx);
 			      char *config, unsigned idx);
 int parse_events_term__clone(struct parse_events_term **new,
 int parse_events_term__clone(struct parse_events_term **new,
 			     struct parse_events_term *term);
 			     struct parse_events_term *term);
-void parse_events__free_terms(struct list_head *terms);
+void parse_events_terms__delete(struct list_head *terms);
+void parse_events_terms__purge(struct list_head *terms);
 int parse_events__modifier_event(struct list_head *list, char *str, bool add);
 int parse_events__modifier_event(struct list_head *list, char *str, bool add);
 int parse_events__modifier_group(struct list_head *list, char *event_mod);
 int parse_events__modifier_group(struct list_head *list, char *event_mod);
 int parse_events_name(struct list_head *list, char *name);
 int parse_events_name(struct list_head *list, char *name);

+ 4 - 4
tools/perf/util/parse-events.y

@@ -218,7 +218,7 @@ PE_NAME '/' event_config '/'
 
 
 	ALLOC_LIST(list);
 	ALLOC_LIST(list);
 	ABORT_ON(parse_events_add_pmu(data, list, $1, $3));
 	ABORT_ON(parse_events_add_pmu(data, list, $1, $3));
-	parse_events__free_terms($3);
+	parse_events_terms__delete($3);
 	$$ = list;
 	$$ = list;
 }
 }
 |
 |
@@ -246,7 +246,7 @@ PE_KERNEL_PMU_EVENT sep_dc
 
 
 	ALLOC_LIST(list);
 	ALLOC_LIST(list);
 	ABORT_ON(parse_events_add_pmu(data, list, "cpu", head));
 	ABORT_ON(parse_events_add_pmu(data, list, "cpu", head));
-	parse_events__free_terms(head);
+	parse_events_terms__delete(head);
 	$$ = list;
 	$$ = list;
 }
 }
 |
 |
@@ -266,7 +266,7 @@ PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc
 
 
 	ALLOC_LIST(list);
 	ALLOC_LIST(list);
 	ABORT_ON(parse_events_add_pmu(data, list, "cpu", head));
 	ABORT_ON(parse_events_add_pmu(data, list, "cpu", head));
-	parse_events__free_terms(head);
+	parse_events_terms__delete(head);
 	$$ = list;
 	$$ = list;
 }
 }
 
 
@@ -285,7 +285,7 @@ value_sym '/' event_config '/'
 
 
 	ALLOC_LIST(list);
 	ALLOC_LIST(list);
 	ABORT_ON(parse_events_add_numeric(data, list, type, config, $3));
 	ABORT_ON(parse_events_add_numeric(data, list, type, config, $3));
-	parse_events__free_terms($3);
+	parse_events_terms__delete($3);
 	$$ = list;
 	$$ = list;
 }
 }
 |
 |

+ 1 - 1
tools/perf/util/pmu.c

@@ -354,7 +354,7 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias,
 	list_for_each_entry(term, &alias->terms, list) {
 	list_for_each_entry(term, &alias->terms, list) {
 		ret = parse_events_term__clone(&cloned, term);
 		ret = parse_events_term__clone(&cloned, term);
 		if (ret) {
 		if (ret) {
-			parse_events__free_terms(&list);
+			parse_events_terms__purge(&list);
 			return ret;
 			return ret;
 		}
 		}
 		list_add_tail(&cloned->list, &list);
 		list_add_tail(&cloned->list, &list);

+ 12 - 11
tools/perf/util/sort.c

@@ -28,7 +28,15 @@ int		sort__has_socket = 0;
 int		sort__has_thread = 0;
 int		sort__has_thread = 0;
 enum sort_mode	sort__mode = SORT_MODE__NORMAL;
 enum sort_mode	sort__mode = SORT_MODE__NORMAL;
 
 
-
+/*
+ * Replaces all occurrences of a char used with the:
+ *
+ * -t, --field-separator
+ *
+ * option, that uses a special separator character and don't pad with spaces,
+ * replacing all occurances of this separator in symbol names (and other
+ * output) with a '.' character, that thus it's the only non valid separator.
+*/
 static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
 static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
 {
 {
 	int n;
 	int n;
@@ -247,10 +255,8 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
 			ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
 			ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
 			ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
 			ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
 					ip - map->unmap_ip(map, sym->start));
 					ip - map->unmap_ip(map, sym->start));
-			ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
-				       width - ret, "");
 		} else {
 		} else {
-			ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
+			ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
 					       width - ret,
 					       width - ret,
 					       sym->name);
 					       sym->name);
 		}
 		}
@@ -258,14 +264,9 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
 		size_t len = BITS_PER_LONG / 4;
 		size_t len = BITS_PER_LONG / 4;
 		ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
 		ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
 				       len, ip);
 				       len, ip);
-		ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
-				       width - ret, "");
 	}
 	}
 
 
-	if (ret > width)
-		bf[width] = '\0';
-
-	return width;
+	return ret;
 }
 }
 
 
 static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
 static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
@@ -811,7 +812,7 @@ static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
 	else
 	else
 		out = "No";
 		out = "No";
 
 
-	return repsep_snprintf(bf, size, "%-*s", width, out);
+	return repsep_snprintf(bf, size, "%.*s", width, out);
 }
 }
 
 
 static int64_t
 static int64_t

+ 4 - 0
tools/perf/util/symbol.c

@@ -1529,6 +1529,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 	if (!runtime_ss && syms_ss)
 	if (!runtime_ss && syms_ss)
 		runtime_ss = syms_ss;
 		runtime_ss = syms_ss;
 
 
+	if (syms_ss && syms_ss->type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
+		if (dso__build_id_is_kmod(dso, name, PATH_MAX))
+			kmod = true;
+
 	if (syms_ss)
 	if (syms_ss)
 		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
 		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
 	else
 	else