]> Pileus Git - ~andy/linux/blobdiff - tools/perf/builtin-record.c
Merge branch 'next' of git://git.monstr.eu/linux-2.6-microblaze
[~andy/linux] / tools / perf / builtin-record.c
index 072aaf0369f88cff9ef931b22f8fbcd5aa653b2f..89a5ddcd1ded753e6835c39935989d4c96ac2fdd 100644 (file)
@@ -34,7 +34,9 @@ static int                    output;
 static const char              *output_name                    = "perf.data";
 static int                     group                           = 0;
 static unsigned int            realtime_prio                   = 0;
+static int                     raw_samples                     = 0;
 static int                     system_wide                     = 0;
+static int                     profile_cpu                     = -1;
 static pid_t                   target_pid                      = -1;
 static int                     inherit                         = 1;
 static int                     force                           = 0;
@@ -43,6 +45,7 @@ static int                    call_graph                      = 0;
 static int                     verbose                         = 0;
 static int                     inherit_stat                    = 0;
 static int                     no_samples                      = 0;
+static int                     sample_address                  = 0;
 
 static long                    samples;
 static struct timeval          last_read;
@@ -202,46 +205,48 @@ static void sig_atexit(void)
        kill(getpid(), signr);
 }
 
-static void pid_synthesize_comm_event(pid_t pid, int full)
+static pid_t pid_synthesize_comm_event(pid_t pid, int full)
 {
        struct comm_event comm_ev;
        char filename[PATH_MAX];
        char bf[BUFSIZ];
-       int fd;
-       size_t size;
-       char *field, *sep;
+       FILE *fp;
+       size_t size = 0;
        DIR *tasks;
        struct dirent dirent, *next;
+       pid_t tgid = 0;
 
-       snprintf(filename, sizeof(filename), "/proc/%d/stat", pid);
+       snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
 
-       fd = open(filename, O_RDONLY);
-       if (fd < 0) {
+       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;
-       }
-       if (read(fd, bf, sizeof(bf)) < 0) {
-               fprintf(stderr, "couldn't read %s\n", filename);
-               exit(EXIT_FAILURE);
+               return 0;
        }
-       close(fd);
 
-       /* 9027 (cat) R 6747 9027 6747 34816 9027 ... */
        memset(&comm_ev, 0, sizeof(comm_ev));
-       field = strchr(bf, '(');
-       if (field == NULL)
-               goto out_failure;
-       sep = strchr(++field, ')');
-       if (sep == NULL)
-               goto out_failure;
-       size = sep - field;
-       memcpy(comm_ev.comm, field, size++);
-
-       comm_ev.pid = pid;
+       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_EVENT_COMM;
        size = ALIGN(size, sizeof(u64));
        comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
@@ -250,7 +255,7 @@ static void pid_synthesize_comm_event(pid_t pid, int full)
                comm_ev.tid = pid;
 
                write_output(&comm_ev, comm_ev.header.size);
-               return;
+               goto out_fclose;
        }
 
        snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
@@ -267,7 +272,10 @@ static void pid_synthesize_comm_event(pid_t pid, int full)
                write_output(&comm_ev, comm_ev.header.size);
        }
        closedir(tasks);
-       return;
+
+out_fclose:
+       fclose(fp);
+       return tgid;
 
 out_failure:
        fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
@@ -275,7 +283,7 @@ out_failure:
        exit(EXIT_FAILURE);
 }
 
