diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-04-01 07:55:17 (GMT) |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-04-01 07:55:17 (GMT) |
commit | aaa9fa387541a30f6f4138bea6e082319de5e3fe (patch) | |
tree | 43905494fe3c7724b8fe4326a4e820e897e7a7e9 | |
parent | ccd41c86ad4d464d0ed4e48d80759ff85c2115b0 (diff) | |
parent | 9870d7809575515e26194f4b3df1750872a6ee60 (diff) | |
download | linux-aaa9fa387541a30f6f4138bea6e082319de5e3fe.tar.xz |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
User visible changes:
- Fix 'perf script' pipe mode segfault, by always initializing ordered_events in
perf_session__new(). (Arnaldo Carvalho de Melo)
- Fix ppid for synthesized fork events. (David Ahern)
- Fix kernel symbol resolution of callchains in S/390 by remembering the
cpumode. (David Hildenbrand)
Infrastructure changes:
- Disable libbabeltrace check by default in the build system. (Jiri Olsa)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/perf/Makefile.perf | 2 | ||||
-rw-r--r-- | tools/perf/config/Makefile | 5 | ||||
-rw-r--r-- | tools/perf/util/event.c | 147 | ||||
-rw-r--r-- | tools/perf/util/event.h | 1 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 28 | ||||
-rw-r--r-- | tools/perf/util/ordered-events.c | 21 | ||||
-rw-r--r-- | tools/perf/util/ordered-events.h | 14 | ||||
-rw-r--r-- | tools/perf/util/session.c | 48 | ||||
-rw-r--r-- | tools/perf/util/session.h | 1 |
9 files changed, 144 insertions, 123 deletions
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index e9925e6..c43a205 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -69,7 +69,7 @@ include config/utilities.mak # # Define NO_ZLIB if you do not want to support compressed kernel modules # -# Define NO_LIBBABELTRACE if you do not want libbabeltrace support +# Define LIBBABELTRACE if you DO want libbabeltrace support # for CTF data format. # # Define NO_LZMA if you do not want to support compressed (xz) kernel modules diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index cd121df..59a98c6 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -95,7 +95,7 @@ ifndef NO_LIBELF FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw endif -ifndef NO_LIBBABELTRACE +ifdef LIBBABELTRACE # for linking with debug library, run like: # make DEBUG=1 LIBBABELTRACE_DIR=/opt/libbabeltrace/ ifdef LIBBABELTRACE_DIR @@ -598,7 +598,7 @@ else NO_PERF_READ_VDSOX32 := 1 endif -ifndef NO_LIBBABELTRACE +ifdef LIBBABELTRACE $(call feature_check,libbabeltrace) ifeq ($(feature-libbabeltrace), 1) CFLAGS += -DHAVE_LIBBABELTRACE_SUPPORT $(LIBBABELTRACE_CFLAGS) @@ -607,7 +607,6 @@ ifndef NO_LIBBABELTRACE $(call detected,CONFIG_LIBBABELTRACE) else msg := $(warning No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-dev[el]/libbabeltrace-ctf-dev); - NO_LIBBABELTRACE := 1 endif endif diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index d5efa50..5516236 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -49,70 +49,103 @@ static struct perf_sample synth_sample = { .period = 1, }; -static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len) +/* + * Assumes that the first 4095 bytes of /proc/pid/stat contains + * the comm, tgid and ppid. + */ +static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len, + pid_t *tgid, pid_t *ppid) { char filename[PATH_MAX]; - char bf[BUFSIZ]; - FILE *fp; - size_t size = 0; - pid_t tgid = -1; + char bf[4096]; + int fd; + size_t size = 0, n; + char *nl, *name, *tgids, *ppids; + + *tgid = -1; + *ppid = -1; snprintf(filename, sizeof(filename), "/proc/%d/status", pid); - fp = fopen(filename, "r"); - if (fp == NULL) { + fd = open(filename, O_RDONLY); + if (fd < 0) { pr_debug("couldn't open %s\n", filename); - return 0; + return -1; } - while (!comm[0] || (tgid < 0)) { - if (fgets(bf, sizeof(bf), fp) == NULL) { - pr_warning("couldn't get COMM and pgid, malformed %s\n", - filename); - break; - } + n = read(fd, bf, sizeof(bf) - 1); + close(fd); + if (n <= 0) { + pr_warning("Couldn't get COMM, tigd and ppid for pid %d\n", + pid); + return -1; + } + bf[n] = '\0'; - if (memcmp(bf, "Name:", 5) == 0) { - char *name = bf + 5; - while (*name && isspace(*name)) - ++name; - size = strlen(name) - 1; - if (size >= len) - size = len - 1; - memcpy(comm, name, size); - comm[size] = '\0'; - - } else if (memcmp(bf, "Tgid:", 5) == 0) { - char *tgids = bf + 5; - while (*tgids && isspace(*tgids)) - ++tgids; - tgid = atoi(tgids); - } + name = strstr(bf, "Name:"); + tgids = strstr(bf, "Tgid:"); + ppids = strstr(bf, "PPid:"); + + if (name) { + name += 5; /* strlen("Name:") */ + + while (*name && isspace(*name)) + ++name; + + nl = strchr(name, '\n'); + if (nl) + *nl = '\0'; + + size = strlen(name); + if (size >= len) + size = len - 1; + memcpy(comm, name, size); + comm[size] = '\0'; + } else { + pr_debug("Name: string not found for pid %d\n", pid); } - fclose(fp); + if (tgids) { + tgids += 5; /* strlen("Tgid:") */ + *tgid = atoi(tgids); + } else { + pr_debug("Tgid: string not found for pid %d\n", pid); + } - return tgid; + if (ppids) { + ppids += 5; /* strlen("PPid:") */ + *ppid = atoi(ppids); + } else { + pr_debug("PPid: string not found for pid %d\n", pid); + } + + return 0; } -static pid_t perf_event__prepare_comm(union perf_event *event, pid_t pid, - struct machine *machine) +static int perf_event__prepare_comm(union perf_event *event, pid_t pid, + struct machine *machine, + pid_t *tgid, pid_t *ppid) { size_t size; - pid_t tgid; + + *ppid = -1; memset(&event->comm, 0, sizeof(event->comm)); - if (machine__is_host(machine)) - tgid = perf_event__get_comm_tgid(pid, event->comm.comm, - sizeof(event->comm.comm)); - else - tgid = machine->pid; + if (machine__is_host(machine)) { + if (perf_event__get_comm_ids(pid, event->comm.comm, + sizeof(event->comm.comm), + tgid, ppid) != 0) { + return -1; + } + } else { + *tgid = machine->pid; + } - if (tgid < 0) - goto out; + if (*tgid < 0) + return -1; - event->comm.pid = tgid; + event->comm.pid = *tgid; event->comm.header.type = PERF_RECORD_COMM; size = strlen(event->comm.comm) + 1; @@ -122,8 +155,8 @@ static pid_t perf_event__prepare_comm(union perf_event *event, pid_t pid, (sizeof(event->comm.comm) - size) + machine->id_hdr_size); event->comm.tid = pid; -out: - return tgid; + + return 0; } static pid_t perf_event__synthesize_comm(struct perf_tool *tool, @@ -131,27 +164,27 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine) { - pid_t tgid = perf_event__prepare_comm(event, pid, machine); + pid_t tgid, ppid; - if (tgid == -1) - goto out; + if (perf_event__prepare_comm(event, pid, machine, &tgid, &ppid) != 0) + return -1; if (process(tool, event, &synth_sample, machine) != 0) return -1; -out: return tgid; } static int perf_event__synthesize_fork(struct perf_tool *tool, - union perf_event *event, pid_t pid, - pid_t tgid, perf_event__handler_t process, + union perf_event *event, + pid_t pid, pid_t tgid, pid_t ppid, + perf_event__handler_t process, struct machine *machine) { memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size); - event->fork.ppid = tgid; - event->fork.ptid = tgid; + event->fork.ppid = ppid; + event->fork.ptid = ppid; event->fork.pid = tgid; event->fork.tid = pid; event->fork.header.type = PERF_RECORD_FORK; @@ -343,7 +376,7 @@ static int __event__synthesize_thread(union perf_event *comm_event, char filename[PATH_MAX]; DIR *tasks; struct dirent dirent, *next; - pid_t tgid; + pid_t tgid, ppid; /* special case: only send one comm event using passed in pid */ if (!full) { @@ -378,12 +411,12 @@ static int __event__synthesize_thread(union perf_event *comm_event, if (*end) continue; - tgid = perf_event__prepare_comm(comm_event, _pid, machine); - if (tgid == -1) + if (perf_event__prepare_comm(comm_event, _pid, machine, + &tgid, &ppid) != 0) return -1; if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid, - process, machine) < 0) + ppid, process, machine) < 0) return -1; /* * Send the prepared comm event diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index c4ffe2b..09b9e8d 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -242,7 +242,6 @@ struct events_stats { u32 nr_invalid_chains; u32 nr_unknown_id; u32 nr_unprocessable_samples; - u32 nr_unordered_events; }; struct attr_event { diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index e335330..e45c8f3 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1408,29 +1408,27 @@ struct mem_info *sample__resolve_mem(struct perf_sample *sample, static int add_callchain_ip(struct thread *thread, struct symbol **parent, struct addr_location *root_al, - bool branch_history, + u8 *cpumode, u64 ip) { struct addr_location al; al.filtered = 0; al.sym = NULL; - if (branch_history) + if (!cpumode) { thread__find_cpumode_addr_location(thread, MAP__FUNCTION, ip, &al); - else { - u8 cpumode = PERF_RECORD_MISC_USER; - + } else { if (ip >= PERF_CONTEXT_MAX) { switch (ip) { case PERF_CONTEXT_HV: - cpumode = PERF_RECORD_MISC_HYPERVISOR; + *cpumode = PERF_RECORD_MISC_HYPERVISOR; break; case PERF_CONTEXT_KERNEL: - cpumode = PERF_RECORD_MISC_KERNEL; + *cpumode = PERF_RECORD_MISC_KERNEL; break; case PERF_CONTEXT_USER: - cpumode = PERF_RECORD_MISC_USER; + *cpumode = PERF_RECORD_MISC_USER; break; default: pr_debug("invalid callchain context: " @@ -1444,8 +1442,8 @@ static int add_callchain_ip(struct thread *thread, } return 0; } - thread__find_addr_location(thread, cpumode, MAP__FUNCTION, - ip, &al); + thread__find_addr_location(thread, *cpumode, MAP__FUNCTION, + ip, &al); } if (al.sym != NULL) { @@ -1538,6 +1536,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread, { struct ip_callchain *chain = sample->callchain; int chain_nr = min(max_stack, (int)chain->nr); + u8 cpumode = PERF_RECORD_MISC_USER; int i, j, err; u64 ip; @@ -1584,7 +1583,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread, ip = lbr_stack->entries[0].to; } - err = add_callchain_ip(thread, parent, root_al, false, ip); + err = add_callchain_ip(thread, parent, root_al, &cpumode, ip); if (err) return (err < 0) ? err : 0; } @@ -1604,6 +1603,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, struct branch_stack *branch = sample->branch_stack; struct ip_callchain *chain = sample->callchain; int chain_nr = min(max_stack, (int)chain->nr); + u8 cpumode = PERF_RECORD_MISC_USER; int i, j, err; int skip_idx = -1; int first_call = 0; @@ -1669,10 +1669,10 @@ static int thread__resolve_callchain_sample(struct thread *thread, for (i = 0; i < nr; i++) { err = add_callchain_ip(thread, parent, root_al, - true, be[i].to); + NULL, be[i].to); if (!err) err = add_callchain_ip(thread, parent, root_al, - true, be[i].from); + NULL, be[i].from); if (err == -EINVAL) break; if (err) @@ -1701,7 +1701,7 @@ check_calls: #endif ip = chain->ips[j]; - err = add_callchain_ip(thread, parent, root_al, false, ip); + err = add_callchain_ip(thread, parent, root_al, &cpumode, ip); if (err) return (err < 0) ? err : 0; diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index 6002fa3..52be201 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -2,7 +2,6 @@ #include <linux/compiler.h> #include <linux/string.h> #include "ordered-events.h" -#include "evlist.h" #include "session.h" #include "asm/bug.h" #include "debug.h" @@ -167,7 +166,7 @@ int ordered_events__queue(struct ordered_events *oe, union perf_event *event, pr_oe_time(oe->last_flush, "last flush, last_flush_type %d\n", oe->last_flush_type); - oe->evlist->stats.nr_unordered_events++; + oe->nr_unordered_events++; } oevent = ordered_events__new_event(oe, timestamp, event); @@ -187,7 +186,6 @@ static int __ordered_events__flush(struct ordered_events *oe) { struct list_head *head = &oe->events; struct ordered_event *tmp, *iter; - struct perf_sample sample; u64 limit = oe->next_flush; u64 last_ts = oe->last ? oe->last->timestamp : 0ULL; bool show_progress = limit == ULLONG_MAX; @@ -206,15 +204,9 @@ static int __ordered_events__flush(struct ordered_events *oe) if (iter->timestamp > limit) break; - - ret = perf_evlist__parse_sample(oe->evlist, iter->event, &sample); + ret = oe->deliver(oe, iter); if (ret) - pr_err("Can't parse sample, err = %d\n", ret); - else { - ret = oe->deliver(oe, iter, &sample); - if (ret) - return ret; - } + return ret; ordered_events__delete(oe, iter); oe->last_flush = iter->timestamp; @@ -292,18 +284,13 @@ int ordered_events__flush(struct ordered_events *oe, enum oe_flush how) return err; } -void ordered_events__init(struct ordered_events *oe, struct machines *machines, - struct perf_evlist *evlist, struct perf_tool *tool, - ordered_events__deliver_t deliver) +void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t deliver) { INIT_LIST_HEAD(&oe->events); INIT_LIST_HEAD(&oe->cache); INIT_LIST_HEAD(&oe->to_free); oe->max_alloc_size = (u64) -1; oe->cur_alloc_size = 0; - oe->evlist = evlist; - oe->machines = machines; - oe->tool = tool; oe->deliver = deliver; } diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h index 173e13f..f403991 100644 --- a/tools/perf/util/ordered-events.h +++ b/tools/perf/util/ordered-events.h @@ -3,10 +3,7 @@ #include <linux/types.h> -struct perf_tool; -struct perf_evlist; struct perf_sample; -struct machines; struct ordered_event { u64 timestamp; @@ -25,8 +22,7 @@ enum oe_flush { struct ordered_events; typedef int (*ordered_events__deliver_t)(struct ordered_events *oe, - struct ordered_event *event, - struct perf_sample *sample); + struct ordered_event *event); struct ordered_events { u64 last_flush; @@ -39,13 +35,11 @@ struct ordered_events { struct list_head to_free; struct ordered_event *buffer; struct ordered_event *last; - struct machines *machines; - struct perf_evlist *evlist; - struct perf_tool *tool; ordered_events__deliver_t deliver; int buffer_idx; unsigned int nr_events; enum oe_flush last_flush_type; + u32 nr_unordered_events; bool copy_on_queue; }; @@ -53,9 +47,7 @@ int ordered_events__queue(struct ordered_events *oe, union perf_event *event, struct perf_sample *sample, u64 file_offset); void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event); int ordered_events__flush(struct ordered_events *oe, enum oe_flush how); -void ordered_events__init(struct ordered_events *oe, struct machines *machines, - struct perf_evlist *evlsit, struct perf_tool *tool, - ordered_events__deliver_t deliver); +void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t deliver); void ordered_events__free(struct ordered_events *oe); static inline diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index adf0740..dfacf1d 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -93,11 +93,20 @@ static void perf_session__set_comm_exec(struct perf_session *session) } static int ordered_events__deliver_event(struct ordered_events *oe, - struct ordered_event *event, - struct perf_sample *sample) + struct ordered_event *event) { - return machines__deliver_event(oe->machines, oe->evlist, event->event, - sample, oe->tool, event->file_offset); + struct perf_sample sample; + struct perf_session *session = container_of(oe, struct perf_session, + ordered_events); + int ret = perf_evlist__parse_sample(session->evlist, event->event, &sample); + + if (ret) { + pr_err("Can't parse sample, err = %d\n", ret); + return ret; + } + + return machines__deliver_event(&session->machines, session->evlist, event->event, + &sample, session->tool, event->file_offset); } struct perf_session *perf_session__new(struct perf_data_file *file, @@ -109,7 +118,9 @@ struct perf_session *perf_session__new(struct perf_data_file *file, goto out; session->repipe = repipe; + session->tool = tool; machines__init(&session->machines); + ordered_events__init(&session->ordered_events, ordered_events__deliver_event); if (file) { if (perf_data_file__open(file)) @@ -139,9 +150,6 @@ struct perf_session *perf_session__new(struct perf_data_file *file, tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) { dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); tool->ordered_events = false; - } else { - ordered_events__init(&session->ordered_events, &session->machines, - session->evlist, tool, ordered_events__deliver_event); } return session; @@ -941,7 +949,7 @@ static s64 perf_session__process_user_event(struct perf_session *session, u64 file_offset) { struct ordered_events *oe = &session->ordered_events; - struct perf_tool *tool = oe->tool; + struct perf_tool *tool = session->tool; int fd = perf_data_file__fd(session->file); int err; @@ -982,7 +990,7 @@ int perf_session__deliver_synth_event(struct perf_session *session, struct perf_sample *sample) { struct perf_evlist *evlist = session->evlist; - struct perf_tool *tool = session->ordered_events.tool; + struct perf_tool *tool = session->tool; events_stats__inc(&evlist->stats, event->header.type); @@ -1060,7 +1068,7 @@ static s64 perf_session__process_event(struct perf_session *session, union perf_event *event, u64 file_offset) { struct perf_evlist *evlist = session->evlist; - struct perf_tool *tool = session->ordered_events.tool; + struct perf_tool *tool = session->tool; struct perf_sample sample; int ret; @@ -1117,10 +1125,12 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se return thread; } -static void perf_tool__warn_about_errors(const struct perf_tool *tool, - const struct events_stats *stats) +static void perf_session__warn_about_errors(const struct perf_session *session) { - if (tool->lost == perf_event__process_lost && + const struct events_stats *stats = &session->evlist->stats; + const struct ordered_events *oe = &session->ordered_events; + + if (session->tool->lost == perf_event__process_lost && stats->nr_events[PERF_RECORD_LOST] != 0) { ui__warning("Processed %d events and lost %d chunks!\n\n" "Check IO/CPU overload!\n\n", @@ -1156,8 +1166,8 @@ static void perf_tool__warn_about_errors(const struct perf_tool *tool, stats->nr_unprocessable_samples); } - if (stats->nr_unordered_events != 0) - ui__warning("%u out of order events recorded.\n", stats->nr_unordered_events); + if (oe->nr_unordered_events != 0) + ui__warning("%u out of order events recorded.\n", oe->nr_unordered_events); } volatile int session_done; @@ -1165,7 +1175,7 @@ volatile int session_done; static int __perf_session__process_pipe_events(struct perf_session *session) { struct ordered_events *oe = &session->ordered_events; - struct perf_tool *tool = oe->tool; + struct perf_tool *tool = session->tool; int fd = perf_data_file__fd(session->file); union perf_event *event; uint32_t size, cur_size = 0; @@ -1248,7 +1258,7 @@ done: err = ordered_events__flush(oe, OE_FLUSH__FINAL); out_err: free(buf); - perf_tool__warn_about_errors(tool, &session->evlist->stats); + perf_session__warn_about_errors(session); ordered_events__free(&session->ordered_events); return err; } @@ -1298,7 +1308,7 @@ static int __perf_session__process_events(struct perf_session *session, u64 file_size) { struct ordered_events *oe = &session->ordered_events; - struct perf_tool *tool = oe->tool; + struct perf_tool *tool = session->tool; int fd = perf_data_file__fd(session->file); u64 head, page_offset, file_offset, file_pos, size; int err, mmap_prot, mmap_flags, map_idx = 0; @@ -1394,7 +1404,7 @@ out: err = ordered_events__flush(oe, OE_FLUSH__FINAL); out_err: ui_progress__finish(); - perf_tool__warn_about_errors(tool, &session->evlist->stats); + perf_session__warn_about_errors(session); ordered_events__free(&session->ordered_events); session->one_mmap = false; return err; diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 1310998..d5fa7b791 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -26,6 +26,7 @@ struct perf_session { u64 one_mmap_offset; struct ordered_events ordered_events; struct perf_data_file *file; + struct perf_tool *tool; }; #define PRINT_IP_OPT_IP (1<<0) |