perf/core improvements and fixes:
User visible: - Add 'vmlinux.debug' to the vmlinux seach path (Ekaterina Tumanova) - Do not show sample_(type|period) in the perf_event_attr dump when using -v with 'perf stat' (Jiri Olsa) - Display the WEIGHT sample bit, when set, in 'perf evlist -v' (Jiri Olsa) - Honour --hide-unresolved in 'report', will honour it as well in 'top' when --hide-unresolved gets supported in that tool (Namhyung Kim) - Fix freeze wit h--call-graph 'flat/folded' due to not properly reinitializing the callchain rb_tree (Namhyumg Kim) - Set dso->long_name when a module name is passed as a parameter to tools like 'perf probe' but the 'struct dso' associated to that module still doesn't have the full path for the module, just the '[name]' one obtained from /proc/modules (Wang Nan) - Fix anon_hugepage mmaps detection using scanf on /proc/PID/smaps (Yannick Brosseau) Infrastructure: - Add helper function for updating bpf maps elements (He Kuang) - Fix traceevents plugins build race (Jiri Olsa) - Add the $OUTPUT path prefix with 'fixdep' (Jiri Olsa) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWV20zAAoJENZQFvNTUqpAPbEQALjHQhbG/28sFR+YOVGnOUSL dI+VPMxE6KymFG5luzuVSmvYVatu1brhIk6SbzI57mRWPhqtDfQ+GCdyyPKvbb3a A3DrIWqaGaoq3SskYP/OvAwFydvYU+m9q4dNdByU3+M+ZpLfC3puTrc8gHrtyalU UEitn6Qjbr/LqIm1kCPg2OZJxbbpyxNtjPsaMcS6tkl/CyGg/kPGD6BbKsycHMvI EJanNhlir0AnqFn+JVW7CNSxWmnHr5py1Fhx3YKN6Nv5eQSTbOA0l35YaKNiz2Rj BjF+dy/TChp5WqimLbjHR1+RkaEsVviyZM+y0EeIa7FYvEo713Au3QcV98VzJ0Cq ERiLb9F4dZxQL85w11pZQG/BKy7WLf72k7QOKmHLJsC4Aq26zjYMo6FRj4k82hgN 1uZEi5lRowKdjafvjD07yu0po+yUbol/AW6sopCaEkk03uby5qxXRwDLwjf7Iu16 aWT6z0087k+oRpgVhBs0UyU6qY2X3dOUVO4+ZwfJ1eWEFuktAR4F945DUflC6QQV eU6j/VlVjxINaqxG2Z47lQRBVvckJ9Fq7hhLlY58cUPzlKmg2Ynac/AXwh8Y0CY2 HhrSBRFkzPuZ7Hfp6musK4V1QipQnzOkzNX8tYIVDLntlSsfaPuwDt/rzbN4pjza VzpD3uaAKzJGS9IwA9Pi =0IPx -----END PGP SIGNATURE----- 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: - Add 'vmlinux.debug' to the vmlinux search path (Ekaterina Tumanova) - Do not show sample_(type|period) in the perf_event_attr dump when using -v with 'perf stat' (Jiri Olsa) - Display the WEIGHT sample bit, when set, in 'perf evlist -v' (Jiri Olsa) - Honour --hide-unresolved in 'report', will honour it as well in 'top' when --hide-unresolved gets supported in that tool (Namhyung Kim) - Fix freeze wit h--call-graph 'flat/folded' due to not properly reinitializing the callchain rb_tree (Namhyumg Kim) - Set dso->long_name when a module name is passed as a parameter to tools like 'perf probe' but the 'struct dso' associated to that module still doesn't have the full path for the module, just the '[name]' one obtained from /proc/modules (Wang Nan) - Fix anon_hugepage mmaps detection using scanf on /proc/PID/smaps (Yannick Brosseau) Infrastructure changes: - Add helper function for updating bpf maps elements (He Kuang) - Fix traceevents plugins build race (Jiri Olsa) - Add the $OUTPUT path prefix with 'fixdep' (Jiri Olsa) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Коммит
3f3b1a46bf
|
@ -25,7 +25,7 @@ export Q srctree CC LD
|
|||
MAKEFLAGS := --no-print-directory
|
||||
build := -f $(srctree)/tools/build/Makefile.build dir=. obj
|
||||
|
||||
all: fixdep
|
||||
all: $(OUTPUT)fixdep
|
||||
|
||||
clean:
|
||||
$(call QUIET_CLEAN, fixdep)
|
||||
|
|
|
@ -4,7 +4,7 @@ ifdef CROSS_COMPILE
|
|||
fixdep:
|
||||
else
|
||||
fixdep:
|
||||
$(Q)$(MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= fixdep
|
||||
$(Q)$(MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= $(OUTPUT)fixdep
|
||||
endif
|
||||
|
||||
.PHONY: fixdep
|
||||
|
|
|
@ -83,3 +83,17 @@ int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns,
|
|||
log_buf[0] = 0;
|
||||
return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
||||
}
|
||||
|
||||
int bpf_map_update_elem(int fd, void *key, void *value,
|
||||
u64 flags)
|
||||
{
|
||||
union bpf_attr attr;
|
||||
|
||||
bzero(&attr, sizeof(attr));
|
||||
attr.map_fd = fd;
|
||||
attr.key = ptr_to_u64(key);
|
||||
attr.value = ptr_to_u64(value);
|
||||
attr.flags = flags;
|
||||
|
||||
return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
|
||||
}
|
||||
|
|
|
@ -20,4 +20,6 @@ int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns,
|
|||
u32 kern_version, char *log_buf,
|
||||
size_t log_buf_sz);
|
||||
|
||||
int bpf_map_update_elem(int fd, void *key, void *value,
|
||||
u64 flags);
|
||||
#endif
|
||||
|
|
|
@ -420,7 +420,7 @@ $(LIBTRACEEVENT)-clean:
|
|||
$(call QUIET_CLEAN, libtraceevent)
|
||||
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
|
||||
|
||||
install-traceevent-plugins: $(LIBTRACEEVENT)
|
||||
install-traceevent-plugins: libtraceevent_plugins
|
||||
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins
|
||||
|
||||
$(LIBAPI): fixdep FORCE
|
||||
|
|
|
@ -45,7 +45,6 @@ struct report {
|
|||
struct perf_tool tool;
|
||||
struct perf_session *session;
|
||||
bool use_tui, use_gtk, use_stdio;
|
||||
bool hide_unresolved;
|
||||
bool dont_use_callchains;
|
||||
bool show_full_info;
|
||||
bool show_threads;
|
||||
|
@ -146,7 +145,7 @@ static int process_sample_event(struct perf_tool *tool,
|
|||
struct hist_entry_iter iter = {
|
||||
.evsel = evsel,
|
||||
.sample = sample,
|
||||
.hide_unresolved = rep->hide_unresolved,
|
||||
.hide_unresolved = symbol_conf.hide_unresolved,
|
||||
.add_entry_cb = hist_iter__report_callback,
|
||||
};
|
||||
int ret = 0;
|
||||
|
@ -157,7 +156,7 @@ static int process_sample_event(struct perf_tool *tool,
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (rep->hide_unresolved && al.sym == NULL)
|
||||
if (symbol_conf.hide_unresolved && al.sym == NULL)
|
||||
goto out_put;
|
||||
|
||||
if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
|
||||
|
@ -740,7 +739,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
|
||||
"separator for columns, no spaces will be added between "
|
||||
"columns '.' is reserved."),
|
||||
OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved,
|
||||
OPT_BOOLEAN('U', "hide-unresolved", &symbol_conf.hide_unresolved,
|
||||
"Only display entries resolved to a symbol"),
|
||||
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
|
||||
"Look for files with symbols relative to this directory"),
|
||||
|
|
|
@ -588,8 +588,17 @@ static void print_sample_flags(u32 flags)
|
|||
printf(" %-4s ", str);
|
||||
}
|
||||
|
||||
static void process_event(union perf_event *event, struct perf_sample *sample,
|
||||
struct perf_evsel *evsel, struct addr_location *al)
|
||||
struct perf_script {
|
||||
struct perf_tool tool;
|
||||
struct perf_session *session;
|
||||
bool show_task_events;
|
||||
bool show_mmap_events;
|
||||
bool show_switch_events;
|
||||
};
|
||||
|
||||
static void process_event(struct perf_script *script __maybe_unused, union perf_event *event,
|
||||
struct perf_sample *sample, struct perf_evsel *evsel,
|
||||
struct addr_location *al)
|
||||
{
|
||||
struct thread *thread = al->thread;
|
||||
struct perf_event_attr *attr = &evsel->attr;
|
||||
|
@ -643,65 +652,33 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
static int default_start_script(const char *script __maybe_unused,
|
||||
int argc __maybe_unused,
|
||||
const char **argv __maybe_unused)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int default_flush_script(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int default_stop_script(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int default_generate_script(struct pevent *pevent __maybe_unused,
|
||||
const char *outfile __maybe_unused)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct scripting_ops default_scripting_ops = {
|
||||
.start_script = default_start_script,
|
||||
.flush_script = default_flush_script,
|
||||
.stop_script = default_stop_script,
|
||||
.process_event = process_event,
|
||||
.generate_script = default_generate_script,
|
||||
};
|
||||
|
||||
static struct scripting_ops *scripting_ops;
|
||||
|
||||
static void setup_scripting(void)
|
||||
{
|
||||
setup_perl_scripting();
|
||||
setup_python_scripting();
|
||||
|
||||
scripting_ops = &default_scripting_ops;
|
||||
}
|
||||
|
||||
static int flush_scripting(void)
|
||||
{
|
||||
return scripting_ops->flush_script();
|
||||
return scripting_ops ? scripting_ops->flush_script() : 0;
|
||||
}
|
||||
|
||||
static int cleanup_scripting(void)
|
||||
{
|
||||
pr_debug("\nperf script stopped\n");
|
||||
|
||||
return scripting_ops->stop_script();
|
||||
return scripting_ops ? scripting_ops->stop_script() : 0;
|
||||
}
|
||||
|
||||
static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
static int process_sample_event(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_evsel *evsel,
|
||||
struct machine *machine)
|
||||
{
|
||||
struct perf_script *scr = container_of(tool, struct perf_script, tool);
|
||||
struct addr_location al;
|
||||
|
||||
if (debug_mode) {
|
||||
|
@ -727,20 +704,16 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
|||
if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
|
||||
goto out_put;
|
||||
|
||||
scripting_ops->process_event(event, sample, evsel, &al);
|
||||
if (scripting_ops)
|
||||
scripting_ops->process_event(event, sample, evsel, &al);
|
||||
else
|
||||
process_event(scr, event, sample, evsel, &al);
|
||||
|
||||
out_put:
|
||||
addr_location__put(&al);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct perf_script {
|
||||
struct perf_tool tool;
|
||||
struct perf_session *session;
|
||||
bool show_task_events;
|
||||
bool show_mmap_events;
|
||||
bool show_switch_events;
|
||||
};
|
||||
|
||||
static int process_attr(struct perf_tool *tool, union perf_event *event,
|
||||
struct perf_evlist **pevlist)
|
||||
{
|
||||
|
|
|
@ -161,6 +161,13 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
|
|||
|
||||
attr->inherit = !no_inherit;
|
||||
|
||||
/*
|
||||
* Some events get initialized with sample_(period/type) set,
|
||||
* like tracepoints. Clear it up for counting.
|
||||
*/
|
||||
attr->sample_period = 0;
|
||||
attr->sample_type = 0;
|
||||
|
||||
if (target__has_cpu(&target))
|
||||
return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
|
||||
|
||||
|
|
|
@ -290,6 +290,7 @@ static void
|
|||
sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
|
||||
u64 min_hit, struct callchain_param *param __maybe_unused)
|
||||
{
|
||||
*rb_root = RB_ROOT;
|
||||
__sort_chain_flat(rb_root, &root->node, min_hit);
|
||||
}
|
||||
|
||||
|
|
|
@ -1192,6 +1192,7 @@ static void __p_sample_type(char *buf, size_t size, u64 value)
|
|||
bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
|
||||
bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
|
||||
bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC),
|
||||
bit_name(WEIGHT),
|
||||
{ .name = NULL, }
|
||||
};
|
||||
#undef bit_name
|
||||
|
|
|
@ -561,6 +561,24 @@ int machine__process_switch_event(struct machine *machine __maybe_unused,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dso__adjust_kmod_long_name(struct dso *dso, const char *filename)
|
||||
{
|
||||
const char *dup_filename;
|
||||
|
||||
if (!filename || !dso || !dso->long_name)
|
||||
return;
|
||||
if (dso->long_name[0] != '[')
|
||||
return;
|
||||
if (!strchr(filename, '/'))
|
||||
return;
|
||||
|
||||
dup_filename = strdup(filename);
|
||||
if (!dup_filename)
|
||||
return;
|
||||
|
||||
dso__set_long_name(dso, filename, true);
|
||||
}
|
||||
|
||||
struct map *machine__findnew_module_map(struct machine *machine, u64 start,
|
||||
const char *filename)
|
||||
{
|
||||
|
@ -573,8 +591,15 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,
|
|||
|
||||
map = map_groups__find_by_name(&machine->kmaps, MAP__FUNCTION,
|
||||
m.name);
|
||||
if (map)
|
||||
if (map) {
|
||||
/*
|
||||
* If the map's dso is an offline module, give dso__load()
|
||||
* a chance to find the file path of that module by fixing
|
||||
* long_name.
|
||||
*/
|
||||
dso__adjust_kmod_long_name(map->dso, filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dso = machine__findnew_module_dso(machine, &m, filename);
|
||||
if (dso == NULL)
|
||||
|
@ -1618,6 +1643,8 @@ static int add_callchain_ip(struct thread *thread,
|
|||
}
|
||||
}
|
||||
|
||||
if (symbol_conf.hide_unresolved && al.sym == NULL)
|
||||
return 0;
|
||||
return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym);
|
||||
}
|
||||
|
||||
|
@ -1872,6 +1899,9 @@ check_calls:
|
|||
static int unwind_entry(struct unwind_entry *entry, void *arg)
|
||||
{
|
||||
struct callchain_cursor *cursor = arg;
|
||||
|
||||
if (symbol_conf.hide_unresolved && entry->sym == NULL)
|
||||
return 0;
|
||||
return callchain_cursor_append(cursor, entry->ip,
|
||||
entry->map, entry->sym);
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ const char *map_type__name[MAP__NR_TYPES] = {
|
|||
static inline int is_anon_memory(const char *filename)
|
||||
{
|
||||
return !strcmp(filename, "//anon") ||
|
||||
!strcmp(filename, "/dev/zero (deleted)") ||
|
||||
!strcmp(filename, "/anon_hugepage (deleted)");
|
||||
!strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) ||
|
||||
!strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1);
|
||||
}
|
||||
|
||||
static inline int is_no_dso_memory(const char *filename)
|
||||
|
|
|
@ -1860,24 +1860,44 @@ static void vmlinux_path__exit(void)
|
|||
zfree(&vmlinux_path);
|
||||
}
|
||||
|
||||
static const char * const vmlinux_paths[] = {
|
||||
"vmlinux",
|
||||
"/boot/vmlinux"
|
||||
};
|
||||
|
||||
static const char * const vmlinux_paths_upd[] = {
|
||||
"/boot/vmlinux-%s",
|
||||
"/usr/lib/debug/boot/vmlinux-%s",
|
||||
"/lib/modules/%s/build/vmlinux",
|
||||
"/usr/lib/debug/lib/modules/%s/vmlinux",
|
||||
"/usr/lib/debug/boot/vmlinux-%s.debug"
|
||||
};
|
||||
|
||||
static int vmlinux_path__add(const char *new_entry)
|
||||
{
|
||||
vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry);
|
||||
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
||||
return -1;
|
||||
++vmlinux_path__nr_entries;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmlinux_path__init(struct perf_env *env)
|
||||
{
|
||||
struct utsname uts;
|
||||
char bf[PATH_MAX];
|
||||
char *kernel_version;
|
||||
unsigned int i;
|
||||
|
||||
vmlinux_path = malloc(sizeof(char *) * 6);
|
||||
vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) +
|
||||
ARRAY_SIZE(vmlinux_paths_upd)));
|
||||
if (vmlinux_path == NULL)
|
||||
return -1;
|
||||
|
||||
vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
|
||||
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
||||
goto out_fail;
|
||||
++vmlinux_path__nr_entries;
|
||||
vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
|
||||
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
||||
goto out_fail;
|
||||
++vmlinux_path__nr_entries;
|
||||
for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++)
|
||||
if (vmlinux_path__add(vmlinux_paths[i]) < 0)
|
||||
goto out_fail;
|
||||
|
||||
/* only try kernel version if no symfs was given */
|
||||
if (symbol_conf.symfs[0] != 0)
|
||||
|
@ -1892,28 +1912,11 @@ static int vmlinux_path__init(struct perf_env *env)
|
|||
kernel_version = uts.release;
|
||||
}
|
||||
|
||||
snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version);
|
||||
vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
|
||||
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
||||
goto out_fail;
|
||||
++vmlinux_path__nr_entries;
|
||||
snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s",
|
||||
kernel_version);
|
||||
vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
|
||||
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
||||
goto out_fail;
|
||||
++vmlinux_path__nr_entries;
|
||||
snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
|
||||
vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
|
||||
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
||||
goto out_fail;
|
||||
++vmlinux_path__nr_entries;
|
||||
snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
|
||||
kernel_version);
|
||||
vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
|
||||
if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
|
||||
goto out_fail;
|
||||
++vmlinux_path__nr_entries;
|
||||
for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) {
|
||||
snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version);
|
||||
if (vmlinux_path__add(bf) < 0)
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -108,7 +108,8 @@ struct symbol_conf {
|
|||
show_hist_headers,
|
||||
branch_callstack,
|
||||
has_filter,
|
||||
show_ref_callgraph;
|
||||
show_ref_callgraph,
|
||||
hide_unresolved;
|
||||
const char *vmlinux_name,
|
||||
*kallsyms_name,
|
||||
*source_prefix,
|
||||
|
|
Загрузка…
Ссылка в новой задаче