96f4a092df372137b85bc7fe4d04fbb2837f24eb
[pandora-kernel.git] / tools / perf / builtin-timechart.c
1 /*
2  * builtin-timechart.c - make an svg timechart of system activity
3  *
4  * (C) Copyright 2009 Intel Corporation
5  *
6  * Authors:
7  *     Arjan van de Ven <arjan@linux.intel.com>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; version 2
12  * of the License.
13  */
14
15 #include "builtin.h"
16
17 #include "util/util.h"
18
19 #include "util/color.h"
20 #include <linux/list.h>
21 #include "util/cache.h"
22 #include <linux/rbtree.h>
23 #include "util/symbol.h"
24 #include "util/callchain.h"
25 #include "util/strlist.h"
26
27 #include "perf.h"
28 #include "util/header.h"
29 #include "util/parse-options.h"
30 #include "util/parse-events.h"
31 #include "util/event.h"
32 #include "util/session.h"
33 #include "util/svghelper.h"
34
35 static char             const *input_name = "perf.data";
36 static char             const *output_name = "output.svg";
37
38 static unsigned int     numcpus;
39 static u64              min_freq;       /* Lowest CPU frequency seen */
40 static u64              max_freq;       /* Highest CPU frequency seen */
41 static u64              turbo_frequency;
42
43 static u64              first_time, last_time;
44
45 static bool             power_only;
46
47
48 struct per_pid;
49 struct per_pidcomm;
50
51 struct cpu_sample;
52 struct power_event;
53 struct wake_event;
54
55 struct sample_wrapper;
56
57 /*
58  * Datastructure layout:
59  * We keep an list of "pid"s, matching the kernels notion of a task struct.
60  * Each "pid" entry, has a list of "comm"s.
61  *      this is because we want to track different programs different, while
62  *      exec will reuse the original pid (by design).
63  * Each comm has a list of samples that will be used to draw
64  * final graph.
65  */
66
67 struct per_pid {
68         struct per_pid *next;
69
70         int             pid;
71         int             ppid;
72
73         u64             start_time;
74         u64             end_time;
75         u64             total_time;
76         int             display;
77
78         struct per_pidcomm *all;
79         struct per_pidcomm *current;
80 };
81
82
83 struct per_pidcomm {
84         struct per_pidcomm *next;
85
86         u64             start_time;
87         u64             end_time;
88         u64             total_time;
89
90         int             Y;
91         int             display;
92
93         long            state;
94         u64             state_since;
95
96         char            *comm;
97
98         struct cpu_sample *samples;
99 };
100
101 struct sample_wrapper {
102         struct sample_wrapper *next;
103
104         u64             timestamp;
105         unsigned char   data[0];
106 };
107
108 #define TYPE_NONE       0
109 #define TYPE_RUNNING    1
110 #define TYPE_WAITING    2
111 #define TYPE_BLOCKED    3
112
113 struct cpu_sample {
114         struct cpu_sample *next;
115
116         u64 start_time;
117         u64 end_time;
118         int type;
119         int cpu;
120 };
121
122 static struct per_pid *all_data;
123
124 #define CSTATE 1
125 #define PSTATE 2
126
127 struct power_event {
128         struct power_event *next;
129         int type;
130         int state;
131         u64 start_time;
132         u64 end_time;
133         int cpu;
134 };
135
136 struct wake_event {
137         struct wake_event *next;
138         int waker;
139         int wakee;
140         u64 time;
141 };
142
143 static struct power_event    *power_events;
144 static struct wake_event     *wake_events;
145
146 struct sample_wrapper *all_samples;
147
148
149 struct process_filter;
150 struct process_filter {
151         char                    *name;
152         int                     pid;
153         struct process_filter   *next;
154 };
155
156 static struct process_filter *process_filter;
157
158
159 static struct per_pid *find_create_pid(int pid)
160 {
161         struct per_pid *cursor = all_data;
162
163         while (cursor) {
164                 if (cursor->pid == pid)
165                         return cursor;
166                 cursor = cursor->next;
167         }
168         cursor = malloc(sizeof(struct per_pid));
169         assert(cursor != NULL);
170         memset(cursor, 0, sizeof(struct per_pid));
171         cursor->pid = pid;
172         cursor->next = all_data;
173         all_data = cursor;
174         return cursor;
175 }
176
177 static void pid_set_comm(int pid, char *comm)
178 {
179         struct per_pid *p;
180         struct per_pidcomm *c;
181         p = find_create_pid(pid);
182         c = p->all;
183         while (c) {
184                 if (c->comm && strcmp(c->comm, comm) == 0) {
185                         p->current = c;
186                         return;
187                 }
188                 if (!c->comm) {
189                         c->comm = strdup(comm);
190                         p->current = c;
191                         return;
192                 }
193                 c = c->next;
194         }
195         c = malloc(sizeof(struct per_pidcomm));
196         assert(c != NULL);
197         memset(c, 0, sizeof(struct per_pidcomm));
198         c->comm = strdup(comm);
199         p->current = c;
200         c->next = p->all;
201         p->all = c;
202 }
203
204 static void pid_fork(int pid, int ppid, u64 timestamp)
205 {
206         struct per_pid *p, *pp;
207         p = find_create_pid(pid);
208         pp = find_create_pid(ppid);
209         p->ppid = ppid;
210         if (pp->current && pp->current->comm && !p->current)
211                 pid_set_comm(pid, pp->current->comm);
212
213         p->start_time = timestamp;
214         if (p->current) {
215                 p->current->start_time = timestamp;
216                 p->current->state_since = timestamp;
217         }
218 }
219
220 static void pid_exit(int pid, u64 timestamp)
221 {
222         struct per_pid *p;
223         p = find_create_pid(pid);
224         p->end_time = timestamp;
225         if (p->current)
226                 p->current->end_time = timestamp;
227 }
228
229 static void
230 pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end)
231 {
232         struct per_pid *p;
233         struct per_pidcomm *c;
234         struct cpu_sample *sample;
235
236         p = find_create_pid(pid);
237         c = p->current;
238         if (!c) {
239                 c = malloc(sizeof(struct per_pidcomm));
240                 assert(c != NULL);
241                 memset(c, 0, sizeof(struct per_pidcomm));
242                 p->current = c;
243                 c->next = p->all;
244                 p->all = c;
245         }
246
247         sample = malloc(sizeof(struct cpu_sample));
248         assert(sample != NULL);
249         memset(sample, 0, sizeof(struct cpu_sample));
250         sample->start_time = start;
251         sample->end_time = end;
252         sample->type = type;
253         sample->next = c->samples;
254         sample->cpu = cpu;
255         c->samples = sample;
256
257         if (sample->type == TYPE_RUNNING && end > start && start > 0) {
258                 c->total_time += (end-start);
259                 p->total_time += (end-start);
260         }
261
262         if (c->start_time == 0 || c->start_time > start)
263                 c->start_time = start;
264         if (p->start_time == 0 || p->start_time > start)
265                 p->start_time = start;
266
267         if (cpu > numcpus)
268                 numcpus = cpu;
269 }
270
271 #define MAX_CPUS 4096
272
273 static u64 cpus_cstate_start_times[MAX_CPUS];
274 static int cpus_cstate_state[MAX_CPUS];
275 static u64 cpus_pstate_start_times[MAX_CPUS];
276 static u64 cpus_pstate_state[MAX_CPUS];
277
278 static int process_comm_event(event_t *event, struct perf_session *session __used)
279 {
280         pid_set_comm(event->comm.tid, event->comm.comm);
281         return 0;
282 }
283
284 static int process_fork_event(event_t *event, struct perf_session *session __used)
285 {
286         pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
287         return 0;
288 }
289
290 static int process_exit_event(event_t *event, struct perf_session *session __used)
291 {
292         pid_exit(event->fork.pid, event->fork.time);
293         return 0;
294 }
295
296 struct trace_entry {
297         unsigned short          type;
298         unsigned char           flags;
299         unsigned char           preempt_count;
300         int                     pid;
301         int                     lock_depth;
302 };
303
304 struct power_entry {
305         struct trace_entry te;
306         s64     type;
307         s64     value;
308 };
309
310 #define TASK_COMM_LEN 16
311 struct wakeup_entry {
312         struct trace_entry te;
313         char comm[TASK_COMM_LEN];
314         int   pid;
315         int   prio;
316         int   success;
317 };
318
319 /*
320  * trace_flag_type is an enumeration that holds different
321  * states when a trace occurs. These are:
322  *  IRQS_OFF            - interrupts were disabled
323  *  IRQS_NOSUPPORT      - arch does not support irqs_disabled_flags
324  *  NEED_RESCED         - reschedule is requested
325  *  HARDIRQ             - inside an interrupt handler
326  *  SOFTIRQ             - inside a softirq handler
327  */
328 enum trace_flag_type {
329         TRACE_FLAG_IRQS_OFF             = 0x01,
330         TRACE_FLAG_IRQS_NOSUPPORT       = 0x02,
331         TRACE_FLAG_NEED_RESCHED         = 0x04,
332         TRACE_FLAG_HARDIRQ              = 0x08,
333         TRACE_FLAG_SOFTIRQ              = 0x10,
334 };
335
336
337
338 struct sched_switch {
339         struct trace_entry te;
340         char prev_comm[TASK_COMM_LEN];
341         int  prev_pid;
342         int  prev_prio;
343         long prev_state; /* Arjan weeps. */
344         char next_comm[TASK_COMM_LEN];
345         int  next_pid;
346         int  next_prio;
347 };
348
349 static void c_state_start(int cpu, u64 timestamp, int state)
350 {
351         cpus_cstate_start_times[cpu] = timestamp;
352         cpus_cstate_state[cpu] = state;
353 }
354
355 static void c_state_end(int cpu, u64 timestamp)
356 {
357         struct power_event *pwr;
358         pwr = malloc(sizeof(struct power_event));
359         if (!pwr)
360                 return;
361         memset(pwr, 0, sizeof(struct power_event));
362
363         pwr->state = cpus_cstate_state[cpu];
364         pwr->start_time = cpus_cstate_start_times[cpu];
365         pwr->end_time = timestamp;
366         pwr->cpu = cpu;
367         pwr->type = CSTATE;
368         pwr->next = power_events;
369
370         power_events = pwr;
371 }
372
373 static void p_state_change(int cpu, u64 timestamp, u64 new_freq)
374 {
375         struct power_event *pwr;
376         pwr = malloc(sizeof(struct power_event));
377
378         if (new_freq > 8000000) /* detect invalid data */
379                 return;
380
381         if (!pwr)
382                 return;
383         memset(pwr, 0, sizeof(struct power_event));
384
385         pwr->state = cpus_pstate_state[cpu];
386         pwr->start_time = cpus_pstate_start_times[cpu];
387         pwr->end_time = timestamp;
388         pwr->cpu = cpu;
389         pwr->type = PSTATE;
390         pwr->next = power_events;
391
392         if (!pwr->start_time)
393                 pwr->start_time = first_time;
394
395         power_events = pwr;
396
397         cpus_pstate_state[cpu] = new_freq;
398         cpus_pstate_start_times[cpu] = timestamp;
399
400         if ((u64)new_freq > max_freq)
401                 max_freq = new_freq;
402
403         if (new_freq < min_freq || min_freq == 0)
404                 min_freq = new_freq;
405
406         if (new_freq == max_freq - 1000)
407                         turbo_frequency = max_freq;
408 }
409
410 static void
411 sched_wakeup(int cpu, u64 timestamp, int pid, struct trace_entry *te)
412 {
413         struct wake_event *we;
414         struct per_pid *p;
415         struct wakeup_entry *wake = (void *)te;
416
417         we = malloc(sizeof(struct wake_event));
418         if (!we)
419                 return;
420
421         memset(we, 0, sizeof(struct wake_event));
422         we->time = timestamp;
423         we->waker = pid;
424
425         if ((te->flags & TRACE_FLAG_HARDIRQ) || (te->flags & TRACE_FLAG_SOFTIRQ))
426                 we->waker = -1;
427
428         we->wakee = wake->pid;
429         we->next = wake_events;
430         wake_events = we;
431         p = find_create_pid(we->wakee);
432
433         if (p && p->current && p->current->state == TYPE_NONE) {
434                 p->current->state_since = timestamp;
435                 p->current->state = TYPE_WAITING;
436         }
437         if (p && p->current && p->current->state == TYPE_BLOCKED) {
438                 pid_put_sample(p->pid, p->current->state, cpu, p->current->state_since, timestamp);
439                 p->current->state_since = timestamp;
440                 p->current->state = TYPE_WAITING;
441         }
442 }
443
444 static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
445 {
446         struct per_pid *p = NULL, *prev_p;
447         struct sched_switch *sw = (void *)te;
448
449
450         prev_p = find_create_pid(sw->prev_pid);
451
452         p = find_create_pid(sw->next_pid);
453
454         if (prev_p->current && prev_p->current->state != TYPE_NONE)
455                 pid_put_sample(sw->prev_pid, TYPE_RUNNING, cpu, prev_p->current->state_since, timestamp);
456         if (p && p->current) {
457                 if (p->current->state != TYPE_NONE)
458                         pid_put_sample(sw->next_pid, p->current->state, cpu, p->current->state_since, timestamp);
459
460                         p->current->state_since = timestamp;
461                         p->current->state = TYPE_RUNNING;
462         }
463
464         if (prev_p->current) {
465                 prev_p->current->state = TYPE_NONE;
466                 prev_p->current->state_since = timestamp;
467                 if (sw->prev_state & 2)
468                         prev_p->current->state = TYPE_BLOCKED;
469                 if (sw->prev_state == 0)
470                         prev_p->current->state = TYPE_WAITING;
471         }
472 }
473
474
475 static int process_sample_event(event_t *event, struct perf_session *session)
476 {
477         struct sample_data data;
478         struct trace_entry *te;
479
480         memset(&data, 0, sizeof(data));
481
482         event__parse_sample(event, session->sample_type, &data);
483
484         if (session->sample_type & PERF_SAMPLE_TIME) {
485                 if (!first_time || first_time > data.time)
486                         first_time = data.time;
487                 if (last_time < data.time)
488                         last_time = data.time;
489         }
490
491         te = (void *)data.raw_data;
492         if (session->sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) {
493                 char *event_str;
494                 struct power_entry *pe;
495
496                 pe = (void *)te;
497
498                 event_str = perf_header__find_event(te->type);
499
500                 if (!event_str)
501                         return 0;
502
503                 if (strcmp(event_str, "power:power_start") == 0)
504                         c_state_start(data.cpu, data.time, pe->value);
505
506                 if (strcmp(event_str, "power:power_end") == 0)
507                         c_state_end(data.cpu, data.time);
508
509                 if (strcmp(event_str, "power:power_frequency") == 0)
510                         p_state_change(data.cpu, data.time, pe->value);
511
512                 if (strcmp(event_str, "sched:sched_wakeup") == 0)
513                         sched_wakeup(data.cpu, data.time, data.pid, te);
514
515                 if (strcmp(event_str, "sched:sched_switch") == 0)
516                         sched_switch(data.cpu, data.time, te);
517         }
518         return 0;
519 }
520
521 /*
522  * After the last sample we need to wrap up the current C/P state
523  * and close out each CPU for these.
524  */
525 static void end_sample_processing(void)
526 {
527         u64 cpu;
528         struct power_event *pwr;
529
530         for (cpu = 0; cpu <= numcpus; cpu++) {
531                 pwr = malloc(sizeof(struct power_event));
532                 if (!pwr)
533                         return;
534                 memset(pwr, 0, sizeof(struct power_event));
535
536                 /* C state */
537 #if 0
538                 pwr->state = cpus_cstate_state[cpu];
539                 pwr->start_time = cpus_cstate_start_times[cpu];
540                 pwr->end_time = last_time;
541                 pwr->cpu = cpu;
542                 pwr->type = CSTATE;
543                 pwr->next = power_events;
544
545                 power_events = pwr;
546 #endif
547                 /* P state */
548
549                 pwr = malloc(sizeof(struct power_event));
550                 if (!pwr)
551                         return;
552                 memset(pwr, 0, sizeof(struct power_event));
553
554                 pwr->state = cpus_pstate_state[cpu];
555                 pwr->start_time = cpus_pstate_start_times[cpu];
556                 pwr->end_time = last_time;
557                 pwr->cpu = cpu;
558                 pwr->type = PSTATE;
559                 pwr->next = power_events;
560
561                 if (!pwr->start_time)
562                         pwr->start_time = first_time;
563                 if (!pwr->state)
564                         pwr->state = min_freq;
565                 power_events = pwr;
566         }
567 }
568
569 static u64 sample_time(event_t *event, const struct perf_session *session)
570 {
571         int cursor;
572
573         cursor = 0;
574         if (session->sample_type & PERF_SAMPLE_IP)
575                 cursor++;
576         if (session->sample_type & PERF_SAMPLE_TID)
577                 cursor++;
578         if (session->sample_type & PERF_SAMPLE_TIME)
579                 return event->sample.array[cursor];
580         return 0;
581 }
582
583
584 /*
585  * We first queue all events, sorted backwards by insertion.
586  * The order will get flipped later.
587  */
588 static int queue_sample_event(event_t *event, struct perf_session *session)
589 {
590         struct sample_wrapper *copy, *prev;
591         int size;
592
593         size = event->sample.header.size + sizeof(struct sample_wrapper) + 8;
594
595         copy = malloc(size);
596         if (!copy)
597                 return 1;
598
599         memset(copy, 0, size);
600
601         copy->next = NULL;
602         copy->timestamp = sample_time(event, session);
603
604         memcpy(&copy->data, event, event->sample.header.size);
605
606         /* insert in the right place in the list */
607
608         if (!all_samples) {
609                 /* first sample ever */
610                 all_samples = copy;
611                 return 0;
612         }
613
614         if (all_samples->timestamp < copy->timestamp) {
615                 /* insert at the head of the list */
616                 copy->next = all_samples;
617                 all_samples = copy;
618                 return 0;
619         }
620
621         prev = all_samples;
622         while (prev->next) {
623                 if (prev->next->timestamp < copy->timestamp) {
624                         copy->next = prev->next;
625                         prev->next = copy;
626                         return 0;
627                 }
628                 prev = prev->next;
629         }
630         /* insert at the end of the list */
631         prev->next = copy;
632
633         return 0;
634 }
635
636 static void sort_queued_samples(void)
637 {
638         struct sample_wrapper *cursor, *next;
639
640         cursor = all_samples;
641         all_samples = NULL;
642
643         while (cursor) {
644                 next = cursor->next;
645                 cursor->next = all_samples;
646                 all_samples = cursor;
647                 cursor = next;
648         }
649 }
650
651 /*
652  * Sort the pid datastructure
653  */
654 static void sort_pids(void)
655 {
656         struct per_pid *new_list, *p, *cursor, *prev;
657         /* sort by ppid first, then by pid, lowest to highest */
658
659         new_list = NULL;
660
661         while (all_data) {
662                 p = all_data;
663                 all_data = p->next;
664                 p->next = NULL;
665
666                 if (new_list == NULL) {
667                         new_list = p;
668                         p->next = NULL;
669                         continue;
670                 }
671                 prev = NULL;
672                 cursor = new_list;
673                 while (cursor) {
674                         if (cursor->ppid > p->ppid ||
675                                 (cursor->ppid == p->ppid && cursor->pid > p->pid)) {
676                                 /* must insert before */
677                                 if (prev) {
678                                         p->next = prev->next;
679                                         prev->next = p;
680                                         cursor = NULL;
681                                         continue;
682                                 } else {
683                                         p->next = new_list;
684                                         new_list = p;
685                                         cursor = NULL;
686                                         continue;
687                                 }
688                         }
689
690                         prev = cursor;
691                         cursor = cursor->next;
692                         if (!cursor)
693                                 prev->next = p;
694                 }
695         }
696         all_data = new_list;
697 }
698
699
700 static void draw_c_p_states(void)
701 {
702         struct power_event *pwr;
703         pwr = power_events;
704
705         /*
706          * two pass drawing so that the P state bars are on top of the C state blocks
707          */
708         while (pwr) {
709                 if (pwr->type == CSTATE)
710                         svg_cstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
711                 pwr = pwr->next;
712         }
713
714         pwr = power_events;
715         while (pwr) {
716                 if (pwr->type == PSTATE) {
717                         if (!pwr->state)
718                                 pwr->state = min_freq;
719                         svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
720                 }
721                 pwr = pwr->next;
722         }
723 }
724
725 static void draw_wakeups(void)
726 {
727         struct wake_event *we;
728         struct per_pid *p;
729         struct per_pidcomm *c;
730
731         we = wake_events;
732         while (we) {
733                 int from = 0, to = 0;
734                 char *task_from = NULL, *task_to = NULL;
735
736                 /* locate the column of the waker and wakee */
737                 p = all_data;
738                 while (p) {
739                         if (p->pid == we->waker || p->pid == we->wakee) {
740                                 c = p->all;
741                                 while (c) {
742                                         if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
743                                                 if (p->pid == we->waker && !from) {
744                                                         from = c->Y;
745                                                         task_from = strdup(c->comm);
746                                                 }
747                                                 if (p->pid == we->wakee && !to) {
748                                                         to = c->Y;
749                                                         task_to = strdup(c->comm);
750                                                 }
751                                         }
752                                         c = c->next;
753                                 }
754                                 c = p->all;
755                                 while (c) {
756                                         if (p->pid == we->waker && !from) {
757                                                 from = c->Y;
758                                                 task_from = strdup(c->comm);
759                                         }
760                                         if (p->pid == we->wakee && !to) {
761                                                 to = c->Y;
762                                                 task_to = strdup(c->comm);
763                                         }
764                                         c = c->next;
765                                 }
766                         }
767                         p = p->next;
768                 }
769
770                 if (!task_from) {
771                         task_from = malloc(40);
772                         sprintf(task_from, "[%i]", we->waker);
773                 }
774                 if (!task_to) {
775                         task_to = malloc(40);
776                         sprintf(task_to, "[%i]", we->wakee);
777                 }
778
779                 if (we->waker == -1)
780                         svg_interrupt(we->time, to);
781                 else if (from && to && abs(from - to) == 1)
782                         svg_wakeline(we->time, from, to);
783                 else
784                         svg_partial_wakeline(we->time, from, task_from, to, task_to);
785                 we = we->next;
786
787                 free(task_from);
788                 free(task_to);
789         }
790 }
791
792 static void draw_cpu_usage(void)
793 {
794         struct per_pid *p;
795         struct per_pidcomm *c;
796         struct cpu_sample *sample;
797         p = all_data;
798         while (p) {
799                 c = p->all;
800                 while (c) {
801                         sample = c->samples;
802                         while (sample) {
803                                 if (sample->type == TYPE_RUNNING)
804                                         svg_process(sample->cpu, sample->start_time, sample->end_time, "sample", c->comm);
805
806                                 sample = sample->next;
807                         }
808                         c = c->next;
809                 }
810                 p = p->next;
811         }
812 }
813
814 static void draw_process_bars(void)
815 {
816         struct per_pid *p;
817         struct per_pidcomm *c;
818         struct cpu_sample *sample;
819         int Y = 0;
820
821         Y = 2 * numcpus + 2;
822
823         p = all_data;
824         while (p) {
825                 c = p->all;
826                 while (c) {
827                         if (!c->display) {
828                                 c->Y = 0;
829                                 c = c->next;
830                                 continue;
831                         }
832
833                         svg_box(Y, c->start_time, c->end_time, "process");
834                         sample = c->samples;
835                         while (sample) {
836                                 if (sample->type == TYPE_RUNNING)
837                                         svg_sample(Y, sample->cpu, sample->start_time, sample->end_time);
838                                 if (sample->type == TYPE_BLOCKED)
839                                         svg_box(Y, sample->start_time, sample->end_time, "blocked");
840                                 if (sample->type == TYPE_WAITING)
841                                         svg_waiting(Y, sample->start_time, sample->end_time);
842                                 sample = sample->next;
843                         }
844
845                         if (c->comm) {
846                                 char comm[256];
847                                 if (c->total_time > 5000000000) /* 5 seconds */
848                                         sprintf(comm, "%s:%i (%2.2fs)", c->comm, p->pid, c->total_time / 1000000000.0);
849                                 else
850                                         sprintf(comm, "%s:%i (%3.1fms)", c->comm, p->pid, c->total_time / 1000000.0);
851
852                                 svg_text(Y, c->start_time, comm);
853                         }
854                         c->Y = Y;
855                         Y++;
856                         c = c->next;
857                 }
858                 p = p->next;
859         }
860 }
861
862 static void add_process_filter(const char *string)
863 {
864         struct process_filter *filt;
865         int pid;
866
867         pid = strtoull(string, NULL, 10);
868         filt = malloc(sizeof(struct process_filter));
869         if (!filt)
870                 return;
871
872         filt->name = strdup(string);
873         filt->pid  = pid;
874         filt->next = process_filter;
875
876         process_filter = filt;
877 }
878
879 static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
880 {
881         struct process_filter *filt;
882         if (!process_filter)
883                 return 1;
884
885         filt = process_filter;
886         while (filt) {
887                 if (filt->pid && p->pid == filt->pid)
888                         return 1;
889                 if (strcmp(filt->name, c->comm) == 0)
890                         return 1;
891                 filt = filt->next;
892         }
893         return 0;
894 }
895
896 static int determine_display_tasks_filtered(void)
897 {
898         struct per_pid *p;
899         struct per_pidcomm *c;
900         int count = 0;
901
902         p = all_data;
903         while (p) {
904                 p->display = 0;
905                 if (p->start_time == 1)
906                         p->start_time = first_time;
907
908                 /* no exit marker, task kept running to the end */
909                 if (p->end_time == 0)
910                         p->end_time = last_time;
911
912                 c = p->all;
913
914                 while (c) {
915                         c->display = 0;
916
917                         if (c->start_time == 1)
918                                 c->start_time = first_time;
919
920                         if (passes_filter(p, c)) {
921                                 c->display = 1;
922                                 p->display = 1;
923                                 count++;
924                         }
925
926                         if (c->end_time == 0)
927                                 c->end_time = last_time;
928
929                         c = c->next;
930                 }
931                 p = p->next;
932         }
933         return count;
934 }
935
936 static int determine_display_tasks(u64 threshold)
937 {
938         struct per_pid *p;
939         struct per_pidcomm *c;
940         int count = 0;
941
942         if (process_filter)
943                 return determine_display_tasks_filtered();
944
945         p = all_data;
946         while (p) {
947                 p->display = 0;
948                 if (p->start_time == 1)
949                         p->start_time = first_time;
950
951                 /* no exit marker, task kept running to the end */
952                 if (p->end_time == 0)
953                         p->end_time = last_time;
954                 if (p->total_time >= threshold && !power_only)
955                         p->display = 1;
956
957                 c = p->all;
958
959                 while (c) {
960                         c->display = 0;
961
962                         if (c->start_time == 1)
963                                 c->start_time = first_time;
964
965                         if (c->total_time >= threshold && !power_only) {
966                                 c->display = 1;
967                                 count++;
968                         }
969
970                         if (c->end_time == 0)
971                                 c->end_time = last_time;
972
973                         c = c->next;
974                 }
975                 p = p->next;
976         }
977         return count;
978 }
979
980
981
982 #define TIME_THRESH 10000000
983
984 static void write_svg_file(const char *filename)
985 {
986         u64 i;
987         int count;
988
989         numcpus++;
990
991
992         count = determine_display_tasks(TIME_THRESH);
993
994         /* We'd like to show at least 15 tasks; be less picky if we have fewer */
995         if (count < 15)
996                 count = determine_display_tasks(TIME_THRESH / 10);
997
998         open_svg(filename, numcpus, count, first_time, last_time);
999
1000         svg_time_grid();
1001         svg_legenda();
1002
1003         for (i = 0; i < numcpus; i++)
1004                 svg_cpu_box(i, max_freq, turbo_frequency);
1005
1006         draw_cpu_usage();
1007         draw_process_bars();
1008         draw_c_p_states();
1009         draw_wakeups();
1010
1011         svg_close();
1012 }
1013
1014 static void process_samples(struct perf_session *session)
1015 {
1016         struct sample_wrapper *cursor;
1017         event_t *event;
1018
1019         sort_queued_samples();
1020
1021         cursor = all_samples;
1022         while (cursor) {
1023                 event = (void *)&cursor->data;
1024                 cursor = cursor->next;
1025                 process_sample_event(event, session);
1026         }
1027 }
1028
1029 static struct perf_event_ops event_ops = {
1030         .comm   = process_comm_event,
1031         .fork   = process_fork_event,
1032         .exit   = process_exit_event,
1033         .sample = queue_sample_event,
1034 };
1035
1036 static int __cmd_timechart(void)
1037 {
1038         struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1039         int ret = -EINVAL;
1040
1041         if (session == NULL)
1042                 return -ENOMEM;
1043
1044         if (!perf_session__has_traces(session, "timechart record"))
1045                 goto out_delete;
1046
1047         ret = perf_session__process_events(session, &event_ops);
1048         if (ret)
1049                 goto out_delete;
1050
1051         process_samples(session);
1052
1053         end_sample_processing();
1054
1055         sort_pids();
1056
1057         write_svg_file(output_name);
1058
1059         pr_info("Written %2.1f seconds of trace to %s.\n",
1060                 (last_time - first_time) / 1000000000.0, output_name);
1061 out_delete:
1062         perf_session__delete(session);
1063         return ret;
1064 }
1065
1066 static const char * const timechart_usage[] = {
1067         "perf timechart [<options>] {record}",
1068         NULL
1069 };
1070
1071 static const char *record_args[] = {
1072         "record",
1073         "-a",
1074         "-R",
1075         "-M",
1076         "-f",
1077         "-c", "1",
1078         "-e", "power:power_start",
1079         "-e", "power:power_end",
1080         "-e", "power:power_frequency",
1081         "-e", "sched:sched_wakeup",
1082         "-e", "sched:sched_switch",
1083 };
1084
1085 static int __cmd_record(int argc, const char **argv)
1086 {
1087         unsigned int rec_argc, i, j;
1088         const char **rec_argv;
1089
1090         rec_argc = ARRAY_SIZE(record_args) + argc - 1;
1091         rec_argv = calloc(rec_argc + 1, sizeof(char *));
1092
1093         for (i = 0; i < ARRAY_SIZE(record_args); i++)
1094                 rec_argv[i] = strdup(record_args[i]);
1095
1096         for (j = 1; j < (unsigned int)argc; j++, i++)
1097                 rec_argv[i] = argv[j];
1098
1099         return cmd_record(i, rec_argv, NULL);
1100 }
1101
1102 static int
1103 parse_process(const struct option *opt __used, const char *arg, int __used unset)
1104 {
1105         if (arg)
1106                 add_process_filter(arg);
1107         return 0;
1108 }
1109
1110 static const struct option options[] = {
1111         OPT_STRING('i', "input", &input_name, "file",
1112                     "input file name"),
1113         OPT_STRING('o', "output", &output_name, "file",
1114                     "output file name"),
1115         OPT_INTEGER('w', "width", &svg_page_width,
1116                     "page width"),
1117         OPT_BOOLEAN('P', "power-only", &power_only,
1118                     "output power data only"),
1119         OPT_CALLBACK('p', "process", NULL, "process",
1120                       "process selector. Pass a pid or process name.",
1121                        parse_process),
1122         OPT_END()
1123 };
1124
1125
1126 int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1127 {
1128         argc = parse_options(argc, argv, options, timechart_usage,
1129                         PARSE_OPT_STOP_AT_NON_OPTION);
1130
1131         symbol__init();
1132
1133         if (argc && !strncmp(argv[0], "rec", 3))
1134                 return __cmd_record(argc, argv);
1135         else if (argc)
1136                 usage_with_options(timechart_usage, options);
1137
1138         setup_pager();
1139
1140         return __cmd_timechart();
1141 }