diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index b5b4d806ffa2..f4190b5764de 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -3889,8 +3889,11 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event goto cont_process; case '*': /* The argument is the length. */ - if (!arg) - die("no argument match"); + if (!arg) { + do_warning("no argument match"); + event->flags |= EVENT_FL_FAILED; + goto out_failed; + } len_arg = eval_num_arg(data, size, event, arg); len_as_arg = 1; arg = arg->next; @@ -3923,15 +3926,21 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event case 'x': case 'X': case 'u': - if (!arg) - die("no argument match"); + if (!arg) { + do_warning("no argument match"); + event->flags |= EVENT_FL_FAILED; + goto out_failed; + } len = ((unsigned long)ptr + 1) - (unsigned long)saveptr; /* should never happen */ - if (len > 31) - die("bad format!"); + if (len > 31) { + do_warning("bad format!"); + event->flags |= EVENT_FL_FAILED; + len = 31; + } memcpy(format, saveptr, len); format[len] = 0; @@ -3995,19 +4004,26 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event trace_seq_printf(s, format, (long long)val); break; default: - die("bad count (%d)", ls); + do_warning("bad count (%d)", ls); + event->flags |= EVENT_FL_FAILED; } break; case 's': - if (!arg) - die("no matching argument"); + if (!arg) { + do_warning("no matching argument"); + event->flags |= EVENT_FL_FAILED; + goto out_failed; + } len = ((unsigned long)ptr + 1) - (unsigned long)saveptr; /* should never happen */ - if (len > 31) - die("bad format!"); + if (len > 31) { + do_warning("bad format!"); + event->flags |= EVENT_FL_FAILED; + len = 31; + } memcpy(format, saveptr, len); format[len] = 0; @@ -4025,6 +4041,11 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event trace_seq_putc(s, *ptr); } + if (event->flags & EVENT_FL_FAILED) { +out_failed: + trace_seq_printf(s, "[FAILED TO PARSE]"); + } + if (args) { free_args(args); free(bprint_fmt); @@ -4812,8 +4833,8 @@ int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum, msg = strerror_r(errnum, buf, buflen); if (msg != buf) { size_t len = strlen(msg); - char *c = mempcpy(buf, msg, min(buflen-1, len)); - *c = '\0'; + memcpy(buf, msg, min(buflen - 1, len)); + *(buf + min(buflen - 1, len)) = '\0'; } return 0; } @@ -5059,6 +5080,7 @@ int pevent_register_print_function(struct pevent *pevent, struct pevent_func_params *param; enum pevent_func_arg_type type; va_list ap; + int ret; func_handle = find_func_handler(pevent, name); if (func_handle) { @@ -5071,14 +5093,21 @@ int pevent_register_print_function(struct pevent *pevent, remove_func_handler(pevent, name); } - func_handle = malloc_or_die(sizeof(*func_handle)); + func_handle = malloc(sizeof(*func_handle)); + if (!func_handle) { + do_warning("Failed to allocate function handler"); + return PEVENT_ERRNO__MEM_ALLOC_FAILED; + } memset(func_handle, 0, sizeof(*func_handle)); func_handle->ret_type = ret_type; func_handle->name = strdup(name); func_handle->func = func; - if (!func_handle->name) - die("Failed to allocate function name"); + if (!func_handle->name) { + do_warning("Failed to allocate function name"); + free(func_handle); + return PEVENT_ERRNO__MEM_ALLOC_FAILED; + } next_param = &(func_handle->params); va_start(ap, name); @@ -5088,11 +5117,17 @@ int pevent_register_print_function(struct pevent *pevent, break; if (type < 0 || type >= PEVENT_FUNC_ARG_MAX_TYPES) { - warning("Invalid argument type %d", type); + do_warning("Invalid argument type %d", type); + ret = PEVENT_ERRNO__INVALID_ARG_TYPE; goto out_free; } - param = malloc_or_die(sizeof(*param)); + param = malloc(sizeof(*param)); + if (!param) { + do_warning("Failed to allocate function param"); + ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; + goto out_free; + } param->type = type; param->next = NULL; @@ -5110,7 +5145,7 @@ int pevent_register_print_function(struct pevent *pevent, out_free: va_end(ap); free_func_handle(func_handle); - return -1; + return ret; } /** @@ -5162,7 +5197,12 @@ int pevent_register_event_handler(struct pevent *pevent, not_found: /* Save for later use. */ - handle = malloc_or_die(sizeof(*handle)); + handle = malloc(sizeof(*handle)); + if (!handle) { + do_warning("Failed to allocate event handler"); + return PEVENT_ERRNO__MEM_ALLOC_FAILED; + } + memset(handle, 0, sizeof(*handle)); handle->id = id; if (event_name) @@ -5172,7 +5212,11 @@ int pevent_register_event_handler(struct pevent *pevent, if ((event_name && !handle->event_name) || (sys_name && !handle->sys_name)) { - die("Failed to allocate event/sys name"); + do_warning("Failed to allocate event/sys name"); + free((void *)handle->event_name); + free((void *)handle->sys_name); + free(handle); + return PEVENT_ERRNO__MEM_ALLOC_FAILED; } handle->func = func; diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 863a0bbda7f1..3318963f1c98 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -351,7 +351,8 @@ enum pevent_flag { _PE(READ_ID_FAILED, "failed to read event id"), \ _PE(READ_FORMAT_FAILED, "failed to read event format"), \ _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ - _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace") + _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ + _PE(INVALID_ARG_TYPE, "invalid argument type") #undef _PE #define _PE(__code, __str) PEVENT_ERRNO__ ## __code diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index 26b823b61aa1..8f8fbc227a46 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore @@ -21,3 +21,5 @@ config.mak config.mak.autogen *-bison.* *-flex.* +*.pyc +*.pyo diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 74d7481ed7a6..ab7f667de1b1 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt @@ -17,6 +17,9 @@ captured via perf record. If no parameters are passed it will assume perf.data.old and perf.data. +The differential profile is displayed only for events matching both +specified perf.data files. + OPTIONS ------- -M:: diff --git a/tools/perf/Makefile b/tools/perf/Makefile index afd507574902..3eda49215730 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -755,6 +755,14 @@ else endif endif +ifdef NO_BACKTRACE + BASIC_CFLAGS += -DNO_BACKTRACE +else + ifneq ($(call try-cc,$(SOURCE_BACKTRACE),),y) + BASIC_CFLAGS += -DNO_BACKTRACE + endif +endif + ifdef ASCIIDOC8 export ASCIIDOC8 endif diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index d29d350fb2b7..e9933fdd256e 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -10,6 +10,7 @@ #include "util/event.h" #include "util/hist.h" #include "util/evsel.h" +#include "util/evlist.h" #include "util/session.h" #include "util/tool.h" #include "util/sort.h" @@ -24,11 +25,6 @@ static char diff__default_sort_order[] = "dso,symbol"; static bool force; static bool show_displacement; -struct perf_diff { - struct perf_tool tool; - struct perf_session *session; -}; - static int hists__add_entry(struct hists *self, struct addr_location *al, u64 period) { @@ -37,14 +33,12 @@ static int hists__add_entry(struct hists *self, return -ENOMEM; } -static int diff__process_sample_event(struct perf_tool *tool, +static int diff__process_sample_event(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel __used, + struct perf_evsel *evsel, struct machine *machine) { - struct perf_diff *_diff = container_of(tool, struct perf_diff, tool); - struct perf_session *session = _diff->session; struct addr_location al; if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { @@ -56,26 +50,24 @@ static int diff__process_sample_event(struct perf_tool *tool, if (al.filtered || al.sym == NULL) return 0; - if (hists__add_entry(&session->hists, &al, sample->period)) { + if (hists__add_entry(&evsel->hists, &al, sample->period)) { pr_warning("problem incrementing symbol period, skipping event\n"); return -1; } - session->hists.stats.total_period += sample->period; + evsel->hists.stats.total_period += sample->period; return 0; } -static struct perf_diff diff = { - .tool = { - .sample = diff__process_sample_event, - .mmap = perf_event__process_mmap, - .comm = perf_event__process_comm, - .exit = perf_event__process_task, - .fork = perf_event__process_task, - .lost = perf_event__process_lost, - .ordered_samples = true, - .ordering_requires_timestamps = true, - }, +static struct perf_tool tool = { + .sample = diff__process_sample_event, + .mmap = perf_event__process_mmap, + .comm = perf_event__process_comm, + .exit = perf_event__process_task, + .fork = perf_event__process_task, + .lost = perf_event__process_lost, + .ordered_samples = true, + .ordering_requires_timestamps = true, }; static void perf_session__insert_hist_entry_by_name(struct rb_root *root, @@ -146,34 +138,71 @@ static void hists__match(struct hists *older, struct hists *newer) } } +static struct perf_evsel *evsel_match(struct perf_evsel *evsel, + struct perf_evlist *evlist) +{ + struct perf_evsel *e; + + list_for_each_entry(e, &evlist->entries, node) + if (perf_evsel__match2(evsel, e)) + return e; + + return NULL; +} + static int __cmd_diff(void) { int ret, i; #define older (session[0]) #define newer (session[1]) struct perf_session *session[2]; + struct perf_evlist *evlist_new, *evlist_old; + struct perf_evsel *evsel; + bool first = true; older = perf_session__new(input_old, O_RDONLY, force, false, - &diff.tool); + &tool); newer = perf_session__new(input_new, O_RDONLY, force, false, - &diff.tool); + &tool); if (session[0] == NULL || session[1] == NULL) return -ENOMEM; for (i = 0; i < 2; ++i) { - diff.session = session[i]; - ret = perf_session__process_events(session[i], &diff.tool); + ret = perf_session__process_events(session[i], &tool); if (ret) goto out_delete; - hists__output_resort(&session[i]->hists); } - if (show_displacement) - hists__resort_entries(&older->hists); + evlist_old = older->evlist; + evlist_new = newer->evlist; + + list_for_each_entry(evsel, &evlist_new->entries, node) + hists__output_resort(&evsel->hists); + + list_for_each_entry(evsel, &evlist_old->entries, node) { + hists__output_resort(&evsel->hists); + + if (show_displacement) + hists__resort_entries(&evsel->hists); + } + + list_for_each_entry(evsel, &evlist_new->entries, node) { + struct perf_evsel *evsel_old; + + evsel_old = evsel_match(evsel, evlist_old); + if (!evsel_old) + continue; + + fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n", + perf_evsel__name(evsel)); + + first = false; + + hists__match(&evsel_old->hists, &evsel->hists); + hists__fprintf(&evsel->hists, &evsel_old->hists, + show_displacement, true, 0, 0, stdout); + } - hists__match(&older->hists, &newer->hists); - hists__fprintf(&newer->hists, &older->hists, - show_displacement, true, 0, 0, stdout); out_delete: for (i = 0; i < 2; ++i) perf_session__delete(session[i]); diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak index 2f1156a62ab7..116690a669d2 100644 --- a/tools/perf/config/feature-tests.mak +++ b/tools/perf/config/feature-tests.mak @@ -179,3 +179,17 @@ int main(void) } endef endif + +ifndef NO_BACKTRACE +define SOURCE_BACKTRACE +#include +#include + +int main(void) +{ + backtrace(NULL, 0); + backtrace_symbols(NULL, 0); + return 0; +} +endef +endif diff --git a/tools/perf/perf.c b/tools/perf/perf.c index e7840e500715..fb8578cfa03c 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -14,6 +14,7 @@ #include "util/run-command.h" #include "util/parse-events.h" #include "util/debugfs.h" +#include const char perf_usage_string[] = "perf [--version] [--help] COMMAND [ARGS]"; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index a6d6bc5d7164..62a6e7a7365d 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -7,6 +7,7 @@ #include "symbol.h" #include #include +#include struct ins; diff --git a/tools/perf/util/dso-test-data.c b/tools/perf/util/dso-test-data.c index 541cdc72c7df..c6caedeb1d6b 100644 --- a/tools/perf/util/dso-test-data.c +++ b/tools/perf/util/dso-test-data.c @@ -23,7 +23,7 @@ static char *test_file(int size) int fd, i; unsigned char *buf; - fd = mkostemp(templ, O_CREAT|O_WRONLY|O_TRUNC); + fd = mkstemp(templ); buf = malloc(size); if (!buf) { diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index a3f562cec433..390690eb8781 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -124,6 +124,13 @@ void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads); (evsel->attr.type == PERF_TYPE_##t && \ evsel->attr.config == PERF_COUNT_##c) +static inline bool perf_evsel__match2(struct perf_evsel *e1, + struct perf_evsel *e2) +{ + return (e1->attr.type == e2->attr.type) && + (e1->attr.config == e2->attr.config); +} + int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, int cpu, int thread, bool scale); diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c index 6f2975a00358..4fa764d8f7d7 100644 --- a/tools/perf/util/help.c +++ b/tools/perf/util/help.c @@ -3,6 +3,7 @@ #include "exec_cmd.h" #include "levenshtein.h" #include "help.h" +#include void add_cmdname(struct cmdnames *cmds, const char *name, size_t len) { diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h index 7a243a143037..2a030c5af3aa 100644 --- a/tools/perf/util/include/linux/rbtree.h +++ b/tools/perf/util/include/linux/rbtree.h @@ -1 +1,2 @@ +#include #include "../../../../include/linux/rbtree.h" diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 176a60902f56..aab414fbb64b 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -36,9 +36,7 @@ struct perf_session { struct pevent *pevent; /* * FIXME: Need to split this up further, we need global - * stats + per event stats. 'perf diff' also needs - * to properly support multiple events in a single - * perf.data file. + * stats + per event stats. */ struct hists hists; int fd; diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 0f5a0a496bc4..7a2fbd8855b7 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -12,8 +12,6 @@ int sort__branch_mode = -1; /* -1 = means not set */ enum sort_type sort__first_dimension; -char * field_sep; - LIST_HEAD(hist_entry__sort_list); static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) @@ -23,11 +21,11 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) va_start(ap, fmt); n = vsnprintf(bf, size, fmt, ap); - if (field_sep && n > 0) { + if (symbol_conf.field_sep && n > 0) { char *sep = bf; while (1) { - sep = strchr(sep, *field_sep); + sep = strchr(sep, *symbol_conf.field_sep); if (sep == NULL) break; *sep = '.'; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index e724b26acd51..e459c981b039 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -32,7 +32,6 @@ extern const char default_sort_order[]; extern int sort__need_collapse; extern int sort__has_parent; extern int sort__branch_mode; -extern char *field_sep; extern struct sort_entry sort_comm; extern struct sort_entry sort_dso; extern struct sort_entry sort_sym; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index fc4b1e630fd9..d3b330cbc3e0 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -10,6 +10,9 @@ #include #include #include +#if defined(__BIONIC__) +#include +#endif #ifndef NO_LIBELF_SUPPORT #include diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 33347ca89ee4..86ff1b15059b 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -5,6 +5,7 @@ #include "types.h" #include #include +#include struct perf_evlist; struct perf_evsel; diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 1b8775c3707d..2055cf38041c 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -1,7 +1,9 @@ #include "../perf.h" #include "util.h" #include +#ifndef NO_BACKTRACE #include +#endif #include #include @@ -163,6 +165,7 @@ size_t hex_width(u64 v) } /* Obtain a backtrace and print it to stdout. */ +#ifndef NO_BACKTRACE void dump_stack(void) { void *array[16]; @@ -177,3 +180,6 @@ void dump_stack(void) free(strings); } +#else +void dump_stack(void) {} +#endif