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