Commit 3f3b1a46 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:

  - 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents a95a49fa 43798bf3
......@@ -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 @@ static int thread__resolve_callchain_sample(struct thread *thread,
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,
......
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