Commit 727cde6c authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf tool fixes from Thomas Gleixner:
 "A couple of fixes for perf tools:

   - Build system updates

   - Plug a memory leak in an error path of perf probe

   - Tear down probes correctly when adding fails

   - Fixes to the perf symbol handling

   - Fix ordering of event processing in buildid-list

   - Fix per DSO filtering in the histogram browser"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf probe: Clear probe_trace_event when add_probe_trace_event() fails
  perf probe: Fix memory leaking on failure by clearing all probe_trace_events
  perf inject: Also re-pipe lost_samples event
  perf buildid-list: Requires ordered events
  perf symbols: Fix dso lookup by long name and missing buildids
  perf symbols: Allow forcing reading of non-root owned files by root
  perf hists browser: The dso can be obtained from popup_action->ms.map->dso
  perf hists browser: Fix 'd' hotkey action to filter by DSO
  perf symbols: Rebuild rbtree when adjusting symbols for kcore
  tools: Add a "make all" rule
  tools: Actually install tmon in the install rule
parents 069ec229 e15bf88a
...@@ -32,6 +32,10 @@ help: ...@@ -32,6 +32,10 @@ help:
@echo ' from the kernel command line to build and install one of' @echo ' from the kernel command line to build and install one of'
@echo ' the tools above' @echo ' the tools above'
@echo '' @echo ''
@echo ' $$ make tools/all'
@echo ''
@echo ' builds all tools.'
@echo ''
@echo ' $$ make tools/install' @echo ' $$ make tools/install'
@echo '' @echo ''
@echo ' installs all tools.' @echo ' installs all tools.'
...@@ -77,6 +81,11 @@ tmon: FORCE ...@@ -77,6 +81,11 @@ tmon: FORCE
freefall: FORCE freefall: FORCE
$(call descend,laptop/$@) $(call descend,laptop/$@)
all: acpi cgroup cpupower hv firewire lguest \
perf selftests turbostat usb \
virtio vm net x86_energy_perf_policy \
tmon freefall
acpi_install: acpi_install:
$(call descend,power/$(@:_install=),install) $(call descend,power/$(@:_install=),install)
...@@ -101,7 +110,7 @@ freefall_install: ...@@ -101,7 +110,7 @@ freefall_install:
install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \ install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \
perf_install selftests_install turbostat_install usb_install \ perf_install selftests_install turbostat_install usb_install \
virtio_install vm_install net_install x86_energy_perf_policy_install \ virtio_install vm_install net_install x86_energy_perf_policy_install \
tmon freefall_install tmon_install freefall_install
acpi_clean: acpi_clean:
$(call descend,power/acpi,clean) $(call descend,power/acpi,clean)
......
...@@ -675,6 +675,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -675,6 +675,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
.fork = perf_event__repipe, .fork = perf_event__repipe,
.exit = perf_event__repipe, .exit = perf_event__repipe,
.lost = perf_event__repipe, .lost = perf_event__repipe,
.lost_samples = perf_event__repipe,
.aux = perf_event__repipe, .aux = perf_event__repipe,
.itrace_start = perf_event__repipe, .itrace_start = perf_event__repipe,
.context_switch = perf_event__repipe, .context_switch = perf_event__repipe,
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
struct report { struct report {
struct perf_tool tool; struct perf_tool tool;
struct perf_session *session; struct perf_session *session;
bool force, use_tui, use_gtk, use_stdio; bool use_tui, use_gtk, use_stdio;
bool hide_unresolved; bool hide_unresolved;
bool dont_use_callchains; bool dont_use_callchains;
bool show_full_info; bool show_full_info;
...@@ -678,7 +678,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -678,7 +678,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
"file", "vmlinux pathname"), "file", "vmlinux pathname"),
OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
"file", "kallsyms pathname"), "file", "kallsyms pathname"),
OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"), OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
"load module symbols - WARNING: use only with -k and LIVE kernel"), "load module symbols - WARNING: use only with -k and LIVE kernel"),
OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
...@@ -832,7 +832,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -832,7 +832,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
} }
file.path = input_name; file.path = input_name;
file.force = report.force; file.force = symbol_conf.force;
repeat: repeat:
session = perf_session__new(&file, false, &report.tool); session = perf_session__new(&file, false, &report.tool);
......
...@@ -1430,7 +1430,6 @@ static int switch_data_file(void) ...@@ -1430,7 +1430,6 @@ static int switch_data_file(void)
struct popup_action { struct popup_action {
struct thread *thread; struct thread *thread;
struct dso *dso;
struct map_symbol ms; struct map_symbol ms;
int socket; int socket;
...@@ -1565,7 +1564,6 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act, ...@@ -1565,7 +1564,6 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act,
return 0; return 0;
act->ms.map = map; act->ms.map = map;
act->dso = map->dso;
act->fn = do_zoom_dso; act->fn = do_zoom_dso;
return 1; return 1;
} }
...@@ -1827,7 +1825,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1827,7 +1825,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
while (1) { while (1) {
struct thread *thread = NULL; struct thread *thread = NULL;
struct dso *dso = NULL;
struct map *map = NULL; struct map *map = NULL;
int choice = 0; int choice = 0;
int socked_id = -1; int socked_id = -1;
...@@ -1839,8 +1836,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1839,8 +1836,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
if (browser->he_selection != NULL) { if (browser->he_selection != NULL) {
thread = hist_browser__selected_thread(browser); thread = hist_browser__selected_thread(browser);
map = browser->selection->map; map = browser->selection->map;
if (map)
dso = map->dso;
socked_id = browser->he_selection->socket; socked_id = browser->he_selection->socket;
} }
switch (key) { switch (key) {
...@@ -1874,7 +1869,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1874,7 +1869,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
hist_browser__dump(browser); hist_browser__dump(browser);
continue; continue;
case 'd': case 'd':
actions->dso = dso; actions->ms.map = map;
do_zoom_dso(browser, actions); do_zoom_dso(browser, actions);
continue; continue;
case 'V': case 'V':
......
...@@ -76,6 +76,7 @@ struct perf_tool build_id__mark_dso_hit_ops = { ...@@ -76,6 +76,7 @@ struct perf_tool build_id__mark_dso_hit_ops = {
.exit = perf_event__exit_del_thread, .exit = perf_event__exit_del_thread,
.attr = perf_event__process_attr, .attr = perf_event__process_attr,
.build_id = perf_event__process_build_id, .build_id = perf_event__process_build_id,
.ordered_events = true,
}; };
int build_id__sprintf(const u8 *build_id, int len, char *bf) int build_id__sprintf(const u8 *build_id, int len, char *bf)
......
...@@ -933,6 +933,7 @@ static struct dso *__dso__findlink_by_longname(struct rb_root *root, ...@@ -933,6 +933,7 @@ static struct dso *__dso__findlink_by_longname(struct rb_root *root,
/* Add new node and rebalance tree */ /* Add new node and rebalance tree */
rb_link_node(&dso->rb_node, parent, p); rb_link_node(&dso->rb_node, parent, p);
rb_insert_color(&dso->rb_node, root); rb_insert_color(&dso->rb_node, root);
dso->root = root;
} }
return NULL; return NULL;
} }
...@@ -945,15 +946,30 @@ static inline struct dso *__dso__find_by_longname(struct rb_root *root, ...@@ -945,15 +946,30 @@ static inline struct dso *__dso__find_by_longname(struct rb_root *root,
void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
{ {
struct rb_root *root = dso->root;
if (name == NULL) if (name == NULL)
return; return;
if (dso->long_name_allocated) if (dso->long_name_allocated)
free((char *)dso->long_name); free((char *)dso->long_name);
if (root) {
rb_erase(&dso->rb_node, root);
/*
* __dso__findlink_by_longname() isn't guaranteed to add it
* back, so a clean removal is required here.
*/
RB_CLEAR_NODE(&dso->rb_node);
dso->root = NULL;
}
dso->long_name = name; dso->long_name = name;
dso->long_name_len = strlen(name); dso->long_name_len = strlen(name);
dso->long_name_allocated = name_allocated; dso->long_name_allocated = name_allocated;
if (root)
__dso__findlink_by_longname(root, dso, NULL);
} }
void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
...@@ -1046,6 +1062,7 @@ struct dso *dso__new(const char *name) ...@@ -1046,6 +1062,7 @@ struct dso *dso__new(const char *name)
dso->kernel = DSO_TYPE_USER; dso->kernel = DSO_TYPE_USER;
dso->needs_swap = DSO_SWAP__UNSET; dso->needs_swap = DSO_SWAP__UNSET;
RB_CLEAR_NODE(&dso->rb_node); RB_CLEAR_NODE(&dso->rb_node);
dso->root = NULL;
INIT_LIST_HEAD(&dso->node); INIT_LIST_HEAD(&dso->node);
INIT_LIST_HEAD(&dso->data.open_entry); INIT_LIST_HEAD(&dso->data.open_entry);
pthread_mutex_init(&dso->lock, NULL); pthread_mutex_init(&dso->lock, NULL);
......
...@@ -135,6 +135,7 @@ struct dso { ...@@ -135,6 +135,7 @@ struct dso {
pthread_mutex_t lock; pthread_mutex_t lock;
struct list_head node; struct list_head node;
struct rb_node rb_node; /* rbtree node sorted by long name */ struct rb_node rb_node; /* rbtree node sorted by long name */
struct rb_root *root; /* root of rbtree that rb_node is in */
struct rb_root symbols[MAP__NR_TYPES]; struct rb_root symbols[MAP__NR_TYPES];
struct rb_root symbol_names[MAP__NR_TYPES]; struct rb_root symbol_names[MAP__NR_TYPES];
struct { struct {
......
...@@ -91,6 +91,7 @@ static void dsos__purge(struct dsos *dsos) ...@@ -91,6 +91,7 @@ static void dsos__purge(struct dsos *dsos)
list_for_each_entry_safe(pos, n, &dsos->head, node) { list_for_each_entry_safe(pos, n, &dsos->head, node) {
RB_CLEAR_NODE(&pos->rb_node); RB_CLEAR_NODE(&pos->rb_node);
pos->root = NULL;
list_del_init(&pos->node); list_del_init(&pos->node);
dso__put(pos); dso__put(pos);
} }
......
...@@ -1183,7 +1183,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) ...@@ -1183,7 +1183,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
container_of(pf, struct trace_event_finder, pf); container_of(pf, struct trace_event_finder, pf);
struct perf_probe_point *pp = &pf->pev->point; struct perf_probe_point *pp = &pf->pev->point;
struct probe_trace_event *tev; struct probe_trace_event *tev;
struct perf_probe_arg *args; struct perf_probe_arg *args = NULL;
int ret, i; int ret, i;
/* Check number of tevs */ /* Check number of tevs */
...@@ -1198,19 +1198,23 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) ...@@ -1198,19 +1198,23 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr,
pp->retprobe, pp->function, &tev->point); pp->retprobe, pp->function, &tev->point);
if (ret < 0) if (ret < 0)
return ret; goto end;
tev->point.realname = strdup(dwarf_diename(sc_die)); tev->point.realname = strdup(dwarf_diename(sc_die));
if (!tev->point.realname) if (!tev->point.realname) {
return -ENOMEM; ret = -ENOMEM;
goto end;
}
pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
tev->point.offset); tev->point.offset);
/* Expand special probe argument if exist */ /* Expand special probe argument if exist */
args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS); args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS);
if (args == NULL) if (args == NULL) {
return -ENOMEM; ret = -ENOMEM;
goto end;
}
ret = expand_probe_args(sc_die, pf, args); ret = expand_probe_args(sc_die, pf, args);
if (ret < 0) if (ret < 0)
...@@ -1234,6 +1238,10 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) ...@@ -1234,6 +1238,10 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
} }
end: end:
if (ret) {
clear_probe_trace_event(tev);
tf->ntevs--;
}
free(args); free(args);
return ret; return ret;
} }
...@@ -1246,7 +1254,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, ...@@ -1246,7 +1254,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
struct trace_event_finder tf = { struct trace_event_finder tf = {
.pf = {.pev = pev, .callback = add_probe_trace_event}, .pf = {.pev = pev, .callback = add_probe_trace_event},
.max_tevs = probe_conf.max_probes, .mod = dbg->mod}; .max_tevs = probe_conf.max_probes, .mod = dbg->mod};
int ret; int ret, i;
/* Allocate result tevs array */ /* Allocate result tevs array */
*tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs); *tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs);
...@@ -1258,6 +1266,8 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, ...@@ -1258,6 +1266,8 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
ret = debuginfo__find_probes(dbg, &tf.pf); ret = debuginfo__find_probes(dbg, &tf.pf);
if (ret < 0) { if (ret < 0) {
for (i = 0; i < tf.ntevs; i++)
clear_probe_trace_event(&tf.tevs[i]);
zfree(tevs); zfree(tevs);
return ret; return ret;
} }
......
...@@ -654,19 +654,24 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, ...@@ -654,19 +654,24 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
struct map_groups *kmaps = map__kmaps(map); struct map_groups *kmaps = map__kmaps(map);
struct map *curr_map; struct map *curr_map;
struct symbol *pos; struct symbol *pos;
int count = 0, moved = 0; int count = 0;
struct rb_root old_root = dso->symbols[map->type];
struct rb_root *root = &dso->symbols[map->type]; struct rb_root *root = &dso->symbols[map->type];
struct rb_node *next = rb_first(root); struct rb_node *next = rb_first(root);
if (!kmaps) if (!kmaps)
return -1; return -1;
*root = RB_ROOT;
while (next) { while (next) {
char *module; char *module;
pos = rb_entry(next, struct symbol, rb_node); pos = rb_entry(next, struct symbol, rb_node);
next = rb_next(&pos->rb_node); next = rb_next(&pos->rb_node);
rb_erase_init(&pos->rb_node, &old_root);
module = strchr(pos->name, '\t'); module = strchr(pos->name, '\t');
if (module) if (module)
*module = '\0'; *module = '\0';
...@@ -674,28 +679,21 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, ...@@ -674,28 +679,21 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
curr_map = map_groups__find(kmaps, map->type, pos->start); curr_map = map_groups__find(kmaps, map->type, pos->start);
if (!curr_map || (filter && filter(curr_map, pos))) { if (!curr_map || (filter && filter(curr_map, pos))) {
rb_erase_init(&pos->rb_node, root);
symbol__delete(pos); symbol__delete(pos);
} else { continue;
pos->start -= curr_map->start - curr_map->pgoff;
if (pos->end)
pos->end -= curr_map->start - curr_map->pgoff;
if (curr_map->dso != map->dso) {
rb_erase_init(&pos->rb_node, root);
symbols__insert(
&curr_map->dso->symbols[curr_map->type],
pos);
++moved;
} else {
++count;
}
} }
pos->start -= curr_map->start - curr_map->pgoff;
if (pos->end)
pos->end -= curr_map->start - curr_map->pgoff;
symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
++count;
} }
/* Symbols have been adjusted */ /* Symbols have been adjusted */
dso->adjust_symbols = 1; dso->adjust_symbols = 1;
return count + moved; return count;
} }
/* /*
...@@ -1438,9 +1436,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) ...@@ -1438,9 +1436,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
if (lstat(dso->name, &st) < 0) if (lstat(dso->name, &st) < 0)
goto out; goto out;
if (st.st_uid && (st.st_uid != geteuid())) { if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) {
pr_warning("File %s not owned by current user or root, " pr_warning("File %s not owned by current user or root, "
"ignoring it.\n", dso->name); "ignoring it (use -f to override).\n", dso->name);
goto out; goto out;
} }
......
...@@ -84,6 +84,7 @@ struct symbol_conf { ...@@ -84,6 +84,7 @@ struct symbol_conf {
unsigned short priv_size; unsigned short priv_size;
unsigned short nr_events; unsigned short nr_events;
bool try_vmlinux_path, bool try_vmlinux_path,
force,
ignore_vmlinux, ignore_vmlinux,
ignore_vmlinux_buildid, ignore_vmlinux_buildid,
show_kernel_path, show_kernel_path,
......
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