提交 7977fed9 编写于 作者: I Ingo Molnar

Merge tag 'perf-urgent-for-mingo-5.6-20200228' of...

Merge tag 'perf-urgent-for-mingo-5.6-20200228' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent

Pull perf/urgent fixes from Arnaldo Carvalho de Melo:

perf annotate:

  Ravi Bangoria:

  - Fix segfault with source toggle.

  - Fix --show-total-period and --show-nr-samples for tui/stdio2.

  - Fix handling of settings in ~/.perfconfig versus the ones passed
    in the command line

  - Re-render title bar after switching back from script browser.

  - Fix options man page, document some missing ones.

perf probe:

  He Zhe:

  - Check return value of strlist__add() for -ENOMEM.

tools UAPI:

  Arnaldo Carvalho de Melo:

  - Sync x86's msr-index.h copy with the kernel sources.

  - Update tools's copy of x86's kvm.h headers.
Signed-off-by: NArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: NIngo Molnar <mingo@kernel.org>
......@@ -512,6 +512,8 @@
#define MSR_K7_HWCR 0xc0010015
#define MSR_K7_HWCR_SMMLOCK_BIT 0
#define MSR_K7_HWCR_SMMLOCK BIT_ULL(MSR_K7_HWCR_SMMLOCK_BIT)
#define MSR_K7_HWCR_IRPERF_EN_BIT 30
#define MSR_K7_HWCR_IRPERF_EN BIT_ULL(MSR_K7_HWCR_IRPERF_EN_BIT)
#define MSR_K7_FID_VID_CTL 0xc0010041
#define MSR_K7_FID_VID_STATUS 0xc0010042
......
......@@ -390,6 +390,7 @@ struct kvm_sync_regs {
#define KVM_STATE_NESTED_GUEST_MODE 0x00000001
#define KVM_STATE_NESTED_RUN_PENDING 0x00000002
#define KVM_STATE_NESTED_EVMCS 0x00000004
#define KVM_STATE_NESTED_MTF_PENDING 0x00000008
#define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001
#define KVM_STATE_NESTED_SMM_VMXON 0x00000002
......
......@@ -239,7 +239,6 @@ buildid.*::
set buildid.dir to /dev/null. The default is $HOME/.debug
annotate.*::
These options work only for TUI.
These are in control of addresses, jump function, source code
in lines of assembly code from a specific program.
......@@ -269,6 +268,8 @@ annotate.*::
│ mov (%rdi),%rdx
│ return n;
This option works with tui, stdio2 browsers.
annotate.use_offset::
Basing on a first address of a loaded function, offset can be used.
Instead of using original addresses of assembly code,
......@@ -287,6 +288,8 @@ annotate.*::
368:│ mov 0x8(%r14),%rdi
This option works with tui, stdio2 browsers.
annotate.jump_arrows::
There can be jump instruction among assembly code.
Depending on a boolean value of jump_arrows,
......@@ -306,6 +309,8 @@ annotate.*::
│1330: mov %r15,%r10
│1333: cmp %r15,%r14
This option works with tui browser.
annotate.show_linenr::
When showing source code if this option is 'true',
line numbers are printed as below.
......@@ -325,6 +330,8 @@ annotate.*::
│ array++;
│ }
This option works with tui, stdio2 browsers.
annotate.show_nr_jumps::
Let's see a part of assembly code.
......@@ -335,6 +342,8 @@ annotate.*::
│1 1382: movb $0x1,-0x270(%rbp)
This option works with tui, stdio2 browsers.
annotate.show_total_period::
To compare two records on an instruction base, with this option
provided, display total number of samples that belong to a line
......@@ -348,11 +357,30 @@ annotate.*::
99.93 │ mov %eax,%eax
This option works with tui, stdio2, stdio browsers.
annotate.show_nr_samples::
By default perf annotate shows percentage of samples. This option
can be used to print absolute number of samples. Ex, when set as
false:
Percent│
74.03 │ mov %fs:0x28,%rax
When set as true:
Samples│
6 │ mov %fs:0x28,%rax
This option works with tui, stdio2, stdio browsers.
annotate.offset_level::
Default is '1', meaning just jump targets will have offsets show right beside
the instruction. When set to '2' 'call' instructions will also have its offsets
shown, 3 or higher will show offsets for all instructions.
This option works with tui, stdio2 browsers.
hist.*::
hist.percentage::
This option control the way to calculate overhead of filtered entries -
......@@ -490,6 +518,12 @@ top.*::
column by default.
The default is 'true'.
top.call-graph::
This is identical to 'call-graph.record-mode', except it is
applicable only for 'top' subcommand. This option ONLY setup
the unwind method. To enable 'perf top' to actually use it,
the command line option -g must be specified.
man.*::
man.viewer::
This option can assign a tool to view manual pages when 'help'
......@@ -517,6 +551,16 @@ record.*::
But if this option is 'no-cache', it will not update the build-id cache.
'skip' skips post-processing and does not update the cache.
record.call-graph::
This is identical to 'call-graph.record-mode', except it is
applicable only for 'record' subcommand. This option ONLY setup
the unwind method. To enable 'perf record' to actually use it,
the command line option -g must be specified.
record.aio::
Use 'n' control blocks in asynchronous (Posix AIO) trace writing
mode ('n' default: 1, max: 4).
diff.*::
diff.order::
This option sets the number of columns to sort the result.
......@@ -566,6 +610,11 @@ trace.*::
"libbeauty", the default, to use the same argument beautifiers used in the
strace-like sys_enter+sys_exit lines.
ftrace.*::
ftrace.tracer::
Can be used to select the default tracer. Possible values are
'function' and 'function_graph'.
llvm.*::
llvm.clang-path::
Path to clang. If omit, search it from $PATH.
......@@ -610,6 +659,29 @@ scripts.*::
The script gets the same options passed as a full perf script,
in particular -i perfdata file, --cpu, --tid
convert.*::
convert.queue-size::
Limit the size of ordered_events queue, so we could control
allocation size of perf data files without proper finished
round events.
intel-pt.*::
intel-pt.cache-divisor::
intel-pt.mispred-all::
If set, Intel PT decoder will set the mispred flag on all
branches.
auxtrace.*::
auxtrace.dumpdir::
s390 only. The directory to save the auxiliary trace buffer
can be changed using this option. Ex, auxtrace.dumpdir=/tmp.
If the directory does not exist or has the wrong file type,
the current directory is used.
SEE ALSO
--------
linkperf:perf[1]
......@@ -566,6 +566,8 @@ int cmd_annotate(int argc, const char **argv)
if (ret < 0)
return ret;
annotation_config__init(&annotate.opts);
argc = parse_options(argc, argv, options, annotate_usage, 0);
if (argc) {
/*
......@@ -605,8 +607,6 @@ int cmd_annotate(int argc, const char **argv)
if (ret < 0)
goto out_delete;
annotation_config__init();
symbol_conf.try_vmlinux_path = true;
ret = symbol__init(&annotate.session->header.env);
......
......@@ -449,7 +449,8 @@ static int perf_del_probe_events(struct strfilter *filter)
ret = probe_file__del_strlist(kfd, klist);
if (ret < 0)
goto error;
}
} else if (ret == -ENOMEM)
goto error;
ret2 = probe_file__get_events(ufd, filter, ulist);
if (ret2 == 0) {
......@@ -459,7 +460,8 @@ static int perf_del_probe_events(struct strfilter *filter)
ret2 = probe_file__del_strlist(ufd, ulist);
if (ret2 < 0)
goto error;
}
} else if (ret2 == -ENOMEM)
goto error;
if (ret == -ENOENT && ret2 == -ENOENT)
pr_warning("\"%s\" does not hit any event.\n", str);
......
......@@ -1507,7 +1507,7 @@ int cmd_report(int argc, const char **argv)
symbol_conf.priv_size += sizeof(u32);
symbol_conf.sort_by_name = true;
}
annotation_config__init();
annotation_config__init(&report.annotation_opts);
}
if (symbol__init(&session->header.env) < 0)
......
......@@ -143,7 +143,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
return err;
}
err = symbol__annotate(&he->ms, evsel, 0, &top->annotation_opts, NULL);
err = symbol__annotate(&he->ms, evsel, &top->annotation_opts, NULL);
if (err == 0) {
top->sym_filter_entry = he;
} else {
......@@ -1683,7 +1683,7 @@ int cmd_top(int argc, const char **argv)
if (status < 0)
goto out_delete_evlist;
annotation_config__init();
annotation_config__init(&top.annotation_opts);
symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
status = symbol__init(NULL);
......
......@@ -754,10 +754,9 @@ static int annotate_browser__run(struct annotate_browser *browser,
"? Search string backwards\n");
continue;
case 'r':
{
script_browse(NULL, NULL);
annotate_browser__show(&browser->b, title, help);
continue;
}
case 'k':
notes->options->show_linenr = !notes->options->show_linenr;
break;
......@@ -834,13 +833,13 @@ static int annotate_browser__run(struct annotate_browser *browser,
map_symbol__annotation_dump(ms, evsel, browser->opts);
continue;
case 't':
if (notes->options->show_total_period) {
notes->options->show_total_period = false;
notes->options->show_nr_samples = true;
} else if (notes->options->show_nr_samples)
notes->options->show_nr_samples = false;
if (symbol_conf.show_total_period) {
symbol_conf.show_total_period = false;
symbol_conf.show_nr_samples = true;
} else if (symbol_conf.show_nr_samples)
symbol_conf.show_nr_samples = false;
else
notes->options->show_total_period = true;
symbol_conf.show_total_period = true;
annotation__update_column_widths(notes);
continue;
case 'c':
......
......@@ -174,7 +174,7 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel,
if (ms->map->dso->annotate_warned)
return -1;
err = symbol__annotate(ms, evsel, 0, &annotation__default_options, NULL);
err = symbol__annotate(ms, evsel, &annotation__default_options, NULL);
if (err) {
char msg[BUFSIZ];
symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
......
......@@ -1143,7 +1143,6 @@ static int disasm_line__parse(char *line, const char **namep, char **rawp)
}
struct annotate_args {
size_t privsize;
struct arch *arch;
struct map_symbol ms;
struct evsel *evsel;
......@@ -1153,74 +1152,53 @@ struct annotate_args {
int line_nr;
};
static void annotation_line__delete(struct annotation_line *al)
static void annotation_line__init(struct annotation_line *al,
struct annotate_args *args,
int nr)
{
void *ptr = (void *) al - al->privsize;
al->offset = args->offset;
al->line = strdup(args->line);
al->line_nr = args->line_nr;
al->data_nr = nr;
}
static void annotation_line__exit(struct annotation_line *al)
{
free_srcline(al->path);
zfree(&al->line);
free(ptr);
}
/*
* Allocating the annotation line data with following
* structure:
*
* --------------------------------------
* private space | struct annotation_line
* --------------------------------------
*
* Size of the private space is stored in 'struct annotation_line'.
*
*/
static struct annotation_line *
annotation_line__new(struct annotate_args *args, size_t privsize)
static size_t disasm_line_size(int nr)
{
struct annotation_line *al;
struct evsel *evsel = args->evsel;
size_t size = privsize + sizeof(*al);
int nr = 1;
if (perf_evsel__is_group_event(evsel))
nr = evsel->core.nr_members;
size += sizeof(al->data[0]) * nr;
al = zalloc(size);
if (al) {
al = (void *) al + privsize;
al->privsize = privsize;
al->offset = args->offset;
al->line = strdup(args->line);
al->line_nr = args->line_nr;
al->data_nr = nr;
}
return al;
return (sizeof(struct disasm_line) + (sizeof(al->data[0]) * nr));
}
/*
* Allocating the disasm annotation line data with
* following structure:
*
* ------------------------------------------------------------
* privsize space | struct disasm_line | struct annotation_line
* ------------------------------------------------------------
* -------------------------------------------
* struct disasm_line | struct annotation_line
* -------------------------------------------
*
* We have 'struct annotation_line' member as last member
* of 'struct disasm_line' to have an easy access.
*
*/
static struct disasm_line *disasm_line__new(struct annotate_args *args)
{
struct disasm_line *dl = NULL;
struct annotation_line *al;
size_t privsize = args->privsize + offsetof(struct disasm_line, al);
int nr = 1;
al = annotation_line__new(args, privsize);
if (al != NULL) {
dl = disasm_line(al);
if (perf_evsel__is_group_event(args->evsel))
nr = args->evsel->core.nr_members;
dl = zalloc(disasm_line_size(nr));
if (!dl)
return NULL;
annotation_line__init(&dl->al, args, nr);
if (dl->al.line == NULL)
goto out_delete;
......@@ -1230,7 +1208,6 @@ static struct disasm_line *disasm_line__new(struct annotate_args *args)
disasm_line__init_ins(dl, args->arch, &args->ms);
}
}
return dl;
......@@ -1248,7 +1225,8 @@ void disasm_line__free(struct disasm_line *dl)
else
ins__delete(&dl->ops);
zfree(&dl->ins.name);
annotation_line__delete(&dl->al);
annotation_line__exit(&dl->al);
free(dl);
}
int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name)
......@@ -2149,13 +2127,12 @@ void symbol__calc_percent(struct symbol *sym, struct evsel *evsel)
annotation__calc_percent(notes, evsel, symbol__size(sym));
}
int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, size_t privsize,
int symbol__annotate(struct map_symbol *ms, struct evsel *evsel,
struct annotation_options *options, struct arch **parch)
{
struct symbol *sym = ms->sym;
struct annotation *notes = symbol__annotation(sym);
struct annotate_args args = {
.privsize = privsize,
.evsel = evsel,
.options = options,
};
......@@ -2644,6 +2621,8 @@ void annotation__set_offsets(struct annotation *notes, s64 size)
struct annotation_line *al;
notes->max_line_len = 0;
notes->nr_entries = 0;
notes->nr_asm_entries = 0;
list_for_each_entry(al, &notes->src->source, node) {
size_t line_len = strlen(al->line);
......@@ -2790,7 +2769,7 @@ int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel,
struct symbol *sym = ms->sym;
struct rb_root source_line = RB_ROOT;
if (symbol__annotate(ms, evsel, 0, opts, NULL) < 0)
if (symbol__annotate(ms, evsel, opts, NULL) < 0)
return -1;
symbol__calc_percent(sym, evsel);
......@@ -2915,9 +2894,9 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
percent = annotation_data__percent(&al->data[i], percent_type);
obj__set_percent_color(obj, percent, current_entry);
if (notes->options->show_total_period) {
if (symbol_conf.show_total_period) {
obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period);
} else if (notes->options->show_nr_samples) {
} else if (symbol_conf.show_nr_samples) {
obj__printf(obj, "%6" PRIu64 " ",
al->data[i].he.nr_samples);
} else {
......@@ -2931,8 +2910,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
obj__printf(obj, "%-*s", pcnt_width, " ");
else {
obj__printf(obj, "%-*s", pcnt_width,
notes->options->show_total_period ? "Period" :
notes->options->show_nr_samples ? "Samples" : "Percent");
symbol_conf.show_total_period ? "Period" :
symbol_conf.show_nr_samples ? "Samples" : "Percent");
}
}
......@@ -3070,7 +3049,7 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel,
if (perf_evsel__is_group_event(evsel))
nr_pcnt = evsel->core.nr_members;
err = symbol__annotate(ms, evsel, 0, options, parch);
err = symbol__annotate(ms, evsel, options, parch);
if (err)
goto out_free_offsets;
......@@ -3094,69 +3073,46 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel,
return err;
}
#define ANNOTATION__CFG(n) \
{ .name = #n, .value = &annotation__default_options.n, }
/*
* Keep the entries sorted, they are bsearch'ed
*/
static struct annotation_config {
const char *name;
void *value;
} annotation__configs[] = {
ANNOTATION__CFG(hide_src_code),
ANNOTATION__CFG(jump_arrows),
ANNOTATION__CFG(offset_level),
ANNOTATION__CFG(show_linenr),
ANNOTATION__CFG(show_nr_jumps),
ANNOTATION__CFG(show_nr_samples),
ANNOTATION__CFG(show_total_period),
ANNOTATION__CFG(use_offset),
};
#undef ANNOTATION__CFG
static int annotation_config__cmp(const void *name, const void *cfgp)
{
const struct annotation_config *cfg = cfgp;
return strcmp(name, cfg->name);
}
static int annotation__config(const char *var, const char *value,
void *data __maybe_unused)
static int annotation__config(const char *var, const char *value, void *data)
{
struct annotation_config *cfg;
const char *name;
struct annotation_options *opt = data;
if (!strstarts(var, "annotate."))
return 0;
name = var + 9;
cfg = bsearch(name, annotation__configs, ARRAY_SIZE(annotation__configs),
sizeof(struct annotation_config), annotation_config__cmp);
if (cfg == NULL)
pr_debug("%s variable unknown, ignoring...", var);
else if (strcmp(var, "annotate.offset_level") == 0) {
perf_config_int(cfg->value, name, value);
if (*(int *)cfg->value > ANNOTATION__MAX_OFFSET_LEVEL)
*(int *)cfg->value = ANNOTATION__MAX_OFFSET_LEVEL;
else if (*(int *)cfg->value < ANNOTATION__MIN_OFFSET_LEVEL)
*(int *)cfg->value = ANNOTATION__MIN_OFFSET_LEVEL;
if (!strcmp(var, "annotate.offset_level")) {
perf_config_u8(&opt->offset_level, "offset_level", value);
if (opt->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
opt->offset_level = ANNOTATION__MAX_OFFSET_LEVEL;
else if (opt->offset_level < ANNOTATION__MIN_OFFSET_LEVEL)
opt->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
} else if (!strcmp(var, "annotate.hide_src_code")) {
opt->hide_src_code = perf_config_bool("hide_src_code", value);
} else if (!strcmp(var, "annotate.jump_arrows")) {
opt->jump_arrows = perf_config_bool("jump_arrows", value);
} else if (!strcmp(var, "annotate.show_linenr")) {
opt->show_linenr = perf_config_bool("show_linenr", value);
} else if (!strcmp(var, "annotate.show_nr_jumps")) {
opt->show_nr_jumps = perf_config_bool("show_nr_jumps", value);
} else if (!strcmp(var, "annotate.show_nr_samples")) {
symbol_conf.show_nr_samples = perf_config_bool("show_nr_samples",
value);
} else if (!strcmp(var, "annotate.show_total_period")) {
symbol_conf.show_total_period = perf_config_bool("show_total_period",
value);
} else if (!strcmp(var, "annotate.use_offset")) {
opt->use_offset = perf_config_bool("use_offset", value);
} else {
*(bool *)cfg->value = perf_config_bool(name, value);
pr_debug("%s variable unknown, ignoring...", var);
}
return 0;
}
void annotation_config__init(void)
void annotation_config__init(struct annotation_options *opt)
{
perf_config(annotation__config, NULL);
annotation__default_options.show_total_period = symbol_conf.show_total_period;
annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples;
perf_config(annotation__config, opt);
}
static unsigned int parse_percent_type(char *str1, char *str2)
......
......@@ -83,8 +83,6 @@ struct annotation_options {
full_path,
show_linenr,
show_nr_jumps,
show_nr_samples,
show_total_period,
show_minmax_cycle,
show_asm_raw,
annotate_src;
......@@ -141,7 +139,6 @@ struct annotation_line {
u64 cycles;
u64 cycles_max;
u64 cycles_min;
size_t privsize;
char *path;
u32 idx;
int idx_asm;
......@@ -309,7 +306,7 @@ static inline int annotation__cycles_width(struct annotation *notes)
static inline int annotation__pcnt_width(struct annotation *notes)
{
return (notes->options->show_total_period ? 12 : 7) * notes->nr_events;
return (symbol_conf.show_total_period ? 12 : 7) * notes->nr_events;
}
static inline bool annotation_line__filter(struct annotation_line *al, struct annotation *notes)
......@@ -352,7 +349,7 @@ struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists);
void symbol__annotate_zero_histograms(struct symbol *sym);
int symbol__annotate(struct map_symbol *ms,
struct evsel *evsel, size_t privsize,
struct evsel *evsel,
struct annotation_options *options,
struct arch **parch);
int symbol__annotate2(struct map_symbol *ms,
......@@ -413,7 +410,7 @@ static inline int symbol__tui_annotate(struct map_symbol *ms __maybe_unused,
}
#endif
void annotation_config__init(void);
void annotation_config__init(struct annotation_options *opt);
int annotate_parse_percent_type(const struct option *opt, const char *_str,
int unset);
......
......@@ -374,6 +374,18 @@ int perf_config_int(int *dest, const char *name, const char *value)
return 0;
}
int perf_config_u8(u8 *dest, const char *name, const char *value)
{
long ret = 0;
if (!perf_parse_long(value, &ret)) {
bad_config(name);
return -1;
}
*dest = ret;
return 0;
}
static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
{
int ret;
......
......@@ -29,6 +29,7 @@ typedef int (*config_fn_t)(const char *, const char *, void *);
int perf_default_config(const char *, const char *, void *);
int perf_config(config_fn_t fn, void *);
int perf_config_int(int *dest, const char *, const char *);
int perf_config_u8(u8 *dest, const char *name, const char *value);
int perf_config_u64(u64 *dest, const char *, const char *);
int perf_config_bool(const char *, const char *);
int config_error_nonbool(const char *);
......
......@@ -301,10 +301,15 @@ int probe_file__get_events(int fd, struct strfilter *filter,
p = strchr(ent->s, ':');
if ((p && strfilter__compare(filter, p + 1)) ||
strfilter__compare(filter, ent->s)) {
strlist__add(plist, ent->s);
ret = strlist__add(plist, ent->s);
if (ret == -ENOMEM) {
pr_err("strlist__add failed with -ENOMEM\n");
goto out;
}
ret = 0;
}
}
out:
strlist__delete(namelist);
return ret;
......@@ -511,7 +516,11 @@ static int probe_cache__load(struct probe_cache *pcache)
ret = -EINVAL;
goto out;
}
strlist__add(entry->tevlist, buf);
ret = strlist__add(entry->tevlist, buf);
if (ret == -ENOMEM) {
pr_err("strlist__add failed with -ENOMEM\n");
goto out;
}
}
}
out:
......@@ -672,7 +681,12 @@ int probe_cache__add_entry(struct probe_cache *pcache,
command = synthesize_probe_trace_command(&tevs[i]);
if (!command)
goto out_err;
strlist__add(entry->tevlist, command);
ret = strlist__add(entry->tevlist, command);
if (ret == -ENOMEM) {
pr_err("strlist__add failed with -ENOMEM\n");
goto out_err;
}
free(command);
}
list_add_tail(&entry->node, &pcache->entries);
......@@ -853,9 +867,15 @@ int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
break;
}
strlist__add(entry->tevlist, buf);
ret = strlist__add(entry->tevlist, buf);
free(buf);
entry = NULL;
if (ret == -ENOMEM) {
pr_err("strlist__add failed with -ENOMEM\n");
break;
}
}
if (entry) {
list_del_init(&entry->node);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册