]> Pileus Git - ~andy/linux/blobdiff - tools/perf/builtin-report.c
perf tools: Librarize idle thread registration
[~andy/linux] / tools / perf / builtin-report.c
index 3b9d24dc0edadfbf2469dcab426881d8365ae65c..cdf9a8d27bb9929c1b546d9545b332945034c583 100644 (file)
@@ -20,6 +20,7 @@
 #include "util/values.h"
 
 #include "perf.h"
+#include "util/debug.h"
 #include "util/header.h"
 
 #include "util/parse-options.h"
 
 #include "util/thread.h"
 
-#define SHOW_KERNEL    1
-#define SHOW_USER      2
-#define SHOW_HV                4
-
 static char            const *input_name = "perf.data";
 
 static char            default_sort_order[] = "comm,dso,symbol";
@@ -40,13 +37,10 @@ static char         *dso_list_str, *comm_list_str, *sym_list_str,
 static struct strlist  *dso_list, *comm_list, *sym_list;
 static char            *field_sep;
 
+static int             force;
 static int             input;
 static int             show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
 
-static int             dump_trace = 0;
-#define dprintf(x...)  do { if (dump_trace) printf(x); } while (0)
-#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0)
-
 static int             full_paths;
 static int             show_nr_samples;
 
@@ -76,6 +70,8 @@ static int            cwdlen;
 static struct rb_root  threads;
 static struct thread   *last_match;
 
+static struct perf_header *header;
+
 static
 struct callchain_param callchain_param = {
        .mode   = CHAIN_GRAPH_REL,
@@ -670,6 +666,34 @@ static void dso__calc_col_width(struct dso *self)
        self->slen_calculated = 1;
 }
 
+static void thread__comm_adjust(struct thread *self)
+{
+       char *comm = self->comm;
+
+       if (!col_width_list_str && !field_sep &&
+           (!comm_list || strlist__has_entry(comm_list, comm))) {
+               unsigned int slen = strlen(comm);
+
+               if (slen > comms__col_width) {
+                       comms__col_width = slen;
+                       threads__col_width = slen + 6;
+               }
+       }
+}
+
+static int thread__set_comm_adjust(struct thread *self, const char *comm)
+{
+       int ret = thread__set_comm(self, comm);
+
+       if (ret)
+               return ret;
+
+       thread__comm_adjust(self);
+
+       return 0;
+}
+
+
 static struct symbol *
 resolve_symbol(struct thread *thread, struct map **mapp,
               struct dso **dsop, u64 *ipp)
@@ -713,8 +737,8 @@ got_map:
                if ((long long)ip < 0)
                dso = kernel_dso;
        }
-       dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
-       dprintf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
+       dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
+       dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
        *ipp  = ip;
 
        if (dsop)
@@ -1056,17 +1080,6 @@ print_entries:
        return ret;
 }
 
-static void register_idle_thread(void)
-{
-       struct thread *thread = threads__findnew(0, &threads, &last_match);
-
-       if (thread == NULL ||
-                       thread__set_comm(thread, "[idle]")) {
-               fprintf(stderr, "problem inserting idle task.\n");
-               exit(-1);
-       }
-}
-
 static unsigned long total = 0,
                     total_mmap = 0,
                     total_comm = 0,
@@ -1108,7 +1121,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
                more_data += sizeof(u64);
        }
 
-       dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
+       dump_printf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
                (void *)(offset + head),
                (void *)(long)(event->header.size),
                event->header.misc,
@@ -1121,7 +1134,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 
                chain = (void *)more_data;
 
-               dprintf("... chain: nr:%Lu\n", chain->nr);
+               dump_printf("... chain: nr:%Lu\n", chain->nr);
 
                if (validate_chain(chain, event) < 0) {
                        eprintf("call-chain problem with event, skipping it.\n");
@@ -1130,11 +1143,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 
                if (dump_trace) {
                        for (i = 0; i < chain->nr; i++)
-                               dprintf("..... %2d: %016Lx\n", i, chain->ips[i]);
+                               dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]);
                }
        }
 
