perf tools: perf_header__read() shouldn't die()
[linux-2.6.git] / tools / perf / builtin-timechart.c
index 23b3f09..dd4d82a 100644 (file)
@@ -46,6 +46,8 @@ static u64            turbo_frequency;
 
 static u64             first_time, last_time;
 
+static int             power_only;
+
 
 static struct perf_header      *header;
 
@@ -151,6 +153,17 @@ static struct wake_event     *wake_events;
 
 struct sample_wrapper *all_samples;
 
+
+struct process_filter;
+struct process_filter {
+       char                    *name;
+       int                     pid;
+       struct process_filter   *next;
+};
+
+static struct process_filter *process_filter;
+
+
 static struct per_pid *find_create_pid(int pid)
 {
        struct per_pid *cursor = all_data;
@@ -547,7 +560,7 @@ static void end_sample_processing(void)
        u64 cpu;
        struct power_event *pwr;
 
-       for (cpu = 0; cpu < numcpus; cpu++) {
+       for (cpu = 0; cpu <= numcpus; cpu++) {
                pwr = malloc(sizeof(struct power_event));
                if (!pwr)
                        return;
@@ -761,21 +774,42 @@ static void draw_wakeups(void)
                                c = p->all;
                                while (c) {
                                        if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
-                                               if (p->pid == we->waker) {
+                                               if (p->pid == we->waker && !from) {
                                                        from = c->Y;
-                                                       task_from = c->comm;
+                                                       task_from = strdup(c->comm);
                                                }
-                                               if (p->pid == we->wakee) {
+                                               if (p->pid == we->wakee && !to) {
                                                        to = c->Y;
-                                                       task_to = c->comm;
+                                                       task_to = strdup(c->comm);
                                                }
                                        }
                                        c = c->next;
                                }
+                               c = p->all;
+                               while (c) {
+                                       if (p->pid == we->waker && !from) {
+                                               from = c->Y;
+                                               task_from = strdup(c->comm);
+                                       }
+                                       if (p->pid == we->wakee && !to) {
+                                               to = c->Y;
+                                               task_to = strdup(c->comm);
+                                       }
+                                       c = c->next;
+                               }
                        }
                        p = p->next;
                }
 
+               if (!task_from) {
+                       task_from = malloc(40);
+                       sprintf(task_from, "[%i]", we->waker);
+               }
+               if (!task_to) {
+                       task_to = malloc(40);
+                       sprintf(task_to, "[%i]", we->wakee);
+               }
+
                if (we->waker == -1)
                        svg_interrupt(we->time, to);
                else if (from && to && abs(from - to) == 1)
@@ -783,6 +817,9 @@ static void draw_wakeups(void)
                else
                        svg_partial_wakeline(we->time, from, task_from, to, task_to);
                we = we->next;
+
+               free(task_from);
+               free(task_to);
        }
 }
 
@@ -856,12 +893,89 @@ static void draw_process_bars(void)
        }
 }
 
