diff --git a/[refs] b/[refs] index b91fcb8a6f75..71ca18e279f1 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: d65a458b348cd458413b3cfec66e43ebd0367646 +refs/heads/master: 669336e4cf3e1cb95800f3f5924558a76d723c21 diff --git a/trunk/kernel/trace/trace_event_perf.c b/trunk/kernel/trace/trace_event_perf.c index 23751659582e..000e6e85b445 100644 --- a/trunk/kernel/trace/trace_event_perf.c +++ b/trunk/kernel/trace/trace_event_perf.c @@ -131,10 +131,10 @@ void perf_trace_destroy(struct perf_event *p_event) tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER); /* - * Ensure our callback won't be called anymore. See - * tracepoint_probe_unregister() and __DO_TRACE(). + * Ensure our callback won't be called anymore. The buffers + * will be freed after that. */ - synchronize_sched(); + tracepoint_synchronize_unregister(); free_percpu(tp_event->perf_events); tp_event->perf_events = NULL; diff --git a/trunk/tools/perf/Documentation/perf-buildid-cache.txt b/trunk/tools/perf/Documentation/perf-buildid-cache.txt index c1057701a7dc..5d1a9500277f 100644 --- a/trunk/tools/perf/Documentation/perf-buildid-cache.txt +++ b/trunk/tools/perf/Documentation/perf-buildid-cache.txt @@ -12,9 +12,9 @@ SYNOPSIS DESCRIPTION ----------- -This command manages the build-id cache. It can add and remove files to/from -the cache. In the future it should as well purge older entries, set upper -limits for the space used by the cache, etc. +This command manages the build-id cache. It can add and remove files to the +cache. In the future it should as well purge older entries, set upper limits +for the space used by the cache, etc. OPTIONS ------- @@ -23,7 +23,7 @@ OPTIONS Add specified file to the cache. -r:: --remove=:: - Remove specified file from the cache. + Remove specified file to the cache. -v:: --verbose:: Be more verbose. diff --git a/trunk/tools/perf/builtin-buildid-list.c b/trunk/tools/perf/builtin-buildid-list.c index 44a47e13bd67..99890728409e 100644 --- a/trunk/tools/perf/builtin-buildid-list.c +++ b/trunk/tools/perf/builtin-buildid-list.c @@ -43,8 +43,10 @@ static int __cmd_buildid_list(void) if (session == NULL) return -1; - if (with_hits) + if (with_hits) { + symbol_conf.full_paths = true; perf_session__process_events(session, &build_id__mark_dso_hit_ops); + } perf_session__fprintf_dsos_buildid(session, stdout, with_hits); diff --git a/trunk/tools/perf/builtin-diff.c b/trunk/tools/perf/builtin-diff.c index fca1d4402910..39e6627ebb96 100644 --- a/trunk/tools/perf/builtin-diff.c +++ b/trunk/tools/perf/builtin-diff.c @@ -180,6 +180,8 @@ static const struct option options[] = { OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), + OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths, + "Don't shorten the pathnames taking into account the cwd"), OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", "only consider symbols in these dsos"), OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", diff --git a/trunk/tools/perf/builtin-probe.c b/trunk/tools/perf/builtin-probe.c index 199d5e19554f..54551867e7e0 100644 --- a/trunk/tools/perf/builtin-probe.c +++ b/trunk/tools/perf/builtin-probe.c @@ -267,3 +267,4 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) } return 0; } + diff --git a/trunk/tools/perf/builtin-record.c b/trunk/tools/perf/builtin-record.c index ff77b805de71..b93879677cca 100644 --- a/trunk/tools/perf/builtin-record.c +++ b/trunk/tools/perf/builtin-record.c @@ -439,8 +439,6 @@ static void atexit_header(void) process_buildids(); perf_header__write(&session->header, output, true); - perf_session__delete(session); - symbol__exit(); } } @@ -560,15 +558,12 @@ static int __cmd_record(int argc, const char **argv) if (!file_new) { err = perf_header__read(session, output); if (err < 0) - goto out_delete_session; + return err; } if (have_tracepoints(attrs, nr_counters)) perf_header__set_feat(&session->header, HEADER_TRACE_INFO); - /* - * perf_session__delete(session) will be called at atexit_header() - */ atexit(atexit_header); if (forks) { @@ -773,10 +768,6 @@ static int __cmd_record(int argc, const char **argv) bytes_written / 24); return 0; - -out_delete_session: - perf_session__delete(session); - return err; } static const char * const record_usage[] = { @@ -833,7 +824,7 @@ static const struct option options[] = { int cmd_record(int argc, const char **argv, const char *prefix __used) { - int i, j, err = -ENOMEM; + int i,j; argc = parse_options(argc, argv, options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); @@ -872,7 +863,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) } else { all_tids=malloc(sizeof(pid_t)); if (!all_tids) - goto out_symbol_exit; + return -ENOMEM; all_tids[0] = target_tid; thread_num = 1; @@ -882,13 +873,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) for (j = 0; j < MAX_COUNTERS; j++) { fd[i][j] = malloc(sizeof(int)*thread_num); if (!fd[i][j]) - goto out_free_fd; + return -ENOMEM; } } event_array = malloc( sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); if (!event_array) - goto out_free_fd; + return -ENOMEM; if (user_interval != ULLONG_MAX) default_interval = user_interval; @@ -904,22 +895,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) default_interval = freq; } else { fprintf(stderr, "frequency and count are zero, aborting\n"); - err = -EINVAL; - goto out_free_event_array; + exit(EXIT_FAILURE); } - err = __cmd_record(argc, argv); - -out_free_event_array: - free(event_array); -out_free_fd: - for (i = 0; i < MAX_NR_CPUS; i++) { - for (j = 0; j < MAX_COUNTERS; j++) - free(fd[i][j]); - } - free(all_tids); - all_tids = NULL; -out_symbol_exit: - symbol__exit(); - return err; + return __cmd_record(argc, argv); } diff --git a/trunk/tools/perf/builtin-report.c b/trunk/tools/perf/builtin-report.c index 2f4b92925b26..ce42bbaa252d 100644 --- a/trunk/tools/perf/builtin-report.c +++ b/trunk/tools/perf/builtin-report.c @@ -441,6 +441,8 @@ static const struct option options[] = { "pretty printing style key: normal raw"), OPT_STRING('s', "sort", &sort_order, "key[,key2...]", "sort by key(s): pid, comm, dso, symbol, parent"), + OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths, + "Don't shorten the pathnames taking into account the cwd"), OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, "Show sample percentage for different cpu modes"), OPT_STRING('p', "parent", &parent_pattern, "regex", diff --git a/trunk/tools/perf/util/build-id.c b/trunk/tools/perf/util/build-id.c index e437edb72417..5c26e2d314af 100644 --- a/trunk/tools/perf/util/build-id.c +++ b/trunk/tools/perf/util/build-id.c @@ -12,7 +12,6 @@ #include "event.h" #include "symbol.h" #include -#include "debug.h" static int build_id__mark_dso_hit(event_t *event, struct perf_session *session) { @@ -35,27 +34,10 @@ static int build_id__mark_dso_hit(event_t *event, struct perf_session *session) return 0; } -static int event__exit_del_thread(event_t *self, struct perf_session *session) -{ - struct thread *thread = perf_session__findnew(session, self->fork.tid); - - dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, - self->fork.ppid, self->fork.ptid); - - if (thread) { - rb_erase(&thread->rb_node, &session->threads); - session->last_match = NULL; - thread__delete(thread); - } - - return 0; -} - struct perf_event_ops build_id__mark_dso_hit_ops = { .sample = build_id__mark_dso_hit, .mmap = event__process_mmap, .fork = event__process_task, - .exit = event__exit_del_thread, }; char *dso__build_id_filename(struct dso *self, char *bf, size_t size) diff --git a/trunk/tools/perf/util/event.c b/trunk/tools/perf/util/event.c index 6b0db5577929..d7f21d71eb69 100644 --- a/trunk/tools/perf/util/event.c +++ b/trunk/tools/perf/util/event.c @@ -340,29 +340,30 @@ int event__synthesize_kernel_mmap(event__handler_t process, return process(&ev, session); } -static void thread__comm_adjust(struct thread *self, struct hists *hists) +static void thread__comm_adjust(struct thread *self) { char *comm = self->comm; if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && (!symbol_conf.comm_list || strlist__has_entry(symbol_conf.comm_list, comm))) { - u16 slen = strlen(comm); + unsigned int slen = strlen(comm); - if (hists__new_col_len(hists, HISTC_COMM, slen)) - hists__set_col_len(hists, HISTC_THREAD, slen + 6); + if (slen > comms__col_width) { + comms__col_width = slen; + threads__col_width = slen + 6; + } } } -static int thread__set_comm_adjust(struct thread *self, const char *comm, - struct hists *hists) +static int thread__set_comm_adjust(struct thread *self, const char *comm) { int ret = thread__set_comm(self, comm); if (ret) return ret; - thread__comm_adjust(self, hists); + thread__comm_adjust(self); return 0; } @@ -373,8 +374,7 @@ int event__process_comm(event_t *self, struct perf_session *session) dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid); - if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm, - &session->hists)) { + if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) { dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); return -1; } @@ -456,7 +456,6 @@ static int event__process_kernel_mmap(event_t *self, goto out_problem; map->dso->short_name = name; - map->dso->sname_alloc = 1; map->end = map->start + self->mmap.len; } else if (is_kernel_mmap) { const char *symbol_name = (self->mmap.filename + @@ -515,13 +514,12 @@ int event__process_mmap(event_t *self, struct perf_session *session) if (machine == NULL) goto out_problem; thread = perf_session__findnew(session, self->mmap.pid); - if (thread == NULL) - goto out_problem; map = map__new(&machine->user_dsos, self->mmap.start, self->mmap.len, self->mmap.pgoff, self->mmap.pid, self->mmap.filename, - MAP__FUNCTION); - if (map == NULL) + MAP__FUNCTION, session->cwd, session->cwdlen); + + if (thread == NULL || map == NULL) goto out_problem; thread__insert_map(thread, map); @@ -643,13 +641,16 @@ void thread__find_addr_location(struct thread *self, al->sym = NULL; } -static void dso__calc_col_width(struct dso *self, struct hists *hists) +static void dso__calc_col_width(struct dso *self) { if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && (!symbol_conf.dso_list || strlist__has_entry(symbol_conf.dso_list, self->name))) { - u16 slen = dso__name_len(self); - hists__new_col_len(hists, HISTC_DSO, slen); + u16 slen = self->short_name_len; + if (verbose) + slen = self->long_name_len; + if (dsos__col_width < slen) + dsos__col_width = slen; } self->slen_calculated = 1; @@ -728,17 +729,16 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session, * sampled. */ if (!sort_dso.elide && !al->map->dso->slen_calculated) - dso__calc_col_width(al->map->dso, &session->hists); + dso__calc_col_width(al->map->dso); al->sym = map__find_symbol(al->map, al->addr, filter); } else { const unsigned int unresolved_col_width = BITS_PER_LONG / 4; - if (hists__col_len(&session->hists, HISTC_DSO) < unresolved_col_width && + if (dsos__col_width < unresolved_col_width && !symbol_conf.col_width_list_str && !symbol_conf.field_sep && !symbol_conf.dso_list) - hists__set_col_len(&session->hists, HISTC_DSO, - unresolved_col_width); + dsos__col_width = unresolved_col_width; } if (symbol_conf.sym_list && al->sym && diff --git a/trunk/tools/perf/util/hist.c b/trunk/tools/perf/util/hist.c index d0f07f7bdf16..7b5848ce1505 100644 --- a/trunk/tools/perf/util/hist.c +++ b/trunk/tools/perf/util/hist.c @@ -5,61 +5,11 @@ #include "sort.h" #include -enum hist_filter { - HIST_FILTER__DSO, - HIST_FILTER__THREAD, - HIST_FILTER__PARENT, -}; - struct callchain_param callchain_param = { .mode = CHAIN_GRAPH_REL, .min_percent = 0.5 }; -u16 hists__col_len(struct hists *self, enum hist_column col) -{ - return self->col_len[col]; -} - -void hists__set_col_len(struct hists *self, enum hist_column col, u16 len) -{ - self->col_len[col] = len; -} - -bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len) -{ - if (len > hists__col_len(self, col)) { - hists__set_col_len(self, col, len); - return true; - } - return false; -} - -static void hists__reset_col_len(struct hists *self) -{ - enum hist_column col; - - for (col = 0; col < HISTC_NR_COLS; ++col) - hists__set_col_len(self, col, 0); -} - -static void hists__calc_col_len(struct hists *self, struct hist_entry *h) -{ - u16 len; - - if (h->ms.sym) - hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen); - - len = thread__comm_len(h->thread); - if (hists__new_col_len(self, HISTC_COMM, len)) - hists__set_col_len(self, HISTC_THREAD, len + 6); - - if (h->ms.map) { - len = dso__name_len(h->ms.map->dso); - hists__new_col_len(self, HISTC_DSO, len); - } -} - static void hist_entry__add_cpumode_period(struct hist_entry *self, unsigned int cpumode, u64 period) { @@ -100,19 +50,11 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) return self; } -static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h) +static void hists__inc_nr_entries(struct hists *self, struct hist_entry *entry) { - if (!h->filtered) { - hists__calc_col_len(self, h); - ++self->nr_entries; - } -} - -static u8 symbol__parent_filter(const struct symbol *parent) -{ - if (symbol_conf.exclude_other && parent == NULL) - return 1 << HIST_FILTER__PARENT; - return 0; + if (entry->ms.sym && self->max_sym_namelen < entry->ms.sym->namelen) + self->max_sym_namelen = entry->ms.sym->namelen; + ++self->nr_entries; } struct hist_entry *__hists__add_entry(struct hists *self, @@ -133,7 +75,6 @@ struct hist_entry *__hists__add_entry(struct hists *self, .level = al->level, .period = period, .parent = sym_parent, - .filtered = symbol__parent_filter(sym_parent), }; int cmp; @@ -251,7 +192,7 @@ void hists__collapse_resort(struct hists *self) tmp = RB_ROOT; next = rb_first(&self->entries); self->nr_entries = 0; - hists__reset_col_len(self); + self->max_sym_namelen = 0; while (next) { n = rb_entry(next, struct hist_entry, rb_node); @@ -308,7 +249,7 @@ void hists__output_resort(struct hists *self) next = rb_first(&self->entries); self->nr_entries = 0; - hists__reset_col_len(self); + self->max_sym_namelen = 0; while (next) { n = rb_entry(next, struct hist_entry, rb_node); @@ -575,9 +516,8 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, } int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, - struct hists *hists, struct hists *pair_hists, - bool show_displacement, long displacement, - bool color, u64 session_total) + struct hists *pair_hists, bool show_displacement, + long displacement, bool color, u64 session_total) { struct sort_entry *se; u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; @@ -681,25 +621,24 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); ret += se->se_snprintf(self, s + ret, size - ret, - hists__col_len(hists, se->se_width_idx)); + se->se_width ? *se->se_width : 0); } return ret; } -int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, - struct hists *pair_hists, bool show_displacement, - long displacement, FILE *fp, u64 session_total) +int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists, + bool show_displacement, long displacement, FILE *fp, + u64 session_total) { char bf[512]; - hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists, + hist_entry__snprintf(self, bf, sizeof(bf), pair_hists, show_displacement, displacement, true, session_total); return fprintf(fp, "%s\n", bf); } -static size_t hist_entry__fprintf_callchain(struct hist_entry *self, - struct hists *hists, FILE *fp, +static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp, u64 session_total) { int left_margin = 0; @@ -707,7 +646,7 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self, if (sort__first_dimension == SORT_COMM) { struct sort_entry *se = list_first_entry(&hist_entry__sort_list, typeof(*se), list); - left_margin = hists__col_len(hists, se->se_width_idx); + left_margin = se->se_width ? *se->se_width : 0; left_margin -= thread__comm_len(self->thread); } @@ -778,17 +717,17 @@ size_t hists__fprintf(struct hists *self, struct hists *pair, continue; } width = strlen(se->se_header); - if (symbol_conf.col_width_list_str) { - if (col_width) { - hists__set_col_len(self, se->se_width_idx, - atoi(col_width)); - col_width = strchr(col_width, ','); - if (col_width) - ++col_width; + if (se->se_width) { + if (symbol_conf.col_width_list_str) { + if (col_width) { + *se->se_width = atoi(col_width); + col_width = strchr(col_width, ','); + if (col_width) + ++col_width; + } } + width = *se->se_width = max(*se->se_width, width); } - if (!hists__new_col_len(self, se->se_width_idx, width)) - width = hists__col_len(self, se->se_width_idx); fprintf(fp, " %*s", width, se->se_header); } fprintf(fp, "\n"); @@ -811,8 +750,9 @@ size_t hists__fprintf(struct hists *self, struct hists *pair, continue; fprintf(fp, " "); - width = hists__col_len(self, se->se_width_idx); - if (width == 0) + if (se->se_width) + width = *se->se_width; + else width = strlen(se->se_header); for (i = 0; i < width; i++) fprintf(fp, "."); @@ -832,12 +772,12 @@ size_t hists__fprintf(struct hists *self, struct hists *pair, displacement = 0; ++position; } - ret += hist_entry__fprintf(h, self, pair, show_displacement, + ret += hist_entry__fprintf(h, pair, show_displacement, displacement, fp, self->stats.total_period); if (symbol_conf.use_callchain) - ret += hist_entry__fprintf_callchain(h, self, fp, - self->stats.total_period); + ret += hist_entry__fprintf_callchain(h, fp, self->stats.total_period); + if (h->ms.map == NULL && verbose > 1) { __map_groups__fprintf_maps(&h->thread->mg, MAP__FUNCTION, verbose, fp); @@ -850,32 +790,10 @@ size_t hists__fprintf(struct hists *self, struct hists *pair, return ret; } -/* - * See hists__fprintf to match the column widths - */ -unsigned int hists__sort_list_width(struct hists *self) -{ - struct sort_entry *se; - int ret = 9; /* total % */ - - if (symbol_conf.show_cpu_utilization) { - ret += 7; /* count_sys % */ - ret += 6; /* count_us % */ - if (perf_guest) { - ret += 13; /* count_guest_sys % */ - ret += 12; /* count_guest_us % */ - } - } - - if (symbol_conf.show_nr_samples) - ret += 11; - - list_for_each_entry(se, &hist_entry__sort_list, list) - if (!se->elide) - ret += 2 + hists__col_len(self, se->se_width_idx); - - return ret; -} +enum hist_filter { + HIST_FILTER__DSO, + HIST_FILTER__THREAD, +}; static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h, enum hist_filter filter) @@ -885,13 +803,11 @@ static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h, return; ++self->nr_entries; - if (h->ms.unfolded) - self->nr_entries += h->nr_rows; - h->row_offset = 0; self->stats.total_period += h->period; self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; - hists__calc_col_len(self, h); + if (h->ms.sym && self->max_sym_namelen < h->ms.sym->namelen) + self->max_sym_namelen = h->ms.sym->namelen; } void hists__filter_by_dso(struct hists *self, const struct dso *dso) @@ -900,7 +816,7 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso) self->nr_entries = self->stats.total_period = 0; self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; - hists__reset_col_len(self); + self->max_sym_namelen = 0; for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); @@ -923,7 +839,7 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread) self->nr_entries = self->stats.total_period = 0; self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; - hists__reset_col_len(self); + self->max_sym_namelen = 0; for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); diff --git a/trunk/tools/perf/util/hist.h b/trunk/tools/perf/util/hist.h index 65a48db46a29..83fa33a7b38b 100644 --- a/trunk/tools/perf/util/hist.h +++ b/trunk/tools/perf/util/hist.h @@ -56,16 +56,6 @@ struct events_stats { u32 nr_unknown_events; }; -enum hist_column { - HISTC_SYMBOL, - HISTC_DSO, - HISTC_THREAD, - HISTC_COMM, - HISTC_PARENT, - HISTC_CPU, - HISTC_NR_COLS, /* Last entry */ -}; - struct hists { struct rb_node rb_node; struct rb_root entries; @@ -74,7 +64,7 @@ struct hists { u64 config; u64 event_stream; u32 type; - u16 col_len[HISTC_NR_COLS]; + u32 max_sym_namelen; }; struct hist_entry *__hists__add_entry(struct hists *self, @@ -82,13 +72,12 @@ struct hist_entry *__hists__add_entry(struct hists *self, struct symbol *parent, u64 period); extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); -int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, - struct hists *pair_hists, bool show_displacement, - long displacement, FILE *fp, u64 total); +int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists, + bool show_displacement, long displacement, FILE *fp, + u64 total); int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, - struct hists *hists, struct hists *pair_hists, - bool show_displacement, long displacement, - bool color, u64 total); + struct hists *pair_hists, bool show_displacement, + long displacement, bool color, u64 total); void hist_entry__free(struct hist_entry *); void hists__output_resort(struct hists *self); @@ -106,10 +95,6 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head); void hists__filter_by_dso(struct hists *self, const struct dso *dso); void hists__filter_by_thread(struct hists *self, const struct thread *thread); -u16 hists__col_len(struct hists *self, enum hist_column col); -void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); -bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); - #ifdef NO_NEWT_SUPPORT static inline int hists__browse(struct hists *self __used, const char *helpline __used, @@ -141,7 +126,4 @@ int hist_entry__tui_annotate(struct hist_entry *self); int hists__tui_browse_tree(struct rb_root *self, const char *help); #endif - -unsigned int hists__sort_list_width(struct hists *self); - #endif /* __PERF_HIST_H */ diff --git a/trunk/tools/perf/util/map.c b/trunk/tools/perf/util/map.c index 15d6a6dd50c5..e672f2fef65b 100644 --- a/trunk/tools/perf/util/map.c +++ b/trunk/tools/perf/util/map.c @@ -17,6 +17,16 @@ static inline int is_anon_memory(const char *filename) return strcmp(filename, "//anon") == 0; } +static int strcommon(const char *pathname, char *cwd, int cwdlen) +{ + int n = 0; + + while (n < cwdlen && pathname[n] == cwd[n]) + ++n; + + return n; +} + void map__init(struct map *self, enum map_type type, u64 start, u64 end, u64 pgoff, struct dso *dso) { @@ -33,7 +43,7 @@ void map__init(struct map *self, enum map_type type, struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, u64 pgoff, u32 pid, char *filename, - enum map_type type) + enum map_type type, char *cwd, int cwdlen) { struct map *self = malloc(sizeof(*self)); @@ -42,6 +52,16 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, struct dso *dso; int anon; + if (cwd) { + int n = strcommon(filename, cwd, cwdlen); + + if (n == cwdlen) { + snprintf(newfilename, sizeof(newfilename), + ".%s", filename + n); + filename = newfilename; + } + } + anon = is_anon_memory(filename); if (anon) { @@ -228,39 +248,6 @@ void map_groups__init(struct map_groups *self) self->machine = NULL; } -static void maps__delete(struct rb_root *self) -{ - struct rb_node *next = rb_first(self); - - while (next) { - struct map *pos = rb_entry(next, struct map, rb_node); - - next = rb_next(&pos->rb_node); - rb_erase(&pos->rb_node, self); - map__delete(pos); - } -} - -static void maps__delete_removed(struct list_head *self) -{ - struct map *pos, *n; - - list_for_each_entry_safe(pos, n, self, node) { - list_del(&pos->node); - map__delete(pos); - } -} - -void map_groups__exit(struct map_groups *self) -{ - int i; - - for (i = 0; i < MAP__NR_TYPES; ++i) { - maps__delete(&self->maps[i]); - maps__delete_removed(&self->removed_maps[i]); - } -} - void map_groups__flush(struct map_groups *self) { int type; @@ -539,32 +526,6 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid) return self->root_dir == NULL ? -ENOMEM : 0; } -static void dsos__delete(struct list_head *self) -{ - struct dso *pos, *n; - - list_for_each_entry_safe(pos, n, self, node) { - list_del(&pos->node); - dso__delete(pos); - } -} - -void machine__exit(struct machine *self) -{ - struct kmap *kmap = map__kmap(self->vmlinux_maps[MAP__FUNCTION]); - - if (kmap->ref_reloc_sym) { - free((char *)kmap->ref_reloc_sym->name); - free(kmap->ref_reloc_sym); - } - - map_groups__exit(&self->kmaps); - dsos__delete(&self->user_dsos); - dsos__delete(&self->kernel_dsos); - free(self->root_dir); - self->root_dir = NULL; -} - struct machine *machines__add(struct rb_root *self, pid_t pid, const char *root_dir) { diff --git a/trunk/tools/perf/util/map.h b/trunk/tools/perf/util/map.h index 0e0984e86fce..f39134512829 100644 --- a/trunk/tools/perf/util/map.h +++ b/trunk/tools/perf/util/map.h @@ -106,7 +106,7 @@ void map__init(struct map *self, enum map_type type, u64 start, u64 end, u64 pgoff, struct dso *dso); struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, u64 pgoff, u32 pid, char *filename, - enum map_type type); + enum map_type type, char *cwd, int cwdlen); void map__delete(struct map *self); struct map *map__clone(struct map *self); int map__overlap(struct map *l, struct map *r); @@ -127,7 +127,6 @@ size_t __map_groups__fprintf_maps(struct map_groups *self, void maps__insert(struct rb_root *maps, struct map *map); struct map *maps__find(struct rb_root *maps, u64 addr); void map_groups__init(struct map_groups *self); -void map_groups__exit(struct map_groups *self); int map_groups__clone(struct map_groups *self, struct map_groups *parent, enum map_type type); size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp); @@ -143,7 +142,6 @@ struct machine *machines__find(struct rb_root *self, pid_t pid); struct machine *machines__findnew(struct rb_root *self, pid_t pid); char *machine__mmap_name(struct machine *self, char *bf, size_t size); int machine__init(struct machine *self, const char *root_dir, pid_t pid); -void machine__exit(struct machine *self); /* * Default guest kernel is defined by parameter --guestkallsyms diff --git a/trunk/tools/perf/util/newt.c b/trunk/tools/perf/util/newt.c index 91de99b58445..7979003adeaf 100644 --- a/trunk/tools/perf/util/newt.c +++ b/trunk/tools/perf/util/newt.c @@ -11,7 +11,6 @@ #define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG #endif #include -#include #include #include #include @@ -343,17 +342,15 @@ static void ui_browser__reset_index(struct ui_browser *self) static int ui_browser__show(struct ui_browser *self, const char *title) { - if (self->form != NULL) { - newtFormDestroy(self->form); - newtPopWindow(); - } + if (self->form != NULL) + return 0; ui_browser__refresh_dimensions(self); - newtCenteredWindow(self->width, self->height, title); + newtCenteredWindow(self->width + 2, self->height, title); self->form = newt_form__new(); if (self->form == NULL) return -1; - self->sb = newtVerticalScrollbar(self->width, 0, self->height, + self->sb = newtVerticalScrollbar(self->width + 1, 0, self->height, HE_COLORSET_NORMAL, HE_COLORSET_SELECTED); if (self->sb == NULL) @@ -510,6 +507,38 @@ static int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es) return 0; } +/* + * When debugging newt problems it was useful to be able to "unroll" + * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate + * a source file with the sequence of calls to these methods, to then + * tweak the arrays to get the intended results, so I'm keeping this code + * here, may be useful again in the future. + */ +#undef NEWT_DEBUG + +static void newt_checkbox_tree__add(newtComponent tree, const char *str, + void *priv, int *indexes) +{ +#ifdef NEWT_DEBUG + /* Print the newtCheckboxTreeAddArray to tinker with its index arrays */ + int i = 0, len = 40 - strlen(str); + + fprintf(stderr, + "\tnewtCheckboxTreeAddItem(tree, %*.*s\"%s\", (void *)%p, 0, ", + len, len, " ", str, priv); + while (indexes[i] != NEWT_ARG_LAST) { + if (indexes[i] != NEWT_ARG_APPEND) + fprintf(stderr, " %d,", indexes[i]); + else + fprintf(stderr, " %s,", "NEWT_ARG_APPEND"); + ++i; + } + fprintf(stderr, " %s", " NEWT_ARG_LAST);\n"); + fflush(stderr); +#endif + newtCheckboxTreeAddArray(tree, str, priv, 0, indexes); +} + static char *callchain_list__sym_name(struct callchain_list *self, char *bf, size_t bfsize) { @@ -545,6 +574,146 @@ static unsigned int hist_entry__annotate_browser_refresh(struct ui_browser *self return row; } +static void __callchain__append_graph_browser(struct callchain_node *self, + newtComponent tree, u64 total, + int *indexes, int depth) +{ + struct rb_node *node; + u64 new_total, remaining; + int idx = 0; + + if (callchain_param.mode == CHAIN_GRAPH_REL) + new_total = self->children_hit; + else + new_total = total; + + remaining = new_total; + node = rb_first(&self->rb_root); + while (node) { + struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); + struct rb_node *next = rb_next(node); + u64 cumul = cumul_hits(child); + struct callchain_list *chain; + int first = true, printed = 0; + int chain_idx = -1; + remaining -= cumul; + + indexes[depth] = NEWT_ARG_APPEND; + indexes[depth + 1] = NEWT_ARG_LAST; + + list_for_each_entry(chain, &child->val, list) { + char ipstr[BITS_PER_LONG / 4 + 1], + *alloc_str = NULL; + const char *str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr)); + + if (first) { + double percent = cumul * 100.0 / new_total; + + first = false; + if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) + str = "Not enough memory!"; + else + str = alloc_str; + } else { + indexes[depth] = idx; + indexes[depth + 1] = NEWT_ARG_APPEND; + indexes[depth + 2] = NEWT_ARG_LAST; + ++chain_idx; + } + newt_checkbox_tree__add(tree, str, &chain->ms, indexes); + free(alloc_str); + ++printed; + } + + indexes[depth] = idx; + if (chain_idx != -1) + indexes[depth + 1] = chain_idx; + if (printed != 0) + ++idx; + __callchain__append_graph_browser(child, tree, new_total, indexes, + depth + (chain_idx != -1 ? 2 : 1)); + node = next; + } +} + +static void callchain__append_graph_browser(struct callchain_node *self, + newtComponent tree, u64 total, + int *indexes, int parent_idx) +{ + struct callchain_list *chain; + int i = 0; + + indexes[1] = NEWT_ARG_APPEND; + indexes[2] = NEWT_ARG_LAST; + + list_for_each_entry(chain, &self->val, list) { + char ipstr[BITS_PER_LONG / 4 + 1], *str; + + if (chain->ip >= PERF_CONTEXT_MAX) + continue; + + if (!i++ && sort__first_dimension == SORT_SYM) + continue; + + str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr)); + newt_checkbox_tree__add(tree, str, &chain->ms, indexes); + } + + indexes[1] = parent_idx; + indexes[2] = NEWT_ARG_APPEND; + indexes[3] = NEWT_ARG_LAST; + __callchain__append_graph_browser(self, tree, total, indexes, 2); +} + +static void hist_entry__append_callchain_browser(struct hist_entry *self, + newtComponent tree, u64 total, int parent_idx) +{ + struct rb_node *rb_node; + int indexes[1024] = { [0] = parent_idx, }; + int idx = 0; + struct callchain_node *chain; + + rb_node = rb_first(&self->sorted_chain); + while (rb_node) { + chain = rb_entry(rb_node, struct callchain_node, rb_node); + switch (callchain_param.mode) { + case CHAIN_FLAT: + break; + case CHAIN_GRAPH_ABS: /* falldown */ + case CHAIN_GRAPH_REL: + callchain__append_graph_browser(chain, tree, total, indexes, idx++); + break; + case CHAIN_NONE: + default: + break; + } + rb_node = rb_next(rb_node); + } +} + +static size_t hist_entry__append_browser(struct hist_entry *self, + newtComponent tree, u64 total) +{ + char s[256]; + size_t ret; + + if (symbol_conf.exclude_other && !self->parent) + return 0; + + ret = hist_entry__snprintf(self, s, sizeof(s), NULL, + false, 0, false, total); + if (symbol_conf.use_callchain) { + int indexes[2]; + + indexes[0] = NEWT_ARG_APPEND; + indexes[1] = NEWT_ARG_LAST; + newt_checkbox_tree__add(tree, s, &self->ms, indexes); + } else + newtListboxAppendEntry(tree, s, &self->ms); + + return ret; +} + int hist_entry__tui_annotate(struct hist_entry *self) { struct ui_browser browser; @@ -580,7 +749,6 @@ int hist_entry__tui_annotate(struct hist_entry *self) browser.width += 18; /* Percentage */ ui_browser__show(&browser, self->ms.sym->name); - newtFormAddHotKey(browser.form, ' '); ret = ui_browser__run(&browser, &es); newtFormDestroy(browser.form); newtPopWindow(); @@ -592,48 +760,157 @@ int hist_entry__tui_annotate(struct hist_entry *self) return ret; } +static const void *newt__symbol_tree_get_current(newtComponent self) +{ + if (symbol_conf.use_callchain) + return newtCheckboxTreeGetCurrent(self); + return newtListboxGetCurrent(self); +} + +static void hist_browser__selection(newtComponent self, void *data) +{ + const struct map_symbol **symbol_ptr = data; + *symbol_ptr = newt__symbol_tree_get_current(self); +} + struct hist_browser { - struct ui_browser b; - struct hists *hists; - struct hist_entry *he_selection; - struct map_symbol *selection; + newtComponent form, tree; + const struct map_symbol *selection; }; -static void hist_browser__reset(struct hist_browser *self); -static int hist_browser__run(struct hist_browser *self, const char *title, - struct newtExitStruct *es); -static unsigned int hist_browser__refresh_entries(struct ui_browser *self); -static void ui_browser__hists_seek(struct ui_browser *self, - off_t offset, int whence); - -static struct hist_browser *hist_browser__new(struct hists *hists) +static struct hist_browser *hist_browser__new(void) { - struct hist_browser *self = zalloc(sizeof(*self)); + struct hist_browser *self = malloc(sizeof(*self)); - if (self) { - self->hists = hists; - self->b.refresh_entries = hist_browser__refresh_entries; - self->b.seek = ui_browser__hists_seek; - } + if (self != NULL) + self->form = NULL; return self; } static void hist_browser__delete(struct hist_browser *self) { - newtFormDestroy(self->b.form); + newtFormDestroy(self->form); newtPopWindow(); free(self); } +static int hist_browser__populate(struct hist_browser *self, struct hists *hists, + const char *title) +{ + int max_len = 0, idx, cols, rows; + struct ui_progress *progress; + struct rb_node *nd; + u64 curr_hist = 0; + char seq[] = ".", unit; + char str[256]; + unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE]; + + if (self->form) { + newtFormDestroy(self->form); + newtPopWindow(); + } + + nr_events = convert_unit(nr_events, &unit); + snprintf(str, sizeof(str), "Events: %lu%c ", + nr_events, unit); + newtDrawRootText(0, 0, str); + + newtGetScreenSize(NULL, &rows); + + if (symbol_conf.use_callchain) + self->tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq, + NEWT_FLAG_SCROLL); + else + self->tree = newtListbox(0, 0, rows - 5, + (NEWT_FLAG_SCROLL | + NEWT_FLAG_RETURNEXIT)); + + newtComponentAddCallback(self->tree, hist_browser__selection, + &self->selection); + + progress = ui_progress__new("Adding entries to the browser...", + hists->nr_entries); + if (progress == NULL) + return -1; + + idx = 0; + for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { + struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); + int len; + + if (h->filtered) + continue; + + len = hist_entry__append_browser(h, self->tree, hists->stats.total_period); + if (len > max_len) + max_len = len; + if (symbol_conf.use_callchain) + hist_entry__append_callchain_browser(h, self->tree, + hists->stats.total_period, idx++); + ++curr_hist; + if (curr_hist % 5) + ui_progress__update(progress, curr_hist); + } + + ui_progress__delete(progress); + + newtGetScreenSize(&cols, &rows); + + if (max_len > cols) + max_len = cols - 3; + + if (!symbol_conf.use_callchain) + newtListboxSetWidth(self->tree, max_len); + + newtCenteredWindow(max_len + (symbol_conf.use_callchain ? 5 : 0), + rows - 5, title); + self->form = newt_form__new(); + if (self->form == NULL) + return -1; + + newtFormAddHotKey(self->form, 'A'); + newtFormAddHotKey(self->form, 'a'); + newtFormAddHotKey(self->form, 'D'); + newtFormAddHotKey(self->form, 'd'); + newtFormAddHotKey(self->form, 'T'); + newtFormAddHotKey(self->form, 't'); + newtFormAddHotKey(self->form, '?'); + newtFormAddHotKey(self->form, 'H'); + newtFormAddHotKey(self->form, 'h'); + newtFormAddHotKey(self->form, NEWT_KEY_F1); + newtFormAddHotKey(self->form, NEWT_KEY_RIGHT); + newtFormAddHotKey(self->form, NEWT_KEY_TAB); + newtFormAddHotKey(self->form, NEWT_KEY_UNTAB); + newtFormAddComponents(self->form, self->tree, NULL); + self->selection = newt__symbol_tree_get_current(self->tree); + + return 0; +} + static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self) { - return self->he_selection; + int *indexes; + + if (!symbol_conf.use_callchain) + goto out; + + indexes = newtCheckboxTreeFindItem(self->tree, (void *)self->selection); + if (indexes) { + bool is_hist_entry = indexes[1] == NEWT_ARG_LAST; + free(indexes); + if (is_hist_entry) + goto out; + } + return NULL; +out: + return container_of(self->selection, struct hist_entry, ms); } static struct thread *hist_browser__selected_thread(struct hist_browser *self) { - return self->he_selection->thread; + struct hist_entry *he = hist_browser__selected_entry(self); + return he ? he->thread : NULL; } static int hist_browser__title(char *bf, size_t size, const char *ev_name, @@ -655,7 +932,7 @@ static int hist_browser__title(char *bf, size_t size, const char *ev_name, int hists__browse(struct hists *self, const char *helpline, const char *ev_name) { - struct hist_browser *browser = hist_browser__new(self); + struct hist_browser *browser = hist_browser__new(); struct pstack *fstack; const struct thread *thread_filter = NULL; const struct dso *dso_filter = NULL; @@ -674,6 +951,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) hist_browser__title(msg, sizeof(msg), ev_name, dso_filter, thread_filter); + if (hist_browser__populate(browser, self, msg) < 0) + goto out_free_stack; while (1) { const struct thread *thread; @@ -682,8 +961,7 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) int nr_options = 0, choice = 0, i, annotate = -2, zoom_dso = -2, zoom_thread = -2; - if (hist_browser__run(browser, msg, &es)) - break; + newtFormRun(browser->form, &es); thread = hist_browser__selected_thread(browser); dso = browser->selection->map ? browser->selection->map->dso : NULL; @@ -818,7 +1096,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) hists__filter_by_dso(self, dso_filter); hist_browser__title(msg, sizeof(msg), ev_name, dso_filter, thread_filter); - hist_browser__reset(browser); + if (hist_browser__populate(browser, self, msg) < 0) + goto out; } else if (choice == zoom_thread) { zoom_thread: if (thread_filter) { @@ -836,7 +1115,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) hists__filter_by_thread(self, thread_filter); hist_browser__title(msg, sizeof(msg), ev_name, dso_filter, thread_filter); - hist_browser__reset(browser); + if (hist_browser__populate(browser, self, msg) < 0) + goto out; } } out_free_stack: @@ -892,13 +1172,6 @@ static struct newtPercentTreeColors { "blue", "lightgray", }; -static void newt_suspend(void *d __used) -{ - newtSuspend(); - raise(SIGTSTP); - newtResume(); -} - void setup_browser(void) { struct newtPercentTreeColors *c = &defaultPercentTreeColors; @@ -912,7 +1185,6 @@ void setup_browser(void) use_browser = 1; newtInit(); newtCls(); - newtSetSuspendCallback(newt_suspend, NULL); ui_helpline__puts(" "); sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); @@ -931,638 +1203,3 @@ void exit_browser(bool wait_for_ok) newtFinished(); } } - -static void hist_browser__refresh_dimensions(struct hist_browser *self) -{ - /* 3 == +/- toggle symbol before actual hist_entry rendering */ - self->b.width = 3 + (hists__sort_list_width(self->hists) + - sizeof("[k]")); -} - -static void hist_browser__reset(struct hist_browser *self) -{ - self->b.nr_entries = self->hists->nr_entries; - hist_browser__refresh_dimensions(self); - ui_browser__reset_index(&self->b); -} - -static char tree__folded_sign(bool unfolded) -{ - return unfolded ? '-' : '+'; -} - -static char map_symbol__folded(const struct map_symbol *self) -{ - return self->has_children ? tree__folded_sign(self->unfolded) : ' '; -} - -static char hist_entry__folded(const struct hist_entry *self) -{ - return map_symbol__folded(&self->ms); -} - -static char callchain_list__folded(const struct callchain_list *self) -{ - return map_symbol__folded(&self->ms); -} - -static bool map_symbol__toggle_fold(struct map_symbol *self) -{ - if (!self->has_children) - return false; - - self->unfolded = !self->unfolded; - return true; -} - -#define LEVEL_OFFSET_STEP 3 - -static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self, - struct callchain_node *chain_node, - u64 total, int level, - unsigned short row, - off_t *row_offset, - bool *is_current_entry) -{ - struct rb_node *node; - int first_row = row, width, offset = level * LEVEL_OFFSET_STEP; - u64 new_total, remaining; - - if (callchain_param.mode == CHAIN_GRAPH_REL) - new_total = chain_node->children_hit; - else - new_total = total; - - remaining = new_total; - node = rb_first(&chain_node->rb_root); - while (node) { - struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); - struct rb_node *next = rb_next(node); - u64 cumul = cumul_hits(child); - struct callchain_list *chain; - char folded_sign = ' '; - int first = true; - int extra_offset = 0; - - remaining -= cumul; - - list_for_each_entry(chain, &child->val, list) { - char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str; - const char *str; - int color; - bool was_first = first; - - if (first) { - first = false; - chain->ms.has_children = chain->list.next != &child->val || - rb_first(&child->rb_root) != NULL; - } else { - extra_offset = LEVEL_OFFSET_STEP; - chain->ms.has_children = chain->list.next == &child->val && - rb_first(&child->rb_root) != NULL; - } - - folded_sign = callchain_list__folded(chain); - if (*row_offset != 0) { - --*row_offset; - goto do_next; - } - - alloc_str = NULL; - str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr)); - if (was_first) { - double percent = cumul * 100.0 / new_total; - - if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) - str = "Not enough memory!"; - else - str = alloc_str; - } - - color = HE_COLORSET_NORMAL; - width = self->b.width - (offset + extra_offset + 2); - if (ui_browser__is_current_entry(&self->b, row)) { - self->selection = &chain->ms; - color = HE_COLORSET_SELECTED; - *is_current_entry = true; - } - - SLsmg_set_color(color); - SLsmg_gotorc(self->b.top + row, self->b.left); - slsmg_write_nstring(" ", offset + extra_offset); - slsmg_printf("%c ", folded_sign); - slsmg_write_nstring(str, width); - free(alloc_str); - - if (++row == self->b.height) - goto out; -do_next: - if (folded_sign == '+') - break; - } - - if (folded_sign == '-') { - const int new_level = level + (extra_offset ? 2 : 1); - row += hist_browser__show_callchain_node_rb_tree(self, child, new_total, - new_level, row, row_offset, - is_current_entry); - } - if (row == self->b.height) - goto out; - node = next; - } -out: - return row - first_row; -} - -static int hist_browser__show_callchain_node(struct hist_browser *self, - struct callchain_node *node, - int level, unsigned short row, - off_t *row_offset, - bool *is_current_entry) -{ - struct callchain_list *chain; - int first_row = row, - offset = level * LEVEL_OFFSET_STEP, - width = self->b.width - offset; - char folded_sign = ' '; - - list_for_each_entry(chain, &node->val, list) { - char ipstr[BITS_PER_LONG / 4 + 1], *s; - int color; - /* - * FIXME: This should be moved to somewhere else, - * probably when the callchain is created, so as not to - * traverse it all over again - */ - chain->ms.has_children = rb_first(&node->rb_root) != NULL; - folded_sign = callchain_list__folded(chain); - - if (*row_offset != 0) { - --*row_offset; - continue; - } - - color = HE_COLORSET_NORMAL; - if (ui_browser__is_current_entry(&self->b, row)) { - self->selection = &chain->ms; - color = HE_COLORSET_SELECTED; - *is_current_entry = true; - } - - s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr)); - SLsmg_gotorc(self->b.top + row, self->b.left); - SLsmg_set_color(color); - slsmg_write_nstring(" ", offset); - slsmg_printf("%c ", folded_sign); - slsmg_write_nstring(s, width - 2); - - if (++row == self->b.height) - goto out; - } - - if (folded_sign == '-') - row += hist_browser__show_callchain_node_rb_tree(self, node, - self->hists->stats.total_period, - level + 1, row, - row_offset, - is_current_entry); -out: - return row - first_row; -} - -static int hist_browser__show_callchain(struct hist_browser *self, - struct rb_root *chain, - int level, unsigned short row, - off_t *row_offset, - bool *is_current_entry) -{ - struct rb_node *nd; - int first_row = row; - - for (nd = rb_first(chain); nd; nd = rb_next(nd)) { - struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); - - row += hist_browser__show_callchain_node(self, node, level, - row, row_offset, - is_current_entry); - if (row == self->b.height) - break; - } - - return row - first_row; -} - -static int hist_browser__show_entry(struct hist_browser *self, - struct hist_entry *entry, - unsigned short row) -{ - char s[256]; - double percent; - int printed = 0; - int color, width = self->b.width; - char folded_sign = ' '; - bool current_entry = ui_browser__is_current_entry(&self->b, row); - off_t row_offset = entry->row_offset; - - if (current_entry) { - self->he_selection = entry; - self->selection = &entry->ms; - } - - if (symbol_conf.use_callchain) { - entry->ms.has_children = !RB_EMPTY_ROOT(&entry->sorted_chain); - folded_sign = hist_entry__folded(entry); - } - - if (row_offset == 0) { - hist_entry__snprintf(entry, s, sizeof(s), self->hists, NULL, false, - 0, false, self->hists->stats.total_period); - percent = (entry->period * 100.0) / self->hists->stats.total_period; - - color = HE_COLORSET_SELECTED; - if (!current_entry) { - if (percent >= MIN_RED) - color = HE_COLORSET_TOP; - else if (percent >= MIN_GREEN) - color = HE_COLORSET_MEDIUM; - else - color = HE_COLORSET_NORMAL; - } - - SLsmg_set_color(color); - SLsmg_gotorc(self->b.top + row, self->b.left); - if (symbol_conf.use_callchain) { - slsmg_printf("%c ", folded_sign); - width -= 2; - } - slsmg_write_nstring(s, width); - ++row; - ++printed; - } else - --row_offset; - - if (folded_sign == '-' && row != self->b.height) { - printed += hist_browser__show_callchain(self, &entry->sorted_chain, - 1, row, &row_offset, - ¤t_entry); - if (current_entry) - self->he_selection = entry; - } - - return printed; -} - -static unsigned int hist_browser__refresh_entries(struct ui_browser *self) -{ - unsigned row = 0; - struct rb_node *nd; - struct hist_browser *hb = container_of(self, struct hist_browser, b); - - if (self->first_visible_entry == NULL) - self->first_visible_entry = rb_first(&hb->hists->entries); - - for (nd = self->first_visible_entry; nd; nd = rb_next(nd)) { - struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); - - if (h->filtered) - continue; - - row += hist_browser__show_entry(hb, h, row); - if (row == self->height) - break; - } - - return row; -} - -static void callchain_node__init_have_children_rb_tree(struct callchain_node *self) -{ - struct rb_node *nd = rb_first(&self->rb_root); - - for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) { - struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); - struct callchain_list *chain; - int first = true; - - list_for_each_entry(chain, &child->val, list) { - if (first) { - first = false; - chain->ms.has_children = chain->list.next != &child->val || - rb_first(&child->rb_root) != NULL; - } else - chain->ms.has_children = chain->list.next == &child->val && - rb_first(&child->rb_root) != NULL; - } - - callchain_node__init_have_children_rb_tree(child); - } -} - -static void callchain_node__init_have_children(struct callchain_node *self) -{ - struct callchain_list *chain; - - list_for_each_entry(chain, &self->val, list) - chain->ms.has_children = rb_first(&self->rb_root) != NULL; - - callchain_node__init_have_children_rb_tree(self); -} - -static void callchain__init_have_children(struct rb_root *self) -{ - struct rb_node *nd; - - for (nd = rb_first(self); nd; nd = rb_next(nd)) { - struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); - callchain_node__init_have_children(node); - } -} - -static void hist_entry__init_have_children(struct hist_entry *self) -{ - if (!self->init_have_children) { - callchain__init_have_children(&self->sorted_chain); - self->init_have_children = true; - } -} - -static struct rb_node *hists__filter_entries(struct rb_node *nd) -{ - while (nd != NULL) { - struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); - if (!h->filtered) - return nd; - - nd = rb_next(nd); - } - - return NULL; -} - -static struct rb_node *hists__filter_prev_entries(struct rb_node *nd) -{ - while (nd != NULL) { - struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); - if (!h->filtered) - return nd; - - nd = rb_prev(nd); - } - - return NULL; -} - -static void ui_browser__hists_seek(struct ui_browser *self, - off_t offset, int whence) -{ - struct hist_entry *h; - struct rb_node *nd; - bool first = true; - - switch (whence) { - case SEEK_SET: - nd = hists__filter_entries(rb_first(self->entries)); - break; - case SEEK_CUR: - nd = self->first_visible_entry; - goto do_offset; - case SEEK_END: - nd = hists__filter_prev_entries(rb_last(self->entries)); - first = false; - break; - default: - return; - } - - /* - * Moves not relative to the first visible entry invalidates its - * row_offset: - */ - h = rb_entry(self->first_visible_entry, struct hist_entry, rb_node); - h->row_offset = 0; - - /* - * Here we have to check if nd is expanded (+), if it is we can't go - * the next top level hist_entry, instead we must compute an offset of - * what _not_ to show and not change the first visible entry. - * - * This offset increments when we are going from top to bottom and - * decreases when we're going from bottom to top. - * - * As we don't have backpointers to the top level in the callchains - * structure, we need to always print the whole hist_entry callchain, - * skipping the first ones that are before the first visible entry - * and stop when we printed enough lines to fill the screen. - */ -do_offset: - if (offset > 0) { - do { - h = rb_entry(nd, struct hist_entry, rb_node); - if (h->ms.unfolded) { - u16 remaining = h->nr_rows - h->row_offset; - if (offset > remaining) { - offset -= remaining; - h->row_offset = 0; - } else { - h->row_offset += offset; - offset = 0; - self->first_visible_entry = nd; - break; - } - } - nd = hists__filter_entries(rb_next(nd)); - if (nd == NULL) - break; - --offset; - self->first_visible_entry = nd; - } while (offset != 0); - } else if (offset < 0) { - while (1) { - h = rb_entry(nd, struct hist_entry, rb_node); - if (h->ms.unfolded) { - if (first) { - if (-offset > h->row_offset) { - offset += h->row_offset; - h->row_offset = 0; - } else { - h->row_offset += offset; - offset = 0; - self->first_visible_entry = nd; - break; - } - } else { - if (-offset > h->nr_rows) { - offset += h->nr_rows; - h->row_offset = 0; - } else { - h->row_offset = h->nr_rows + offset; - offset = 0; - self->first_visible_entry = nd; - break; - } - } - } - - nd = hists__filter_prev_entries(rb_prev(nd)); - if (nd == NULL) - break; - ++offset; - self->first_visible_entry = nd; - if (offset == 0) { - /* - * Last unfiltered hist_entry, check if it is - * unfolded, if it is then we should have - * row_offset at its last entry. - */ - h = rb_entry(nd, struct hist_entry, rb_node); - if (h->ms.unfolded) - h->row_offset = h->nr_rows; - break; - } - first = false; - } - } else { - self->first_visible_entry = nd; - h = rb_entry(nd, struct hist_entry, rb_node); - h->row_offset = 0; - } -} - -static int callchain_node__count_rows_rb_tree(struct callchain_node *self) -{ - int n = 0; - struct rb_node *nd; - - for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) { - struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); - struct callchain_list *chain; - char folded_sign = ' '; /* No children */ - - list_for_each_entry(chain, &child->val, list) { - ++n; - /* We need this because we may not have children */ - folded_sign = callchain_list__folded(chain); - if (folded_sign == '+') - break; - } - - if (folded_sign == '-') /* Have children and they're unfolded */ - n += callchain_node__count_rows_rb_tree(child); - } - - return n; -} - -static int callchain_node__count_rows(struct callchain_node *node) -{ - struct callchain_list *chain; - bool unfolded = false; - int n = 0; - - list_for_each_entry(chain, &node->val, list) { - ++n; - unfolded = chain->ms.unfolded; - } - - if (unfolded) - n += callchain_node__count_rows_rb_tree(node); - - return n; -} - -static int callchain__count_rows(struct rb_root *chain) -{ - struct rb_node *nd; - int n = 0; - - for (nd = rb_first(chain); nd; nd = rb_next(nd)) { - struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); - n += callchain_node__count_rows(node); - } - - return n; -} - -static bool hist_browser__toggle_fold(struct hist_browser *self) -{ - if (map_symbol__toggle_fold(self->selection)) { - struct hist_entry *he = self->he_selection; - - hist_entry__init_have_children(he); - self->hists->nr_entries -= he->nr_rows; - - if (he->ms.unfolded) - he->nr_rows = callchain__count_rows(&he->sorted_chain); - else - he->nr_rows = 0; - self->hists->nr_entries += he->nr_rows; - self->b.nr_entries = self->hists->nr_entries; - - return true; - } - - /* If it doesn't have children, no toggling performed */ - return false; -} - -static int hist_browser__run(struct hist_browser *self, const char *title, - struct newtExitStruct *es) -{ - char str[256], unit; - unsigned long nr_events = self->hists->stats.nr_events[PERF_RECORD_SAMPLE]; - - self->b.entries = &self->hists->entries; - self->b.nr_entries = self->hists->nr_entries; - - hist_browser__refresh_dimensions(self); - - nr_events = convert_unit(nr_events, &unit); - snprintf(str, sizeof(str), "Events: %lu%c ", - nr_events, unit); - newtDrawRootText(0, 0, str); - - if (ui_browser__show(&self->b, title) < 0) - return -1; - - newtFormAddHotKey(self->b.form, 'A'); - newtFormAddHotKey(self->b.form, 'a'); - newtFormAddHotKey(self->b.form, '?'); - newtFormAddHotKey(self->b.form, 'h'); - newtFormAddHotKey(self->b.form, 'H'); - newtFormAddHotKey(self->b.form, 'd'); - - newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT); - newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT); - newtFormAddHotKey(self->b.form, NEWT_KEY_ENTER); - - while (1) { - ui_browser__run(&self->b, es); - - if (es->reason != NEWT_EXIT_HOTKEY) - break; - switch (es->u.key) { - case 'd': { /* Debug */ - static int seq; - struct hist_entry *h = rb_entry(self->b.first_visible_entry, - struct hist_entry, rb_node); - ui_helpline__pop(); - ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", - seq++, self->b.nr_entries, - self->hists->nr_entries, - self->b.height, - self->b.index, - self->b.first_visible_entry_idx, - h->row_offset, h->nr_rows); - } - continue; - case NEWT_KEY_ENTER: - if (hist_browser__toggle_fold(self)) - break; - /* fall thru */ - default: - return 0; - } - } - return 0; -} diff --git a/trunk/tools/perf/util/probe-event.c b/trunk/tools/perf/util/probe-event.c index 2e665cb84055..4445a1e7052f 100644 --- a/trunk/tools/perf/util/probe-event.c +++ b/trunk/tools/perf/util/probe-event.c @@ -1,5 +1,5 @@ /* - * probe-event.c : perf-probe definition to probe_events format converter + * probe-event.c : perf-probe definition to kprobe_events format converter * * Written by Masami Hiramatsu * @@ -120,11 +120,8 @@ static int open_vmlinux(void) return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY); } -/* - * Convert trace point to probe point with debuginfo - * Currently only handles kprobes. - */ -static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, +/* Convert trace point to probe point with debuginfo */ +static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, struct perf_probe_point *pp) { struct symbol *sym; @@ -154,8 +151,8 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, } /* 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, +static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, + struct kprobe_trace_event **tevs, int max_tevs) { bool need_dwarf = perf_probe_event_need_dwarf(pev); @@ -172,11 +169,11 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, } /* Searching trace events corresponding to probe event */ - ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); + ntevs = find_kprobe_trace_events(fd, pev, tevs, max_tevs); close(fd); if (ntevs > 0) { /* Succeeded to find trace events */ - pr_debug("find %d probe_trace_events.\n", ntevs); + pr_debug("find %d kprobe_trace_events.\n", ntevs); return ntevs; } @@ -380,8 +377,8 @@ int show_line_range(struct line_range *lr) #else /* !DWARF_SUPPORT */ -static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, - struct perf_probe_point *pp) +static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, + struct perf_probe_point *pp) { pp->function = strdup(tp->symbol); if (pp->function == NULL) @@ -392,8 +389,8 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, return 0; } -static int try_to_find_probe_trace_events(struct perf_probe_event *pev, - struct probe_trace_event **tevs __unused, +static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, + struct kprobe_trace_event **tevs __unused, int max_tevs __unused) { if (perf_probe_event_need_dwarf(pev)) { @@ -784,17 +781,16 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) return false; } -/* Parse probe_events event into struct probe_point */ -static int parse_probe_trace_command(const char *cmd, - struct probe_trace_event *tev) +/* Parse kprobe_events event into struct probe_point */ +int parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev) { - struct probe_trace_point *tp = &tev->point; + struct kprobe_trace_point *tp = &tev->point; char pr; char *p; int ret, i, argc; char **argv; - pr_debug("Parsing probe_events: %s\n", cmd); + pr_debug("Parsing kprobe_events: %s\n", cmd); argv = argv_split(cmd, &argc); if (!argv) { pr_debug("Failed to split arguments.\n"); @@ -826,7 +822,7 @@ static int parse_probe_trace_command(const char *cmd, tp->offset = 0; tev->nargs = argc - 2; - tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); + tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); if (tev->args == NULL) { ret = -ENOMEM; goto out; @@ -972,13 +968,13 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev) } #endif -static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, +static int __synthesize_kprobe_trace_arg_ref(struct kprobe_trace_arg_ref *ref, char **buf, size_t *buflen, int depth) { int ret; if (ref->next) { - depth = __synthesize_probe_trace_arg_ref(ref->next, buf, + depth = __synthesize_kprobe_trace_arg_ref(ref->next, buf, buflen, depth + 1); if (depth < 0) goto out; @@ -996,10 +992,10 @@ static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, } -static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, +static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, char *buf, size_t buflen) { - struct probe_trace_arg_ref *ref = arg->ref; + struct kprobe_trace_arg_ref *ref = arg->ref; int ret, depth = 0; char *tmp = buf; @@ -1019,7 +1015,7 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, /* Dereferencing arguments */ if (ref) { - depth = __synthesize_probe_trace_arg_ref(ref, &buf, + depth = __synthesize_kprobe_trace_arg_ref(ref, &buf, &buflen, 1); if (depth < 0) return depth; @@ -1055,9 +1051,9 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, return buf - tmp; } -char *synthesize_probe_trace_command(struct probe_trace_event *tev) +char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev) { - struct probe_trace_point *tp = &tev->point; + struct kprobe_trace_point *tp = &tev->point; char *buf; int i, len, ret; @@ -1073,7 +1069,7 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev) goto error; for (i = 0; i < tev->nargs; i++) { - ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, + ret = synthesize_kprobe_trace_arg(&tev->args[i], buf + len, MAX_CMDLEN - len); if (ret <= 0) goto error; @@ -1086,7 +1082,7 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev) return NULL; } -static int convert_to_perf_probe_event(struct probe_trace_event *tev, +int convert_to_perf_probe_event(struct kprobe_trace_event *tev, struct perf_probe_event *pev) { char buf[64] = ""; @@ -1099,7 +1095,7 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev, return -ENOMEM; /* Convert trace_point to probe_point */ - ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); + ret = convert_to_perf_probe_point(&tev->point, &pev->point); if (ret < 0) return ret; @@ -1112,7 +1108,7 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev, if (tev->args[i].name) pev->args[i].name = strdup(tev->args[i].name); else { - ret = synthesize_probe_trace_arg(&tev->args[i], + ret = synthesize_kprobe_trace_arg(&tev->args[i], buf, 64); pev->args[i].name = strdup(buf); } @@ -1163,9 +1159,9 @@ void clear_perf_probe_event(struct perf_probe_event *pev) memset(pev, 0, sizeof(*pev)); } -static void clear_probe_trace_event(struct probe_trace_event *tev) +void clear_kprobe_trace_event(struct kprobe_trace_event *tev) { - struct probe_trace_arg_ref *ref, *next; + struct kprobe_trace_arg_ref *ref, *next; int i; if (tev->event) @@ -1226,7 +1222,7 @@ static int open_kprobe_events(bool readwrite) } /* Get raw string list of current kprobe_events */ -static struct strlist *get_probe_trace_command_rawlist(int fd) +static struct strlist *get_kprobe_trace_command_rawlist(int fd) { int ret, idx; FILE *fp; @@ -1294,7 +1290,7 @@ static int show_perf_probe_event(struct perf_probe_event *pev) int show_perf_probe_events(void) { int fd, ret; - struct probe_trace_event tev; + struct kprobe_trace_event tev; struct perf_probe_event pev; struct strlist *rawlist; struct str_node *ent; @@ -1311,20 +1307,20 @@ int show_perf_probe_events(void) if (fd < 0) return fd; - rawlist = get_probe_trace_command_rawlist(fd); + rawlist = get_kprobe_trace_command_rawlist(fd); close(fd); if (!rawlist) return -ENOENT; strlist__for_each(ent, rawlist) { - ret = parse_probe_trace_command(ent->s, &tev); + ret = parse_kprobe_trace_command(ent->s, &tev); if (ret >= 0) { ret = convert_to_perf_probe_event(&tev, &pev); if (ret >= 0) ret = show_perf_probe_event(&pev); } clear_perf_probe_event(&pev); - clear_probe_trace_event(&tev); + clear_kprobe_trace_event(&tev); if (ret < 0) break; } @@ -1334,19 +1330,20 @@ int show_perf_probe_events(void) } /* Get current perf-probe event names */ -static struct strlist *get_probe_trace_event_names(int fd, bool include_group) +static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group) { char buf[128]; struct strlist *sl, *rawlist; struct str_node *ent; - struct probe_trace_event tev; + struct kprobe_trace_event tev; int ret = 0; memset(&tev, 0, sizeof(tev)); - rawlist = get_probe_trace_command_rawlist(fd); + + rawlist = get_kprobe_trace_command_rawlist(fd); sl = strlist__new(true, NULL); strlist__for_each(ent, rawlist) { - ret = parse_probe_trace_command(ent->s, &tev); + ret = parse_kprobe_trace_command(ent->s, &tev); if (ret < 0) break; if (include_group) { @@ -1356,7 +1353,7 @@ static struct strlist *get_probe_trace_event_names(int fd, bool include_group) ret = strlist__add(sl, buf); } else ret = strlist__add(sl, tev.event); - clear_probe_trace_event(&tev); + clear_kprobe_trace_event(&tev); if (ret < 0) break; } @@ -1369,13 +1366,13 @@ static struct strlist *get_probe_trace_event_names(int fd, bool include_group) return sl; } -static int write_probe_trace_event(int fd, struct probe_trace_event *tev) +static int write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev) { int ret = 0; - char *buf = synthesize_probe_trace_command(tev); + char *buf = synthesize_kprobe_trace_command(tev); if (!buf) { - pr_debug("Failed to synthesize probe trace event.\n"); + pr_debug("Failed to synthesize kprobe trace event.\n"); return -EINVAL; } @@ -1428,12 +1425,12 @@ static int get_new_event_name(char *buf, size_t len, const char *base, return ret; } -static int __add_probe_trace_events(struct perf_probe_event *pev, - struct probe_trace_event *tevs, +static int __add_kprobe_trace_events(struct perf_probe_event *pev, + struct kprobe_trace_event *tevs, int ntevs, bool allow_suffix) { int i, fd, ret; - struct probe_trace_event *tev = NULL; + struct kprobe_trace_event *tev = NULL; char buf[64]; const char *event, *group; struct strlist *namelist; @@ -1442,7 +1439,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, if (fd < 0) return fd; /* Get current event names */ - namelist = get_probe_trace_event_names(fd, false); + namelist = get_kprobe_trace_event_names(fd, false); if (!namelist) { pr_debug("Failed to get current event list.\n"); return -EIO; @@ -1477,7 +1474,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, ret = -ENOMEM; break; } - ret = write_probe_trace_event(fd, tev); + ret = write_kprobe_trace_event(fd, tev); if (ret < 0) break; /* Add added event name to namelist */ @@ -1514,21 +1511,21 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, return ret; } -static int convert_to_probe_trace_events(struct perf_probe_event *pev, - struct probe_trace_event **tevs, +static int convert_to_kprobe_trace_events(struct perf_probe_event *pev, + struct kprobe_trace_event **tevs, int max_tevs) { struct symbol *sym; int ret = 0, i; - struct probe_trace_event *tev; + struct kprobe_trace_event *tev; /* Convert perf_probe_event with debuginfo */ - ret = try_to_find_probe_trace_events(pev, tevs, max_tevs); + ret = try_to_find_kprobe_trace_events(pev, tevs, max_tevs); if (ret != 0) return ret; /* Allocate trace event buffer */ - tev = *tevs = zalloc(sizeof(struct probe_trace_event)); + tev = *tevs = zalloc(sizeof(struct kprobe_trace_event)); if (tev == NULL) return -ENOMEM; @@ -1541,7 +1538,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, tev->point.offset = pev->point.offset; tev->nargs = pev->nargs; if (tev->nargs) { - tev->args = zalloc(sizeof(struct probe_trace_arg) + tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); if (tev->args == NULL) { ret = -ENOMEM; @@ -1582,7 +1579,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, return 1; error: - clear_probe_trace_event(tev); + clear_kprobe_trace_event(tev); free(tev); *tevs = NULL; return ret; @@ -1590,7 +1587,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, struct __event_package { struct perf_probe_event *pev; - struct probe_trace_event *tevs; + struct kprobe_trace_event *tevs; int ntevs; }; @@ -1613,7 +1610,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, for (i = 0; i < npevs; i++) { pkgs[i].pev = &pevs[i]; /* Convert with or without debuginfo */ - ret = convert_to_probe_trace_events(pkgs[i].pev, + ret = convert_to_kprobe_trace_events(pkgs[i].pev, &pkgs[i].tevs, max_tevs); if (ret < 0) goto end; @@ -1622,24 +1619,24 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, /* Loop 2: add all events */ for (i = 0; i < npevs && ret >= 0; i++) - ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, + ret = __add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs, pkgs[i].ntevs, force_add); end: /* Loop 3: cleanup trace events */ for (i = 0; i < npevs; i++) for (j = 0; j < pkgs[i].ntevs; j++) - clear_probe_trace_event(&pkgs[i].tevs[j]); + clear_kprobe_trace_event(&pkgs[i].tevs[j]); return ret; } -static int __del_trace_probe_event(int fd, struct str_node *ent) +static int __del_trace_kprobe_event(int fd, struct str_node *ent) { char *p; char buf[128]; int ret; - /* Convert from perf-probe event to trace-probe event */ + /* Convert from perf-probe event to trace-kprobe event */ ret = e_snprintf(buf, 128, "-:%s", ent->s); if (ret < 0) goto error; @@ -1665,7 +1662,7 @@ static int __del_trace_probe_event(int fd, struct str_node *ent) return ret; } -static int del_trace_probe_event(int fd, const char *group, +static int del_trace_kprobe_event(int fd, const char *group, const char *event, struct strlist *namelist) { char buf[128]; @@ -1682,7 +1679,7 @@ static int del_trace_probe_event(int fd, const char *group, strlist__for_each_safe(ent, n, namelist) if (strglobmatch(ent->s, buf)) { found++; - ret = __del_trace_probe_event(fd, ent); + ret = __del_trace_kprobe_event(fd, ent); if (ret < 0) break; strlist__remove(namelist, ent); @@ -1691,7 +1688,7 @@ static int del_trace_probe_event(int fd, const char *group, ent = strlist__find(namelist, buf); if (ent) { found++; - ret = __del_trace_probe_event(fd, ent); + ret = __del_trace_kprobe_event(fd, ent); if (ret >= 0) strlist__remove(namelist, ent); } @@ -1715,7 +1712,7 @@ int del_perf_probe_events(struct strlist *dellist) return fd; /* Get current event names */ - namelist = get_probe_trace_event_names(fd, true); + namelist = get_kprobe_trace_event_names(fd, true); if (namelist == NULL) return -EINVAL; @@ -1736,7 +1733,7 @@ int del_perf_probe_events(struct strlist *dellist) event = str; } pr_debug("Group: %s, Event: %s\n", group, event); - ret = del_trace_probe_event(fd, group, event, namelist); + ret = del_trace_kprobe_event(fd, group, event, namelist); free(str); if (ret < 0) break; diff --git a/trunk/tools/perf/util/probe-event.h b/trunk/tools/perf/util/probe-event.h index 5af39243a25b..ed362acff4b6 100644 --- a/trunk/tools/perf/util/probe-event.h +++ b/trunk/tools/perf/util/probe-event.h @@ -7,33 +7,33 @@ extern bool probe_event_dry_run; /* kprobe-tracer tracing point */ -struct probe_trace_point { +struct kprobe_trace_point { char *symbol; /* Base symbol */ unsigned long offset; /* Offset from symbol */ bool retprobe; /* Return probe flag */ }; -/* probe-tracer tracing argument referencing offset */ -struct probe_trace_arg_ref { - struct probe_trace_arg_ref *next; /* Next reference */ +/* kprobe-tracer tracing argument referencing offset */ +struct kprobe_trace_arg_ref { + struct kprobe_trace_arg_ref *next; /* Next reference */ long offset; /* Offset value */ }; /* kprobe-tracer tracing argument */ -struct probe_trace_arg { +struct kprobe_trace_arg { char *name; /* Argument name */ char *value; /* Base value */ char *type; /* Type name */ - struct probe_trace_arg_ref *ref; /* Referencing offset */ + struct kprobe_trace_arg_ref *ref; /* Referencing offset */ }; /* kprobe-tracer tracing event (point + arg) */ -struct probe_trace_event { +struct kprobe_trace_event { char *event; /* Event name */ char *group; /* Group name */ - struct probe_trace_point point; /* Trace point */ + struct kprobe_trace_point point; /* Trace point */ int nargs; /* Number of args */ - struct probe_trace_arg *args; /* Arguments */ + struct kprobe_trace_arg *args; /* Arguments */ }; /* Perf probe probing point */ @@ -93,18 +93,25 @@ struct line_range { /* Command string to events */ extern int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev); +extern int parse_kprobe_trace_command(const char *cmd, + struct kprobe_trace_event *tev); /* Events to command string */ extern char *synthesize_perf_probe_command(struct perf_probe_event *pev); -extern char *synthesize_probe_trace_command(struct probe_trace_event *tev); +extern char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev); extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len); /* Check the perf_probe_event needs debuginfo */ extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); +/* Convert from kprobe_trace_event to perf_probe_event */ +extern int convert_to_perf_probe_event(struct kprobe_trace_event *tev, + struct perf_probe_event *pev); + /* Release event contents */ extern void clear_perf_probe_event(struct perf_probe_event *pev); +extern void clear_kprobe_trace_event(struct kprobe_trace_event *tev); /* Command string to line-range */ extern int parse_line_range_desc(const char *cmd, struct line_range *lr); diff --git a/trunk/tools/perf/util/probe-finder.c b/trunk/tools/perf/util/probe-finder.c index 840f1aabbb74..f88070ea5b90 100644 --- a/trunk/tools/perf/util/probe-finder.c +++ b/trunk/tools/perf/util/probe-finder.c @@ -366,10 +366,10 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, * Probe finder related functions */ -static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) +static struct kprobe_trace_arg_ref *alloc_trace_arg_ref(long offs) { - struct probe_trace_arg_ref *ref; - ref = zalloc(sizeof(struct probe_trace_arg_ref)); + struct kprobe_trace_arg_ref *ref; + ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); if (ref != NULL) ref->offset = offs; return ref; @@ -385,7 +385,7 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf) Dwarf_Word offs = 0; bool ref = false; const char *regs; - struct probe_trace_arg *tvar = pf->tvar; + struct kprobe_trace_arg *tvar = pf->tvar; int ret; /* TODO: handle more than 1 exprs */ @@ -459,10 +459,10 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf) } static int convert_variable_type(Dwarf_Die *vr_die, - struct probe_trace_arg *tvar, + struct kprobe_trace_arg *tvar, const char *cast) { - struct probe_trace_arg_ref **ref_ptr = &tvar->ref; + struct kprobe_trace_arg_ref **ref_ptr = &tvar->ref; Dwarf_Die type; char buf[16]; int ret; @@ -500,7 +500,7 @@ static int convert_variable_type(Dwarf_Die *vr_die, while (*ref_ptr) ref_ptr = &(*ref_ptr)->next; /* Add new reference with offset +0 */ - *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); + *ref_ptr = zalloc(sizeof(struct kprobe_trace_arg_ref)); if (*ref_ptr == NULL) { pr_warning("Out of memory error\n"); return -ENOMEM; @@ -545,10 +545,10 @@ static int convert_variable_type(Dwarf_Die *vr_die, static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, struct perf_probe_arg_field *field, - struct probe_trace_arg_ref **ref_ptr, + struct kprobe_trace_arg_ref **ref_ptr, Dwarf_Die *die_mem) { - struct probe_trace_arg_ref *ref = *ref_ptr; + struct kprobe_trace_arg_ref *ref = *ref_ptr; Dwarf_Die type; Dwarf_Word offs; int ret, tag; @@ -574,7 +574,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, pr_debug2("Array real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); if (tag == DW_TAG_pointer_type) { - ref = zalloc(sizeof(struct probe_trace_arg_ref)); + ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); if (ref == NULL) return -ENOMEM; if (*ref_ptr) @@ -605,7 +605,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, return -EINVAL; } - ref = zalloc(sizeof(struct probe_trace_arg_ref)); + ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); if (ref == NULL) return -ENOMEM; if (*ref_ptr) @@ -738,7 +738,7 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) /* Show a probe point to output buffer */ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) { - struct probe_trace_event *tev; + struct kprobe_trace_event *tev; Dwarf_Addr eaddr; Dwarf_Die die_mem; const char *name; @@ -803,7 +803,7 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) /* Find each argument */ tev->nargs = pf->pev->nargs; - tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); + tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); if (tev->args == NULL) return -ENOMEM; for (i = 0; i < pf->pev->nargs; i++) { @@ -1060,9 +1060,9 @@ static int find_probe_point_by_func(struct probe_finder *pf) return _param.retval; } -/* Find probe_trace_events specified by perf_probe_event from debuginfo */ -int find_probe_trace_events(int fd, struct perf_probe_event *pev, - struct probe_trace_event **tevs, int max_tevs) +/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ +int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, + struct kprobe_trace_event **tevs, int max_tevs) { struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs}; struct perf_probe_point *pp = &pev->point; @@ -1072,7 +1072,7 @@ int find_probe_trace_events(int fd, struct perf_probe_event *pev, Dwarf *dbg; int ret = 0; - pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); + pf.tevs = zalloc(sizeof(struct kprobe_trace_event) * max_tevs); if (pf.tevs == NULL) return -ENOMEM; *tevs = pf.tevs; diff --git a/trunk/tools/perf/util/probe-finder.h b/trunk/tools/perf/util/probe-finder.h index 4507d519f183..e1f61dcd18ff 100644 --- a/trunk/tools/perf/util/probe-finder.h +++ b/trunk/tools/perf/util/probe-finder.h @@ -16,9 +16,9 @@ static inline int is_c_varname(const char *name) } #ifdef DWARF_SUPPORT -/* Find probe_trace_events specified by perf_probe_event from debuginfo */ -extern int find_probe_trace_events(int fd, struct perf_probe_event *pev, - struct probe_trace_event **tevs, +/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ +extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, + struct kprobe_trace_event **tevs, int max_tevs); /* Find a perf_probe_point from debuginfo */ @@ -33,7 +33,7 @@ extern int find_line_range(int fd, struct line_range *lr); struct probe_finder { struct perf_probe_event *pev; /* Target probe event */ - struct probe_trace_event *tevs; /* Result trace events */ + struct kprobe_trace_event *tevs; /* Result trace events */ int ntevs; /* Number of trace events */ int max_tevs; /* Max number of trace events */ @@ -50,7 +50,7 @@ struct probe_finder { #endif Dwarf_Op *fb_ops; /* Frame base attribute */ struct perf_probe_arg *pvar; /* Current target variable */ - struct probe_trace_arg *tvar; /* Current result variable */ + struct kprobe_trace_arg *tvar; /* Current result variable */ }; struct line_finder { diff --git a/trunk/tools/perf/util/session.c b/trunk/tools/perf/util/session.c index 04a3b3db9e90..030791870e33 100644 --- a/trunk/tools/perf/util/session.c +++ b/trunk/tools/perf/util/session.c @@ -96,6 +96,8 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc self->hists_tree = RB_ROOT; self->last_match = NULL; self->mmap_window = 32; + self->cwd = NULL; + self->cwdlen = 0; self->machines = RB_ROOT; self->repipe = repipe; INIT_LIST_HEAD(&self->ordered_samples.samples_head); @@ -124,36 +126,11 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc return NULL; } -static void perf_session__delete_dead_threads(struct perf_session *self) -{ - struct thread *n, *t; - - list_for_each_entry_safe(t, n, &self->dead_threads, node) { - list_del(&t->node); - thread__delete(t); - } -} - -static void perf_session__delete_threads(struct perf_session *self) -{ - struct rb_node *nd = rb_first(&self->threads); - - while (nd) { - struct thread *t = rb_entry(nd, struct thread, rb_node); - - rb_erase(&t->rb_node, &self->threads); - nd = rb_next(nd); - thread__delete(t); - } -} - void perf_session__delete(struct perf_session *self) { perf_header__exit(&self->header); - perf_session__delete_dead_threads(self); - perf_session__delete_threads(self); - machine__exit(&self->host_machine); close(self->fd); + free(self->cwd); free(self); } @@ -855,6 +832,23 @@ int perf_session__process_events(struct perf_session *self, if (perf_session__register_idle_thread(self) == NULL) return -ENOMEM; + if (!symbol_conf.full_paths) { + char bf[PATH_MAX]; + + if (getcwd(bf, sizeof(bf)) == NULL) { + err = -errno; +out_getcwd_err: + pr_err("failed to get the current directory\n"); + goto out_err; + } + self->cwd = strdup(bf); + if (self->cwd == NULL) { + err = -ENOMEM; + goto out_getcwd_err; + } + self->cwdlen = strlen(self->cwd); + } + if (!self->fd_pipe) err = __perf_session__process_events(self, self->header.data_offset, @@ -862,7 +856,7 @@ int perf_session__process_events(struct perf_session *self, self->size, ops); else err = __perf_session__process_pipe_events(self, ops); - +out_err: return err; } diff --git a/trunk/tools/perf/util/sort.c b/trunk/tools/perf/util/sort.c index 1c61a4f4aa8a..c27b4b03fbc1 100644 --- a/trunk/tools/perf/util/sort.c +++ b/trunk/tools/perf/util/sort.c @@ -1,5 +1,4 @@ #include "sort.h" -#include "hist.h" regex_t parent_regex; const char default_parent_pattern[] = "^sys_|^do_page_fault"; @@ -11,6 +10,11 @@ int sort__has_parent = 0; enum sort_type sort__first_dimension; +unsigned int dsos__col_width; +unsigned int comms__col_width; +unsigned int threads__col_width; +unsigned int cpus__col_width; +static unsigned int parent_symbol__col_width; char * field_sep; LIST_HEAD(hist_entry__sort_list); @@ -32,7 +36,7 @@ struct sort_entry sort_thread = { .se_header = "Command: Pid", .se_cmp = sort__thread_cmp, .se_snprintf = hist_entry__thread_snprintf, - .se_width_idx = HISTC_THREAD, + .se_width = &threads__col_width, }; struct sort_entry sort_comm = { @@ -40,35 +44,34 @@ struct sort_entry sort_comm = { .se_cmp = sort__comm_cmp, .se_collapse = sort__comm_collapse, .se_snprintf = hist_entry__comm_snprintf, - .se_width_idx = HISTC_COMM, + .se_width = &comms__col_width, }; struct sort_entry sort_dso = { .se_header = "Shared Object", .se_cmp = sort__dso_cmp, .se_snprintf = hist_entry__dso_snprintf, - .se_width_idx = HISTC_DSO, + .se_width = &dsos__col_width, }; struct sort_entry sort_sym = { .se_header = "Symbol", .se_cmp = sort__sym_cmp, .se_snprintf = hist_entry__sym_snprintf, - .se_width_idx = HISTC_SYMBOL, }; struct sort_entry sort_parent = { .se_header = "Parent symbol", .se_cmp = sort__parent_cmp, .se_snprintf = hist_entry__parent_snprintf, - .se_width_idx = HISTC_PARENT, + .se_width = &parent_symbol__col_width, }; struct sort_entry sort_cpu = { .se_header = "CPU", .se_cmp = sort__cpu_cmp, .se_snprintf = hist_entry__cpu_snprintf, - .se_width_idx = HISTC_CPU, + .se_width = &cpus__col_width, }; struct sort_dimension { diff --git a/trunk/tools/perf/util/sort.h b/trunk/tools/perf/util/sort.h index 46e531d09e8b..560c855417e4 100644 --- a/trunk/tools/perf/util/sort.h +++ b/trunk/tools/perf/util/sort.h @@ -36,14 +36,12 @@ extern struct sort_entry sort_comm; extern struct sort_entry sort_dso; extern struct sort_entry sort_sym; extern struct sort_entry sort_parent; +extern unsigned int dsos__col_width; +extern unsigned int comms__col_width; +extern unsigned int threads__col_width; +extern unsigned int cpus__col_width; extern enum sort_type sort__first_dimension; -/** - * struct hist_entry - histogram entry - * - * @row_offset - offset from the first callchain expanded to appear on screen - * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding - */ struct hist_entry { struct rb_node rb_node; u64 period; @@ -56,12 +54,6 @@ struct hist_entry { u64 ip; s32 cpu; u32 nr_events; - - /* XXX These two should move to some tree widget lib */ - u16 row_offset; - u16 nr_rows; - - bool init_have_children; char level; u8 filtered; struct symbol *parent; @@ -95,7 +87,7 @@ struct sort_entry { int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *); int (*se_snprintf)(struct hist_entry *self, char *bf, size_t size, unsigned int width); - u8 se_width_idx; + unsigned int *se_width; bool elide; }; diff --git a/trunk/tools/perf/util/symbol.c b/trunk/tools/perf/util/symbol.c index 94cdf68440cd..971d0a05d6b4 100644 --- a/trunk/tools/perf/util/symbol.c +++ b/trunk/tools/perf/util/symbol.c @@ -12,7 +12,6 @@ #include #include #include "build-id.h" -#include "debug.h" #include "symbol.h" #include "strlist.h" @@ -26,8 +25,6 @@ #define NT_GNU_BUILD_ID 3 #endif -static bool dso__build_id_equal(const struct dso *self, u8 *build_id); -static int elf_read_build_id(Elf *elf, void *bf, size_t size); static void dsos__add(struct list_head *head, struct dso *dso); static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); static int dso__load_kernel_sym(struct dso *self, struct map *map, @@ -43,14 +40,6 @@ struct symbol_conf symbol_conf = { .try_vmlinux_path = true, }; -int dso__name_len(const struct dso *self) -{ - if (verbose) - return self->long_name_len; - - return self->short_name_len; -} - bool dso__loaded(const struct dso *self, enum map_type type) { return self->loaded & (1 << type); @@ -226,9 +215,7 @@ void dso__delete(struct dso *self) int i; for (i = 0; i < MAP__NR_TYPES; ++i) symbols__delete(&self->symbols[i]); - if (self->sname_alloc) - free((char *)self->short_name); - if (self->lname_alloc) + if (self->long_name != self->name) free(self->long_name); free(self); } @@ -966,8 +953,7 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) } static int dso__load_sym(struct dso *self, struct map *map, const char *name, - int fd, symbol_filter_t filter, int kmodule, - int want_symtab) + int fd, symbol_filter_t filter, int kmodule) { struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; struct map *curr_map = map; @@ -987,32 +973,17 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); if (elf == NULL) { - pr_debug("%s: cannot read %s ELF file.\n", __func__, name); + pr_err("%s: cannot read %s ELF file.\n", __func__, name); goto out_close; } if (gelf_getehdr(elf, &ehdr) == NULL) { - pr_debug("%s: cannot get elf header.\n", __func__); + pr_err("%s: cannot get elf header.\n", __func__); goto out_elf_end; } - /* Always reject images with a mismatched build-id: */ - if (self->has_build_id) { - u8 build_id[BUILD_ID_SIZE]; - - if (elf_read_build_id(elf, build_id, - BUILD_ID_SIZE) != BUILD_ID_SIZE) - goto out_elf_end; - - if (!dso__build_id_equal(self, build_id)) - goto out_elf_end; - } - sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); if (sec == NULL) { - if (want_symtab) - goto out_elf_end; - sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); if (sec == NULL) goto out_elf_end; @@ -1211,26 +1182,37 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) */ #define NOTE_ALIGN(n) (((n) + 3) & -4U) -static int elf_read_build_id(Elf *elf, void *bf, size_t size) +int filename__read_build_id(const char *filename, void *bf, size_t size) { - int err = -1; + int fd, err = -1; GElf_Ehdr ehdr; GElf_Shdr shdr; Elf_Data *data; Elf_Scn *sec; Elf_Kind ek; void *ptr; + Elf *elf; if (size < BUILD_ID_SIZE) goto out; + fd = open(filename, O_RDONLY); + if (fd < 0) + goto out; + + elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (elf == NULL) { + pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); + goto out_close; + } + ek = elf_kind(elf); if (ek != ELF_K_ELF) - goto out; + goto out_elf_end; if (gelf_getehdr(elf, &ehdr) == NULL) { pr_err("%s: cannot get elf header.\n", __func__); - goto out; + goto out_elf_end; } sec = elf_section_by_name(elf, &ehdr, &shdr, @@ -1239,12 +1221,12 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) sec = elf_section_by_name(elf, &ehdr, &shdr, ".notes", NULL); if (sec == NULL) - goto out; + goto out_elf_end; } data = elf_getdata(sec, NULL); if (data == NULL) - goto out; + goto out_elf_end; ptr = data->d_buf; while (ptr < (data->d_buf + data->d_size)) { @@ -1266,31 +1248,7 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) } ptr += descsz; } - -out: - return err; -} - -int filename__read_build_id(const char *filename, void *bf, size_t size) -{ - int fd, err = -1; - Elf *elf; - - if (size < BUILD_ID_SIZE) - goto out; - - fd = open(filename, O_RDONLY); - if (fd < 0) - goto out; - - elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); - if (elf == NULL) { - pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); - goto out_close; - } - - err = elf_read_build_id(elf, bf, size); - +out_elf_end: elf_end(elf); out_close: close(fd); @@ -1366,11 +1324,11 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) { int size = PATH_MAX; char *name; + u8 build_id[BUILD_ID_SIZE]; int ret = -1; int fd; struct machine *machine; const char *root_dir; - int want_symtab; dso__set_loaded(self, map->type); @@ -1397,18 +1355,13 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) return ret; } - /* Iterate over candidate debug images. - * On the first pass, only load images if they have a full symtab. - * Failing that, do a second pass where we accept .dynsym also - */ - for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; - self->origin != DSO__ORIG_NOT_FOUND; - self->origin++) { + self->origin = DSO__ORIG_BUILD_ID_CACHE; + if (dso__build_id_filename(self, name, size) != NULL) + goto open_file; +more: + do { + self->origin++; switch (self->origin) { - case DSO__ORIG_BUILD_ID_CACHE: - if (dso__build_id_filename(self, name, size) == NULL) - continue; - break; case DSO__ORIG_FEDORA: snprintf(name, size, "/usr/lib/debug%s.debug", self->long_name); @@ -1417,20 +1370,21 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) snprintf(name, size, "/usr/lib/debug%s", self->long_name); break; - case DSO__ORIG_BUILDID: { - char build_id_hex[BUILD_ID_SIZE * 2 + 1]; - - if (!self->has_build_id) - continue; - - build_id__sprintf(self->build_id, - sizeof(self->build_id), - build_id_hex); - snprintf(name, size, - "/usr/lib/debug/.build-id/%.2s/%s.debug", - build_id_hex, build_id_hex + 2); + case DSO__ORIG_BUILDID: + if (filename__read_build_id(self->long_name, build_id, + sizeof(build_id))) { + char build_id_hex[BUILD_ID_SIZE * 2 + 1]; + build_id__sprintf(build_id, sizeof(build_id), + build_id_hex); + snprintf(name, size, + "/usr/lib/debug/.build-id/%.2s/%s.debug", + build_id_hex, build_id_hex + 2); + if (self->has_build_id) + goto compare_build_id; + break; } - break; + self->origin++; + /* Fall thru */ case DSO__ORIG_DSO: snprintf(name, size, "%s", self->long_name); break; @@ -1443,41 +1397,36 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) break; default: - /* - * If we wanted a full symtab but no image had one, - * relax our requirements and repeat the search. - */ - if (want_symtab) { - want_symtab = 0; - self->origin = DSO__ORIG_BUILD_ID_CACHE; - } else - continue; + goto out; } - /* Name is now the name of the next image to try */ + if (self->has_build_id) { + if (filename__read_build_id(name, build_id, + sizeof(build_id)) < 0) + goto more; +compare_build_id: + if (!dso__build_id_equal(self, build_id)) + goto more; + } +open_file: fd = open(name, O_RDONLY); - if (fd < 0) - continue; + } while (fd < 0); - ret = dso__load_sym(self, map, name, fd, filter, 0, - want_symtab); - close(fd); + ret = dso__load_sym(self, map, name, fd, filter, 0); + close(fd); - /* - * Some people seem to have debuginfo files _WITHOUT_ debug - * info!?!? - */ - if (!ret) - continue; + /* + * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? + */ + if (!ret) + goto more; - if (ret > 0) { - int nr_plt = dso__synthesize_plt_symbols(self, map, filter); - if (nr_plt > 0) - ret += nr_plt; - break; - } + if (ret > 0) { + int nr_plt = dso__synthesize_plt_symbols(self, map, filter); + if (nr_plt > 0) + ret += nr_plt; } - +out: free(name); if (ret < 0 && strstr(self->name, " (deleted)") != NULL) return 0; @@ -1572,7 +1521,6 @@ static int map_groups__set_modules_path_dir(struct map_groups *self, if (long_name == NULL) goto failure; dso__set_long_name(map->dso, long_name); - map->dso->lname_alloc = 1; dso__kernel_module_get_build_id(map->dso, ""); } } @@ -1736,12 +1684,36 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, { int err = -1, fd; + if (self->has_build_id) { + u8 build_id[BUILD_ID_SIZE]; + + if (filename__read_build_id(vmlinux, build_id, + sizeof(build_id)) < 0) { + pr_debug("No build_id in %s, ignoring it\n", vmlinux); + return -1; + } + if (!dso__build_id_equal(self, build_id)) { + char expected_build_id[BUILD_ID_SIZE * 2 + 1], + vmlinux_build_id[BUILD_ID_SIZE * 2 + 1]; + + build_id__sprintf(self->build_id, + sizeof(self->build_id), + expected_build_id); + build_id__sprintf(build_id, sizeof(build_id), + vmlinux_build_id); + pr_debug("build_id in %s is %s while expected is %s, " + "ignoring it\n", vmlinux, vmlinux_build_id, + expected_build_id); + return -1; + } + } + fd = open(vmlinux, O_RDONLY); if (fd < 0) return -1; dso__set_loaded(self, map->type); - err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0); + err = dso__load_sym(self, map, vmlinux, fd, filter, 0); close(fd); if (err > 0) @@ -2245,15 +2217,6 @@ int symbol__init(void) return -1; } -void symbol__exit(void) -{ - strlist__delete(symbol_conf.sym_list); - strlist__delete(symbol_conf.dso_list); - strlist__delete(symbol_conf.comm_list); - vmlinux_path__exit(); - symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; -} - int machines__create_kernel_maps(struct rb_root *self, pid_t pid) { struct machine *machine = machines__findnew(self, pid); diff --git a/trunk/tools/perf/util/symbol.h b/trunk/tools/perf/util/symbol.h index 33d53ce28958..80e569bbdecc 100644 --- a/trunk/tools/perf/util/symbol.h +++ b/trunk/tools/perf/util/symbol.h @@ -68,6 +68,7 @@ struct symbol_conf { show_nr_samples, use_callchain, exclude_other, + full_paths, show_cpu_utilization; const char *vmlinux_name, *source_prefix, @@ -101,8 +102,6 @@ struct ref_reloc_sym { struct map_symbol { struct map *map; struct symbol *sym; - bool unfolded; - bool has_children; }; struct addr_location { @@ -126,14 +125,12 @@ struct dso { struct list_head node; struct rb_root symbols[MAP__NR_TYPES]; struct rb_root symbol_names[MAP__NR_TYPES]; - enum dso_kernel_type kernel; u8 adjust_symbols:1; u8 slen_calculated:1; u8 has_build_id:1; + enum dso_kernel_type kernel; u8 hit:1; u8 annotate_warned:1; - u8 sname_alloc:1; - u8 lname_alloc:1; unsigned char origin; u8 sorted_by_name; u8 loaded; @@ -149,8 +146,6 @@ struct dso *dso__new(const char *name); struct dso *dso__new_kernel(const char *name); void dso__delete(struct dso *self); -int dso__name_len(const struct dso *self); - bool dso__loaded(const struct dso *self, enum map_type type); bool dso__sorted_by_name(const struct dso *self, enum map_type type); @@ -219,7 +214,6 @@ int machines__create_kernel_maps(struct rb_root *self, pid_t pid); int machines__create_guest_kernel_maps(struct rb_root *self); int symbol__init(void); -void symbol__exit(void); bool symbol_type__is_a(char symbol_type, enum map_type map_type); size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp); diff --git a/trunk/tools/perf/util/thread.c b/trunk/tools/perf/util/thread.c index 8c72d888e449..9a448b47400c 100644 --- a/trunk/tools/perf/util/thread.c +++ b/trunk/tools/perf/util/thread.c @@ -62,13 +62,6 @@ static struct thread *thread__new(pid_t pid) return self; } -void thread__delete(struct thread *self) -{ - map_groups__exit(&self->mg); - free(self->comm); - free(self); -} - int thread__set_comm(struct thread *self, const char *comm) { int err; diff --git a/trunk/tools/perf/util/thread.h b/trunk/tools/perf/util/thread.h index 688500ff826f..ee6bbcf277ca 100644 --- a/trunk/tools/perf/util/thread.h +++ b/trunk/tools/perf/util/thread.h @@ -20,8 +20,6 @@ struct thread { struct perf_session; -void thread__delete(struct thread *self); - int find_all_tid(int pid, pid_t ** all_tid); int thread__set_comm(struct thread *self, const char *comm); int thread__comm_len(struct thread *self);