diff options
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r-- | tools/perf/builtin-record.c | 235 |
1 files changed, 58 insertions, 177 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ac5ddfff445..82260c56db3 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -17,6 +17,7 @@ #include "util/header.h" #include "util/event.h" #include "util/debug.h" +#include "util/symbol.h" #include <unistd.h> #include <sched.h> @@ -109,6 +110,24 @@ static void write_output(void *buf, size_t size) } } +static void write_event(event_t *buf, size_t size) +{ + /* + * Add it to the list of DSOs, so that when we finish this + * record session we can pick the available build-ids. + */ + if (buf->header.type == PERF_RECORD_MMAP) + dsos__findnew(buf->mmap.filename); + + write_output(buf, size); +} + +static int process_synthesized_event(event_t *event) +{ + write_event(event, event->header.size); + return 0; +} + static void mmap_read(struct mmap_data *md) { unsigned int head = mmap_read_head(md); @@ -157,14 +176,14 @@ static void mmap_read(struct mmap_data *md) size = md->mask + 1 - (old & md->mask); old += size; - write_output(buf, size); + write_event(buf, size); } buf = &data[old & md->mask]; size = head - old; old += size; - write_output(buf, size); + write_event(buf, size); md->prev = old; mmap_write_tail(md, old); @@ -191,168 +210,6 @@ static void sig_atexit(void) kill(getpid(), signr); } -static pid_t pid_synthesize_comm_event(pid_t pid, int full) -{ - struct comm_event comm_ev; - char filename[PATH_MAX]; - char bf[BUFSIZ]; - FILE *fp; - size_t size = 0; - DIR *tasks; - struct dirent dirent, *next; - pid_t tgid = 0; - - snprintf(filename, sizeof(filename), "/proc/%d/status", pid); - - fp = fopen(filename, "r"); - if (fp == NULL) { - /* - * We raced with a task exiting - just return: - */ - if (verbose) - fprintf(stderr, "couldn't open %s\n", filename); - return 0; - } - - memset(&comm_ev, 0, sizeof(comm_ev)); - while (!comm_ev.comm[0] || !comm_ev.pid) { - if (fgets(bf, sizeof(bf), fp) == NULL) - goto out_failure; - - if (memcmp(bf, "Name:", 5) == 0) { - char *name = bf + 5; - while (*name && isspace(*name)) - ++name; - size = strlen(name) - 1; - memcpy(comm_ev.comm, name, size++); - } else if (memcmp(bf, "Tgid:", 5) == 0) { - char *tgids = bf + 5; - while (*tgids && isspace(*tgids)) - ++tgids; - tgid = comm_ev.pid = atoi(tgids); - } - } - - comm_ev.header.type = PERF_RECORD_COMM; - size = ALIGN(size, sizeof(u64)); - comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); - - if (!full) { - comm_ev.tid = pid; - - write_output(&comm_ev, comm_ev.header.size); - goto out_fclose; - } - - snprintf(filename, sizeof(filename), "/proc/%d/task", pid); - - tasks = opendir(filename); - while (!readdir_r(tasks, &dirent, &next) && next) { - char *end; - pid = strtol(dirent.d_name, &end, 10); - if (*end) - continue; - - comm_ev.tid = pid; - - write_output(&comm_ev, comm_ev.header.size); - } - closedir(tasks); - -out_fclose: - fclose(fp); - return tgid; - -out_failure: - fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", - filename); - exit(EXIT_FAILURE); -} - -static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid) -{ - char filename[PATH_MAX]; - FILE *fp; - - snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); - - fp = fopen(filename, "r"); - if (fp == NULL) { - /* - * We raced with a task exiting - just return: - */ - if (verbose) - fprintf(stderr, "couldn't open %s\n", filename); - return; - } - while (1) { - char bf[BUFSIZ], *pbf = bf; - struct mmap_event mmap_ev = { - .header = { .type = PERF_RECORD_MMAP }, - }; - int n; - size_t size; - if (fgets(bf, sizeof(bf), fp) == NULL) - break; - - /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ - n = hex2u64(pbf, &mmap_ev.start); - if (n < 0) - continue; - pbf += n + 1; - n = hex2u64(pbf, &mmap_ev.len); - if (n < 0) - continue; - pbf += n + 3; - if (*pbf == 'x') { /* vm_exec */ - char *execname = strchr(bf, '/'); - - /* Catch VDSO */ - if (execname == NULL) - execname = strstr(bf, "[vdso]"); - - if (execname == NULL) - continue; - - size = strlen(execname); - execname[size - 1] = '\0'; /* Remove \n */ - memcpy(mmap_ev.filename, execname, size); - size = ALIGN(size, sizeof(u64)); - mmap_ev.len -= mmap_ev.start; - mmap_ev.header.size = (sizeof(mmap_ev) - - (sizeof(mmap_ev.filename) - size)); - mmap_ev.pid = tgid; - mmap_ev.tid = pid; - - write_output(&mmap_ev, mmap_ev.header.size); - } - } - - fclose(fp); -} - -static void synthesize_all(void) -{ - DIR *proc; - struct dirent dirent, *next; - - proc = opendir("/proc"); - - while (!readdir_r(proc, &dirent, &next) && next) { - char *end; - pid_t pid, tgid; - - pid = strtol(dirent.d_name, &end, 10); - if (*end) /* only interested in proper numerical dirents */ - continue; - - tgid = pid_synthesize_comm_event(pid, 1); - pid_synthesize_mmap_samples(pid, tgid); - } - - closedir(proc); -} - static int group_fd; static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) @@ -363,7 +220,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n h_attr = header->attr[nr]; } else { h_attr = perf_header_attr__new(a); - perf_header__add_attr(header, h_attr); + if (h_attr != NULL) + if (perf_header__add_attr(header, h_attr) < 0) { + perf_header_attr__delete(h_attr); + h_attr = NULL; + } } return h_attr; @@ -424,7 +285,7 @@ try_again: if (fd[nr_cpu][counter] < 0) { int err = errno; - if (err == EPERM) + if (err == EPERM || err == EACCES) die("Permission error - are you root?\n"); else if (err == ENODEV && profile_cpu != -1) die("No such device - did you specify an out-of-range profile CPU?\n"); @@ -451,6 +312,8 @@ try_again: } h_attr = get_header_attr(attr, counter); + if (h_attr == NULL) + die("nomem\n"); if (!file_new) { if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { @@ -464,7 +327,10 @@ try_again: exit(-1); } - perf_header_attr__add_id(h_attr, read_data.id); + if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { + pr_warning("Not enough memory to add id\n"); + exit(-1); + } assert(fd[nr_cpu][counter] >= 0); fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); @@ -525,7 +391,7 @@ static void atexit_header(void) { header->data_size += bytes_written; - perf_header__write(header, output); + perf_header__write(header, output, true); } static int __cmd_record(int argc, const char **argv) @@ -573,12 +439,17 @@ static int __cmd_record(int argc, const char **argv) else header = perf_header__new(); + if (header == NULL) { + pr_err("Not enough memory for reading perf file header\n"); + return -1; + } + if (raw_samples) { - perf_header__feat_trace_info(header); + perf_header__set_feat(header, HEADER_TRACE_INFO); } else { for (i = 0; i < nr_counters; i++) { if (attrs[i].sample_type & PERF_SAMPLE_RAW) { - perf_header__feat_trace_info(header); + perf_header__set_feat(header, HEADER_TRACE_INFO); break; } } @@ -602,24 +473,32 @@ static int __cmd_record(int argc, const char **argv) } if (file_new) - perf_header__write(header, output); + perf_header__write(header, output, false); - if (!system_wide) { - pid_t tgid = pid_synthesize_comm_event(pid, 0); - pid_synthesize_mmap_samples(pid, tgid); - } else - synthesize_all(); + if (!system_wide) + event__synthesize_thread(pid, process_synthesized_event); + else + event__synthesize_threads(process_synthesized_event); if (target_pid == -1 && argc) { pid = fork(); if (pid < 0) - perror("failed to fork"); + die("failed to fork"); if (!pid) { if (execvp(argv[0], (char **)argv)) { perror(argv[0]); exit(-1); } + } else { + /* + * Wait a bit for the execv'ed child to appear + * and be updated in /proc + * FIXME: Do you know a less heuristical solution? + */ + usleep(1000); + event__synthesize_thread(pid, + process_synthesized_event); } child_pid = pid; @@ -729,6 +608,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) { int counter; + symbol__init(0); + argc = parse_options(argc, argv, options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (!argc && target_pid == -1 && !system_wide) |