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