diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/build-id.c | 1 | ||||
-rw-r--r-- | tools/perf/util/event.c | 56 | ||||
-rw-r--r-- | tools/perf/util/event.h | 19 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 21 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 16 | ||||
-rw-r--r-- | tools/perf/util/header.c | 3 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 53 | ||||
-rw-r--r-- | tools/perf/util/machine.h | 1 | ||||
-rw-r--r-- | tools/perf/util/map.c | 8 | ||||
-rw-r--r-- | tools/perf/util/map.h | 8 | ||||
-rw-r--r-- | tools/perf/util/session.c | 68 | ||||
-rw-r--r-- | tools/perf/util/tool.h | 1 |
12 files changed, 198 insertions, 57 deletions
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index fb584092eb88..7ded71d19d75 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -67,6 +67,7 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, struct perf_tool build_id__mark_dso_hit_ops = { .sample = build_id__mark_dso_hit, .mmap = perf_event__process_mmap, + .mmap2 = perf_event__process_mmap2, .fork = perf_event__process_fork, .exit = perf_event__exit_del_thread, .attr = perf_event__process_attr, diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 8d51f21107aa..9b393e7dca6f 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -11,6 +11,7 @@ static const char *perf_event__names[] = { [0] = "TOTAL", [PERF_RECORD_MMAP] = "MMAP", + [PERF_RECORD_MMAP2] = "MMAP2", [PERF_RECORD_LOST] = "LOST", [PERF_RECORD_COMM] = "COMM", [PERF_RECORD_EXIT] = "EXIT", @@ -186,7 +187,7 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, return -1; } - event->header.type = PERF_RECORD_MMAP; + event->header.type = PERF_RECORD_MMAP2; /* * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c */ @@ -197,7 +198,9 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, char prot[5]; char execname[PATH_MAX]; char anonstr[] = "//anon"; + unsigned int ino; size_t size; + ssize_t n; if (fgets(bf, sizeof(bf), fp) == NULL) break; @@ -206,9 +209,16 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, strcpy(execname, ""); /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ - sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n", - &event->mmap.start, &event->mmap.len, prot, - &event->mmap.pgoff, execname); + n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n", + &event->mmap2.start, &event->mmap2.len, prot, + &event->mmap2.pgoff, &event->mmap2.maj, + &event->mmap2.min, + &ino, execname); + + event->mmap2.ino = (u64)ino; + + if (n != 8) + continue; if (prot[2] != 'x') continue; @@ -217,15 +227,15 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, strcpy(execname, anonstr); size = strlen(execname) + 1; - memcpy(event->mmap.filename, execname, size); + memcpy(event->mmap2.filename, execname, size); size = PERF_ALIGN(size, sizeof(u64)); - event->mmap.len -= event->mmap.start; - event->mmap.header.size = (sizeof(event->mmap) - - (sizeof(event->mmap.filename) - size)); - memset(event->mmap.filename + size, 0, machine->id_hdr_size); - event->mmap.header.size += machine->id_hdr_size; - event->mmap.pid = tgid; - event->mmap.tid = pid; + event->mmap2.len -= event->mmap.start; + event->mmap2.header.size = (sizeof(event->mmap2) - + (sizeof(event->mmap2.filename) - size)); + memset(event->mmap2.filename + size, 0, machine->id_hdr_size); + event->mmap2.header.size += machine->id_hdr_size; + event->mmap2.pid = tgid; + event->mmap2.tid = pid; if (process(tool, event, &synth_sample, machine) != 0) { rc = -1; @@ -527,6 +537,17 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) event->mmap.len, event->mmap.pgoff, event->mmap.filename); } +size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) +{ + return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 + " %02x:%02x %"PRIu64" %"PRIu64"]: %s\n", + event->mmap2.pid, event->mmap2.tid, event->mmap2.start, + event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj, + event->mmap2.min, event->mmap2.ino, + event->mmap2.ino_generation, + event->mmap2.filename); +} + int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample __maybe_unused, @@ -535,6 +556,14 @@ int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, return machine__process_mmap_event(machine, event); } +int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine) +{ + return machine__process_mmap2_event(machine, event); +} + size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) { return fprintf(fp, "(%d:%d):(%d:%d)\n", @@ -574,6 +603,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp) case PERF_RECORD_MMAP: ret += perf_event__fprintf_mmap(event, fp); break; + case PERF_RECORD_MMAP2: + ret += perf_event__fprintf_mmap2(event, fp); + break; default: ret += fprintf(fp, "\n"); } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 93130d856bf0..c67ecc457d29 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -17,6 +17,19 @@ struct mmap_event { char filename[PATH_MAX]; }; +struct mmap2_event { + struct perf_event_header header; + u32 pid, tid; + u64 start; + u64 len; + u64 pgoff; + u32 maj; + u32 min; + u64 ino; + u64 ino_generation; + char filename[PATH_MAX]; +}; + struct comm_event { struct perf_event_header header; u32 pid, tid; @@ -159,6 +172,7 @@ struct tracing_data_event { union perf_event { struct perf_event_header header; struct mmap_event mmap; + struct mmap2_event mmap2; struct comm_event comm; struct fork_event fork; struct lost_event lost; @@ -208,6 +222,10 @@ int perf_event__process_mmap(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); +int perf_event__process_mmap2(struct perf_tool *tool, + union perf_event *event, + struct perf_sample *sample, + struct machine *machine); int perf_event__process_fork(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, @@ -238,6 +256,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); size_t perf_event__fprintf(union perf_event *event, FILE *fp); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b8727ae45e3b..f9f77bee0b1b 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -64,6 +64,16 @@ void perf_evlist__set_id_pos(struct perf_evlist *evlist) evlist->is_pos = first->is_pos; } +static void perf_evlist__update_id_pos(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + list_for_each_entry(evsel, &evlist->entries, node) + perf_evsel__calc_id_pos(evsel); + + perf_evlist__set_id_pos(evlist); +} + static void perf_evlist__purge(struct perf_evlist *evlist) { struct perf_evsel *pos, *n; @@ -446,20 +456,25 @@ static int perf_evlist__event2id(struct perf_evlist *evlist, static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, union perf_event *event) { + struct perf_evsel *first = perf_evlist__first(evlist); struct hlist_head *head; struct perf_sample_id *sid; int hash; u64 id; if (evlist->nr_entries == 1) - return perf_evlist__first(evlist); + return first; + + if (!first->attr.sample_id_all && + event->header.type != PERF_RECORD_SAMPLE) + return first; if (perf_evlist__event2id(evlist, event, &id)) return NULL; /* Synthesized events have an id of zero */ if (!id) - return perf_evlist__first(evlist); + return first; hash = hash_64(id, PERF_EVLIST__HLIST_BITS); head = &evlist->heads[hash]; @@ -915,6 +930,8 @@ int perf_evlist__open(struct perf_evlist *evlist) struct perf_evsel *evsel; int err; + perf_evlist__update_id_pos(evlist); + list_for_each_entry(evsel, &evlist->entries, node) { err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); if (err < 0) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 3612183e2cc5..0ce9febf1ba0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -27,6 +27,7 @@ static struct { bool sample_id_all; bool exclude_guest; + bool mmap2; } perf_missing_features; #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) @@ -676,8 +677,9 @@ void perf_evsel__config(struct perf_evsel *evsel, if (opts->sample_weight) attr->sample_type |= PERF_SAMPLE_WEIGHT; - attr->mmap = track; - attr->comm = track; + attr->mmap = track; + attr->mmap2 = track && !perf_missing_features.mmap2; + attr->comm = track; /* * XXX see the function comment above @@ -1016,6 +1018,8 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, } fallback_missing_features: + if (perf_missing_features.mmap2) + evsel->attr.mmap2 = 0; if (perf_missing_features.exclude_guest) evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; retry_sample_id: @@ -1080,8 +1084,11 @@ try_fallback: if (err != -EINVAL || cpu > 0 || thread > 0) goto out_close; - if (!perf_missing_features.exclude_guest && - (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { + if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { + perf_missing_features.mmap2 = true; + goto fallback_missing_features; + } else if (!perf_missing_features.exclude_guest && + (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { perf_missing_features.exclude_guest = true; goto fallback_missing_features; } else if (!perf_missing_features.sample_id_all) { @@ -1925,6 +1932,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, if_print(exclude_hv); if_print(exclude_idle); if_print(mmap); + if_print(mmap2); if_print(comm); if_print(freq); if_print(inherit_stat); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index a33197a4fd21..26441d0e571b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1351,6 +1351,9 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip); + fprintf(fp, ", attr_mmap2 = %d", evsel->attr.mmap2); + fprintf(fp, ", attr_mmap = %d", evsel->attr.mmap); + fprintf(fp, ", attr_mmap_data = %d", evsel->attr.mmap_data); if (evsel->ids) { fprintf(fp, ", id = {"); for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) { diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 1dca61f0512d..933d14f287ca 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -997,6 +997,54 @@ out_problem: return -1; } +int machine__process_mmap2_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) + perf_event__fprintf_mmap2(event, stdout); + + if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || + cpumode == PERF_RECORD_MISC_KERNEL) { + ret = machine__process_kernel_mmap_event(machine, event); + if (ret < 0) + goto out_problem; + return 0; + } + + thread = machine__findnew_thread(machine, event->mmap2.pid, + event->mmap2.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->mmap2.start, + event->mmap2.len, event->mmap2.pgoff, + event->mmap2.pid, event->mmap2.maj, + event->mmap2.min, event->mmap2.ino, + event->mmap2.ino_generation, + event->mmap2.filename, type); + + if (map == NULL) + goto out_problem; + + thread__insert_map(thread, map); + return 0; + +out_problem: + dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n"); + return 0; +} + int machine__process_mmap_event(struct machine *machine, union perf_event *event) { u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; @@ -1028,7 +1076,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event map = map__new(&machine->user_dsos, event->mmap.start, event->mmap.len, event->mmap.pgoff, - event->mmap.pid, event->mmap.filename, + event->mmap.pid, 0, 0, 0, 0, + event->mmap.filename, type); if (map == NULL) @@ -1101,6 +1150,8 @@ int machine__process_event(struct machine *machine, union perf_event *event) ret = machine__process_comm_event(machine, event); break; case PERF_RECORD_MMAP: ret = machine__process_mmap_event(machine, event); break; + case PERF_RECORD_MMAP2: + ret = machine__process_mmap2_event(machine, event); break; case PERF_RECORD_FORK: ret = machine__process_fork_event(machine, event); break; case PERF_RECORD_EXIT: diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 0df925ba6a44..58a6be1fc739 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -45,6 +45,7 @@ int machine__process_exit_event(struct machine *machine, union perf_event *event int machine__process_fork_event(struct machine *machine, union perf_event *event); int machine__process_lost_event(struct machine *machine, union perf_event *event); int machine__process_mmap_event(struct machine *machine, union perf_event *event); +int machine__process_mmap2_event(struct machine *machine, union perf_event *event); int machine__process_event(struct machine *machine, union perf_event *event); typedef void (*machine__process_t)(struct machine *machine, void *data); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 9e8304ca343e..4f6680d2043b 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -48,7 +48,8 @@ void map__init(struct map *map, enum map_type type, } struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, - u64 pgoff, u32 pid, char *filename, + u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, + u64 ino_gen, char *filename, enum map_type type) { struct map *map = malloc(sizeof(*map)); @@ -62,6 +63,11 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, vdso = is_vdso_map(filename); no_dso = is_no_dso_memory(filename); + map->maj = d_maj; + map->min = d_min; + map->ino = ino; + map->ino_generation = ino_gen; + if (anon) { snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); filename = newfilename; diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 2cc93cbf0e17..4886ca280536 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -36,6 +36,9 @@ struct map { bool erange_warned; u32 priv; u64 pgoff; + u32 maj, min; /* only valid for MMAP2 record */ + u64 ino; /* only valid for MMAP2 record */ + u64 ino_generation;/* only valid for MMAP2 record */ /* ip -> dso rip */ u64 (*map_ip)(struct map *, u64); @@ -88,8 +91,9 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); void map__init(struct map *map, 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); + u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, + u64 ino_gen, + char *filename, enum map_type type); struct map *map__new2(u64 start, struct dso *dso, enum map_type type); void map__delete(struct map *map); struct map *map__clone(struct map *map); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 1fc0c628683e..51f5edf2a6d0 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -351,6 +351,25 @@ static void perf_event__mmap_swap(union perf_event *event, } } +static void perf_event__mmap2_swap(union perf_event *event, + bool sample_id_all) +{ + event->mmap2.pid = bswap_32(event->mmap2.pid); + event->mmap2.tid = bswap_32(event->mmap2.tid); + event->mmap2.start = bswap_64(event->mmap2.start); + event->mmap2.len = bswap_64(event->mmap2.len); + event->mmap2.pgoff = bswap_64(event->mmap2.pgoff); + event->mmap2.maj = bswap_32(event->mmap2.maj); + event->mmap2.min = bswap_32(event->mmap2.min); + event->mmap2.ino = bswap_64(event->mmap2.ino); + + if (sample_id_all) { + void *data = &event->mmap2.filename; + + data += PERF_ALIGN(strlen(data) + 1, sizeof(u64)); + swap_sample_id_all(event, data); + } +} static void perf_event__task_swap(union perf_event *event, bool sample_id_all) { event->fork.pid = bswap_32(event->fork.pid); @@ -455,6 +474,7 @@ typedef void (*perf_event__swap_op)(union perf_event *event, static perf_event__swap_op perf_event__swap_ops[] = { [PERF_RECORD_MMAP] = perf_event__mmap_swap, + [PERF_RECORD_MMAP2] = perf_event__mmap2_swap, [PERF_RECORD_COMM] = perf_event__comm_swap, [PERF_RECORD_FORK] = perf_event__task_swap, [PERF_RECORD_EXIT] = perf_event__task_swap, @@ -504,6 +524,7 @@ static int flush_sample_queue(struct perf_session *s, u64 limit = os->next_flush; u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; unsigned idx = 0, progress_next = os->nr_samples / 16; + bool show_progress = limit == ULLONG_MAX; int ret; if (!tool->ordered_samples || !limit) @@ -526,7 +547,7 @@ static int flush_sample_queue(struct perf_session *s, os->last_flush = iter->timestamp; list_del(&iter->list); list_add(&iter->list, &os->sample_cache); - if (++idx >= progress_next) { + if (show_progress && (++idx >= progress_next)) { progress_next += os->nr_samples / 16; ui_progress__update(idx, os->nr_samples, "Processing time ordered events..."); @@ -850,7 +871,8 @@ static struct machine * (cpumode == PERF_RECORD_MISC_GUEST_USER))) { u32 pid; - if (event->header.type == PERF_RECORD_MMAP) + if (event->header.type == PERF_RECORD_MMAP + || event->header.type == PERF_RECORD_MMAP2) pid = event->mmap.pid; else pid = sample->pid; @@ -977,6 +999,8 @@ static int perf_session_deliver_event(struct perf_session *session, sample, evsel, machine); case PERF_RECORD_MMAP: return tool->mmap(tool, event, sample, machine); + case PERF_RECORD_MMAP2: + return tool->mmap2(tool, event, sample, machine); case PERF_RECORD_COMM: return tool->comm(tool, event, sample, machine); case PERF_RECORD_FORK: @@ -1619,52 +1643,26 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session, const struct perf_evsel_str_handler *assocs, size_t nr_assocs) { - struct perf_evlist *evlist = session->evlist; - struct event_format *format; struct perf_evsel *evsel; - char *tracepoint, *name; size_t i; int err; for (i = 0; i < nr_assocs; i++) { - err = -ENOMEM; - tracepoint = strdup(assocs[i].name); - if (tracepoint == NULL) - goto out; - - err = -ENOENT; - name = strchr(tracepoint, ':'); - if (name == NULL) - goto out_free; - - *name++ = '\0'; - format = pevent_find_event_by_name(session->pevent, - tracepoint, name); - if (format == NULL) { - /* - * Adding a handler for an event not in the session, - * just ignore it. - */ - goto next; - } - - evsel = perf_evlist__find_tracepoint_by_id(evlist, format->id); + /* + * Adding a handler for an event not in the session, + * just ignore it. + */ + evsel = perf_evlist__find_tracepoint_by_name(session->evlist, assocs[i].name); if (evsel == NULL) - goto next; + continue; err = -EEXIST; if (evsel->handler.func != NULL) - goto out_free; + goto out; evsel->handler.func = assocs[i].handler; -next: - free(tracepoint); } err = 0; out: return err; - -out_free: - free(tracepoint); - goto out; } diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 62b16b6165ba..4385816d3d49 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -29,6 +29,7 @@ struct perf_tool { event_sample sample, read; event_op mmap, + mmap2, comm, fork, exit, |