Commit fe7a2eaa authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents a7636d9e 1ad826ba
......@@ -8,7 +8,7 @@ perf-config - Get and set variables in a configuration file.
SYNOPSIS
--------
[verse]
'perf config' -l | --list
'perf config' [<file-option>] -l | --list
DESCRIPTION
-----------
......@@ -21,6 +21,14 @@ OPTIONS
--list::
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
------------------
......@@ -30,6 +38,10 @@ The '$HOME/.perfconfig' file is used to store a per-user configuration.
The file '$(sysconfdir)/perfconfig' can be used to
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
~~~~~~
......
......@@ -139,6 +139,8 @@ $(call allow-override,CC,$(CROSS_COMPILE)gcc)
$(call allow-override,AR,$(CROSS_COMPILE)ar)
$(call allow-override,LD,$(CROSS_COMPILE)ld)
LD += $(EXTRA_LDFLAGS)
PKG_CONFIG = $(CROSS_COMPILE)pkg-config
RM = rm -f
......
......@@ -89,7 +89,7 @@ static int intel_pt_parse_terms_with_default(struct list_head *formats,
*config = attr.config;
out_free:
parse_events__free_terms(terms);
parse_events_terms__delete(terms);
return err;
}
......
......@@ -13,8 +13,10 @@
#include "util/util.h"
#include "util/debug.h"
static bool use_system_config, use_user_config;
static const char * const config_usage[] = {
"perf config [options]",
"perf config [<file-option>] [options]",
NULL
};
......@@ -25,6 +27,8 @@ enum actions {
static struct option config_options[] = {
OPT_SET_UINT('l', "list", &actions,
"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()
};
......@@ -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 ret = 0;
char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
argc = parse_options(argc, argv, config_options, config_usage,
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) {
case ACTION_LIST:
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);
} else {
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, "
"please check your ~/.perfconfig file\n");
"please check your %s \n", config_filename);
}
}
break;
default:
......
......@@ -71,7 +71,10 @@ try:
except:
if not audit_package_warned:
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):
try:
......
......@@ -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;
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_SETSIG, signal);
fcntl(fd, F_SETSIG, sig);
fcntl(fd, F_SETOWN, getpid());
ioctl(fd, PERF_EVENT_IOC_RESET, 0);
......@@ -141,14 +141,14 @@ static int __event(bool is_x, void *addr, int signal)
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)
......
......@@ -1666,7 +1666,7 @@ static int test_term(struct terms_test *t)
}
ret = t->check(&terms);
parse_events__free_terms(&terms);
parse_events_terms__purge(&terms);
return ret;
}
......
......@@ -1061,7 +1061,6 @@ static int hist_browser__show_entry(struct hist_browser *browser,
struct hist_entry *entry,
unsigned short row)
{
char s[256];
int printed = 0;
int width = browser->b.width;
char folded_sign = ' ';
......@@ -1086,16 +1085,18 @@ static int hist_browser__show_entry(struct hist_browser *browser,
.folded_sign = folded_sign,
.current_entry = current_entry,
};
struct perf_hpp hpp = {
.buf = s,
.size = sizeof(s),
.ptr = &arg,
};
int column = 0;
hist_browser__gotorc(browser, row, 0);
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) ||
column++ < browser->b.horiz_scroll)
continue;
......@@ -1120,11 +1121,18 @@ static int hist_browser__show_entry(struct hist_browser *browser,
}
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 {
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);
}
width -= hpp.buf - s;
}
/* The scroll bar isn't being used */
......@@ -1452,9 +1460,10 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
first = false;
ret = fmt->entry(fmt, &hpp, he);
ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
advance_hpp(&hpp, ret);
}
printed += fprintf(fp, "%s\n", rtrim(s));
printed += fprintf(fp, "%s\n", s);
if (folded_sign == '-')
printed += hist_browser__fprintf_callchain(browser, he, fp);
......
......@@ -403,6 +403,7 @@ static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
else
ret = fmt->entry(fmt, hpp, he);
ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
advance_hpp(hpp, ret);
}
......
......@@ -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);
}
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) \
list_for_each_entry(pos, head, node) \
if (!pos->has_build_id) \
......
......@@ -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);
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,
struct perf_sample *sample, struct perf_evsel *evsel,
......
......@@ -23,6 +23,8 @@
#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
#define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
extern const char *config_exclusive_filename;
typedef int (*config_fn_t)(const char *, const char *, void *);
extern int perf_default_config(const char *, const char *, 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 config_error_nonbool(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);
int split_cmdline(char *cmdline, const char ***argv);
......
......@@ -26,7 +26,7 @@ static const char *config_file_name;
static int config_linenr;
static int config_file_eof;
static const char *config_exclusive_filename;
const char *config_exclusive_filename;
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;
}
static const char *perf_etc_perfconfig(void)
const char *perf_etc_perfconfig(void)
{
static const char *system_wide;
if (!system_wide)
......
......@@ -858,6 +858,23 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session)
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)
{
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,
c.events_count);
cleanup_events(session);
perf_session__delete(session);
ctf_writer__cleanup(cw);
......
......@@ -1014,6 +1014,27 @@ void hist_entry__delete(struct hist_entry *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
*/
......
......@@ -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 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__collapse(struct hist_entry *left, struct hist_entry *right);
int hist_entry__transaction_len(void);
int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size,
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 perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog);
......
......@@ -1386,8 +1386,7 @@ int parse_events_terms(struct list_head *terms, const char *str)
return 0;
}
if (data.terms)
parse_events__free_terms(data.terms);
parse_events_terms__delete(data.terms);
return ret;
}
......@@ -2068,12 +2067,22 @@ int parse_events_term__clone(struct parse_events_term **new,
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;
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);
}
}
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,
......
......@@ -115,7 +115,8 @@ int parse_events_term__sym_hw(struct parse_events_term **term,
char *config, unsigned idx);
int parse_events_term__clone(struct parse_events_term **new,
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_group(struct list_head *list, char *event_mod);
int parse_events_name(struct list_head *list, char *name);
......
......@@ -218,7 +218,7 @@ PE_NAME '/' event_config '/'
ALLOC_LIST(list);
ABORT_ON(parse_events_add_pmu(data, list, $1, $3));
parse_events__free_terms($3);
parse_events_terms__delete($3);
$$ = list;
}
|
......@@ -246,7 +246,7 @@ PE_KERNEL_PMU_EVENT sep_dc
ALLOC_LIST(list);
ABORT_ON(parse_events_add_pmu(data, list, "cpu", head));
parse_events__free_terms(head);
parse_events_terms__delete(head);
$$ = list;
}
|
......@@ -266,7 +266,7 @@ PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc
ALLOC_LIST(list);
ABORT_ON(parse_events_add_pmu(data, list, "cpu", head));
parse_events__free_terms(head);
parse_events_terms__delete(head);
$$ = list;
}
......@@ -285,7 +285,7 @@ value_sym '/' event_config '/'
ALLOC_LIST(list);
ABORT_ON(parse_events_add_numeric(data, list, type, config, $3));
parse_events__free_terms($3);
parse_events_terms__delete($3);
$$ = list;
}
|
......
......@@ -354,7 +354,7 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias,
list_for_each_entry(term, &alias->terms, list) {
ret = parse_events_term__clone(&cloned, term);
if (ret) {
parse_events__free_terms(&list);
parse_events_terms__purge(&list);
return ret;
}
list_add_tail(&cloned->list, &list);
......
......@@ -28,7 +28,15 @@ int sort__has_socket = 0;
int sort__has_thread = 0;
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, ...)
{
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, "+0x%llx",
ip - map->unmap_ip(map, sym->start));
ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
width - ret, "");
} else {
ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
width - ret,
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;
ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
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,
......@@ -811,7 +812,7 @@ static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
else
out = "No";
return repsep_snprintf(bf, size, "%-*s", width, out);
return repsep_snprintf(bf, size, "%.*s", width, out);
}
static int64_t
......
......@@ -1529,6 +1529,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
if (!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)
ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment