From ff1a70e75fd005821ab5f2211312a8aa13bbf959 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 23 Aug 2012 11:22:01 -0400 Subject: [PATCH 01/25] tools lib traceevent: Modify header to work in C++ programs Replace keyword "private" to "priv" in event-parse.h to allow it to be used in C++ programs. Signed-off-by: Steven Rostedt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1345735321.5069.62.camel@gandalf.local.home Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-parse.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 527df038a25f..863a0bbda7f1 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -49,7 +49,7 @@ struct pevent_record { int cpu; int ref_count; int locked; /* Do not free, even if ref_count is zero */ - void *private; + void *priv; #if DEBUG_RECORD struct pevent_record *prev; struct pevent_record *next; @@ -106,7 +106,7 @@ struct plugin_option { char *plugin_alias; char *description; char *value; - void *private; + void *priv; int set; }; From d25380cd3be38baff4ab31935b9d19b7f58ba7ac Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 26 Aug 2012 12:24:41 -0600 Subject: [PATCH 02/25] perf session: flush_sample_queue needs to handle errors from handlers Allows errors to propogate through event processing code and back to commands. Signed-off-by: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1346005487-62961-2-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f7bb7ae328da..945375897c2a 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -692,7 +692,7 @@ static int perf_session_deliver_event(struct perf_session *session, struct perf_tool *tool, u64 file_offset); -static void flush_sample_queue(struct perf_session *s, +static int flush_sample_queue(struct perf_session *s, struct perf_tool *tool) { struct ordered_samples *os = &s->ordered_samples; @@ -705,7 +705,7 @@ static void flush_sample_queue(struct perf_session *s, int ret; if (!tool->ordered_samples || !limit) - return; + return 0; list_for_each_entry_safe(iter, tmp, head, list) { if (iter->timestamp > limit) @@ -715,9 +715,12 @@ static void flush_sample_queue(struct perf_session *s, s->header.needs_swap); if (ret) pr_err("Can't parse sample, err = %d\n", ret); - else - perf_session_deliver_event(s, iter->event, &sample, tool, - iter->file_offset); + else { + ret = perf_session_deliver_event(s, iter->event, &sample, tool, + iter->file_offset); + if (ret) + return ret; + } os->last_flush = iter->timestamp; list_del(&iter->list); @@ -737,6 +740,8 @@ static void flush_sample_queue(struct perf_session *s, } os->nr_samples = 0; + + return 0; } /* @@ -782,10 +787,11 @@ static int process_finished_round(struct perf_tool *tool, union perf_event *event __used, struct perf_session *session) { - flush_sample_queue(session, tool); - session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; + int ret = flush_sample_queue(session, tool); + if (!ret) + session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; - return 0; + return ret; } /* The queue is ordered by time */ @@ -1443,7 +1449,7 @@ more: err = 0; /* do the final flush for ordered samples */ session->ordered_samples.next_flush = ULLONG_MAX; - flush_sample_queue(session, tool); + err = flush_sample_queue(session, tool); out_err: perf_session__warn_about_errors(session, tool); perf_session_free_sample_buffers(session); From 1e6d53223884225f0c3f9f1a3ac54a224d97ab24 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 26 Aug 2012 12:24:42 -0600 Subject: [PATCH 03/25] perf tool: handle errors in synthesized event functions Handle error from process callback and propagate back to caller. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1346005487-62961-3-git-send-email-dsahern@gmail.com Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 3a0f1a5da91c..84ff6f160cd0 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -120,7 +120,9 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool, if (!full) { event->comm.tid = pid; - process(tool, event, &synth_sample, machine); + if (process(tool, event, &synth_sample, machine) != 0) + return -1; + goto out; } @@ -151,7 +153,10 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool, event->comm.tid = pid; - process(tool, event, &synth_sample, machine); + if (process(tool, event, &synth_sample, machine) != 0) { + tgid = -1; + break; + } } closedir(tasks); @@ -167,6 +172,7 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, { char filename[PATH_MAX]; FILE *fp; + int rc = 0; snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); @@ -231,18 +237,22 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, event->mmap.pid = tgid; event->mmap.tid = pid; - process(tool, event, &synth_sample, machine); + if (process(tool, event, &synth_sample, machine) != 0) { + rc = -1; + break; + } } } fclose(fp); - return 0; + return rc; } int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine) { + int rc = 0; struct rb_node *nd; struct map_groups *kmaps = &machine->kmaps; union perf_event *event = zalloc((sizeof(event->mmap) + @@ -284,11 +294,14 @@ int perf_event__synthesize_modules(struct perf_tool *tool, memcpy(event->mmap.filename, pos->dso->long_name, pos->dso->long_name_len + 1); - process(tool, event, &synth_sample, machine); + if (process(tool, event, &synth_sample, machine) != 0) { + rc = -1; + break; + } } free(event); - return 0; + return rc; } static int __event__synthesize_thread(union perf_event *comm_event, @@ -392,12 +405,16 @@ int perf_event__synthesize_threads(struct perf_tool *tool, if (*end) /* only interested in proper numerical dirents */ continue; - __event__synthesize_thread(comm_event, mmap_event, pid, 1, - process, tool, machine); + if (__event__synthesize_thread(comm_event, mmap_event, pid, 1, + process, tool, machine) != 0) { + err = -1; + goto out_closedir; + } } - closedir(proc); err = 0; +out_closedir: + closedir(proc); out_free_mmap: free(mmap_event); out_free_comm: From 33d6aef5136075930f7e9a05175bf4f772d8428e Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 26 Aug 2012 12:24:43 -0600 Subject: [PATCH 04/25] perf lock: Remove use of die and handle errors Allows perf to clean up properly on exit. Signed-off-by: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1346005487-62961-4-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-lock.c | 181 ++++++++++++++++++++++++++------------ 1 file changed, 124 insertions(+), 57 deletions(-) diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 585aae2858b8..75153c87e650 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -161,8 +161,10 @@ static struct thread_stat *thread_stat_findnew_after_first(u32 tid) return st; st = zalloc(sizeof(struct thread_stat)); - if (!st) - die("memory allocation failed\n"); + if (!st) { + pr_err("memory allocation failed\n"); + return NULL; + } st->tid = tid; INIT_LIST_HEAD(&st->seq_list); @@ -181,8 +183,10 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid) struct thread_stat *st; st = zalloc(sizeof(struct thread_stat)); - if (!st) - die("memory allocation failed\n"); + if (!st) { + pr_err("memory allocation failed\n"); + return NULL; + } st->tid = tid; INIT_LIST_HEAD(&st->seq_list); @@ -248,18 +252,20 @@ struct lock_key keys[] = { { NULL, NULL } }; -static void select_key(void) +static int select_key(void) { int i; for (i = 0; keys[i].name; i++) { if (!strcmp(keys[i].name, sort_key)) { compare = keys[i].key; - return; + return 0; } } - die("Unknown compare key:%s\n", sort_key); + pr_err("Unknown compare key: %s\n", sort_key); + + return -1; } static void insert_to_result(struct lock_stat *st, @@ -324,7 +330,8 @@ static struct lock_stat *lock_stat_findnew(void *addr, const char *name) return new; alloc_failed: - die("memory allocation failed\n"); + pr_err("memory allocation failed\n"); + return NULL; } static const char *input_name; @@ -356,16 +363,16 @@ struct trace_release_event { }; struct trace_lock_handler { - void (*acquire_event)(struct trace_acquire_event *, + int (*acquire_event)(struct trace_acquire_event *, const struct perf_sample *sample); - void (*acquired_event)(struct trace_acquired_event *, + int (*acquired_event)(struct trace_acquired_event *, const struct perf_sample *sample); - void (*contended_event)(struct trace_contended_event *, + int (*contended_event)(struct trace_contended_event *, const struct perf_sample *sample); - void (*release_event)(struct trace_release_event *, + int (*release_event)(struct trace_release_event *, const struct perf_sample *sample); }; @@ -379,8 +386,10 @@ static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr) } seq = zalloc(sizeof(struct lock_seq_stat)); - if (!seq) - die("Not enough memory\n"); + if (!seq) { + pr_err("memory allocation failed\n"); + return NULL; + } seq->state = SEQ_STATE_UNINITIALIZED; seq->addr = addr; @@ -403,7 +412,7 @@ enum acquire_flags { READ_LOCK = 2, }; -static void +static int report_lock_acquire_event(struct trace_acquire_event *acquire_event, const struct perf_sample *sample) { @@ -412,11 +421,18 @@ report_lock_acquire_event(struct trace_acquire_event *acquire_event, struct lock_seq_stat *seq; ls = lock_stat_findnew(acquire_event->addr, acquire_event->name); + if (!ls) + return -1; if (ls->discard) - return; + return 0; ts = thread_stat_findnew(sample->tid); + if (!ts) + return -1; + seq = get_seq(ts, acquire_event->addr); + if (!seq) + return -1; switch (seq->state) { case SEQ_STATE_UNINITIALIZED: @@ -461,10 +477,10 @@ broken: ls->nr_acquire++; seq->prev_event_time = sample->time; end: - return; + return 0; } -static void +static int report_lock_acquired_event(struct trace_acquired_event *acquired_event, const struct perf_sample *sample) { @@ -475,16 +491,23 @@ report_lock_acquired_event(struct trace_acquired_event *acquired_event, u64 contended_term; ls = lock_stat_findnew(acquired_event->addr, acquired_event->name); + if (!ls) + return -1; if (ls->discard) - return; + return 0; ts = thread_stat_findnew(sample->tid); + if (!ts) + return -1; + seq = get_seq(ts, acquired_event->addr); + if (!seq) + return -1; switch (seq->state) { case SEQ_STATE_UNINITIALIZED: /* orphan event, do nothing */ - return; + return 0; case SEQ_STATE_ACQUIRING: break; case SEQ_STATE_CONTENDED: @@ -515,10 +538,10 @@ report_lock_acquired_event(struct trace_acquired_event *acquired_event, ls->nr_acquired++; seq->prev_event_time = timestamp; end: - return; + return 0; } -static void +static int report_lock_contended_event(struct trace_contended_event *contended_event, const struct perf_sample *sample) { @@ -527,16 +550,23 @@ report_lock_contended_event(struct trace_contended_event *contended_event, struct lock_seq_stat *seq; ls = lock_stat_findnew(contended_event->addr, contended_event->name); + if (!ls) + return -1; if (ls->discard) - return; + return 0; ts = thread_stat_findnew(sample->tid); + if (!ts) + return -1; + seq = get_seq(ts, contended_event->addr); + if (!seq) + return -1; switch (seq->state) { case SEQ_STATE_UNINITIALIZED: /* orphan event, do nothing */ - return; + return 0; case SEQ_STATE_ACQUIRING: break; case SEQ_STATE_RELEASED: @@ -559,10 +589,10 @@ report_lock_contended_event(struct trace_contended_event *contended_event, ls->nr_contended++; seq->prev_event_time = sample->time; end: - return; + return 0; } -static void +static int report_lock_release_event(struct trace_release_event *release_event, const struct perf_sample *sample) { @@ -571,11 +601,18 @@ report_lock_release_event(struct trace_release_event *release_event, struct lock_seq_stat *seq; ls = lock_stat_findnew(release_event->addr, release_event->name); + if (!ls) + return -1; if (ls->discard) - return; + return 0; ts = thread_stat_findnew(sample->tid); + if (!ts) + return -1; + seq = get_seq(ts, release_event->addr); + if (!seq) + return -1; switch (seq->state) { case SEQ_STATE_UNINITIALIZED: @@ -609,7 +646,7 @@ free_seq: list_del(&seq->list); free(seq); end: - return; + return 0; } /* lock oriented handlers */ @@ -623,13 +660,14 @@ static struct trace_lock_handler report_lock_ops = { static struct trace_lock_handler *trace_handler; -static void perf_evsel__process_lock_acquire(struct perf_evsel *evsel, +static int perf_evsel__process_lock_acquire(struct perf_evsel *evsel, struct perf_sample *sample) { struct trace_acquire_event acquire_event; struct event_format *event = evsel->tp_format; void *data = sample->raw_data; u64 tmp; /* this is required for casting... */ + int rc = 0; tmp = raw_field_value(event, "lockdep_addr", data); memcpy(&acquire_event.addr, &tmp, sizeof(void *)); @@ -637,70 +675,84 @@ static void perf_evsel__process_lock_acquire(struct perf_evsel *evsel, acquire_event.flag = (int)raw_field_value(event, "flag", data); if (trace_handler->acquire_event) - trace_handler->acquire_event(&acquire_event, sample); + rc = trace_handler->acquire_event(&acquire_event, sample); + + return rc; } -static void perf_evsel__process_lock_acquired(struct perf_evsel *evsel, +static int perf_evsel__process_lock_acquired(struct perf_evsel *evsel, struct perf_sample *sample) { struct trace_acquired_event acquired_event; struct event_format *event = evsel->tp_format; void *data = sample->raw_data; u64 tmp; /* this is required for casting... */ + int rc = 0; tmp = raw_field_value(event, "lockdep_addr", data); memcpy(&acquired_event.addr, &tmp, sizeof(void *)); acquired_event.name = (char *)raw_field_ptr(event, "name", data); - if (trace_handler->acquire_event) - trace_handler->acquired_event(&acquired_event, sample); + if (trace_handler->acquired_event) + rc = trace_handler->acquired_event(&acquired_event, sample); + + return rc; } -static void perf_evsel__process_lock_contended(struct perf_evsel *evsel, +static int perf_evsel__process_lock_contended(struct perf_evsel *evsel, struct perf_sample *sample) { struct trace_contended_event contended_event; struct event_format *event = evsel->tp_format; void *data = sample->raw_data; u64 tmp; /* this is required for casting... */ + int rc = 0; tmp = raw_field_value(event, "lockdep_addr", data); memcpy(&contended_event.addr, &tmp, sizeof(void *)); contended_event.name = (char *)raw_field_ptr(event, "name", data); - if (trace_handler->acquire_event) - trace_handler->contended_event(&contended_event, sample); + if (trace_handler->contended_event) + rc = trace_handler->contended_event(&contended_event, sample); + + return rc; } -static void perf_evsel__process_lock_release(struct perf_evsel *evsel, +static int perf_evsel__process_lock_release(struct perf_evsel *evsel, struct perf_sample *sample) { struct trace_release_event release_event; struct event_format *event = evsel->tp_format; void *data = sample->raw_data; u64 tmp; /* this is required for casting... */ + int rc = 0; tmp = raw_field_value(event, "lockdep_addr", data); memcpy(&release_event.addr, &tmp, sizeof(void *)); release_event.name = (char *)raw_field_ptr(event, "name", data); - if (trace_handler->acquire_event) - trace_handler->release_event(&release_event, sample); + if (trace_handler->release_event) + rc = trace_handler->release_event(&release_event, sample); + + return rc; } -static void perf_evsel__process_lock_event(struct perf_evsel *evsel, +static int perf_evsel__process_lock_event(struct perf_evsel *evsel, struct perf_sample *sample) { struct event_format *event = evsel->tp_format; + int rc = 0; if (!strcmp(event->name, "lock_acquire")) - perf_evsel__process_lock_acquire(evsel, sample); + rc = perf_evsel__process_lock_acquire(evsel, sample); if (!strcmp(event->name, "lock_acquired")) - perf_evsel__process_lock_acquired(evsel, sample); + rc = perf_evsel__process_lock_acquired(evsel, sample); if (!strcmp(event->name, "lock_contended")) - perf_evsel__process_lock_contended(evsel, sample); + rc = perf_evsel__process_lock_contended(evsel, sample); if (!strcmp(event->name, "lock_release")) - perf_evsel__process_lock_release(evsel, sample); + rc = perf_evsel__process_lock_release(evsel, sample); + + return rc; } static void print_bad_events(int bad, int total) @@ -802,14 +854,20 @@ static void dump_map(void) } } -static void dump_info(void) +static int dump_info(void) { + int rc = 0; + if (info_threads) dump_threads(); else if (info_map) dump_map(); - else - die("Unknown type of information\n"); + else { + rc = -1; + pr_err("Unknown type of information\n"); + } + + return rc; } static int process_sample_event(struct perf_tool *tool __used, @@ -826,8 +884,7 @@ static int process_sample_event(struct perf_tool *tool __used, return -1; } - perf_evsel__process_lock_event(evsel, sample); - return 0; + return perf_evsel__process_lock_event(evsel, sample); } static struct perf_tool eops = { @@ -839,8 +896,10 @@ static struct perf_tool eops = { static int read_events(void) { session = perf_session__new(input_name, O_RDONLY, 0, false, &eops); - if (!session) - die("Initializing perf session failed\n"); + if (!session) { + pr_err("Initializing perf session failed\n"); + return -1; + } return perf_session__process_events(session, &eops); } @@ -857,13 +916,18 @@ static void sort_result(void) } } -static void __cmd_report(void) +static int __cmd_report(void) { setup_pager(); - select_key(); - read_events(); + + if ((select_key() != 0) || + (read_events() != 0)) + return -1; + sort_result(); print_result(); + + return 0; } static const char * const report_usage[] = { @@ -959,6 +1023,7 @@ static int __cmd_record(int argc, const char **argv) int cmd_lock(int argc, const char **argv, const char *prefix __used) { unsigned int i; + int rc = 0; symbol__init(); for (i = 0; i < LOCKHASH_SIZE; i++) @@ -993,11 +1058,13 @@ int cmd_lock(int argc, const char **argv, const char *prefix __used) /* recycling report_lock_ops */ trace_handler = &report_lock_ops; setup_pager(); - read_events(); - dump_info(); + if (read_events() != 0) + rc = -1; + else + rc = dump_info(); } else { usage_with_options(lock_usage, lock_options); } - return 0; + return rc; } From fceda7feb4a7822feee9662bc64968230d8f37bf Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 26 Aug 2012 12:24:44 -0600 Subject: [PATCH 05/25] perf stat: Remove use of die/exit and handle errors Allows perf to clean up properly on program termination. Signed-off-by: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1346005487-62961-5-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index d53d8ab099b1..02f49eba677f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -428,7 +428,7 @@ static int run_perf_stat(int argc __used, const char **argv) if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { perror("failed to create pipes"); - exit(1); + return -1; } if (forks) { @@ -510,7 +510,8 @@ static int run_perf_stat(int argc __used, const char **argv) } if (child_pid != -1) kill(child_pid, SIGTERM); - die("Not all events could be opened.\n"); + + pr_err("Not all events could be opened.\n"); return -1; } counter->supported = true; @@ -1189,7 +1190,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) output = fopen(output_name, mode); if (!output) { perror("failed to create output file"); - exit(-1); + return -1; } clock_gettime(CLOCK_REALTIME, &tm); fprintf(output, "# started on %s\n", ctime(&tm.tv_sec)); From cc58482133296f52873be909a2795f6d934ecec9 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 26 Aug 2012 12:24:45 -0600 Subject: [PATCH 06/25] perf help: Remove use of die and handle errors Allows perf to clean up properly on exit. Signed-off-by: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1346005487-62961-6-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-help.c | 48 +++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 6d5a8a7faf48..f9daae5ac47a 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -24,13 +24,14 @@ static struct man_viewer_info_list { } *man_viewer_info_list; enum help_format { + HELP_FORMAT_NONE, HELP_FORMAT_MAN, HELP_FORMAT_INFO, HELP_FORMAT_WEB, }; static bool show_all = false; -static enum help_format help_format = HELP_FORMAT_MAN; +static enum help_format help_format = HELP_FORMAT_NONE; static struct option builtin_help_options[] = { OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), @@ -54,7 +55,9 @@ static enum help_format parse_help_format(const char *format) return HELP_FORMAT_INFO; if (!strcmp(format, "web") || !strcmp(format, "html")) return HELP_FORMAT_WEB; - die("unrecognized help format '%s'", format); + + pr_err("unrecognized help format '%s'", format); + return HELP_FORMAT_NONE; } static const char *get_man_viewer_info(const char *name) @@ -259,6 +262,8 @@ static int perf_help_config(const char *var, const char *value, void *cb) if (!value) return config_error_nonbool(var); help_format = parse_help_format(value); + if (help_format == HELP_FORMAT_NONE) + return -1; return 0; } if (!strcmp(var, "man.viewer")) { @@ -352,7 +357,7 @@ static void exec_viewer(const char *name, const char *page) warning("'%s': unknown man viewer.", name); } -static void show_man_page(const char *perf_cmd) +static int show_man_page(const char *perf_cmd) { struct man_viewer_list *viewer; const char *page = cmd_to_page(perf_cmd); @@ -365,28 +370,35 @@ static void show_man_page(const char *perf_cmd) if (fallback) exec_viewer(fallback, page); exec_viewer("man", page); - die("no man viewer handled the request"); + + pr_err("no man viewer handled the request"); + return -1; } -static void show_info_page(const char *perf_cmd) +static int show_info_page(const char *perf_cmd) { const char *page = cmd_to_page(perf_cmd); setenv("INFOPATH", system_path(PERF_INFO_PATH), 1); execlp("info", "info", "perfman", page, NULL); + return -1; } -static void get_html_page_path(struct strbuf *page_path, const char *page) +static int get_html_page_path(struct strbuf *page_path, const char *page) { struct stat st; const char *html_path = system_path(PERF_HTML_PATH); /* Check that we have a perf documentation directory. */ if (stat(mkpath("%s/perf.html", html_path), &st) - || !S_ISREG(st.st_mode)) - die("'%s': not a documentation directory.", html_path); + || !S_ISREG(st.st_mode)) { + pr_err("'%s': not a documentation directory.", html_path); + return -1; + } strbuf_init(page_path, 0); strbuf_addf(page_path, "%s/%s.html", html_path, page); + + return 0; } /* @@ -401,19 +413,23 @@ static void open_html(const char *path) } #endif -static void show_html_page(const char *perf_cmd) +static int show_html_page(const char *perf_cmd) { const char *page = cmd_to_page(perf_cmd); struct strbuf page_path; /* it leaks but we exec bellow */ - get_html_page_path(&page_path, page); + if (get_html_page_path(&page_path, page) != 0) + return -1; open_html(page_path.buf); + + return 0; } int cmd_help(int argc, const char **argv, const char *prefix __used) { const char *alias; + int rc = 0; load_command_list("perf-", &main_cmds, &other_cmds); @@ -444,16 +460,20 @@ int cmd_help(int argc, const char **argv, const char *prefix __used) switch (help_format) { case HELP_FORMAT_MAN: - show_man_page(argv[0]); + rc = show_man_page(argv[0]); break; case HELP_FORMAT_INFO: - show_info_page(argv[0]); + rc = show_info_page(argv[0]); break; case HELP_FORMAT_WEB: - show_html_page(argv[0]); + rc = show_html_page(argv[0]); + break; + case HELP_FORMAT_NONE: + /* fall-through */ default: + rc = -1; break; } - return 0; + return rc; } From d54b1a9e0eaca92cde678d19bd82b9594ed00450 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 26 Aug 2012 12:24:46 -0600 Subject: [PATCH 07/25] perf script: Remove use of die/exit Allows perf to clean up properly on exit. Only exits left are exec failures which are appropriate and usage callbacks that list available options. Signed-off-by: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1346005487-62961-7-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 60 +++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 2d6e3b226aad..c350cfee3157 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1153,18 +1153,23 @@ static const struct option options[] = { OPT_END() }; -static bool have_cmd(int argc, const char **argv) +static int have_cmd(int argc, const char **argv) { char **__argv = malloc(sizeof(const char *) * argc); - if (!__argv) - die("malloc"); + if (!__argv) { + pr_err("malloc failed\n"); + return -1; + } + memcpy(__argv, argv, sizeof(const char *) * argc); argc = parse_options(argc, (const char **)__argv, record_options, NULL, PARSE_OPT_STOP_AT_NON_OPTION); free(__argv); - return argc != 0; + system_wide = (argc == 0); + + return 0; } int cmd_script(int argc, const char **argv, const char *prefix __used) @@ -1231,13 +1236,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) if (pipe(live_pipe) < 0) { perror("failed to create pipe"); - exit(-1); + return -1; } pid = fork(); if (pid < 0) { perror("failed to fork"); - exit(-1); + return -1; } if (!pid) { @@ -1249,13 +1254,18 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) if (is_top_script(argv[0])) { system_wide = true; } else if (!system_wide) { - system_wide = !have_cmd(argc - rep_args, - &argv[rep_args]); + if (have_cmd(argc - rep_args, &argv[rep_args]) != 0) { + err = -1; + goto out; + } } __argv = malloc((argc + 6) * sizeof(const char *)); - if (!__argv) - die("malloc"); + if (!__argv) { + pr_err("malloc failed\n"); + err = -ENOMEM; + goto out; + } __argv[j++] = "/bin/sh"; __argv[j++] = rec_script_path; @@ -1277,8 +1287,12 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) close(live_pipe[1]); __argv = malloc((argc + 4) * sizeof(const char *)); - if (!__argv) - die("malloc"); + if (!__argv) { + pr_err("malloc failed\n"); + err = -ENOMEM; + goto out; + } + j = 0; __argv[j++] = "/bin/sh"; __argv[j++] = rep_script_path; @@ -1303,12 +1317,20 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) if (!rec_script_path) system_wide = false; - else if (!system_wide) - system_wide = !have_cmd(argc - 1, &argv[1]); + else if (!system_wide) { + if (have_cmd(argc - 1, &argv[1]) != 0) { + err = -1; + goto out; + } + } __argv = malloc((argc + 2) * sizeof(const char *)); - if (!__argv) - die("malloc"); + if (!__argv) { + pr_err("malloc failed\n"); + err = -ENOMEM; + goto out; + } + __argv[j++] = "/bin/sh"; __argv[j++] = script_path; if (system_wide) @@ -1357,18 +1379,18 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) input = open(session->filename, O_RDONLY); /* input_name */ if (input < 0) { perror("failed to open file"); - exit(-1); + return -1; } err = fstat(input, &perf_stat); if (err < 0) { perror("failed to stat file"); - exit(-1); + return -1; } if (!perf_stat.st_size) { fprintf(stderr, "zero-sized file, nothing to do!\n"); - exit(0); + return 0; } scripting_ops = script_spec__lookup(generate_script_lang); From 8d3eca20b9f31cf10088e283d704f6a71b9a4ee2 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 26 Aug 2012 12:24:47 -0600 Subject: [PATCH 08/25] perf record: Remove use of die/exit Allows perf to clean up properly on exit. If perf-record is exiting due to failure, the on_exit should not run as the session has been deleted. Signed-off-by: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1346005487-62961-8-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 158 +++++++++++++++++++++++++----------- 1 file changed, 109 insertions(+), 49 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 479ff2a038fc..7b8b891d4d56 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -71,19 +71,23 @@ static void advance_output(struct perf_record *rec, size_t size) rec->bytes_written += size; } -static void write_output(struct perf_record *rec, void *buf, size_t size) +static int write_output(struct perf_record *rec, void *buf, size_t size) { while (size) { int ret = write(rec->output, buf, size); - if (ret < 0) - die("failed to write"); + if (ret < 0) { + pr_err("failed to write\n"); + return -1; + } size -= ret; buf += ret; rec->bytes_written += ret; } + + return 0; } static int process_synthesized_event(struct perf_tool *tool, @@ -92,11 +96,13 @@ static int process_synthesized_event(struct perf_tool *tool, struct machine *machine __used) { struct perf_record *rec = container_of(tool, struct perf_record, tool); - write_output(rec, event, event->header.size); + if (write_output(rec, event, event->header.size) < 0) + return -1; + return 0; } -static void perf_record__mmap_read(struct perf_record *rec, +static int perf_record__mmap_read(struct perf_record *rec, struct perf_mmap *md) { unsigned int head = perf_mmap__read_head(md); @@ -104,9 +110,10 @@ static void perf_record__mmap_read(struct perf_record *rec, unsigned char *data = md->base + rec->page_size; unsigned long size; void *buf; + int rc = 0; if (old == head) - return; + return 0; rec->samples++; @@ -117,17 +124,26 @@ static void perf_record__mmap_read(struct perf_record *rec, size = md->mask + 1 - (old & md->mask); old += size; - write_output(rec, buf, size); + if (write_output(rec, buf, size) < 0) { + rc = -1; + goto out; + } } buf = &data[old & md->mask]; size = head - old; old += size; - write_output(rec, buf, size); + if (write_output(rec, buf, size) < 0) { + rc = -1; + goto out; + } md->prev = old; perf_mmap__write_tail(md, old); + +out: + return rc; } static volatile int done = 0; @@ -183,12 +199,13 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, return true; } -static void perf_record__open(struct perf_record *rec) +static int perf_record__open(struct perf_record *rec) { struct perf_evsel *pos; struct perf_evlist *evlist = rec->evlist; struct perf_session *session = rec->session; struct perf_record_opts *opts = &rec->opts; + int rc = 0; perf_evlist__config_attrs(evlist, opts); @@ -222,10 +239,13 @@ try_again: if (err == EPERM || err == EACCES) { ui__error_paranoid(); - exit(EXIT_FAILURE); + rc = -err; + goto out; } else if (err == ENODEV && opts->target.cpu_list) { - die("No such device - did you specify" - " an out-of-range profile CPU?\n"); + pr_err("No such device - did you specify" + " an out-of-range profile CPU?\n"); + rc = -err; + goto out; } else if (err == EINVAL) { if (!opts->exclude_guest_missing && (attr->exclude_guest || attr->exclude_host)) { @@ -272,7 +292,8 @@ try_again: if (err == ENOENT) { ui__error("The %s event is not supported.\n", perf_evsel__name(pos)); - exit(EXIT_FAILURE); + rc = -err; + goto out; } printf("\n"); @@ -280,34 +301,46 @@ try_again: err, strerror(err)); #if defined(__i386__) || defined(__x86_64__) - if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) - die("No hardware sampling interrupt available." - " No APIC? If so then you can boot the kernel" - " with the \"lapic\" boot parameter to" - " force-enable it.\n"); + if (attr->type == PERF_TYPE_HARDWARE && + err == EOPNOTSUPP) { + pr_err("No hardware sampling interrupt available." + " No APIC? If so then you can boot the kernel" + " with the \"lapic\" boot parameter to" + " force-enable it.\n"); + rc = -err; + goto out; + } #endif - die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); + pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); + rc = -err; + goto out; } } if (perf_evlist__set_filters(evlist)) { error("failed to set filter with %d (%s)\n", errno, strerror(errno)); - exit(-1); + rc = -1; + goto out; } if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { - if (errno == EPERM) - die("Permission error mapping pages.\n" - "Consider increasing " - "/proc/sys/kernel/perf_event_mlock_kb,\n" - "or try again with a smaller value of -m/--mmap_pages.\n" - "(current value: %d)\n", opts->mmap_pages); - else if (!is_power_of_2(opts->mmap_pages)) - die("--mmap_pages/-m value must be a power of two."); - - die("failed to mmap with %d (%s)\n", errno, strerror(errno)); + if (errno == EPERM) { + pr_err("Permission error mapping pages.\n" + "Consider increasing " + "/proc/sys/kernel/perf_event_mlock_kb,\n" + "or try again with a smaller value of -m/--mmap_pages.\n" + "(current value: %d)\n", opts->mmap_pages); + rc = -errno; + } else if (!is_power_of_2(opts->mmap_pages)) { + pr_err("--mmap_pages/-m value must be a power of two."); + rc = -EINVAL; + } else { + pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); + rc = -errno; + } + goto out; } if (rec->file_new) @@ -315,11 +348,14 @@ try_again: else { if (!perf_evlist__equal(session->evlist, evlist)) { fprintf(stderr, "incompatible append\n"); - exit(-1); + rc = -1; + goto out; } } perf_session__set_id_hdr_size(session); +out: + return rc; } static int process_buildids(struct perf_record *rec) @@ -335,10 +371,13 @@ static int process_buildids(struct perf_record *rec) size, &build_id__mark_dso_hit_ops); } -static void perf_record__exit(int status __used, void *arg) +static void perf_record__exit(int status, void *arg) { struct perf_record *rec = arg; + if (status != 0) + return; + if (!rec->opts.pipe_output) { rec->session->header.data_size += rec->bytes_written; @@ -393,17 +432,26 @@ static struct perf_event_header finished_round_event = { .type = PERF_RECORD_FINISHED_ROUND, }; -static void perf_record__mmap_read_all(struct perf_record *rec) +static int perf_record__mmap_read_all(struct perf_record *rec) { int i; + int rc = 0; for (i = 0; i < rec->evlist->nr_mmaps; i++) { - if (rec->evlist->mmap[i].base) - perf_record__mmap_read(rec, &rec->evlist->mmap[i]); + if (rec->evlist->mmap[i].base) { + if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { + rc = -1; + goto out; + } + } } if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) - write_output(rec, &finished_round_event, sizeof(finished_round_event)); + rc = write_output(rec, &finished_round_event, + sizeof(finished_round_event)); + +out: + return rc; } static int __cmd_record(struct perf_record *rec, int argc, const char **argv) @@ -463,7 +511,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) output = open(output_name, flags, S_IRUSR | S_IWUSR); if (output < 0) { perror("failed to create output file"); - exit(-1); + return -1; } rec->output = output; @@ -503,7 +551,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) } } - perf_record__open(rec); + if (perf_record__open(rec) != 0) { + err = -1; + goto out_delete_session; + } /* * perf_session__delete(session) will be called at perf_record__exit() @@ -513,19 +564,20 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) if (opts->pipe_output) { err = perf_header__write_pipe(output); if (err < 0) - return err; + goto out_delete_session; } else if (rec->file_new) { err = perf_session__write_header(session, evsel_list, output, false); if (err < 0) - return err; + goto out_delete_session; } if (!rec->no_buildid && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { pr_err("Couldn't generate buildids. " "Use --no-buildid to profile anyway.\n"); - return -1; + err = -1; + goto out_delete_session; } rec->post_processing_offset = lseek(output, 0, SEEK_CUR); @@ -533,7 +585,8 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) machine = perf_session__find_host_machine(session); if (!machine) { pr_err("Couldn't find native kernel information.\n"); - return -1; + err = -1; + goto out_delete_session; } if (opts->pipe_output) { @@ -541,14 +594,14 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) process_synthesized_event); if (err < 0) { pr_err("Couldn't synthesize attrs.\n"); - return err; + goto out_delete_session; } err = perf_event__synthesize_event_types(tool, process_synthesized_event, machine); if (err < 0) { pr_err("Couldn't synthesize event_types.\n"); - return err; + goto out_delete_session; } if (have_tracepoints(&evsel_list->entries)) { @@ -564,7 +617,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) process_synthesized_event); if (err <= 0) { pr_err("Couldn't record tracing data.\n"); - return err; + goto out_delete_session; } advance_output(rec, err); } @@ -592,20 +645,24 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) perf_event__synthesize_guest_os); if (!opts->target.system_wide) - perf_event__synthesize_thread_map(tool, evsel_list->threads, + err = perf_event__synthesize_thread_map(tool, evsel_list->threads, process_synthesized_event, machine); else - perf_event__synthesize_threads(tool, process_synthesized_event, + err = perf_event__synthesize_threads(tool, process_synthesized_event, machine); + if (err != 0) + goto out_delete_session; + if (rec->realtime_prio) { struct sched_param param; param.sched_priority = rec->realtime_prio; if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { pr_err("Could not set realtime priority.\n"); - exit(-1); + err = -1; + goto out_delete_session; } } @@ -620,7 +677,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) for (;;) { int hits = rec->samples; - perf_record__mmap_read_all(rec); + if (perf_record__mmap_read_all(rec) < 0) { + err = -1; + goto out_delete_session; + } if (hits == rec->samples) { if (done) From 09a2f16a916178489fc4bf439de668d81fda7616 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 27 Aug 2012 13:05:54 -0600 Subject: [PATCH 09/25] perf tools: Fix x86 builds with ARCH specified on the command line e.g., compiling i386 on x86_64 using: $ make -C tools/perf ARCH=i386 fails with: CC /tmp/pbuild/util/evsel.o In file included from util/evsel.c:21:0: util/perf_regs.h:5:23: fatal error: perf_regs.h: No such file or directory compilation terminated. Adding V=1 you see that the include argument for the arch is '-Iarch/i386/include' is wrong. It is supposed to be -Iarch/x86/include per the redefinition of ARCH in the Makefile. According to the make manual, http://www.gnu.org/software/make/manual/make.html#Override-Directive: "If a variable has been set with a command argument (see Overriding Variables), then ordinary assignments in the makefile are ignored. If you want to set the variable in the makefile even though it was set with a command argument, you can use an override directive ..." Make it so. Signed-off-by: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1346094354-74356-1-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 722ddee61f9f..939cf6d898a5 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -64,12 +64,12 @@ AR = $(CROSS_COMPILE)ar # Additional ARCH settings for x86 ifeq ($(ARCH),i386) - ARCH := x86 + override ARCH := x86 NO_PERF_REGS := 0 LIBUNWIND_LIBS = -lunwind -lunwind-x86 endif ifeq ($(ARCH),x86_64) - ARCH := x86 + override ARCH := x86 IS_X86_64 := 0 ifeq (, $(findstring m32,$(EXTRA_CFLAGS))) IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1) From 60ebf328762914b80d3e4e5f07bda599043c8eda Mon Sep 17 00:00:00 2001 From: "Suzuki K. Poulose" Date: Fri, 31 Aug 2012 12:28:47 +0530 Subject: [PATCH 10/25] perf tools: Fix intlist node removal Similar to the one in : https://lkml.org/lkml/2012/8/29/27 Make sure we remove the node from the rblist before we delete the node. The rblist__remove_node() will invoke rblist->node_delete, which will take care of deleting the node with the suitable function provided by the user. Signed-off-by: Suzuki K Poulose Acked-by: David Ahern Cc: David Ahern Cc: Suzuki K Poulose Link: http://lkml.kernel.org/r/20120831065840.5167.90318.stgit@suzukikp.in.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intlist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c index fd530dced9cb..77c504ff0088 100644 --- a/tools/perf/util/intlist.c +++ b/tools/perf/util/intlist.c @@ -52,9 +52,9 @@ int intlist__add(struct intlist *ilist, int i) return rblist__add_node(&ilist->rblist, (void *)((long)i)); } -void intlist__remove(struct intlist *ilist __used, struct int_node *node) +void intlist__remove(struct intlist *ilist, struct int_node *node) { - int_node__delete(node); + rblist__remove_node(&ilist->rblist, &node->rb_node); } struct int_node *intlist__find(struct intlist *ilist, int i) From 4592281403e74dc4401d5803ec9948d43bbee7ae Mon Sep 17 00:00:00 2001 From: "Suzuki K. Poulose" Date: Wed, 29 Aug 2012 11:30:07 +0530 Subject: [PATCH 11/25] perf tools: Remove the node from rblist in strlist__remove The following commit: author David Ahern Tue, 31 Jul 2012 04:31:33 +0000 (22:31 -0600) committer Arnaldo Carvalho de Melo Fri, 3 Aug 2012 13:39:51 +0000 (10:39 -0300) commit ee8dd3ca43f151d9fbe1edeef68fb8a77eb9f047 causes a double free during a probe deletion as the node is never removed from the list via strlist__remove(), even though it gets 'deleted' (read free()'d). This causes a double free when we do strlist__delete() as the node is already deleted but present in the rblist. [suzukikp@suzukikp perf]$ sudo ./perf probe -a do_fork Added new event: probe:do_fork (on do_fork) You can now use it in all perf tools, such as: perf record -e probe:do_fork -aR sleep 1 [suzukikp@suzukikp perf]$ sudo ./perf probe -d do_fork Removed event: probe:do_fork *** glibc detected *** ./perf: double free or corruption (fasttop): 0x000000000133d600 *** ======= Backtrace: ========= /lib64/libc.so.6[0x38eec7dda6] ./perf(rblist__delete+0x5c)[0x47d3dc] ./perf(del_perf_probe_events+0xb6)[0x47b826] ./perf(cmd_probe+0x471)[0x42c8d1] ./perf[0x4150b3] ./perf(main+0x501)[0x4148e1] /lib64/libc.so.6(__libc_start_main+0xed)[0x38eec2169d] ./perf[0x414a61] Make sure we remove the node from the rblist before we delete the node. The rblist__remove_node() will invoke rblist->node_delete, which will take care of deleting the node with the suitable function provided by the user. Reported-by: Ananth N. Mavinakayanahalli Signed-off-by: Suzuki K. Poulose Acked-by: David Ahern Cc: Ananth N Mavinakayanahalli Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20120829055840.7802.1459.stgit@suzukikp.in.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/strlist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c index 95856ff3dda4..155d8b7078a7 100644 --- a/tools/perf/util/strlist.c +++ b/tools/perf/util/strlist.c @@ -93,7 +93,7 @@ out: void strlist__remove(struct strlist *slist, struct str_node *snode) { - str_node__delete(snode, slist->dupstr); + rblist__remove_node(&slist->rblist, &snode->rb_node); } struct str_node *strlist__find(struct strlist *slist, const char *entry) From 12046099160e65cddb639f8b3dda2bd0701c09d6 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 29 Aug 2012 09:55:32 -0600 Subject: [PATCH 12/25] perf tools: remove unneeded include of network header files perf does not have networking related functionality, and the inclusion of these headers is one of the causes of compile failures for Android: https://lkml.org/lkml/2012/8/23/316 https://lkml.org/lkml/2012/8/28/293 So, remove them. Signed-off-by: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1346255732-93246-1-git-send-email-dsahern@gmail.com [ committer note: fix trace-event-perl.c compile failure by reordering includes ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/scripting-engines/trace-event-perl.c | 8 ++++---- tools/perf/util/util.h | 5 ----- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index d28001016fb5..94e673643bcb 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -25,16 +25,16 @@ #include #include -#include "../../perf.h" #include "../util.h" +#include +#include + +#include "../../perf.h" #include "../thread.h" #include "../event.h" #include "../trace-event.h" #include "../evsel.h" -#include -#include - void boot_Perf__Trace__Context(pTHX_ CV *cv); void boot_DynaLoader(pTHX_ CV *cv); typedef PerlInterpreter * INTERP; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 00a93a91a235..67a371355c75 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -69,11 +69,6 @@ #include #include #include -#include -#include -#include -#include -#include #include #include "../../../include/linux/magic.h" #include "types.h" From 74ba9e11f02a4ce0c7708dc77d1756b93065e440 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 5 Sep 2012 14:02:47 +0900 Subject: [PATCH 13/25] perf header: Use evlist->nr_entries on write_event_desc() Number of events (evsels) in a evlist is kept on nr_entries field so that we don't need to recalculate it. Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1346821373-31621-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 9696e64c9dbd..a124b9328170 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -610,11 +610,10 @@ static int write_event_desc(int fd, struct perf_header *h __used, struct perf_evlist *evlist) { struct perf_evsel *evsel; - u32 nre = 0, nri, sz; + u32 nre, nri, sz; int ret; - list_for_each_entry(evsel, &evlist->entries, node) - nre++; + nre = evlist->nr_entries; /* * write number of events From 618a3f1d30ea0ee2ff3a88661b8d6a4035123211 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 5 Sep 2012 14:02:48 +0900 Subject: [PATCH 14/25] perf header: Set tracepoint event name only if not set The event name can be set already by processing a event_desc data. So check it before setting to prevent possible leak. Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1346821373-31621-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index a124b9328170..05c9310c3da1 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2314,7 +2314,7 @@ static int perf_evlist__set_tracepoint_names(struct perf_evlist *evlist, struct perf_evsel *pos; list_for_each_entry(pos, &evlist->entries, node) { - if (pos->attr.type == PERF_TYPE_TRACEPOINT && + if (pos->attr.type == PERF_TYPE_TRACEPOINT && !pos->name && perf_evsel__set_tracepoint_name(pos, pevent)) return -1; } From be4a2dedf6816871349fbddd018f266e93e3c22d Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 5 Sep 2012 14:02:49 +0900 Subject: [PATCH 15/25] perf header: Swap pmu mapping numbers if needed Like others, the numbers can be saved in a different endian format than a host machine. Swap them if needed. Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Robert Richter Link: http://lkml.kernel.org/r/1346821373-31621-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 05c9310c3da1..43425b75f0c9 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1440,6 +1440,9 @@ static void print_pmu_mappings(struct perf_header *ph, int fd, FILE *fp) if (ret != sizeof(pmu_num)) goto error; + if (ph->needs_swap) + pmu_num = bswap_32(pmu_num); + if (!pmu_num) { fprintf(fp, "# pmu mappings: not available\n"); return; @@ -1448,6 +1451,9 @@ static void print_pmu_mappings(struct perf_header *ph, int fd, FILE *fp) while (pmu_num) { if (read(fd, &type, sizeof(type)) != sizeof(type)) break; + if (ph->needs_swap) + type = bswap_32(type); + name = do_read_string(fd, ph); if (!name) break; From 60ff92f515a4efb36931f1b5b042332016e0f123 Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Wed, 29 Aug 2012 01:22:16 +0300 Subject: [PATCH 16/25] perf tools: Replace mempcpy with memcpy mempcpy is not supported by bionic in Android and will lead to compilation errors. Replacing mempcpy with memcpy so it will work in Android. Signed-off-by: Irina Tirdea Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/CANg8OW+Y3ZMG-GdhYu2_yKOYH_XEMgw73PdCX_23UTnfYhmttA@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/target.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c index 051eaa68095e..065528b7563e 100644 --- a/tools/perf/util/target.c +++ b/tools/perf/util/target.c @@ -117,8 +117,8 @@ int perf_target__strerror(struct perf_target *target, int errnum, if (err != buf) { size_t len = strlen(err); - char *c = mempcpy(buf, err, min(buflen - 1, len)); - *c = '\0'; + memcpy(buf, err, min(buflen - 1, len)); + *(buf + min(buflen - 1, len)) = '\0'; } return 0; From 7a4ec938857cf534270b23545495300fbac7f5de Mon Sep 17 00:00:00 2001 From: Maciek Borzecki Date: Tue, 4 Sep 2012 12:32:30 +0200 Subject: [PATCH 17/25] perf tools: Allow user to indicate path to objdump in command line When analyzing perf data from hosts of other architecture than one of the local host it's useful to call objdump that is part of a toolchain for that architecture. Instead of calling regular objdump, call one that user specified in command line. Signed-off-by: Maciek Borzecki Acked-by: David Ahern Link: http://lkml.kernel.org/r/1346754750.16299.3.camel@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-annotate.txt | 3 +++ tools/perf/Documentation/perf-report.txt | 3 +++ tools/perf/builtin-annotate.c | 2 ++ tools/perf/builtin-report.c | 2 ++ tools/perf/util/annotate.c | 4 +++- tools/perf/util/annotate.h | 1 + 6 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index c89f9e1453f7..c8ffd9fd5c6a 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt @@ -85,6 +85,9 @@ OPTIONS -M:: --disassembler-style=:: Set disassembler style for objdump. +--objdump=:: + Path to objdump binary. + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-report[1] diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 495210a612c4..f4d91bebd59d 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -168,6 +168,9 @@ OPTIONS branch stacks and it will automatically switch to the branch view mode, unless --no-branch-stack is used. +--objdump=:: + Path to objdump binary. + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-annotate[1] diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 67522cf87405..2f3f0029c0f7 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -282,6 +282,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) "Display raw encoding of assembly instructions (default)"), OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), + OPT_STRING(0, "objdump", &objdump_path, "path", + "objdump binary to use for disassembly and annotations"), OPT_END() }; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index d61825371adc..1f8d11b4f7ff 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -638,6 +638,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) "Show a column with the sum of periods"), OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "", "use branch records for histogram filling", parse_branch_mode), + OPT_STRING(0, "objdump", &objdump_path, "path", + "objdump binary to use for disassembly and annotations"), OPT_END() }; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 3a282c0057d2..51ef69c9841d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -17,6 +17,7 @@ #include const char *disassembler_style; +const char *objdump_path; static struct ins *ins__find(const char *name); static int disasm_line__parse(char *line, char **namep, char **rawp); @@ -820,9 +821,10 @@ fallback: dso, dso->long_name, sym, sym->name); snprintf(command, sizeof(command), - "objdump %s%s --start-address=0x%016" PRIx64 + "%s %s%s --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 " -d %s %s -C %s|grep -v %s|expand", + objdump_path ? objdump_path : "objdump", disassembler_style ? "-M " : "", disassembler_style ? disassembler_style : "", map__rip_2objdump(map, sym->start), diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 78a5692dd718..a6d6bc5d7164 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -152,5 +152,6 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, #endif extern const char *disassembler_style; +extern const char *objdump_path; #endif /* __PERF_ANNOTATE_H */ From eea9b6842950924876a1a21ca197f189f8bb335a Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 5 Sep 2012 18:53:36 -0600 Subject: [PATCH 18/25] perf tools: Clean target should do clean for lib/traceevent too It's built as part of perf, so it should be cleaned too. Tested-by: Namhyung Kim Signed-off-by: David Ahern Cc: Namhyung Kim Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1346892816-61779-1-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 939cf6d898a5..afd507574902 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -917,6 +917,9 @@ $(LIB_FILE): $(LIB_OBJS) $(LIBTRACEEVENT): $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libtraceevent.a +$(LIBTRACEEVENT)-clean: + $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean + help: @echo 'Perf make targets:' @echo ' doc - make *all* documentation (see below)' @@ -1056,7 +1059,7 @@ quick-install-html: ### Cleaning rules -clean: +clean: $(LIBTRACEEVENT)-clean $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(RM) $(ALL_PROGRAMS) perf $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* From ae42c6bb9300cf25990bd15f1bd6ee38598f7483 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 6 Sep 2012 11:10:45 +0900 Subject: [PATCH 19/25] perf header: Fix a typo on evsel For checking return value of the strdup, 'event' should be 'evsel'. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1346897446-16569-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 43425b75f0c9..8b0b873c2295 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2307,7 +2307,7 @@ static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel, snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name); evsel->name = strdup(bf); - if (event->name == NULL) + if (evsel->name == NULL) return -1; evsel->tp_format = event; From 831394bdd9dd3ac1661336505c7cbdfd786d8cd4 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 6 Sep 2012 11:10:46 +0900 Subject: [PATCH 20/25] perf header: Prepare tracepoint events regardless of name Current perf_evlist__set_tracepoint_names is a misnomer because it finds and sets correspoding event_format in addition to the name. So skipping it when a event has set name already caused a trouble. Rename it and set name only a event doesn't have one. Reported-by: David Ahern Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1346897446-16569-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 8b0b873c2295..d07bc134e562 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2295,33 +2295,39 @@ static int read_attr(int fd, struct perf_header *ph, return ret <= 0 ? -1 : 0; } -static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel, - struct pevent *pevent) +static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, + struct pevent *pevent) { - struct event_format *event = pevent_find_event(pevent, - evsel->attr.config); + struct event_format *event; char bf[128]; + /* already prepared */ + if (evsel->tp_format) + return 0; + + event = pevent_find_event(pevent, evsel->attr.config); if (event == NULL) return -1; - snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name); - evsel->name = strdup(bf); - if (evsel->name == NULL) - return -1; + if (!evsel->name) { + snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name); + evsel->name = strdup(bf); + if (evsel->name == NULL) + return -1; + } evsel->tp_format = event; return 0; } -static int perf_evlist__set_tracepoint_names(struct perf_evlist *evlist, - struct pevent *pevent) +static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, + struct pevent *pevent) { struct perf_evsel *pos; list_for_each_entry(pos, &evlist->entries, node) { - if (pos->attr.type == PERF_TYPE_TRACEPOINT && !pos->name && - perf_evsel__set_tracepoint_name(pos, pevent)) + if (pos->attr.type == PERF_TYPE_TRACEPOINT && + perf_evsel__prepare_tracepoint_event(pos, pevent)) return -1; } @@ -2409,7 +2415,8 @@ int perf_session__read_header(struct perf_session *session, int fd) lseek(fd, header->data_offset, SEEK_SET); - if (perf_evlist__set_tracepoint_names(session->evlist, session->pevent)) + if (perf_evlist__prepare_tracepoint_events(session->evlist, + session->pevent)) goto out_delete_evlist; header->frozen = 1; @@ -2643,7 +2650,8 @@ int perf_event__process_tracing_data(union perf_event *event, if (size_read + padding != size) die("tracing data size mismatch"); - perf_evlist__set_tracepoint_names(session->evlist, session->pevent); + perf_evlist__prepare_tracepoint_events(session->evlist, + session->pevent); return size_read + padding; } From 8ad7013b252ba683055df19e657eb03d98f4f312 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 6 Sep 2012 13:11:18 -0300 Subject: [PATCH 21/25] perf test: Add round trip test for sw and hw event names It basically traverses the hardware and software event name arrays creating an evlist with all events, then it uses perf_evsel__name to check that the name is the expected one. With it I noticed this problem: [root@sandy ~]# perf test 10 10: roundtrip evsel->name check:invalid or unsupported event: 'CPU-migrations' Run 'perf list' for a list of valid events FAILED! Changed it to "cpu-migrations" in the software event arrays and it worked. This is to catch problems like the one reported by Joel Uckelman in http://permalink.gmane.org/gmane.linux.kernel.perf.user/1016 Hardware cache events will be checked in the following patch. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-5jskfkuqvf2fi257zmni0ftz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-test.c | 53 +++++++++++++++++++++++++++++++++++++++ tools/perf/util/evsel.c | 6 ++--- tools/perf/util/evsel.h | 6 +++-- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 381d5ab87124..ba94fbe1fa44 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -1092,6 +1092,55 @@ static int test__perf_pmu(void) return perf_pmu__test(); } +static int __perf_evsel__name_array_test(const char *names[], int nr_names) +{ + int i, err; + struct perf_evsel *evsel; + struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); + + if (evlist == NULL) + return -ENOMEM; + + for (i = 0; i < nr_names; ++i) { + err = parse_events(evlist, names[i], 0); + if (err) { + pr_debug("failed to parse event '%s', err %d\n", + names[i], err); + goto out_delete_evlist; + } + } + + err = 0; + list_for_each_entry(evsel, &evlist->entries, node) { + if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) { + --err; + pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]); + } + } + +out_delete_evlist: + perf_evlist__delete(evlist); + return err; +} + +#define perf_evsel__name_array_test(names) \ + __perf_evsel__name_array_test(names, ARRAY_SIZE(names)) + +static int perf_evsel__roundtrip_name_test(void) +{ + int err = 0, ret = 0; + + err = perf_evsel__name_array_test(perf_evsel__hw_names); + if (err) + ret = err; + + err = perf_evsel__name_array_test(perf_evsel__sw_names); + if (err) + ret = err; + + return ret; +} + static struct test { const char *desc; int (*func)(void); @@ -1134,6 +1183,10 @@ static struct test { .desc = "Test dso data interface", .func = dso__test_data, }, + { + .desc = "roundtrip evsel->name check", + .func = perf_evsel__roundtrip_name_test, + }, { .func = NULL, }, diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 7ff3c8fb736c..06f76441547a 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -68,7 +68,7 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) return evsel; } -static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = { +const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = { "cycles", "instructions", "cache-references", @@ -131,12 +131,12 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); } -static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = { +const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = { "cpu-clock", "task-clock", "page-faults", "context-switches", - "CPU-migrations", + "cpu-migrations", "minor-faults", "major-faults", "alignment-faults", diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 94f6ba16747f..a3f562cec433 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -97,8 +97,10 @@ extern const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX] [PERF_EVSEL__MAX_ALIASES]; extern const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX] [PERF_EVSEL__MAX_ALIASES]; -const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] - [PERF_EVSEL__MAX_ALIASES]; +extern const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] + [PERF_EVSEL__MAX_ALIASES]; +extern const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX]; +extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX]; int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, char *bf, size_t size); const char *perf_evsel__name(struct perf_evsel *evsel); From 42e1fb776087713b5482cd7cf6cac998fbdd6544 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 6 Sep 2012 14:43:28 -0300 Subject: [PATCH 22/25] perf tools: Remove extraneous newline when parsing hardware cache events Noticed while developing a 'perf test' entry to verify that perf_evsel__name works. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-xz6zgh38mp3cjnd2udh38z8f@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index b24630398b92..66d235e0cc98 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -308,7 +308,7 @@ int parse_events_add_cache(struct list_head **list, int *idx, for (i = 0; (i < 2) && (op_result[i]); i++) { char *str = op_result[i]; - snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str); + snprintf(name + n, MAX_NAME_LEN - n, "-%s", str); if (cache_op == -1) { cache_op = parse_aliases(str, perf_evsel__hw_cache_op, From 78f067b38bed1adce6a2fa7868cf8ea37d61f537 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 6 Sep 2012 14:54:11 -0300 Subject: [PATCH 23/25] perf evlist: Add fprintf method For debugging, etc. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-fjimge1ovgh976qlt8dtmlp0@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 13 +++++++++++++ tools/perf/util/evlist.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 4774ac1e3d5f..892353729c7a 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -889,3 +889,16 @@ int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *even struct perf_evsel *evsel = perf_evlist__first(evlist); return perf_evsel__parse_sample(evsel, event, sample, swapped); } + +size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) +{ + struct perf_evsel *evsel; + size_t printed = 0; + + list_for_each_entry(evsel, &evlist->entries, node) { + printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "", + perf_evsel__name(evsel)); + } + + return printed + fprintf(fp, "\n");; +} diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 2ed255792c6b..3f2e1e4ccdd5 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -143,4 +143,6 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist) { return list_entry(evlist->entries.prev, struct perf_evsel, node); } + +size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); #endif /* __PERF_EVLIST_H */ From 49f20d723e25a221fbcf1cbf4e51bb2942326e4f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 6 Sep 2012 14:55:44 -0300 Subject: [PATCH 24/25] perf test: Add roundtrip test for hardware cache events That nicely catches the problem reported by Joel Uckelman in http://permalink.gmane.org/gmane.linux.kernel.perf.user/1016 : [root@sandy ~]# perf test 1: vmlinux symtab matches kallsyms: Ok 2: detect open syscall event: Ok 3: detect open syscall event on all cpus: Ok 4: read samples using the mmap interface: Ok 5: parse events tests: Ok 6: x86 rdpmc test: Ok 7: Validate PERF_RECORD_* events & perf_sample fields: Ok 8: Test perf pmu format parsing: Ok 9: Test dso data interface: Ok 10: roundtrip evsel->name check: FAILED! [root@sandy ~]# perf test -v 10 10: roundtrip evsel->name check: --- start --- L1-dcache-misses != L1-dcache-load-misses L1-dcache-misses != L1-dcache-store-misses L1-dcache-misses != L1-dcache-prefetch-misses L1-icache-misses != L1-icache-load-misses L1-icache-misses != L1-icache-prefetch-misses LLC-misses != LLC-load-misses LLC-misses != LLC-store-misses LLC-misses != LLC-prefetch-misses dTLB-misses != dTLB-load-misses dTLB-misses != dTLB-store-misses dTLB-misses != dTLB-prefetch-misses iTLB-misses != iTLB-load-misses branch-misses != branch-load-misses node-misses != node-load-misses node-misses != node-store-misses node-misses != node-prefetch-misses ---- end ---- roundtrip evsel->name check: FAILED! [root@sandy ~]# Now lemme apply Jiri's fix and try it again... Cc: David Ahern Cc: Frederic Weisbecker Cc: Joel Uckelman Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-bbewtxw0rfipp5qy1j3jtg5d@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-test.c | 61 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index ba94fbe1fa44..cf33e5081c36 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -1092,6 +1092,63 @@ static int test__perf_pmu(void) return perf_pmu__test(); } +static int perf_evsel__roundtrip_cache_name_test(void) +{ + char name[128]; + int type, op, err = 0, ret = 0, i, idx; + struct perf_evsel *evsel; + struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); + + if (evlist == NULL) + return -ENOMEM; + + for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { + for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { + /* skip invalid cache type */ + if (!perf_evsel__is_cache_op_valid(type, op)) + continue; + + for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { + __perf_evsel__hw_cache_type_op_res_name(type, op, i, + name, sizeof(name)); + err = parse_events(evlist, name, 0); + if (err) + ret = err; + } + } + } + + idx = 0; + evsel = perf_evlist__first(evlist); + + for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { + for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { + /* skip invalid cache type */ + if (!perf_evsel__is_cache_op_valid(type, op)) + continue; + + for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { + __perf_evsel__hw_cache_type_op_res_name(type, op, i, + name, sizeof(name)); + if (evsel->idx != idx) + continue; + + ++idx; + + if (strcmp(perf_evsel__name(evsel), name)) { + pr_debug("%s != %s\n", perf_evsel__name(evsel), name); + ret = -1; + } + + evsel = perf_evsel__next(evsel); + } + } + } + + perf_evlist__delete(evlist); + return ret; +} + static int __perf_evsel__name_array_test(const char *names[], int nr_names) { int i, err; @@ -1138,6 +1195,10 @@ static int perf_evsel__roundtrip_name_test(void) if (err) ret = err; + err = perf_evsel__roundtrip_cache_name_test(); + if (err) + ret = err; + return ret; } From 275ef3878f698941353780440fec6926107a320b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 5 Sep 2012 19:51:33 +0200 Subject: [PATCH 25/25] perf tools: Fix cache event name generation If the event name is specified with all 3 components, the last one overwrites the previous one during the name composing within the parse_events_add_cache function. Fixing this by properly adjusting the string index. Reported-by: Joel Uckelman Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Joel Uckelman Cc: Paul Mackerras Cc: Peter Zijlstra LPU-Reference: 20120905175133.GA18352@krava.brq.redhat.com [ committer note: Remove the newline fix, done already in 42e1fb7 ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 66d235e0cc98..a031ee1f54f6 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -308,7 +308,7 @@ int parse_events_add_cache(struct list_head **list, int *idx, for (i = 0; (i < 2) && (op_result[i]); i++) { char *str = op_result[i]; - snprintf(name + n, MAX_NAME_LEN - n, "-%s", str); + n += snprintf(name + n, MAX_NAME_LEN - n, "-%s", str); if (cache_op == -1) { cache_op = parse_aliases(str, perf_evsel__hw_cache_op,