-static void pid_synthesize_mmap_samples(pid_t pid)
+static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
 {
        char filename[PATH_MAX];
        FILE *fp;
@@ -327,7 +335,7 @@ static void pid_synthesize_mmap_samples(pid_t pid)
                        mmap_ev.len -= mmap_ev.start;
                        mmap_ev.header.size = (sizeof(mmap_ev) -
                                               (sizeof(mmap_ev.filename) - size));
-                       mmap_ev.pid = pid;
+                       mmap_ev.pid = tgid;
                        mmap_ev.tid = pid;
 
                        write_output(&mmap_ev, mmap_ev.header.size);
@@ -346,14 +354,14 @@ static void synthesize_all(void)
 
        while (!readdir_r(proc, &dirent, &next) && next) {
                char *end;
-               pid_t pid;
+               pid_t pid, tgid;
 
                pid = strtol(dirent.d_name, &end, 10);
                if (*end) /* only interested in proper numerical dirents */
                        continue;
 
-               pid_synthesize_comm_event(pid, 1);
-               pid_synthesize_mmap_samples(pid);
+               tgid = pid_synthesize_comm_event(pid, 1);
+               pid_synthesize_mmap_samples(pid, tgid);
        }
 
        closedir(proc);
@@ -391,7 +399,7 @@ static void create_counter(int counter, int cpu, pid_t pid)
                                  PERF_FORMAT_TOTAL_TIME_RUNNING |
                                  PERF_FORMAT_ID;
 
-       attr->sample_type       = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
+       attr->sample_type       |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
 
        if (freq) {
                attr->sample_type       |= PERF_SAMPLE_PERIOD;
@@ -405,9 +413,15 @@ static void create_counter(int counter, int cpu, pid_t pid)
        if (inherit_stat)
                attr->inherit_stat = 1;
 
+       if (sample_address)
+               attr->sample_type       |= PERF_SAMPLE_ADDR;
+
        if (call_graph)
                attr->sample_type       |= PERF_SAMPLE_CALLCHAIN;
 
+       if (raw_samples)
+               attr->sample_type       |= PERF_SAMPLE_RAW;
+
        attr->mmap              = track;
        attr->comm              = track;
        attr->inherit           = (cpu < 0) && inherit;
@@ -421,6 +435,8 @@ try_again:
 
                if (err == EPERM)
                        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");
 
                /*
                 * If it's cycles then fall back to hrtimer
@@ -520,10 +536,14 @@ static int __cmd_record(int argc, const char **argv)
        signal(SIGCHLD, sig_handler);
        signal(SIGINT, sig_handler);
 
-       if (!stat(output_name, &st) && !force && !append_file) {
-               fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n",
-                               output_name);
-               exit(-1);
+       if (!stat(output_name, &st) && st.st_size) {
+               if (!force && !append_file) {
+                       fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n",
+                                       output_name);
+                       exit(-1);
+               }
+       } else {
+               append_file = 0;
        }
 
        flags = O_CREAT|O_RDWR;
@@ -550,16 +570,22 @@ static int __cmd_record(int argc, const char **argv)
                if (pid == -1)
                        pid = getpid();
 
-               open_counters(-1, pid);
-       } else for (i = 0; i < nr_cpus; i++)
-               open_counters(i, target_pid);
+               open_counters(profile_cpu, pid);
+       } else {
+               if (profile_cpu != -1) {
+                       open_counters(profile_cpu, target_pid);
+               } else {
+                       for (i = 0; i < nr_cpus; i++)
+                               open_counters(i, target_pid);
+               }
+       }
 
        if (file_new)
                perf_header__write(header, output);
 
        if (!system_wide) {
-               pid_synthesize_comm_event(pid, 0);
-               pid_synthesize_mmap_samples(pid);
+               pid_t tgid = pid_synthesize_comm_event(pid, 0);
+               pid_synthesize_mmap_samples(pid, tgid);
        } else
                synthesize_all();
 
@@ -627,10 +653,14 @@ static const struct option options[] = {
                    "record events on existing pid"),
        OPT_INTEGER('r', "realtime", &realtime_prio,
                    "collect data with this RT SCHED_FIFO priority"),
+       OPT_BOOLEAN('R', "raw-samples", &raw_samples,
+                   "collect raw sample records from all opened counters"),
        OPT_BOOLEAN('a', "all-cpus", &system_wide,
                            "system-wide collection from all CPUs"),
        OPT_BOOLEAN('A', "append", &append_file,
                            "append to the output file to do incremental profiling"),
+       OPT_INTEGER('C', "profile_cpu", &profile_cpu,
+                           "CPU to profile on"),
        OPT_BOOLEAN('f', "force", &force,
                        "overwrite existing data file"),
        OPT_LONG('c', "count", &default_interval,
@@ -649,6 +679,8 @@ static const struct option options[] = {
                    "be more verbose (show counter open errors, etc)"),
        OPT_BOOLEAN('s', "stat", &inherit_stat,
                    "per thread counts"),
+       OPT_BOOLEAN('d', "data", &sample_address,
+                   "Sample addresses"),
        OPT_BOOLEAN('n', "no-samples", &no_samples,
                    "don't sample"),
        OPT_END()
@@ -658,7 +690,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
 {
        int counter;
 
-       argc = parse_options(argc, argv, options, record_usage, 0);
+       argc = parse_options(argc, argv, options, record_usage,
+               PARSE_OPT_STOP_AT_NON_OPTION);
        if (!argc && target_pid == -1 && !system_wide)
                usage_with_options(record_usage, options);