-       dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
+       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
 
        if (thread == NULL) {
                eprintf("problem processing %d event, skipping it.\n",
@@ -1153,7 +1166,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 
                dso = kernel_dso;
 
-               dprintf(" ...... dso: %s\n", dso->name);
+               dump_printf(" ...... dso: %s\n", dso->name);
 
        } else if (cpumode == PERF_EVENT_MISC_USER) {
 
@@ -1166,7 +1179,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 
                dso = hypervisor_dso;
 
-               dprintf(" ...... dso: [hypervisor]\n");
+               dump_printf(" ...... dso: [hypervisor]\n");
        }
 
        if (show & show_mask) {
@@ -1197,7 +1210,7 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
 
        thread = threads__findnew(event->mmap.pid, &threads, &last_match);
 
-       dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
+       dump_printf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
                (void *)(offset + head),
                (void *)(long)(event->header.size),
                event->mmap.pid,
@@ -1208,7 +1221,7 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
                event->mmap.filename);
 
        if (thread == NULL || map == NULL) {
-               dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n");
+               dump_printf("problem processing PERF_EVENT_MMAP, skipping event.\n");
                return 0;
        }
 
@@ -1225,14 +1238,14 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
 
        thread = threads__findnew(event->comm.pid, &threads, &last_match);
 
-       dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
+       dump_printf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
                (void *)(offset + head),
                (void *)(long)(event->header.size),
                event->comm.comm, event->comm.pid);
 
        if (thread == NULL ||
-           thread__set_comm(thread, event->comm.comm)) {
-               dprintf("problem processing PERF_EVENT_COMM, skipping event.\n");
+           thread__set_comm_adjust(thread, event->comm.comm)) {
+               dump_printf("problem processing PERF_EVENT_COMM, skipping event.\n");
                return -1;
        }
        total_comm++;
@@ -1249,7 +1262,7 @@ process_task_event(event_t *event, unsigned long offset, unsigned long head)
        thread = threads__findnew(event->fork.pid, &threads, &last_match);
        parent = threads__findnew(event->fork.ppid, &threads, &last_match);
 
-       dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
+       dump_printf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
                (void *)(offset + head),
                (void *)(long)(event->header.size),
                event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT",
@@ -1267,7 +1280,7 @@ process_task_event(event_t *event, unsigned long offset, unsigned long head)
                return 0;
 
        if (!thread || !parent || thread__fork(thread, parent)) {
-               dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
+               dump_printf("problem processing PERF_EVENT_FORK, skipping event.\n");
                return -1;
        }
        total_fork++;
@@ -1278,7 +1291,7 @@ process_task_event(event_t *event, unsigned long offset, unsigned long head)
 static int
 process_lost_event(event_t *event, unsigned long offset, unsigned long head)
 {
-       dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
+       dump_printf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
                (void *)(offset + head),
                (void *)(long)(event->header.size),
                event->lost.id,
@@ -1289,65 +1302,12 @@ process_lost_event(event_t *event, unsigned long offset, unsigned long head)
        return 0;
 }
 
-static void trace_event(event_t *event)
-{
-       unsigned char *raw_event = (void *)event;
-       const char *color = PERF_COLOR_BLUE;
-       int i, j;
-
-       if (!dump_trace)
-               return;
-
-       dprintf(".");
-       cdprintf("\n. ... raw event: size %d bytes\n", event->header.size);
-
-       for (i = 0; i < event->header.size; i++) {
-               if ((i & 15) == 0) {
-                       dprintf(".");
-                       cdprintf("  %04x: ", i);
-               }
-
-               cdprintf(" %02x", raw_event[i]);
-
-               if (((i & 15) == 15) || i == event->header.size-1) {
-                       cdprintf("  ");
-                       for (j = 0; j < 15-(i & 15); j++)
-                               cdprintf("   ");
-                       for (j = 0; j < (i & 15); j++) {
-                               if (isprint(raw_event[i-15+j]))
-                                       cdprintf("%c", raw_event[i-15+j]);
-                               else
-                                       cdprintf(".");
-                       }
-                       cdprintf("\n");
-               }
-       }
-       dprintf(".\n");
-}
-
-static struct perf_header      *header;
-
-static struct perf_counter_attr *perf_header__find_attr(u64 id)
-{
-       int i;
-
-       for (i = 0; i < header->attrs; i++) {
-               struct perf_header_attr *attr = header->attr[i];
-               int j;
-
-               for (j = 0; j < attr->ids; j++) {
-                       if (attr->id[j] == id)
-                               return &attr->attr;
-               }
-       }
-
-       return NULL;
-}
-
 static int
 process_read_event(event_t *event, unsigned long offset, unsigned long head)
 {
-       struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
+       struct perf_counter_attr *attr;
+
+       attr = perf_header__find_attr(event->read.id, header);
 
        if (show_threads) {
                const char *name = attr ? __event_name(attr->type, attr->config)
@@ -1359,7 +1319,7 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
                                           event->read.value);
        }
 
