diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/annotate.h | 2 | ||||
-rw-r--r-- | tools/perf/util/cpumap.c | 86 | ||||
-rw-r--r-- | tools/perf/util/cpumap.h | 12 | ||||
-rw-r--r-- | tools/perf/util/event.h | 9 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 19 | ||||
-rw-r--r-- | tools/perf/util/header.c | 11 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 110 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 23 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 42 | ||||
-rw-r--r-- | tools/perf/util/machine.h | 3 | ||||
-rw-r--r-- | tools/perf/util/session.c | 8 | ||||
-rw-r--r-- | tools/perf/util/sort.c | 414 | ||||
-rw-r--r-- | tools/perf/util/sort.h | 12 | ||||
-rw-r--r-- | tools/perf/util/symbol-elf.c | 9 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 1 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 9 | ||||
-rw-r--r-- | tools/perf/util/trace-event-info.c | 347 | ||||
-rw-r--r-- | tools/perf/util/trace-event-read.c | 272 | ||||
-rw-r--r-- | tools/perf/util/trace-event.h | 2 | ||||
-rw-r--r-- | tools/perf/util/util.h | 2 |
20 files changed, 1144 insertions, 249 deletions
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 6f3c16f01ab..af755156d27 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -150,7 +150,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, bool print_lines, bool full_paths, int min_pcnt, int max_lines); -#ifdef NEWT_SUPPORT +#ifdef SLANG_SUPPORT int symbol__tui_annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, struct hist_browser_timer *hbt); diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index f817046e22b..beb8cf9f997 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -4,6 +4,7 @@ #include "cpumap.h" #include <assert.h> #include <stdio.h> +#include <stdlib.h> static struct cpu_map *cpu_map__default_new(void) { @@ -219,7 +220,7 @@ int cpu_map__get_socket(struct cpu_map *map, int idx) if (!mnt) return -1; - sprintf(path, + snprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d/topology/physical_package_id", mnt, cpu); @@ -231,27 +232,88 @@ int cpu_map__get_socket(struct cpu_map *map, int idx) return ret == 1 ? cpu : -1; } -int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) +static int cmp_ids(const void *a, const void *b) { - struct cpu_map *sock; + return *(int *)a - *(int *)b; +} + +static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, + int (*f)(struct cpu_map *map, int cpu)) +{ + struct cpu_map *c; int nr = cpus->nr; int cpu, s1, s2; - sock = calloc(1, sizeof(*sock) + nr * sizeof(int)); - if (!sock) + /* allocate as much as possible */ + c = calloc(1, sizeof(*c) + nr * sizeof(int)); + if (!c) return -1; for (cpu = 0; cpu < nr; cpu++) { - s1 = cpu_map__get_socket(cpus, cpu); - for (s2 = 0; s2 < sock->nr; s2++) { - if (s1 == sock->map[s2]) + s1 = f(cpus, cpu); + for (s2 = 0; s2 < c->nr; s2++) { + if (s1 == c->map[s2]) break; } - if (s2 == sock->nr) { - sock->map[sock->nr] = s1; - sock->nr++; + if (s2 == c->nr) { + c->map[c->nr] = s1; + c->nr++; } } - *sockp = sock; + /* ensure we process id in increasing order */ + qsort(c->map, c->nr, sizeof(int), cmp_ids); + + *res = c; return 0; } + +int cpu_map__get_core(struct cpu_map *map, int idx) +{ + FILE *fp; + const char *mnt; + char path[PATH_MAX]; + int cpu, ret, s; + + if (idx > map->nr) + return -1; + + cpu = map->map[idx]; + + mnt = sysfs_find_mountpoint(); + if (!mnt) + return -1; + + snprintf(path, PATH_MAX, + "%s/devices/system/cpu/cpu%d/topology/core_id", + mnt, cpu); + + fp = fopen(path, "r"); + if (!fp) + return -1; + ret = fscanf(fp, "%d", &cpu); + fclose(fp); + if (ret != 1) + return -1; + + s = cpu_map__get_socket(map, idx); + if (s == -1) + return -1; + + /* + * encode socket in upper 16 bits + * core_id is relative to socket, and + * we need a global id. So we combine + * socket+ core id + */ + return (s << 16) | (cpu & 0xffff); +} + +int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) +{ + return cpu_map__build_map(cpus, sockp, cpu_map__get_socket); +} + +int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep) +{ + return cpu_map__build_map(cpus, corep, cpu_map__get_core); +} diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 161b00756a1..9bed02e5fb3 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -15,7 +15,9 @@ void cpu_map__delete(struct cpu_map *map); struct cpu_map *cpu_map__read(FILE *file); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); int cpu_map__get_socket(struct cpu_map *map, int idx); +int cpu_map__get_core(struct cpu_map *map, int idx); int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); +int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep); static inline int cpu_map__socket(struct cpu_map *sock, int s) { @@ -24,6 +26,16 @@ static inline int cpu_map__socket(struct cpu_map *sock, int s) return sock->map[s]; } +static inline int cpu_map__id_to_socket(int id) +{ + return id >> 16; +} + +static inline int cpu_map__id_to_cpu(int id) +{ + return id & 0xffff; +} + static inline int cpu_map__nr(const struct cpu_map *map) { return map ? map->nr : 1; diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 0d573ff4771..181389535c0 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -88,8 +88,10 @@ struct perf_sample { u64 id; u64 stream_id; u64 period; + u64 weight; u32 cpu; u32 raw_size; + u64 data_src; void *raw_data; struct ip_callchain *callchain; struct branch_stack *branch_stack; @@ -97,6 +99,13 @@ struct perf_sample { struct stack_dump user_stack; }; +#define PERF_MEM_DATA_SRC_NONE \ + (PERF_MEM_S(OP, NA) |\ + PERF_MEM_S(LVL, NA) |\ + PERF_MEM_S(SNOOP, NA) |\ + PERF_MEM_S(LOCK, NA) |\ + PERF_MEM_S(TLB, NA)) + struct build_id_event { struct perf_event_header header; pid_t pid; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 1adb824610f..07b1a3ad3e2 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -554,6 +554,9 @@ void perf_evsel__config(struct perf_evsel *evsel, perf_evsel__set_sample_bit(evsel, CPU); } + if (opts->sample_address) + attr->sample_type |= PERF_SAMPLE_DATA_SRC; + if (opts->no_delay) { attr->watermark = 0; attr->wakeup_events = 1; @@ -563,6 +566,9 @@ void perf_evsel__config(struct perf_evsel *evsel, attr->branch_sample_type = opts->branch_stack; } + if (opts->sample_weight) + attr->sample_type |= PERF_SAMPLE_WEIGHT; + attr->mmap = track; attr->comm = track; @@ -1017,6 +1023,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, data->cpu = data->pid = data->tid = -1; data->stream_id = data->id = data->time = -1ULL; data->period = 1; + data->weight = 0; if (event->header.type != PERF_RECORD_SAMPLE) { if (!evsel->attr.sample_id_all) @@ -1167,6 +1174,18 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, } } + data->weight = 0; + if (type & PERF_SAMPLE_WEIGHT) { + data->weight = *array; + array++; + } + + data->data_src = PERF_MEM_DATA_SRC_NONE; + if (type & PERF_SAMPLE_DATA_SRC) { + data->data_src = *array; + array++; + } + return 0; } diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index a9b7349f7c5..326068a593a 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1,5 +1,3 @@ -#define _FILE_OFFSET_BITS 64 - #include "util.h" #include <sys/types.h> #include <byteswap.h> @@ -1672,8 +1670,8 @@ static int process_tracing_data(struct perf_file_section *section __maybe_unused struct perf_header *ph __maybe_unused, int fd, void *data) { - trace_report(fd, data, false); - return 0; + ssize_t ret = trace_report(fd, data, false); + return ret < 0 ? -1 : 0; } static int process_build_id(struct perf_file_section *section, @@ -2752,6 +2750,11 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, if (evsel->tp_format) return 0; + if (pevent == NULL) { + pr_debug("broken or missing trace data\n"); + return -1; + } + event = pevent_find_event(pevent, evsel->attr.config); if (event == NULL) return -1; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index f855941bebe..6b32721f829 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -67,12 +67,16 @@ static void hists__set_unres_dso_col_len(struct hists *hists, int dso) void hists__calc_col_len(struct hists *hists, struct hist_entry *h) { const unsigned int unresolved_col_width = BITS_PER_LONG / 4; + int symlen; u16 len; if (h->ms.sym) hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4); - else + else { + symlen = unresolved_col_width + 4 + 2; + hists__new_col_len(hists, HISTC_SYMBOL, symlen); hists__set_unres_dso_col_len(hists, HISTC_DSO); + } len = thread__comm_len(h->thread); if (hists__new_col_len(hists, HISTC_COMM, len)) @@ -87,7 +91,6 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen); if (h->branch_info) { - int symlen; /* * +4 accounts for '[x] ' priv level info * +2 account of 0x prefix on raw addresses @@ -116,6 +119,42 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) hists__set_unres_dso_col_len(hists, HISTC_DSO_TO); } } + + if (h->mem_info) { + /* + * +4 accounts for '[x] ' priv level info + * +2 account of 0x prefix on raw addresses + */ + if (h->mem_info->daddr.sym) { + symlen = (int)h->mem_info->daddr.sym->namelen + 4 + + unresolved_col_width + 2; + hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, + symlen); + } else { + symlen = unresolved_col_width + 4 + 2; + hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, + symlen); + } + if (h->mem_info->daddr.map) { + symlen = dso__name_len(h->mem_info->daddr.map->dso); + hists__new_col_len(hists, HISTC_MEM_DADDR_DSO, + symlen); + } else { + symlen = unresolved_col_width + 4 + 2; + hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO); + } + } else { + symlen = unresolved_col_width + 4 + 2; + hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen); + hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO); + } + + hists__new_col_len(hists, HISTC_MEM_LOCKED, 6); + hists__new_col_len(hists, HISTC_MEM_TLB, 22); + hists__new_col_len(hists, HISTC_MEM_SNOOP, 12); + hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3); + hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12); + hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12); } void hists__output_recalc_col_len(struct hists *hists, int max_rows) @@ -155,9 +194,12 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he, } } -static void he_stat__add_period(struct he_stat *he_stat, u64 period) +static void he_stat__add_period(struct he_stat *he_stat, u64 period, + u64 weight) { + he_stat->period += period; + he_stat->weight += weight; he_stat->nr_events += 1; } @@ -169,12 +211,14 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src) dest->period_guest_sys += src->period_guest_sys; dest->period_guest_us += src->period_guest_us; dest->nr_events += src->nr_events; + dest->weight += src->weight; } static void hist_entry__decay(struct hist_entry *he) { he->stat.period = (he->stat.period * 7) / 8; he->stat.nr_events = (he->stat.nr_events * 7) / 8; + /* XXX need decay for weight too? */ } static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) @@ -239,7 +283,7 @@ void hists__decay_entries_threaded(struct hists *hists, static struct hist_entry *hist_entry__new(struct hist_entry *template) { size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; - struct hist_entry *he = malloc(sizeof(*he) + callchain_size); + struct hist_entry *he = zalloc(sizeof(*he) + callchain_size); if (he != NULL) { *he = *template; @@ -254,6 +298,13 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) he->branch_info->to.map->referenced = true; } + if (he->mem_info) { + if (he->mem_info->iaddr.map) + he->mem_info->iaddr.map->referenced = true; + if (he->mem_info->daddr.map) + he->mem_info->daddr.map->referenced = true; + } + if (symbol_conf.use_callchain) callchain_init(he->callchain); @@ -282,7 +333,8 @@ static u8 symbol__parent_filter(const struct symbol *parent) static struct hist_entry *add_hist_entry(struct hists *hists, struct hist_entry *entry, struct addr_location *al, - u64 period) + u64 period, + u64 weight) { struct rb_node **p; struct rb_node *parent = NULL; @@ -306,7 +358,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists, cmp = hist_entry__cmp(he, entry); if (!cmp) { - he_stat__add_period(&he->stat, period); + he_stat__add_period(&he->stat, period, weight); /* If the map of an existing hist_entry has * become out-of-date due to an exec() or @@ -341,11 +393,42 @@ out_unlock: return he; } +struct hist_entry *__hists__add_mem_entry(struct hists *self, + struct addr_location *al, + struct symbol *sym_parent, + struct mem_info *mi, + u64 period, + u64 weight) +{ + struct hist_entry entry = { + .thread = al->thread, + .ms = { + .map = al->map, + .sym = al->sym, + }, + .stat = { + .period = period, + .weight = weight, + .nr_events = 1, + }, + .cpu = al->cpu, + .ip = al->addr, + .level = al->level, + .parent = sym_parent, + .filtered = symbol__parent_filter(sym_parent), + .hists = self, + .mem_info = mi, + .branch_info = NULL, + }; + return add_hist_entry(self, &entry, al, period, weight); +} + struct hist_entry *__hists__add_branch_entry(struct hists *self, struct addr_location *al, struct symbol *sym_parent, struct branch_info *bi, - u64 period) + u64 period, + u64 weight) { struct hist_entry entry = { .thread = al->thread, @@ -359,19 +442,22 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self, .stat = { .period = period, .nr_events = 1, + .weight = weight, }, .parent = sym_parent, .filtered = symbol__parent_filter(sym_parent), .branch_info = bi, .hists = self, + .mem_info = NULL, }; - return add_hist_entry(self, &entry, al, period); + return add_hist_entry(self, &entry, al, period, weight); } struct hist_entry *__hists__add_entry(struct hists *self, struct addr_location *al, - struct symbol *sym_parent, u64 period) + struct symbol *sym_parent, u64 period, + u64 weight) { struct hist_entry entry = { .thread = al->thread, @@ -385,13 +471,16 @@ struct hist_entry *__hists__add_entry(struct hists *self, .stat = { .period = period, .nr_events = 1, + .weight = weight, }, .parent = sym_parent, .filtered = symbol__parent_filter(sym_parent), .hists = self, + .branch_info = NULL, + .mem_info = NULL, }; - return add_hist_entry(self, &entry, al, period); + return add_hist_entry(self, &entry, al, period, weight); } int64_t @@ -431,6 +520,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) void hist_entry__free(struct hist_entry *he) { free(he->branch_info); + free(he->mem_info); free(he); } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 848331377bd..14c2fe20aa6 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -49,6 +49,14 @@ enum hist_column { HISTC_DSO_FROM, HISTC_DSO_TO, HISTC_SRCLINE, + HISTC_LOCAL_WEIGHT, + HISTC_GLOBAL_WEIGHT, + HISTC_MEM_DADDR_SYMBOL, + HISTC_MEM_DADDR_DSO, + HISTC_MEM_LOCKED, + HISTC_MEM_TLB, + HISTC_MEM_LVL, + HISTC_MEM_SNOOP, HISTC_NR_COLS, /* Last entry */ }; @@ -73,7 +81,8 @@ struct hists { struct hist_entry *__hists__add_entry(struct hists *self, struct addr_location *al, - struct symbol *parent, u64 period); + struct symbol *parent, u64 period, + u64 weight); int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size, @@ -84,7 +93,15 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self, struct addr_location *al, struct symbol *sym_parent, struct branch_info *bi, - u64 period); + u64 period, + u64 weight); + +struct hist_entry *__hists__add_mem_entry(struct hists *self, + struct addr_location *al, + struct symbol *sym_parent, + struct mem_info *mi, + u64 period, + u64 weight); void hists__output_resort(struct hists *self); void hists__output_resort_threaded(struct hists *hists); @@ -175,7 +192,7 @@ struct hist_browser_timer { int refresh; }; -#ifdef NEWT_SUPPORT +#ifdef SLANG_SUPPORT #include "../ui/keysyms.h" int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, struct hist_browser_timer *hbt); diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index c5e3b123782..b2ecad6ec46 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -955,6 +955,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; struct thread *thread; struct map *map; + enum map_type type; int ret = 0; if (dump_trace) @@ -971,10 +972,17 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event thread = machine__findnew_thread(machine, event->mmap.pid); if (thread == NULL) goto out_problem; + + if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) + type = MAP__VARIABLE; + else + type = MAP__FUNCTION; + map = map__new(&machine->user_dsos, event->mmap.start, event->mmap.len, event->mmap.pgoff, event->mmap.pid, event->mmap.filename, - MAP__FUNCTION); + type); + if (map == NULL) goto out_problem; @@ -1097,6 +1105,38 @@ found: ams->map = al.map; } +static void ip__resolve_data(struct machine *machine, struct thread *thread, + u8 m, struct addr_map_symbol *ams, u64 addr) +{ + struct addr_location al; + + memset(&al, 0, sizeof(al)); + + thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al, + NULL); + ams->addr = addr; + ams->al_addr = al.addr; + ams->sym = al.sym; + ams->map = al.map; +} + +struct mem_info *machine__resolve_mem(struct machine *machine, + struct thread *thr, + struct perf_sample *sample, + u8 cpumode) +{ + struct mem_info *mi = zalloc(sizeof(*mi)); + + if (!mi) + return NULL; + + ip__resolve_ams(machine, thr, &mi->iaddr, sample->ip); + ip__resolve_data(machine, thr, cpumode, &mi->daddr, sample->addr); + mi->data_src.val = sample->data_src; + + return mi; +} + struct branch_info *machine__resolve_bstack(struct machine *machine, struct thread *thr, struct branch_stack *bs) diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index e0b2c00b2e7..77940680f1f 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -76,6 +76,9 @@ void machine__delete(struct machine *machine); struct branch_info *machine__resolve_bstack(struct machine *machine, struct thread *thread, struct branch_stack *bs); +struct mem_info *machine__resolve_mem(struct machine *machine, + struct thread *thread, + struct perf_sample *sample, u8 cpumode); int machine__resolve_callchain(struct machine *machine, struct perf_evsel *evsel, struct thread *thread, diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index ab265c2cfab..cf1fe01b7e8 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1,5 +1,3 @@ -#define _FILE_OFFSET_BITS 64 - #include <linux/kernel.h> #include <byteswap.h> @@ -800,6 +798,12 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, if (sample_type & PERF_SAMPLE_STACK_USER) stack_user__printf(&sample->user_stack); + + if (sample_type & PERF_SAMPLE_WEIGHT) + printf("... weight: %" PRIu64 "\n", sample->weight); + + if (sample_type & PERF_SAMPLE_DATA_SRC) + printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); } static struct machine * diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index d41926cb9e3..5f52d492590 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -198,11 +198,19 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, } ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level); - if (sym) - ret += repsep_snprintf(bf + ret, size - ret, "%-*s", - width - ret, - sym->name); - else { + if (sym && map) { + if (map->type == MAP__VARIABLE) { + ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name); + ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", + ip - map->unmap_ip(map, sym->start)); + ret += repsep_snprintf(bf + ret, size - ret, "%-*s", + width - ret, ""); + } else { + ret += repsep_snprintf(bf + ret, size - ret, "%-*s", + width - ret, + sym->name); + } + } else { size_t len = BITS_PER_LONG / 4; ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", len, ip); @@ -457,6 +465,304 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf, return repsep_snprintf(bf, size, "%-*s", width, out); } +/* --sort daddr_sym */ +static int64_t +sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right) +{ + uint64_t l = 0, r = 0; + + if (left->mem_info) + l = left->mem_info->daddr.addr; + if (right->mem_info) + r = right->mem_info->daddr.addr; + + return (int64_t)(r - l); +} + +static int hist_entry__daddr_snprintf(struct hist_entry *self, char *bf, + size_t size, unsigned int width) +{ + uint64_t addr = 0; + struct map *map = NULL; + struct symbol *sym = NULL; + + if (self->mem_info) { + addr = self->mem_info->daddr.addr; + map = self->mem_info->daddr.map; + sym = self->mem_info->daddr.sym; + } + return _hist_entry__sym_snprintf(map, sym, addr, self->level, bf, size, + width); +} + +static int64_t +sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right) +{ + struct map *map_l = NULL; + struct map *map_r = NULL; + + if (left->mem_info) + map_l = left->mem_info->daddr.map; + if (right->mem_info) + map_r = right->mem_info->daddr.map; + + return _sort__dso_cmp(map_l, map_r); +} + +static int hist_entry__dso_daddr_snprintf(struct hist_entry *self, char *bf, + size_t size, unsigned int width) +{ + struct map *map = NULL; + + if (self->mem_info) + map = self->mem_info->daddr.map; + + return _hist_entry__dso_snprintf(map, bf, size, width); +} + +static int64_t +sort__locked_cmp(struct hist_entry *left, struct hist_entry *right) +{ + union perf_mem_data_src data_src_l; + union perf_mem_data_src data_src_r; + + if (left->mem_info) + data_src_l = left->mem_info->data_src; + else + data_src_l.mem_lock = PERF_MEM_LOCK_NA; + + if (right->mem_info) + data_src_r = right->mem_info->data_src; + else + data_src_r.mem_lock = PERF_MEM_LOCK_NA; + + return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock); +} + +static int hist_entry__locked_snprintf(struct hist_entry *self, char *bf, + size_t size, unsigned int width) +{ + const char *out; + u64 mask = PERF_MEM_LOCK_NA; + + if (self->mem_info) + mask = self->mem_info->data_src.mem_lock; + + if (mask & PERF_MEM_LOCK_NA) + out = "N/A"; + else if (mask & PERF_MEM_LOCK_LOCKED) + out = "Yes"; + else + out = "No"; + + return repsep_snprintf(bf, size, "%-*s", width, out); +} + +static int64_t +sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right) +{ + union perf_mem_data_src data_src_l; + union perf_mem_data_src data_src_r; + + if (left->mem_info) + data_src_l = left->mem_info->data_src; + else + data_src_l.mem_dtlb = PERF_MEM_TLB_NA; + + if (right->mem_info) + data_src_r = right->mem_info->data_src; + else + data_src_r.mem_dtlb = PERF_MEM_TLB_NA; + + return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb); +} + +static const char * const tlb_access[] = { + "N/A", + "HIT", + "MISS", + "L1", + "L2", + "Walker", + "Fault", +}; +#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *)) + +static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf, + size_t size, unsigned int width) +{ + char out[64]; + size_t sz = sizeof(out) - 1; /* -1 for null termination */ + size_t l = 0, i; + u64 m = PERF_MEM_TLB_NA; + u64 hit, miss; + + out[0] = '\0'; + + if (self->mem_info) + m = self->mem_info->data_src.mem_dtlb; + + hit = m & PERF_MEM_TLB_HIT; + miss = m & PERF_MEM_TLB_MISS; + + /* already taken care of */ + m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS); + + for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) { + if (!(m & 0x1)) + continue; + if (l) { + strcat(out, " or "); + l += 4; + } + strncat(out, tlb_access[i], sz - l); + l += strlen(tlb_access[i]); + } + if (*out == '\0') + strcpy(out, "N/A"); + if (hit) + strncat(out, " hit", sz - l); + if (miss) + strncat(out, " miss", sz - l); + + return repsep_snprintf(bf, size, "%-*s", width, out); +} + +static int64_t +sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right) +{ + union perf_mem_data_src data_src_l; + union perf_mem_data_src data_src_r; + + if (left->mem_info) + data_src_l = left->mem_info->data_src; + else + data_src_l.mem_lvl = PERF_MEM_LVL_NA; + + if (right->mem_info) + data_src_r = right->mem_info->data_src; + else + data_src_r.mem_lvl = PERF_MEM_LVL_NA; + + return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl); +} + +static const char * const mem_lvl[] = { + "N/A", + "HIT", + "MISS", + "L1", + "LFB", + "L2", + "L3", + "Local RAM", + "Remote RAM (1 hop)", + "Remote RAM (2 hops)", + "Remote Cache (1 hop)", + "Remote Cache (2 hops)", + "I/O", + "Uncached", +}; +#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *)) + +static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf, + size_t size, unsigned int width) +{ + char out[64]; + size_t sz = sizeof(out) - 1; /* -1 for null termination */ + size_t i, l = 0; + u64 m = PERF_MEM_LVL_NA; + u64 hit, miss; + + if (self->mem_info) + m = self->mem_info->data_src.mem_lvl; + + out[0] = '\0'; + + hit = m & PERF_MEM_LVL_HIT; + miss = m & PERF_MEM_LVL_MISS; + + /* already taken care of */ + m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS); + + for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) { + if (!(m & 0x1)) + continue; + if (l) { + strcat(out, " or "); + l += 4; + } + strncat(out, mem_lvl[i], sz - l); + l += strlen(mem_lvl[i]); + } + if (*out == '\0') + strcpy(out, "N/A"); + if (hit) + strncat(out, " hit", sz - l); + if (miss) + strncat(out, " miss", sz - l); + + return repsep_snprintf(bf, size, "%-*s", width, out); +} + +static int64_t +sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right) +{ + union perf_mem_data_src data_src_l; + union perf_mem_data_src data_src_r; + + if (left->mem_info) + data_src_l = left->mem_info->data_src; + else + data_src_l.mem_snoop = PERF_MEM_SNOOP_NA; + + if (right->mem_info) + data_src_r = right->mem_info->data_src; + else + data_src_r.mem_snoop = PERF_MEM_SNOOP_NA; + + return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop); +} + +static const char * const snoop_access[] = { + "N/A", + "None", + "Miss", + "Hit", + "HitM", +}; +#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *)) + +static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf, + size_t size, unsigned int width) +{ + char out[64]; + size_t sz = sizeof(out) - 1; /* -1 for null termination */ + size_t i, l = 0; + u64 m = PERF_MEM_SNOOP_NA; + + out[0] = '\0'; + + if (self->mem_info) + m = self->mem_info->data_src.mem_snoop; + + for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) { + if (!(m & 0x1)) + continue; + if (l) { + strcat(out, " or "); + l += 4; + } + strncat(out, snoop_access[i], sz - l); + l += strlen(snoop_access[i]); + } + + if (*out == '\0') + strcpy(out, "N/A"); + + return repsep_snprintf(bf, size, "%-*s", width, out); +} + struct sort_entry sort_mispredict = { .se_header = "Branch Mispredicted", .se_cmp = sort__mispredict_cmp, @@ -464,6 +770,91 @@ struct sort_entry sort_mispredict = { .se_width_idx = HISTC_MISPREDICT, }; +static u64 he_weight(struct hist_entry *he) +{ + return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0; +} + +static int64_t +sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right) +{ + return he_weight(left) - he_weight(right); +} + +static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf, + size_t size, unsigned int width) +{ + return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self)); +} + +struct sort_entry sort_local_weight = { + .se_header = "Local Weight", + .se_cmp = sort__local_weight_cmp, + .se_snprintf = hist_entry__local_weight_snprintf, + .se_width_idx = HISTC_LOCAL_WEIGHT, +}; + +static int64_t +sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right) +{ + return left->stat.weight - right->stat.weight; +} + +static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf, + size_t size, unsigned int width) +{ + return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight); +} + +struct sort_entry sort_global_weight = { + .se_header = "Weight", + .se_cmp = sort__global_weight_cmp, + .se_snprintf = hist_entry__global_weight_snprintf, + .se_width_idx = HISTC_GLOBAL_WEIGHT, +}; + +struct sort_entry sort_mem_daddr_sym = { + .se_header = "Data Symbol", + .se_cmp = sort__daddr_cmp, + .se_snprintf = hist_entry__daddr_snprintf, + .se_width_idx = HISTC_MEM_DADDR_SYMBOL, +}; + +struct sort_entry sort_mem_daddr_dso = { + .se_header = "Data Object", + .se_cmp = sort__dso_daddr_cmp, + .se_snprintf = hist_entry__dso_daddr_snprintf, + .se_width_idx = HISTC_MEM_DADDR_SYMBOL, +}; + +struct sort_entry sort_mem_locked = { + .se_header = "Locked", + .se_cmp = sort__locked_cmp, + .se_snprintf = hist_entry__locked_snprintf, + .se_width_idx = HISTC_MEM_LOCKED, +}; + +struct sort_entry sort_mem_tlb = { + .se_header = "TLB access", + .se_cmp = sort__tlb_cmp, + .se_snprintf = hist_entry__tlb_snprintf, + .se_width_idx = HISTC_MEM_TLB, +}; + +struct sort_entry sort_mem_lvl = { + .se_header = "Memory access", + .se_cmp = sort__lvl_cmp, + .se_snprintf = hist_entry__lvl_snprintf, + .se_width_idx = HISTC_MEM_LVL, +}; + +struct sort_entry sort_mem_snoop = { + .se_header = "Snoop", + .se_cmp = sort__snoop_cmp, + .se_snprintf = hist_entry__snoop_snprintf, + .se_width_idx = HISTC_MEM_SNOOP, +}; + struct sort_dimension { const char *name; struct sort_entry *entry; @@ -480,6 +871,14 @@ static struct sort_dimension common_sort_dimensions[] = { DIM(SORT_PARENT, "parent", sort_parent), DIM(SORT_CPU, "cpu", sort_cpu), DIM(SORT_SRCLINE, "srcline", sort_srcline), + DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), + DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), + DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym), + DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso), + DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked), + DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), + DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), + DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), }; #undef DIM @@ -516,7 +915,10 @@ int sort_dimension__add(const char *tok) return -EINVAL; } sort__has_parent = 1; - } else if (sd->entry == &sort_sym) { + } else if (sd->entry == &sort_sym || + sd->entry == &sort_sym_from || + sd->entry == &sort_sym_to || + sd->entry == &sort_mem_daddr_sym) { sort__has_sym = 1; } diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index b13e56f6ccb..f24bdf64238 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -49,6 +49,7 @@ struct he_stat { u64 period_us; u64 period_guest_sys; u64 period_guest_us; + u64 weight; u32 nr_events; }; @@ -100,7 +101,8 @@ struct hist_entry { struct rb_root sorted_chain; struct branch_info *branch_info; struct hists *hists; - struct callchain_root callchain[0]; + struct mem_info *mem_info; + struct callchain_root callchain[0]; /* must be last member */ }; static inline bool hist_entry__has_pairs(struct hist_entry *he) @@ -130,6 +132,14 @@ enum sort_type { SORT_PARENT, SORT_CPU, SORT_SRCLINE, + SORT_LOCAL_WEIGHT, + SORT_GLOBAL_WEIGHT, + SORT_MEM_DADDR_SYMBOL, + SORT_MEM_DADDR_DSO, + SORT_MEM_LOCKED, + SORT_MEM_TLB, + SORT_MEM_LVL, + SORT_MEM_SNOOP, /* branch stack specific sort keys */ __SORT_BRANCH_STACK, diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 54efcb5659a..4b12bf85032 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -806,9 +806,12 @@ int dso__load_sym(struct dso *dso, struct map *map, * DWARF DW_compile_unit has this, but we don't always have access * to it... */ - demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); - if (demangled != NULL) - elf_name = demangled; + if (symbol_conf.demangle) { + demangled = bfd_demangle(NULL, elf_name, + DMGL_PARAMS | DMGL_ANSI); + if (demangled != NULL) + elf_name = demangled; + } new_symbol: f = symbol__new(sym.st_value, sym.st_size, GELF_ST_BIND(sym.st_info), elf_name); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e6432d85b43..8cf3b5426a9 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -36,6 +36,7 @@ struct symbol_conf symbol_conf = { .use_modules = true, .try_vmlinux_path = true, .annotate_src = true, + .demangle = true, .symfs = "", }; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index b62ca37c4b7..5f720dc076d 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -97,7 +97,8 @@ struct symbol_conf { kptr_restrict, annotate_asm_raw, annotate_src, - event_group; + event_group, + demangle; const char *vmlinux_name, *kallsyms_name, *source_prefix, @@ -155,6 +156,12 @@ struct branch_info { struct branch_flags flags; }; +struct mem_info { + struct addr_map_symbol iaddr; + struct addr_map_symbol daddr; + union perf_mem_data_src data_src; +}; + struct addr_location { struct thread *thread; struct map *map; diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 5729f434c5b..3917eb9a847 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -43,26 +43,15 @@ #define VERSION "0.5" -static const char *output_file = "trace.info"; static int output_fd; -static void *malloc_or_die(unsigned int size) -{ - void *data; - - data = malloc(size); - if (!data) - die("malloc"); - return data; -} - static const char *find_debugfs(void) { const char *path = perf_debugfs_mount(NULL); if (!path) - die("Your kernel not support debugfs filesystem"); + pr_debug("Your kernel does not support the debugfs filesystem"); return path; } @@ -81,8 +70,12 @@ static const char *find_tracing_dir(void) return tracing; debugfs = find_debugfs(); + if (!debugfs) + return NULL; - tracing = malloc_or_die(strlen(debugfs) + 9); + tracing = malloc(strlen(debugfs) + 9); + if (!tracing) + return NULL; sprintf(tracing, "%s/tracing", debugfs); @@ -99,7 +92,9 @@ static char *get_tracing_file(const char *name) if (!tracing) return NULL; - file = malloc_or_die(strlen(tracing) + strlen(name) + 2); + file = malloc(strlen(tracing) + strlen(name) + 2); + if (!file) + return NULL; sprintf(file, "%s/%s", tracing, name); return file; @@ -110,17 +105,6 @@ static void put_tracing_file(char *file) free(file); } -static ssize_t write_or_die(const void *buf, size_t len) -{ - int ret; - - ret = write(output_fd, buf, len); - if (ret < 0) - die("writing to '%s'", output_file); - - return ret; -} - int bigendian(void) { unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; @@ -131,59 +115,106 @@ int bigendian(void) } /* unfortunately, you can not stat debugfs or proc files for size */ -static void record_file(const char *file, size_t hdr_sz) +static int record_file(const char *file, ssize_t hdr_sz) { unsigned long long size = 0; char buf[BUFSIZ], *sizep; off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR); int r, fd; + int err = -EIO; fd = open(file, O_RDONLY); - if (fd < 0) - die("Can't read '%s'", file); + if (fd < 0) { + pr_debug("Can't read '%s'", file); + return -errno; + } /* put in zeros for file size, then fill true size later */ - if (hdr_sz) - write_or_die(&size, hdr_sz); + if (hdr_sz) { + if (write(output_fd, &size, hdr_sz) != hdr_sz) + goto out; + } do { r = read(fd, buf, BUFSIZ); if (r > 0) { size += r; - write_or_die(buf, r); + if (write(output_fd, buf, r) != r) + goto out; } } while (r > 0); - close(fd); /* ugh, handle big-endian hdr_size == 4 */ sizep = (char*)&size; if (bigendian()) sizep += sizeof(u64) - hdr_sz; - if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) - die("writing to %s", output_file); + if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) { + pr_debug("writing file size failed\n"); + goto out; + } + + err = 0; +out: + close(fd); + return err; } -static void read_header_files(void) +static int read_header_files(void) { char *path; struct stat st; + int err = -EIO; path = get_tracing_file("events/header_page"); - if (stat(path, &st) < 0) - die("can't read '%s'", path); + if (!path) { + pr_debug("can't get tracing/events/header_page"); + return -ENOMEM; + } + + if (stat(path, &st) < 0) { + pr_debug("can't read '%s'", path); + goto out; + } + + if (write(output_fd, "header_page", 12) != 12) { + pr_debug("can't write header_page\n"); + goto out; + } + + if (record_file(path, 8) < 0) { + pr_debug("can't record header_page file\n"); + goto out; + } - write_or_die("header_page", 12); - record_file(path, 8); put_tracing_file(path); path = get_tracing_file("events/header_event"); - if (stat(path, &st) < 0) - die("can't read '%s'", path); + if (!path) { + pr_debug("can't get tracing/events/header_event"); + err = -ENOMEM; + goto out; + } + + if (stat(path, &st) < 0) { + pr_debug("can't read '%s'", path); + goto out; + } + + if (write(output_fd, "header_event", 13) != 13) { + pr_debug("can't write header_event\n"); + goto out; + } + + if (record_file(path, 8) < 0) { + pr_debug("can't record header_event file\n"); + goto out; + } - write_or_die("header_event", 13); - record_file(path, 8); + err = 0; +out: put_tracing_file(path); + return err; } static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) @@ -197,7 +228,7 @@ static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) return false; } -static void copy_event_system(const char *sys, struct tracepoint_path *tps) +static int copy_event_system(const char *sys, struct tracepoint_path *tps) { struct dirent *dent; struct stat st; @@ -205,10 +236,13 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps) DIR *dir; int count = 0; int ret; + int err; dir = opendir(sys); - if (!dir) - die("can't read directory '%s'", sys); + if (!dir) { + pr_debug("can't read directory '%s'", sys); + return -errno; + } while ((dent = readdir(dir))) { if (dent->d_type != DT_DIR || @@ -216,7 +250,11 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps) strcmp(dent->d_name, "..") == 0 || !name_in_tp_list(dent->d_name, tps)) continue; - format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); + format = malloc(strlen(sys) + strlen(dent->d_name) + 10); + if (!format) { + err = -ENOMEM; + goto out; + } sprintf(format, "%s/%s/format", sys, dent->d_name); ret = stat(format, &st); free(format); @@ -225,7 +263,11 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps) count++; } - write_or_die(&count, 4); + if (write(output_fd, &count, 4) != 4) { + err = -EIO; + pr_debug("can't write count\n"); + goto out; + } rewinddir(dir); while ((dent = readdir(dir))) { @@ -234,27 +276,45 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps) strcmp(dent->d_name, "..") == 0 || !name_in_tp_list(dent->d_name, tps)) continue; - format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); + format = malloc(strlen(sys) + strlen(dent->d_name) + 10); + if (!format) { + err = -ENOMEM; + goto out; + } sprintf(format, "%s/%s/format", sys, dent->d_name); ret = stat(format, &st); - if (ret >= 0) - record_file(format, 8); - + if (ret >= 0) { + err = record_file(format, 8); + if (err) { + free(format); + goto out; + } + } free(format); } + err = 0; +out: closedir(dir); + return err; } -static void read_ftrace_files(struct tracepoint_path *tps) +static int read_ftrace_files(struct tracepoint_path *tps) { char *path; + int ret; path = get_tracing_file("events/ftrace"); + if (!path) { + pr_debug("can't get tracing/events/ftrace"); + return -ENOMEM; + } - copy_event_system(path, tps); + ret = copy_event_system(path, tps); put_tracing_file(path); + + return ret; } static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) @@ -268,7 +328,7 @@ static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) return false; } -static void read_event_files(struct tracepoint_path *tps) +static int read_event_files(struct tracepoint_path *tps) { struct dirent *dent; struct stat st; @@ -277,12 +337,20 @@ static void read_event_files(struct tracepoint_path *tps) DIR *dir; int count = 0; int ret; + int err; path = get_tracing_file("events"); + if (!path) { + pr_debug("can't get tracing/events"); + return -ENOMEM; + } dir = opendir(path); - if (!dir) - die("can't read directory '%s'", path); + if (!dir) { + err = -errno; + pr_debug("can't read directory '%s'", path); + goto out; + } while ((dent = readdir(dir))) { if (dent->d_type != DT_DIR || @@ -294,7 +362,11 @@ static void read_event_files(struct tracepoint_path *tps) count++; } - write_or_die(&count, 4); + if (write(output_fd, &count, 4) != 4) { + err = -EIO; + pr_debug("can't write count\n"); + goto out; + } rewinddir(dir); while ((dent = readdir(dir))) { @@ -304,56 +376,90 @@ static void read_event_files(struct tracepoint_path *tps) strcmp(dent->d_name, "ftrace") == 0 || !system_in_tp_list(dent->d_name, tps)) continue; - sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); + sys = malloc(strlen(path) + strlen(dent->d_name) + 2); + if (!sys) { + err = -ENOMEM; + goto out; + } sprintf(sys, "%s/%s", path, dent->d_name); ret = stat(sys, &st); if (ret >= 0) { - write_or_die(dent->d_name, strlen(dent->d_name) + 1); - copy_event_system(sys, tps); + ssize_t size = strlen(dent->d_name) + 1; + + if (write(output_fd, dent->d_name, size) != size || + copy_event_system(sys, tps) < 0) { + err = -EIO; + free(sys); + goto out; + } } free(sys); } - + err = 0; +out: closedir(dir); put_tracing_file(path); + + return err; } -static void read_proc_kallsyms(void) +static int read_proc_kallsyms(void) { unsigned int size; const char *path = "/proc/kallsyms"; struct stat st; - int ret; + int ret, err = 0; ret = stat(path, &st); if (ret < 0) { /* not found */ size = 0; - write_or_die(&size, 4); - return; + if (write(output_fd, &size, 4) != 4) + err = -EIO; + return err; } - record_file(path, 4); + return record_file(path, 4); } -static void read_ftrace_printk(void) +static int read_ftrace_printk(void) { unsigned int size; char *path; struct stat st; - int ret; + int ret, err = 0; path = get_tracing_file("printk_formats"); + if (!path) { + pr_debug("can't get tracing/printk_formats"); + return -ENOMEM; + } + ret = stat(path, &st); if (ret < 0) { /* not found */ size = 0; - write_or_die(&size, 4); + if (write(output_fd, &size, 4) != 4) + err = -EIO; goto out; } - record_file(path, 4); + err = record_file(path, 4); out: put_tracing_file(path); + return err; +} + +static void +put_tracepoints_path(struct tracepoint_path *tps) +{ + while (tps) { + struct tracepoint_path *t = tps; + + tps = tps->next; + free(t->name); + free(t->system); + free(t); + } } static struct tracepoint_path * @@ -368,27 +474,17 @@ get_tracepoints_path(struct list_head *pattrs) continue; ++nr_tracepoints; ppath->next = tracepoint_id_to_path(pos->attr.config); - if (!ppath->next) - die("%s\n", "No memory to alloc tracepoints list"); + if (!ppath->next) { + pr_debug("No memory to alloc tracepoints list\n"); + put_tracepoints_path(&path); + return NULL; + } ppath = ppath->next; } return nr_tracepoints > 0 ? path.next : NULL; } -static void -put_tracepoints_path(struct tracepoint_path *tps) -{ - while (tps) { - struct tracepoint_path *t = tps; - - tps = tps->next; - free(t->name); - free(t->system); - free(t); - } -} - bool have_tracepoints(struct list_head *pattrs) { struct perf_evsel *pos; @@ -400,9 +496,10 @@ bool have_tracepoints(struct list_head *pattrs) return false; } -static void tracing_data_header(void) +static int tracing_data_header(void) { char buf[20]; + ssize_t size; /* just guessing this is someone's birthday.. ;) */ buf[0] = 23; @@ -410,9 +507,12 @@ static void tracing_data_header(void) buf[2] = 68; memcpy(buf + 3, "tracing", 7); - write_or_die(buf, 10); + if (write(output_fd, buf, 10) != 10) + return -1; - write_or_die(VERSION, strlen(VERSION) + 1); + size = strlen(VERSION) + 1; + if (write(output_fd, VERSION, size) != size) + return -1; /* save endian */ if (bigendian()) @@ -422,14 +522,19 @@ static void tracing_data_header(void) read_trace_init(buf[0], buf[0]); - write_or_die(buf, 1); + if (write(output_fd, buf, 1) != 1) + return -1; /* save size of long */ buf[0] = sizeof(long); - write_or_die(buf, 1); + if (write(output_fd, buf, 1) != 1) + return -1; /* save page_size */ - write_or_die(&page_size, 4); + if (write(output_fd, &page_size, 4) != 4) + return -1; + + return 0; } struct tracing_data *tracing_data_get(struct list_head *pattrs, @@ -437,6 +542,7 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, { struct tracepoint_path *tps; struct tracing_data *tdata; + int err; output_fd = fd; @@ -444,7 +550,10 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, if (!tps) return NULL; - tdata = malloc_or_die(sizeof(*tdata)); + tdata = malloc(sizeof(*tdata)); + if (!tdata) + return NULL; + tdata->temp = temp; tdata->size = 0; @@ -453,12 +562,16 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, snprintf(tdata->temp_file, sizeof(tdata->temp_file), "/tmp/perf-XXXXXX"); - if (!mkstemp(tdata->temp_file)) - die("Can't make temp file"); + if (!mkstemp(tdata->temp_file)) { + pr_debug("Can't make temp file"); + return NULL; + } temp_fd = open(tdata->temp_file, O_RDWR); - if (temp_fd < 0) - die("Can't read '%s'", tdata->temp_file); + if (temp_fd < 0) { + pr_debug("Can't read '%s'", tdata->temp_file); + return NULL; + } /* * Set the temp file the default output, so all the @@ -467,13 +580,24 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, output_fd = temp_fd; } - tracing_data_header(); - read_header_files(); - read_ftrace_files(tps); - read_event_files(tps); - read_proc_kallsyms(); - read_ftrace_printk(); + err = tracing_data_header(); + if (err) + goto out; + err = read_header_files(); + if (err) + goto out; + err = read_ftrace_files(tps); + if (err) + goto out; + err = read_event_files(tps); + if (err) + goto out; + err = read_proc_kallsyms(); + if (err) + goto out; + err = read_ftrace_printk(); +out: /* * All tracing data are stored by now, we can restore * the default output file in case we used temp file. @@ -484,22 +608,31 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, output_fd = fd; } + if (err) { + free(tdata); + tdata = NULL; + } + put_tracepoints_path(tps); return tdata; } -void tracing_data_put(struct tracing_data *tdata) +int tracing_data_put(struct tracing_data *tdata) { + int err = 0; + if (tdata->temp) { - record_file(tdata->temp_file, 0); + err = record_file(tdata->temp_file, 0); unlink(tdata->temp_file); } free(tdata); + return err; } int read_tracing_data(int fd, struct list_head *pattrs) { + int err; struct tracing_data *tdata; /* @@ -510,6 +643,6 @@ int read_tracing_data(int fd, struct list_head *pattrs) if (!tdata) return -ENOMEM; - tracing_data_put(tdata); - return 0; + err = tracing_data_put(tdata); + return err; } diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 7cb24635adf..af215c0d237 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -18,8 +18,6 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -#define _FILE_OFFSET_BITS 64 - #include <dirent.h> #include <stdio.h> #include <stdlib.h> @@ -45,20 +43,10 @@ int file_bigendian; int host_bigendian; static int long_size; -static ssize_t calc_data_size; +static ssize_t trace_data_size; static bool repipe; -static void *malloc_or_die(int size) -{ - void *ret; - - ret = malloc(size); - if (!ret) - die("malloc"); - return ret; -} - -static int do_read(int fd, void *buf, int size) +static int __do_read(int fd, void *buf, int size) { int rsize = size; @@ -71,8 +59,10 @@ static int do_read(int fd, void *buf, int size) if (repipe) { int retw = write(STDOUT_FILENO, buf, ret); - if (retw <= 0 || retw != ret) - die("repiping input file"); + if (retw <= 0 || retw != ret) { + pr_debug("repiping input file"); + return -1; + } } size -= ret; @@ -82,17 +72,18 @@ static int do_read(int fd, void *buf, int size) return rsize; } -static int read_or_die(void *data, int size) +static int do_read(void *data, int size) { int r; - r = do_read(input_fd, data, size); - if (r <= 0) - die("reading input file (size expected=%d received=%d)", - size, r); + r = __do_read(input_fd, data, size); + if (r <= 0) { + pr_debug("reading input file (size expected=%d received=%d)", + size, r); + return -1; + } - if (calc_data_size) - calc_data_size += r; + trace_data_size += r; return r; } @@ -105,7 +96,7 @@ static void skip(int size) while (size) { r = size > BUFSIZ ? BUFSIZ : size; - read_or_die(buf, r); + do_read(buf, r); size -= r; }; } @@ -114,7 +105,8 @@ static unsigned int read4(struct pevent *pevent) { unsigned int data; - read_or_die(&data, 4); + if (do_read(&data, 4) < 0) + return 0; return __data2host4(pevent, data); } @@ -122,7 +114,8 @@ static unsigned long long read8(struct pevent *pevent) { unsigned long long data; - read_or_die(&data, 8); + if (do_read(&data, 8) < 0) + return 0; return __data2host8(pevent, data); } @@ -136,17 +129,23 @@ static char *read_string(void) for (;;) { r = read(input_fd, &c, 1); - if (r < 0) - die("reading input file"); + if (r < 0) { + pr_debug("reading input file"); + goto out; + } - if (!r) - die("no data"); + if (!r) { + pr_debug("no data"); + goto out; + } if (repipe) { int retw = write(STDOUT_FILENO, &c, 1); - if (retw <= 0 || retw != r) - die("repiping input file string"); + if (retw <= 0 || retw != r) { + pr_debug("repiping input file string"); + goto out; + } } buf[size++] = c; @@ -155,60 +154,79 @@ static char *read_string(void) break; } - if (calc_data_size) - calc_data_size += size; - - str = malloc_or_die(size); - memcpy(str, buf, size); + trace_data_size += size; + str = malloc(size); + if (str) + memcpy(str, buf, size); +out: return str; } -static void read_proc_kallsyms(struct pevent *pevent) +static int read_proc_kallsyms(struct pevent *pevent) { unsigned int size; char *buf; size = read4(pevent); if (!size) - return; + return 0; - buf = malloc_or_die(size + 1); - read_or_die(buf, size); + buf = malloc(size + 1); + if (buf == NULL) + return -1; + + if (do_read(buf, size) < 0) { + free(buf); + return -1; + } buf[size] = '\0'; parse_proc_kallsyms(pevent, buf, size); free(buf); + return 0; } -static void read_ftrace_printk(struct pevent *pevent) +static int read_ftrace_printk(struct pevent *pevent) { unsigned int size; char *buf; + /* it can have 0 size */ size = read4(pevent); if (!size) - return; + return 0; - buf = malloc_or_die(size); - read_or_die(buf, size); + buf = malloc(size); + if (buf == NULL) + return -1; + + if (do_read(buf, size) < 0) { + free(buf); + return -1; + } parse_ftrace_printk(pevent, buf, size); free(buf); + return 0; } -static void read_header_files(struct pevent *pevent) +static int read_header_files(struct pevent *pevent) { unsigned long long size; char *header_event; char buf[BUFSIZ]; + int ret = 0; - read_or_die(buf, 12); + if (do_read(buf, 12) < 0) + return -1; - if (memcmp(buf, "header_page", 12) != 0) - die("did not read header page"); + if (memcmp(buf, "header_page", 12) != 0) { + pr_debug("did not read header page"); + return -1; + } size = read8(pevent); skip(size); @@ -219,70 +237,107 @@ static void read_header_files(struct pevent *pevent) */ long_size = header_page_size_size; - read_or_die(buf, 13); - if (memcmp(buf, "header_event", 13) != 0) - die("did not read header event"); + if (do_read(buf, 13) < 0) + return -1; + + if (memcmp(buf, "header_event", 13) != 0) { + pr_debug("did not read header event"); + return -1; + } size = read8(pevent); - header_event = malloc_or_die(size); - read_or_die(header_event, size); + header_event = malloc(size); + if (header_event == NULL) + return -1; + + if (do_read(header_event, size) < 0) + ret = -1; + free(header_event); + return ret; } -static void read_ftrace_file(struct pevent *pevent, unsigned long long size) +static int read_ftrace_file(struct pevent *pevent, unsigned long long size) { char *buf; - buf = malloc_or_die(size); - read_or_die(buf, size); + buf = malloc(size); + if (buf == NULL) + return -1; + + if (do_read(buf, size) < 0) { + free(buf); + return -1; + } + parse_ftrace_file(pevent, buf, size); free(buf); + return 0; } -static void read_event_file(struct pevent *pevent, char *sys, +static int read_event_file(struct pevent *pevent, char *sys, unsigned long long size) { char *buf; - buf = malloc_or_die(size); - read_or_die(buf, size); + buf = malloc(size); + if (buf == NULL) + return -1; + + if (do_read(buf, size) < 0) { + free(buf); + return -1; + } + parse_event_file(pevent, buf, size, sys); free(buf); + return 0; } -static void read_ftrace_files(struct pevent *pevent) +static int read_ftrace_files(struct pevent *pevent) { unsigned long long size; int count; int i; + int ret; count = read4(pevent); for (i = 0; i < count; i++) { size = read8(pevent); - read_ftrace_file(pevent, size); + ret = read_ftrace_file(pevent, size); + if (ret) + return ret; } + return 0; } -static void read_event_files(struct pevent *pevent) +static int read_event_files(struct pevent *pevent) { unsigned long long size; char *sys; int systems; int count; int i,x; + int ret; systems = read4(pevent); for (i = 0; i < systems; i++) { sys = read_string(); + if (sys == NULL) + return -1; count = read4(pevent); + for (x=0; x < count; x++) { size = read8(pevent); - read_event_file(pevent, sys, size); + ret = read_event_file(pevent, sys, size); + if (ret) + return ret; } } + return 0; } ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) @@ -293,58 +348,85 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) int show_version = 0; int show_funcs = 0; int show_printk = 0; - ssize_t size; + ssize_t size = -1; + struct pevent *pevent; + int err; - calc_data_size = 1; - repipe = __repipe; + *ppevent = NULL; + repipe = __repipe; input_fd = fd; - read_or_die(buf, 3); - if (memcmp(buf, test, 3) != 0) - die("no trace data in the file"); + if (do_read(buf, 3) < 0) + return -1; + if (memcmp(buf, test, 3) != 0) { + pr_debug("no trace data in the file"); + return -1; + } - read_or_die(buf, 7); - if (memcmp(buf, "tracing", 7) != 0) - die("not a trace file (missing 'tracing' tag)"); + if (do_read(buf, 7) < 0) + return -1; + if (memcmp(buf, "tracing", 7) != 0) { + pr_debug("not a trace file (missing 'tracing' tag)"); + return -1; + } version = read_string(); + if (version == NULL) + return -1; if (show_version) printf("version = %s\n", version); free(version); - read_or_die(buf, 1); + if (do_read(buf, 1) < 0) + return -1; file_bigendian = buf[0]; host_bigendian = bigendian(); - *ppevent = read_trace_init(file_bigendian, host_bigendian); - if (*ppevent == NULL) - die("read_trace_init failed"); + pevent = read_trace_init(file_bigendian, host_bigendian); + if (pevent == NULL) { + pr_debug("read_trace_init failed"); + goto out; + } - read_or_die(buf, 1); + if (do_read(buf, 1) < 0) + goto out; long_size = buf[0]; - page_size = read4(*ppevent); - - read_header_files(*ppevent); - - read_ftrace_files(*ppevent); - read_event_files(*ppevent); - read_proc_kallsyms(*ppevent); - read_ftrace_printk(*ppevent); - - size = calc_data_size - 1; - calc_data_size = 0; + page_size = read4(pevent); + if (!page_size) + goto out; + + err = read_header_files(pevent); + if (err) + goto out; + err = read_ftrace_files(pevent); + if (err) + goto out; + err = read_event_files(pevent); + if (err) + goto out; + err = read_proc_kallsyms(pevent); + if (err) + goto out; + err = read_ftrace_printk(pevent); + if (err) + goto out; + + size = trace_data_size; repipe = false; if (show_funcs) { - pevent_print_funcs(*ppevent); - return size; - } - if (show_printk) { - pevent_print_printk(*ppevent); - return size; + pevent_print_funcs(pevent); + } else if (show_printk) { + pevent_print_printk(pevent); } + *ppevent = pevent; + pevent = NULL; + +out: + if (pevent) + pevent_free(pevent); return size; } diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 28ccde8ba20..1978c398ad8 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -68,7 +68,7 @@ struct tracing_data { struct tracing_data *tracing_data_get(struct list_head *pattrs, int fd, bool temp); -void tracing_data_put(struct tracing_data *tdata); +int tracing_data_put(struct tracing_data *tdata); struct addr_location; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 6a0781c3a57..a45710b70a5 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -1,8 +1,6 @@ #ifndef GIT_COMPAT_UTIL_H #define GIT_COMPAT_UTIL_H -#define _FILE_OFFSET_BITS 64 - #ifndef FLEX_ARRAY /* * See if our compiler is known to support flexible array members. |