+static void add_process_filter(const char *string)
+{
+       struct process_filter *filt;
+       int pid;
+
+       pid = strtoull(string, NULL, 10);
+       filt = malloc(sizeof(struct process_filter));
+       if (!filt)
+               return;
+
+       filt->name = strdup(string);
+       filt->pid  = pid;
+       filt->next = process_filter;
+
+       process_filter = filt;
+}
+
+static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
+{
+       struct process_filter *filt;
+       if (!process_filter)
+               return 1;
+
+       filt = process_filter;
+       while (filt) {
+               if (filt->pid && p->pid == filt->pid)
+                       return 1;
+               if (strcmp(filt->name, c->comm) == 0)
+                       return 1;
+               filt = filt->next;
+       }
+       return 0;
+}
+
+static int determine_display_tasks_filtered(void)
+{
+       struct per_pid *p;
+       struct per_pidcomm *c;
+       int count = 0;
+
+       p = all_data;
+       while (p) {
+               p->display = 0;
+               if (p->start_time == 1)
+                       p->start_time = first_time;
+
+               /* no exit marker, task kept running to the end */
+               if (p->end_time == 0)
+                       p->end_time = last_time;
+
+               c = p->all;
+
+               while (c) {
+                       c->display = 0;
+
+                       if (c->start_time == 1)
+                               c->start_time = first_time;
+
+                       if (passes_filter(p, c)) {
+                               c->display = 1;
+                               p->display = 1;
+                               count++;
+                       }
+
+                       if (c->end_time == 0)
+                               c->end_time = last_time;
+
+                       c = c->next;
+               }
+               p = p->next;
+       }
+       return count;
+}
+
 static int determine_display_tasks(u64 threshold)
 {
        struct per_pid *p;
        struct per_pidcomm *c;
        int count = 0;
 
+       if (process_filter)
+               return determine_display_tasks_filtered();
+
        p = all_data;
        while (p) {
                p->display = 0;
@@ -871,7 +985,7 @@ static int determine_display_tasks(u64 threshold)
                /* no exit marker, task kept running to the end */
                if (p->end_time == 0)
                        p->end_time = last_time;
-               if (p->total_time >= threshold)
+               if (p->total_time >= threshold && !power_only)
                        p->display = 1;
 
                c = p->all;
@@ -882,7 +996,7 @@ static int determine_display_tasks(u64 threshold)
                        if (c->start_time == 1)
                                c->start_time = first_time;
 
-                       if (c->total_time >= threshold) {
+                       if (c->total_time >= threshold && !power_only) {
                                c->display = 1;
                                count++;
                        }
@@ -915,9 +1029,9 @@ static void write_svg_file(const char *filename)
        if (count < 15)
                count = determine_display_tasks(TIME_THRESH / 10);
 
-       open_svg(filename, numcpus, count);
+       open_svg(filename, numcpus, count, first_time, last_time);
 
-       svg_time_grid(first_time, last_time);
+       svg_time_grid();
        svg_legenda();
 
        for (i = 0; i < numcpus; i++)
@@ -937,21 +1051,21 @@ process_event(event_t *event)
 
        switch (event->header.type) {
 
-       case PERF_EVENT_COMM:
+       case PERF_RECORD_COMM:
                return process_comm_event(event);
-       case PERF_EVENT_FORK:
+       case PERF_RECORD_FORK:
                return process_fork_event(event);
-       case PERF_EVENT_EXIT:
+       case PERF_RECORD_EXIT:
                return process_exit_event(event);
-       case PERF_EVENT_SAMPLE:
+       case PERF_RECORD_SAMPLE:
                return queue_sample_event(event);
 
        /*
         * We dont process them right now but they are fine:
         */
-       case PERF_EVENT_MMAP:
-       case PERF_EVENT_THROTTLE:
-       case PERF_EVENT_UNTHROTTLE:
+       case PERF_RECORD_MMAP:
+       case PERF_RECORD_THROTTLE:
+       case PERF_RECORD_UNTHROTTLE:
                return 0;
 
        default:
@@ -979,7 +1093,7 @@ static void process_samples(void)
 
 static int __cmd_timechart(void)
 {
-       int ret, rc = EXIT_FAILURE;
+       int err, rc = EXIT_FAILURE;
        unsigned long offset = 0;
        unsigned long head, shift;
        struct stat statbuf;
@@ -997,8 +1111,8 @@ static int __cmd_timechart(void)
                exit(-1);
        }
 
-       ret = fstat(input, &statbuf);
-       if (ret < 0) {
+       err = fstat(input, &statbuf);
+       if (err < 0) {
                perror("failed to stat file");
                exit(-1);
        }
@@ -1008,7 +1122,16 @@ static int __cmd_timechart(void)
                exit(0);
        }
 
-       header = perf_header__read(input);
+       header = perf_header__new();
+       if (header == NULL)
+               return -ENOMEM;
+
+       err = perf_header__read(header, input);
+       if (err < 0) {
+               perf_header__delete(header);
+               return err;
+       }
+
        head = header->data_offset;
 
        sample_type = perf_header__sample_type(header);
@@ -1048,12 +1171,10 @@ more:
        size = event->header.size;
 
        if (!size || process_event(event) < 0) {
-
-               printf("%p [%p]: skipping unknown header type: %d\n",
-                       (void *)(offset + head),
-                       (void *)(long)(event->header.size),
-                       event->header.type);
-
+               pr_warning("%p [%p]: skipping unknown header type: %d\n",
+                          (void *)(offset + head),
+                          (void *)(long)(event->header.size),
+                          event->header.type);
                /*
                 * assume we lost track of the stream, check alignment, and
                 * increment a single u64 in the hope to catch on again 'soon'.
@@ -1086,7 +1207,8 @@ done:
 
        write_svg_file(output_name);
 
-       printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name);
+       pr_info("Written %2.1f seconds of trace to %s.\n",
+               (last_time - first_time) / 1000000000.0, output_name);
 
        return rc;
 }
@@ -1127,18 +1249,33 @@ static int __cmd_record(int argc, const char **argv)
        return cmd_record(i, rec_argv, NULL);
 }
 
+static int
+parse_process(const struct option *opt __used, const char *arg, int __used unset)
+{
+       if (arg)
+               add_process_filter(arg);
+       return 0;
+}
+
 static const struct option options[] = {
        OPT_STRING('i', "input", &input_name, "file",
                    "input file name"),
        OPT_STRING('o', "output", &output_name, "file",
                    "output file name"),
+       OPT_INTEGER('w', "width", &svg_page_width,
+                   "page width"),
+       OPT_BOOLEAN('P', "power-only", &power_only,
+                   "output power data only"),
+       OPT_CALLBACK('p', "process", NULL, "process",
+                     "process selector. Pass a pid or process name.",
+                      parse_process),
        OPT_END()
 };
 
 
 int cmd_timechart(int argc, const char **argv, const char *prefix __used)
 {
-       symbol__init();
+       symbol__init(0);
 
        page_size = getpagesize();