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