-       dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
+       dump_printf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
                        (void *)(offset + head),
                        (void *)(long)(event->header.size),
                        event->read.pid,
@@ -1411,34 +1371,19 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
        return 0;
 }
 
-static u64 perf_header__sample_type(void)
-{
-       u64 type = 0;
-       int i;
-
-       for (i = 0; i < header->attrs; i++) {
-               struct perf_header_attr *attr = header->attr[i];
-
-               if (!type)
-                       type = attr->attr.sample_type;
-               else if (type != attr->attr.sample_type)
-                       die("non matching sample_type");
-       }
-
-       return type;
-}
-
 static int __cmd_report(void)
 {
        int ret, rc = EXIT_FAILURE;
        unsigned long offset = 0;
        unsigned long head, shift;
        struct stat input_stat;
+       struct thread *idle;
        event_t *event;
        uint32_t size;
        char *buf;
 
-       register_idle_thread();
+       idle = register_idle_thread(&threads, &last_match);
+       thread__comm_adjust(idle);
 
        if (show_threads)
                perf_read_values_init(&show_threads_values);
@@ -1458,6 +1403,11 @@ static int __cmd_report(void)
                exit(-1);
        }
 
+       if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
+               fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
+               exit(-1);
+       }
+
        if (!input_stat.st_size) {
                fprintf(stderr, "zero-sized file, nothing to do!\n");
                exit(0);
@@ -1466,7 +1416,7 @@ static int __cmd_report(void)
        header = perf_header__read(input);
        head = header->data_offset;
 
-       sample_type = perf_header__sample_type();
+       sample_type = perf_header__sample_type(header);
 
        if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
                if (sort__has_parent) {
@@ -1476,7 +1426,7 @@ static int __cmd_report(void)
                        exit(-1);
                }
                if (callchain) {
-                       fprintf(stderr, "selected -c but no callchain data."
+                       fprintf(stderr, "selected -g but no callchain data."
                                        " Did you call perf record without"
                                        " -g?\n");
                        exit(-1);
@@ -1540,14 +1490,14 @@ more:
 
        size = event->header.size;
 
-       dprintf("\n%p [%p]: event: %d\n",
+       dump_printf("\n%p [%p]: event: %d\n",
                        (void *)(offset + head),
                        (void *)(long)event->header.size,
                        event->header.type);
 
        if (!size || process_event(event, offset, head) < 0) {
 
-               dprintf("%p [%p]: skipping unknown header type: %d\n",
+               dump_printf("%p [%p]: skipping unknown header type: %d\n",
                        (void *)(offset + head),
                        (void *)(long)(event->header.size),
                        event->header.type);
@@ -1577,12 +1527,12 @@ done:
        rc = EXIT_SUCCESS;
        close(input);
 
-       dprintf("      IP events: %10ld\n", total);
-       dprintf("    mmap events: %10ld\n", total_mmap);
-       dprintf("    comm events: %10ld\n", total_comm);
-       dprintf("    fork events: %10ld\n", total_fork);
-       dprintf("    lost events: %10ld\n", total_lost);
-       dprintf(" unknown events: %10ld\n", total_unknown);
+       dump_printf("      IP events: %10ld\n", total);
+       dump_printf("    mmap events: %10ld\n", total_mmap);
+       dump_printf("    comm events: %10ld\n", total_comm);
+       dump_printf("    fork events: %10ld\n", total_fork);
+       dump_printf("    lost events: %10ld\n", total_lost);
+       dump_printf(" unknown events: %10ld\n", total_unknown);
 
        if (dump_trace)
                return 0;
@@ -1669,6 +1619,7 @@ static const struct option options[] = {
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
                    "dump raw trace in ASCII"),
        OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
+       OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
        OPT_BOOLEAN('m', "modules", &modules,
                    "load module symbols - WARNING: use only with -k and LIVE kernel"),
        OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,