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
This commit is contained in:
commit
727cde6c3a
|
@ -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
|
||||||
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:
|
||||||
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)
|
||||||
.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 @@
|
||||||
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)
|
||||||
"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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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 @@ close_file_and_continue:
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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 = {
|
||||||
.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,
|
||||||
/* 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,
|
||||||
|
|
||||||
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)
|
||||||
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 {
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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;
|
pos->start -= curr_map->start - curr_map->pgoff;
|
||||||
if (pos->end)
|
if (pos->end)
|
||||||
pos->end -= curr_map->start - curr_map->pgoff;
|
pos->end -= curr_map->start - curr_map->pgoff;
|
||||||
if (curr_map->dso != map->dso) {
|
symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
|
||||||
rb_erase_init(&pos->rb_node, root);
|
|
||||||
symbols__insert(
|
|
||||||
&curr_map->dso->symbols[curr_map->type],
|
|
||||||
pos);
|
|
||||||
++moved;
|
|
||||||
} else {
|
|
||||||
++count;
|
++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)
|
||||||
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 {
|
||||||
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,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user