diff options
author | Ingo Molnar | 2014-01-19 13:09:01 +0100 |
---|---|---|
committer | Ingo Molnar | 2014-01-19 13:09:01 +0100 |
commit | 45e6af06367e7b2eb8dc49671092462d8f8a5f47 (patch) | |
tree | 68187bf0c9d8a1eb653d230dbd0d38ffd0046a27 | |
parent | 3e7e09dbd1080de5dcf10092830e39bc2e2932ec (diff) | |
parent | 2a29190c040c0b11e39197c67abf6f87e0a61f9a (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf improvements and fixes from Arnaldo Carvalho de Melo:
Infrastructure changes:
* Improve callchain processing by removing unnecessary work. (Frederic Weisbecker)
* Fix comm override error handling (Frederic Weisbecker)
* Improve 'perf probe' exit path, release resources (Masami Hiramatsu)
* Improve libtraceevent plugins exit path, allowing the registering of
an unregister handler to be called at exit time (Namhyung Kim)
* Add an alias to the build test makefile (make -C tools/perf build-test)
(Namhyung Kim)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/lib/traceevent/event-parse.c | 136 | ||||
-rw-r--r-- | tools/lib/traceevent/event-parse.h | 5 | ||||
-rw-r--r-- | tools/lib/traceevent/plugin_cfg80211.c | 6 | ||||
-rw-r--r-- | tools/lib/traceevent/plugin_function.c | 3 | ||||
-rw-r--r-- | tools/lib/traceevent/plugin_hrtimer.c | 10 | ||||
-rw-r--r-- | tools/lib/traceevent/plugin_jbd2.c | 9 | ||||
-rw-r--r-- | tools/lib/traceevent/plugin_kmem.c | 22 | ||||
-rw-r--r-- | tools/lib/traceevent/plugin_kvm.c | 29 | ||||
-rw-r--r-- | tools/lib/traceevent/plugin_mac80211.c | 7 | ||||
-rw-r--r-- | tools/lib/traceevent/plugin_sched_switch.c | 12 | ||||
-rw-r--r-- | tools/lib/traceevent/plugin_scsi.c | 6 | ||||
-rw-r--r-- | tools/lib/traceevent/plugin_xen.c | 6 | ||||
-rw-r--r-- | tools/perf/Makefile | 6 | ||||
-rw-r--r-- | tools/perf/builtin-probe.c | 48 | ||||
-rw-r--r-- | tools/perf/util/callchain.c | 23 | ||||
-rw-r--r-- | tools/perf/util/comm.c | 19 | ||||
-rw-r--r-- | tools/perf/util/comm.h | 2 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 111 | ||||
-rw-r--r-- | tools/perf/util/probe-event.h | 6 | ||||
-rw-r--r-- | tools/perf/util/symbol-elf.c | 5 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 5 | ||||
-rw-r--r-- | tools/perf/util/thread.c | 5 | ||||
-rw-r--r-- | tools/perf/util/unwind.c | 20 |
23 files changed, 389 insertions, 112 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 2ce565a73dd5..1587ea392ad6 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -5561,6 +5561,52 @@ int pevent_register_print_function(struct pevent *pevent, } /** + * pevent_unregister_print_function - unregister a helper function + * @pevent: the handle to the pevent + * @func: the function to process the helper function + * @name: the name of the helper function + * + * This function removes existing print handler for function @name. + * + * Returns 0 if the handler was removed successully, -1 otherwise. + */ +int pevent_unregister_print_function(struct pevent *pevent, + pevent_func_handler func, char *name) +{ + struct pevent_function_handler *func_handle; + + func_handle = find_func_handler(pevent, name); + if (func_handle && func_handle->func == func) { + remove_func_handler(pevent, name); + return 0; + } + return -1; +} + +static struct event_format *pevent_search_event(struct pevent *pevent, int id, + const char *sys_name, + const char *event_name) +{ + struct event_format *event; + + if (id >= 0) { + /* search by id */ + event = pevent_find_event(pevent, id); + if (!event) + return NULL; + if (event_name && (strcmp(event_name, event->name) != 0)) + return NULL; + if (sys_name && (strcmp(sys_name, event->system) != 0)) + return NULL; + } else { + event = pevent_find_event_by_name(pevent, sys_name, event_name); + if (!event) + return NULL; + } + return event; +} + +/** * pevent_register_event_handler - register a way to parse an event * @pevent: the handle to the pevent * @id: the id of the event to register @@ -5584,20 +5630,9 @@ int pevent_register_event_handler(struct pevent *pevent, int id, struct event_format *event; struct event_handler *handle; - if (id >= 0) { - /* search by id */ - event = pevent_find_event(pevent, id); - if (!event) - goto not_found; - if (event_name && (strcmp(event_name, event->name) != 0)) - goto not_found; - if (sys_name && (strcmp(sys_name, event->system) != 0)) - goto not_found; - } else { - event = pevent_find_event_by_name(pevent, sys_name, event_name); - if (!event) - goto not_found; - } + event = pevent_search_event(pevent, id, sys_name, event_name); + if (event == NULL) + goto not_found; pr_stat("overriding event (%d) %s:%s with new print handler", event->id, event->system, event->name); @@ -5637,6 +5672,79 @@ int pevent_register_event_handler(struct pevent *pevent, int id, return -1; } +static int handle_matches(struct event_handler *handler, int id, + const char *sys_name, const char *event_name, + pevent_event_handler_func func, void *context) +{ + if (id >= 0 && id != handler->id) + return 0; + + if (event_name && (strcmp(event_name, handler->event_name) != 0)) + return 0; + + if (sys_name && (strcmp(sys_name, handler->sys_name) != 0)) + return 0; + + if (func != handler->func || context != handler->context) + return 0; + + return 1; +} + +/** + * pevent_unregister_event_handler - unregister an existing event handler + * @pevent: the handle to the pevent + * @id: the id of the event to unregister + * @sys_name: the system name the handler belongs to + * @event_name: the name of the event handler + * @func: the function to call to parse the event information + * @context: the data to be passed to @func + * + * This function removes existing event handler (parser). + * + * If @id is >= 0, then it is used to find the event. + * else @sys_name and @event_name are used. + * + * Returns 0 if handler was removed successfully, -1 if event was not found. + */ +int pevent_unregister_event_handler(struct pevent *pevent, int id, + const char *sys_name, const char *event_name, + pevent_event_handler_func func, void *context) +{ + struct event_format *event; + struct event_handler *handle; + struct event_handler **next; + + event = pevent_search_event(pevent, id, sys_name, event_name); + if (event == NULL) + goto not_found; + + if (event->handler == func && event->context == context) { + pr_stat("removing override handler for event (%d) %s:%s. Going back to default handler.", + event->id, event->system, event->name); + + event->handler = NULL; + event->context = NULL; + return 0; + } + +not_found: + for (next = &pevent->handlers; *next; next = &(*next)->next) { + handle = *next; + if (handle_matches(handle, id, sys_name, event_name, + func, context)) + break; + } + + if (!(*next)) + return -1; + + *next = handle->next; + free_handler(handle); + + return 0; +} + /** * pevent_alloc - create a pevent handle */ diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index a3beca56cb35..791c539374c7 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -624,10 +624,15 @@ int pevent_print_func_field(struct trace_seq *s, const char *fmt, int pevent_register_event_handler(struct pevent *pevent, int id, const char *sys_name, const char *event_name, pevent_event_handler_func func, void *context); +int pevent_unregister_event_handler(struct pevent *pevent, int id, + const char *sys_name, const char *event_name, + pevent_event_handler_func func, void *context); int pevent_register_print_function(struct pevent *pevent, pevent_func_handler func, enum pevent_func_arg_type ret_type, char *name, ...); +int pevent_unregister_print_function(struct pevent *pevent, + pevent_func_handler func, char *name); struct format_field *pevent_find_common_field(struct event_format *event, const char *name); struct format_field *pevent_find_field(struct event_format *event, const char *name); diff --git a/tools/lib/traceevent/plugin_cfg80211.c b/tools/lib/traceevent/plugin_cfg80211.c index 57e98221db20..c066b25905f8 100644 --- a/tools/lib/traceevent/plugin_cfg80211.c +++ b/tools/lib/traceevent/plugin_cfg80211.c @@ -22,3 +22,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) PEVENT_FUNC_ARG_VOID); return 0; } + +void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +{ + pevent_unregister_print_function(pevent, process___le16_to_cpup, + "__le16_to_cpup"); +} diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c index 39461485f9a7..80ba4ff1fe84 100644 --- a/tools/lib/traceevent/plugin_function.c +++ b/tools/lib/traceevent/plugin_function.c @@ -148,6 +148,9 @@ void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) { int i, x; + pevent_unregister_event_handler(pevent, -1, "ftrace", "function", + function_handler, NULL); + for (i = 0; i <= cpus; i++) { for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++) free(fstack[i].stack[x]); diff --git a/tools/lib/traceevent/plugin_hrtimer.c b/tools/lib/traceevent/plugin_hrtimer.c index 0b0ebf30aa44..12bf14cc1152 100644 --- a/tools/lib/traceevent/plugin_hrtimer.c +++ b/tools/lib/traceevent/plugin_hrtimer.c @@ -76,3 +76,13 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) timer_start_handler, NULL); return 0; } + +void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +{ + pevent_unregister_event_handler(pevent, -1, + "timer", "hrtimer_expire_entry", + timer_expire_handler, NULL); + + pevent_unregister_event_handler(pevent, -1, "timer", "hrtimer_start", + timer_start_handler, NULL); +} diff --git a/tools/lib/traceevent/plugin_jbd2.c b/tools/lib/traceevent/plugin_jbd2.c index 2f93f81f0bac..0db714c721be 100644 --- a/tools/lib/traceevent/plugin_jbd2.c +++ b/tools/lib/traceevent/plugin_jbd2.c @@ -66,3 +66,12 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) PEVENT_FUNC_ARG_VOID); return 0; } + +void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +{ + pevent_unregister_print_function(pevent, process_jbd2_dev_to_name, + "jbd2_dev_to_name"); + + pevent_unregister_print_function(pevent, process_jiffies_to_msecs, + "jiffies_to_msecs"); +} diff --git a/tools/lib/traceevent/plugin_kmem.c b/tools/lib/traceevent/plugin_kmem.c index 7115c8037ea8..70650ff48d78 100644 --- a/tools/lib/traceevent/plugin_kmem.c +++ b/tools/lib/traceevent/plugin_kmem.c @@ -70,3 +70,25 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) call_site_handler, NULL); return 0; } + +void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +{ + pevent_unregister_event_handler(pevent, -1, "kmem", "kfree", + call_site_handler, NULL); + + pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc", + call_site_handler, NULL); + + pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node", + call_site_handler, NULL); + + pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", + call_site_handler, NULL); + + pevent_unregister_event_handler(pevent, -1, "kmem", + "kmem_cache_alloc_node", + call_site_handler, NULL); + + pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free", + call_site_handler, NULL); +} diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c index a0e282c6b967..9e0e8c61b43b 100644 --- a/tools/lib/traceevent/plugin_kvm.c +++ b/tools/lib/traceevent/plugin_kvm.c @@ -434,3 +434,32 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) PEVENT_FUNC_ARG_VOID); return 0; } + +void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +{ + pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_exit", + kvm_exit_handler, NULL); + + pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", + kvm_emulate_insn_handler, NULL); + + pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", + kvm_mmu_get_page_handler, NULL); + + pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", + kvm_mmu_print_role, NULL); + + pevent_unregister_event_handler(pevent, -1, + "kvmmmu", "kvm_mmu_unsync_page", + kvm_mmu_print_role, NULL); + + pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", + kvm_mmu_print_role, NULL); + + pevent_unregister_event_handler(pevent, -1, "kvmmmu", + "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, + NULL); + + pevent_unregister_print_function(pevent, process_is_writable_pte, + "is_writable_pte"); +} diff --git a/tools/lib/traceevent/plugin_mac80211.c b/tools/lib/traceevent/plugin_mac80211.c index 558a3b91c046..7e15a0f1c2fd 100644 --- a/tools/lib/traceevent/plugin_mac80211.c +++ b/tools/lib/traceevent/plugin_mac80211.c @@ -93,3 +93,10 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) drv_bss_info_changed, NULL); return 0; } + +void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +{ + pevent_unregister_event_handler(pevent, -1, "mac80211", + "drv_bss_info_changed", + drv_bss_info_changed, NULL); +} diff --git a/tools/lib/traceevent/plugin_sched_switch.c b/tools/lib/traceevent/plugin_sched_switch.c index fea3724aa24f..f1ce60065258 100644 --- a/tools/lib/traceevent/plugin_sched_switch.c +++ b/tools/lib/traceevent/plugin_sched_switch.c @@ -146,3 +146,15 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) sched_wakeup_handler, NULL); return 0; } + +void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +{ + pevent_unregister_event_handler(pevent, -1, "sched", "sched_switch", + sched_switch_handler, NULL); + + pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup", + sched_wakeup_handler, NULL); + + pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new", + sched_wakeup_handler, NULL); +} diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugin_scsi.c index 7ef16cc96562..eda326fc8620 100644 --- a/tools/lib/traceevent/plugin_scsi.c +++ b/tools/lib/traceevent/plugin_scsi.c @@ -421,3 +421,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) PEVENT_FUNC_ARG_VOID); return 0; } + +void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +{ + pevent_unregister_print_function(pevent, process_scsi_trace_parse_cdb, + "scsi_trace_parse_cdb"); +} diff --git a/tools/lib/traceevent/plugin_xen.c b/tools/lib/traceevent/plugin_xen.c index e7794298f3a9..3a413eaada68 100644 --- a/tools/lib/traceevent/plugin_xen.c +++ b/tools/lib/traceevent/plugin_xen.c @@ -128,3 +128,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) PEVENT_FUNC_ARG_VOID); return 0; } + +void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) +{ + pevent_unregister_print_function(pevent, process_xen_hypercall_name, + "xen_hypercall_name"); +} diff --git a/tools/perf/Makefile b/tools/perf/Makefile index eefb9fb0c02f..cb2e5868c8e8 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -75,6 +75,12 @@ clean: $(make) # +# The build-test target is not really parallel, don't print the jobs info: +# +build-test: + @$(MAKE) -f tests/make --no-print-directory + +# # All other targets get passed through: # %: diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 43ff33d0007b..78948882e3de 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -59,7 +59,7 @@ static struct { struct perf_probe_event events[MAX_PROBES]; struct strlist *dellist; struct line_range line_range; - const char *target; + char *target; int max_probe_points; struct strfilter *filter; } params; @@ -98,7 +98,10 @@ static int set_target(const char *ptr) * short module name. */ if (!params.target && ptr && *ptr == '/') { - params.target = ptr; + params.target = strdup(ptr); + if (!params.target) + return -ENOMEM; + found = 1; buf = ptr + (strlen(ptr) - 3); @@ -116,6 +119,9 @@ static int parse_probe_event_argv(int argc, const char **argv) char *buf; found_target = set_target(argv[0]); + if (found_target < 0) + return found_target; + if (found_target && argc == 1) return 0; @@ -217,7 +223,6 @@ static int opt_show_lines(const struct option *opt __maybe_unused, params.show_lines = true; ret = parse_line_range_desc(str, ¶ms.line_range); - INIT_LIST_HEAD(¶ms.line_range.line_list); return ret; } @@ -263,7 +268,28 @@ static int opt_set_filter(const struct option *opt __maybe_unused, return 0; } -int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) +static void init_params(void) +{ + line_range__init(¶ms.line_range); +} + +static void cleanup_params(void) +{ + int i; + + for (i = 0; i < params.nevents; i++) + clear_perf_probe_event(params.events + i); + if (params.dellist) + strlist__delete(params.dellist); + line_range__clear(¶ms.line_range); + free(params.target); + if (params.filter) + strfilter__delete(params.filter); + memset(¶ms, 0, sizeof(params)); +} + +static int +__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) { const char * const probe_usage[] = { "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", @@ -417,6 +443,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) ret = show_available_funcs(params.target, params.filter, params.uprobes); strfilter__delete(params.filter); + params.filter = NULL; if (ret < 0) pr_err(" Error: Failed to show functions." " (%d)\n", ret); @@ -456,6 +483,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) params.filter, params.show_ext_vars); strfilter__delete(params.filter); + params.filter = NULL; if (ret < 0) pr_err(" Error: Failed to show vars. (%d)\n", ret); return ret; @@ -464,7 +492,6 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) if (params.dellist) { ret = del_perf_probe_events(params.dellist); - strlist__delete(params.dellist); if (ret < 0) { pr_err(" Error: Failed to delete events. (%d)\n", ret); return ret; @@ -483,3 +510,14 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) } return 0; } + +int cmd_probe(int argc, const char **argv, const char *prefix) +{ + int ret; + + init_params(); + ret = __cmd_probe(argc, argv, prefix); + cleanup_params(); + + return ret; +} diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 9eb4f57f8663..8d9db454f1a9 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -15,6 +15,8 @@ #include <errno.h> #include <math.h> +#include "asm/bug.h" + #include "hist.h" #include "util.h" #include "sort.h" @@ -358,19 +360,14 @@ append_chain_children(struct callchain_node *root, /* lookup in childrens */ while (*p) { s64 ret; - struct callchain_list *cnode; parent = *p; rnode = rb_entry(parent, struct callchain_node, rb_node_in); - cnode = list_first_entry(&rnode->val, struct callchain_list, - list); - /* just check first entry */ - ret = match_chain(node, cnode); - if (ret == 0) { - append_chain(rnode, cursor, period); + /* If at least first entry matches, rely to children */ + ret = append_chain(rnode, cursor, period); + if (ret == 0) goto inc_children_hit; - } if (ret < 0) p = &parent->rb_left; @@ -391,11 +388,11 @@ append_chain(struct callchain_node *root, struct callchain_cursor *cursor, u64 period) { - struct callchain_cursor_node *curr_snap = cursor->curr; struct callchain_list *cnode; u64 start = cursor->pos; bool found = false; u64 matches; + int cmp = 0; /* * Lookup in the current node @@ -410,7 +407,8 @@ append_chain(struct callchain_node *root, if (!node) break; - if (match_chain(node, cnode) != 0) + cmp = match_chain(node, cnode); + if (cmp) break; found = true; @@ -420,9 +418,8 @@ append_chain(struct callchain_node *root, /* matches not, relay no the parent */ if (!found) { - cursor->curr = curr_snap; - cursor->pos = start; - return -1; + WARN_ONCE(!cmp, "Chain comparison error\n"); + return cmp; } matches = cursor->pos - start; diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c index 67d1e404c0cb..f9e777629e21 100644 --- a/tools/perf/util/comm.c +++ b/tools/perf/util/comm.c @@ -94,19 +94,20 @@ struct comm *comm__new(const char *str, u64 timestamp) return comm; } -void comm__override(struct comm *comm, const char *str, u64 timestamp) +int comm__override(struct comm *comm, const char *str, u64 timestamp) { - struct comm_str *old = comm->comm_str; + struct comm_str *new, *old = comm->comm_str; - comm->comm_str = comm_str__findnew(str, &comm_str_root); - if (!comm->comm_str) { - comm->comm_str = old; - return; - } + new = comm_str__findnew(str, &comm_str_root); + if (!new) + return -ENOMEM; - comm->start = timestamp; - comm_str__get(comm->comm_str); + comm_str__get(new); comm_str__put(old); + comm->comm_str = new; + comm->start = timestamp; + + return 0; } void comm__free(struct comm *comm) diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h index 7a86e5656710..fac5bd51befc 100644 --- a/tools/perf/util/comm.h +++ b/tools/perf/util/comm.h @@ -16,6 +16,6 @@ struct comm { void comm__free(struct comm *comm); struct comm *comm__new(const char *str, u64 timestamp); const char *comm__str(const struct comm *comm); -void comm__override(struct comm *comm, const char *str, u64 timestamp); +int comm__override(struct comm *comm, const char *str, u64 timestamp); #endif /* __PERF_COMM_H */ diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index a4ee6b4a840f..a8a9b6cd93a8 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -72,6 +72,7 @@ static int e_snprintf(char *str, size_t size, const char *format, ...) static char *synthesize_perf_probe_point(struct perf_probe_point *pp); static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec); +static void clear_probe_trace_event(struct probe_trace_event *tev); static struct machine machine; /* Initialize symbol maps and path of vmlinux/modules */ @@ -172,54 +173,6 @@ const char *kernel_get_module_path(const char *module) return (dso) ? dso->long_name : NULL; } -#ifdef HAVE_DWARF_SUPPORT -/* Copied from unwind.c */ -static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, - GElf_Shdr *shp, const char *name) -{ - Elf_Scn *sec = NULL; - - while ((sec = elf_nextscn(elf, sec)) != NULL) { - char *str; - - gelf_getshdr(sec, shp); - str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); - if (!strcmp(name, str)) - break; - } - - return sec; -} - -static int get_text_start_address(const char *exec, unsigned long *address) -{ - Elf *elf; - GElf_Ehdr ehdr; - GElf_Shdr shdr; - int fd, ret = -ENOENT; - - fd = open(exec, O_RDONLY); - if (fd < 0) - return -errno; - - elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); - if (elf == NULL) - return -EINVAL; - - if (gelf_getehdr(elf, &ehdr) == NULL) - goto out; - - if (!elf_section_by_name(elf, &ehdr, &shdr, ".text")) - goto out; - - *address = shdr.sh_addr - shdr.sh_offset; - ret = 0; -out: - elf_end(elf); - return ret; -} -#endif - static int init_user_exec(void) { int ret = 0; @@ -340,6 +293,34 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, return 0; } +static int get_text_start_address(const char *exec, unsigned long *address) +{ + Elf *elf; + GElf_Ehdr ehdr; + GElf_Shdr shdr; + int fd, ret = -ENOENT; + + fd = open(exec, O_RDONLY); + if (fd < 0) + return -errno; + + elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (elf == NULL) + return -EINVAL; + + if (gelf_getehdr(elf, &ehdr) == NULL) + goto out; + + if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL)) + goto out; + + *address = shdr.sh_addr - shdr.sh_offset; + ret = 0; +out: + elf_end(elf); + return ret; +} + static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, int ntevs, const char *exec) { @@ -407,6 +388,14 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, return ret; } +static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) +{ + int i; + + for (i = 0; i < ntevs; i++) + clear_probe_trace_event(tevs + i); +} + /* Try to find perf_probe_event with debuginfo */ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, struct probe_trace_event **tevs, @@ -442,6 +431,10 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, ret = add_module_to_probe_trace_events(*tevs, ntevs, target); } + if (ret < 0) { + clear_probe_trace_events(*tevs, ntevs); + zfree(tevs); + } return ret < 0 ? ret : ntevs; } @@ -781,6 +774,28 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused, } #endif +void line_range__clear(struct line_range *lr) +{ + struct line_node *ln; + + free(lr->function); + free(lr->file); + free(lr->path); + free(lr->comp_dir); + while (!list_empty(&lr->line_list)) { + ln = list_first_entry(&lr->line_list, struct line_node, list); + list_del(&ln->list); + free(ln); + } + memset(lr, 0, sizeof(*lr)); +} + +void line_range__init(struct line_range *lr) +{ + memset(lr, 0, sizeof(*lr)); + INIT_LIST_HEAD(&lr->line_list); +} + static int parse_line_num(char **ptr, int *val, const char *what) { const char *start = *ptr; diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index d481c46e0796..fcaf7273e85a 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -120,6 +120,12 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev); /* Command string to line-range */ extern int parse_line_range_desc(const char *cmd, struct line_range *lr); +/* Release line range members */ +extern void line_range__clear(struct line_range *lr); + +/* Initialize line range */ +extern void line_range__init(struct line_range *lr); + /* Internal use: Return kernel/module path */ extern const char *kernel_get_module_path(const char *module); diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 4b0a127a4d3b..759456728703 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -136,9 +136,8 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) return -1; } -static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, - GElf_Shdr *shp, const char *name, - size_t *idx) +Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, + GElf_Shdr *shp, const char *name, size_t *idx) { Elf_Scn *sec = NULL; size_t cnt = 1; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index cbd680361806..fffe2888a1c7 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -52,6 +52,11 @@ static inline char *bfd_demangle(void __maybe_unused *v, # define PERF_ELF_C_READ_MMAP ELF_C_READ #endif +#ifdef HAVE_LIBELF_SUPPORT +extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, + GElf_Shdr *shp, const char *name, size_t *idx); +#endif + #ifndef DMGL_PARAMS #define DMGL_PARAMS (1 << 0) /* Include function args */ #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index e3948612543e..0358882c8910 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -66,10 +66,13 @@ struct comm *thread__comm(const struct thread *thread) int thread__set_comm(struct thread *thread, const char *str, u64 timestamp) { struct comm *new, *curr = thread__comm(thread); + int err; /* Override latest entry if it had no specific time coverage */ if (!curr->start) { - comm__override(curr, str, timestamp); + err = comm__override(curr, str, timestamp); + if (err) + return err; } else { new = comm__new(str, timestamp); if (!new) diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c index 416f22bf3693..742f23bf35ff 100644 --- a/tools/perf/util/unwind.c +++ b/tools/perf/util/unwind.c @@ -28,6 +28,7 @@ #include "session.h" #include "perf_regs.h" #include "unwind.h" +#include "symbol.h" #include "util.h" extern int @@ -158,23 +159,6 @@ static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, __v; \ }) -static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, - GElf_Shdr *shp, const char *name) -{ - Elf_Scn *sec = NULL; - - while ((sec = elf_nextscn(elf, sec)) != NULL) { - char *str; - - gelf_getshdr(sec, shp); - str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); - if (!strcmp(name, str)) - break; - } - - return sec; -} - static u64 elf_section_offset(int fd, const char *name) { Elf *elf; @@ -190,7 +174,7 @@ static u64 elf_section_offset(int fd, const char *name) if (gelf_getehdr(elf, &ehdr) == NULL) break; - if (!elf_section_by_name(elf, &ehdr, &shdr, name)) + if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL)) break; offset = shdr.sh_offset; |