perf timechart: Introduce tool struct
[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 <traceevent/event-parse.h>
16
17 #include "builtin.h"
18
19 #include "util/util.h"
20
21 #include "util/color.h"
22 #include <linux/list.h>
23 #include "util/cache.h"
24 #include "util/evlist.h"
25 #include "util/evsel.h"
26 #include <linux/rbtree.h>
27 #include "util/symbol.h"
28 #include "util/callchain.h"
29 #include "util/strlist.h"
30
31 #include "perf.h"
32 #include "util/header.h"
33 #include "util/parse-options.h"
34 #include "util/parse-events.h"
35 #include "util/event.h"
36 #include "util/session.h"
37 #include "util/svghelper.h"
38 #include "util/tool.h"
39 #include "util/data.h"
40
41 #define SUPPORT_OLD_POWER_EVENTS 1
42 #define PWR_EVENT_EXIT -1
43
44 struct timechart {
45         struct perf_tool        tool;
46         int                     proc_num;
47         unsigned int            numcpus;
48         u64                     min_freq,       /* Lowest CPU frequency seen */
49                                 max_freq,       /* Highest CPU frequency seen */
50                                 turbo_frequency,
51                                 first_time, last_time;
52         bool                    power_only,
53                                 tasks_only,
54                                 with_backtrace;
55 };
56
57 struct per_pidcomm;
58 struct cpu_sample;
59
60 /*
61  * Datastructure layout:
62  * We keep an list of "pid"s, matching the kernels notion of a task struct.
63  * Each "pid" entry, has a list of "comm"s.
64  *      this is because we want to track different programs different, while
65  *      exec will reuse the original pid (by design).
66  * Each comm has a list of samples that will be used to draw
67  * final graph.
68  */
69
70 struct per_pid {
71         struct per_pid *next;
72
73         int             pid;
74         int             ppid;
75
76         u64             start_time;
77         u64             end_time;
78         u64             total_time;
79         int             display;
80
81         struct per_pidcomm *all;
82         struct per_pidcomm *current;
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         const char *backtrace;
124 };
125
126 static struct per_pid *all_data;
127
128 #define CSTATE 1
129 #define PSTATE 2
130
131 struct power_event {
132         struct power_event *next;
133         int type;
134         int state;
135         u64 start_time;
136         u64 end_time;
137         int cpu;
138 };
139
140 struct wake_event {
141         struct wake_event *next;
142         int waker;
143         int wakee;
144         u64 time;
145         const char *backtrace;
146 };
147
148 static struct power_event    *power_events;
149 static struct wake_event     *wake_events;
150
151 struct process_filter {
152         char                    *name;
153         int                     pid;
154         struct process_filter   *next;
155 };
156
157 static struct process_filter *process_filter;
158
159
160 static struct per_pid *find_create_pid(int pid)
161 {
162         struct per_pid *cursor = all_data;
163
164         while (cursor) {
165                 if (cursor->pid == pid)
166                         return cursor;
167                 cursor = cursor->next;
168         }
169         cursor = zalloc(sizeof(*cursor));
170         assert(cursor != NULL);
171         cursor->pid = pid;
172         cursor->next = all_data;
173         all_data = cursor;
174         return cursor;
175 }
176
177 static void pid_set_comm(int pid, char *comm)
178 {
179         struct per_pid *p;
180         struct per_pidcomm *c;
181         p = find_create_pid(pid);
182         c = p->all;
183         while (c) {
184                 if (c->comm && strcmp(c->comm, comm) == 0) {
185                         p->current = c;
186                         return;
187                 }
188                 if (!c->comm) {
189                         c->comm = strdup(comm);
190                         p->current = c;
191                         return;
192                 }
193                 c = c->next;
194         }
195         c = zalloc(sizeof(*c));
196         assert(c != NULL);
197         c->comm = strdup(comm);
198         p->current = c;
199         c->next = p->all;
200         p->all = c;
201 }
202
203 static void pid_fork(int pid, int ppid, u64 timestamp)
204 {
205         struct per_pid *p, *pp;
206         p = find_create_pid(pid);
207         pp = find_create_pid(ppid);
208         p->ppid = ppid;
209         if (pp->current && pp->current->comm && !p->current)
210                 pid_set_comm(pid, pp->current->comm);
211
212         p->start_time = timestamp;
213         if (p->current) {
214                 p->current->start_time = timestamp;
215                 p->current->state_since = timestamp;
216         }
217 }
218
219 static void pid_exit(int pid, u64 timestamp)
220 {
221         struct per_pid *p;
222         p = find_create_pid(pid);
223         p->end_time = timestamp;
224         if (p->current)
225                 p->current->end_time = timestamp;
226 }
227
228 static void
229 pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end,
230                const char *backtrace)
231 {
232         struct per_pid *p;
233         struct per_pidcomm *c;
234         struct cpu_sample *sample;
235
236         p = find_create_pid(pid);
237         c = p->current;
238         if (!c) {
239                 c = zalloc(sizeof(*c));
240                 assert(c != NULL);
241                 p->current = c;
242                 c->next = p->all;
243                 p->all = c;
244         }
245
246         sample = zalloc(sizeof(*sample));
247         assert(sample != NULL);
248         sample->start_time = start;
249         sample->end_time = end;
250         sample->type = type;
251         sample->next = c->samples;
252         sample->cpu = cpu;
253         sample->backtrace = backtrace;
254         c->samples = sample;
255
256         if (sample->type == TYPE_RUNNING && end > start && start > 0) {
257                 c->total_time += (end-start);
258                 p->total_time += (end-start);
259         }
260
261         if (c->start_time == 0 || c->start_time > start)
262                 c->start_time = start;
263         if (p->start_time == 0 || p->start_time > start)
264                 p->start_time = start;
265 }
266
267 #define MAX_CPUS 4096
268
269 static u64 cpus_cstate_start_times[MAX_CPUS];
270 static int cpus_cstate_state[MAX_CPUS];
271 static u64 cpus_pstate_start_times[MAX_CPUS];
272 static u64 cpus_pstate_state[MAX_CPUS];
273
274 static int process_comm_event(struct perf_tool *tool __maybe_unused,
275                               union perf_event *event,
276                               struct perf_sample *sample __maybe_unused,
277                               struct machine *machine __maybe_unused)
278 {
279         pid_set_comm(event->comm.tid, event->comm.comm);
280         return 0;
281 }
282
283 static int process_fork_event(struct perf_tool *tool __maybe_unused,
284                               union perf_event *event,
285                               struct perf_sample *sample __maybe_unused,
286                               struct machine *machine __maybe_unused)
287 {
288         pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
289         return 0;
290 }
291
292 static int process_exit_event(struct perf_tool *tool __maybe_unused,
293                               union perf_event *event,
294                               struct perf_sample *sample __maybe_unused,
295                               struct machine *machine __maybe_unused)
296 {
297         pid_exit(event->fork.pid, event->fork.time);
298         return 0;
299 }
300
301 #ifdef SUPPORT_OLD_POWER_EVENTS
302 static int use_old_power_events;
303 #endif
304
305 static void c_state_start(int cpu, u64 timestamp, int state)
306 {
307         cpus_cstate_start_times[cpu] = timestamp;
308         cpus_cstate_state[cpu] = state;
309 }
310
311 static void c_state_end(int cpu, u64 timestamp)
312 {
313         struct power_event *pwr = zalloc(sizeof(*pwr));
314
315         if (!pwr)
316                 return;
317
318         pwr->state = cpus_cstate_state[cpu];
319         pwr->start_time = cpus_cstate_start_times[cpu];
320         pwr->end_time = timestamp;
321         pwr->cpu = cpu;
322         pwr->type = CSTATE;
323         pwr->next = power_events;
324
325         power_events = pwr;
326 }
327
328 static void p_state_change(struct timechart *tchart, int cpu, u64 timestamp, u64 new_freq)
329 {
330         struct power_event *pwr;
331
332         if (new_freq > 8000000) /* detect invalid data */
333                 return;
334
335         pwr = zalloc(sizeof(*pwr));
336         if (!pwr)
337                 return;
338
339         pwr->state = cpus_pstate_state[cpu];
340         pwr->start_time = cpus_pstate_start_times[cpu];
341         pwr->end_time = timestamp;
342         pwr->cpu = cpu;
343         pwr->type = PSTATE;
344         pwr->next = power_events;
345
346         if (!pwr->start_time)
347                 pwr->start_time = tchart->first_time;
348
349         power_events = pwr;
350
351         cpus_pstate_state[cpu] = new_freq;
352         cpus_pstate_start_times[cpu] = timestamp;
353
354         if ((u64)new_freq > tchart->max_freq)
355                 tchart->max_freq = new_freq;
356
357         if (new_freq < tchart->min_freq || tchart->min_freq == 0)
358                 tchart->min_freq = new_freq;
359
360         if (new_freq == tchart->max_freq - 1000)
361                 tchart->turbo_frequency = tchart->max_freq;
362 }
363
364 static void sched_wakeup(int cpu, u64 timestamp, int waker, int wakee,
365                          u8 flags, const char *backtrace)
366 {
367         struct per_pid *p;
368         struct wake_event *we = zalloc(sizeof(*we));
369
370         if (!we)
371                 return;
372
373         we->time = timestamp;
374         we->waker = waker;
375         we->backtrace = backtrace;
376
377         if ((flags & TRACE_FLAG_HARDIRQ) || (flags & TRACE_FLAG_SOFTIRQ))
378                 we->waker = -1;
379
380         we->wakee = wakee;
381         we->next = wake_events;
382         wake_events = we;
383         p = find_create_pid(we->wakee);
384
385         if (p && p->current && p->current->state == TYPE_NONE) {
386                 p->current->state_since = timestamp;
387                 p->current->state = TYPE_WAITING;
388         }
389         if (p && p->current && p->current->state == TYPE_BLOCKED) {
390                 pid_put_sample(p->pid, p->current->state, cpu,
391                                p->current->state_since, timestamp, NULL);
392                 p->current->state_since = timestamp;
393                 p->current->state = TYPE_WAITING;
394         }
395 }
396
397 static void sched_switch(int cpu, u64 timestamp, int prev_pid, int next_pid,
398                          u64 prev_state, const char *backtrace)
399 {
400         struct per_pid *p = NULL, *prev_p;
401
402         prev_p = find_create_pid(prev_pid);
403
404         p = find_create_pid(next_pid);
405
406         if (prev_p->current && prev_p->current->state != TYPE_NONE)
407                 pid_put_sample(prev_pid, TYPE_RUNNING, cpu,
408                                prev_p->current->state_since, timestamp,
409                                backtrace);
410         if (p && p->current) {
411                 if (p->current->state != TYPE_NONE)
412                         pid_put_sample(next_pid, p->current->state, cpu,
413                                        p->current->state_since, timestamp,
414                                        backtrace);
415
416                 p->current->state_since = timestamp;
417                 p->current->state = TYPE_RUNNING;
418         }
419
420         if (prev_p->current) {
421                 prev_p->current->state = TYPE_NONE;
422                 prev_p->current->state_since = timestamp;
423                 if (prev_state & 2)
424                         prev_p->current->state = TYPE_BLOCKED;
425                 if (prev_state == 0)
426                         prev_p->current->state = TYPE_WAITING;
427         }
428 }
429
430 static const char *cat_backtrace(union perf_event *event,
431                                  struct perf_sample *sample,
432                                  struct machine *machine)
433 {
434         struct addr_location al;
435         unsigned int i;
436         char *p = NULL;
437         size_t p_len;
438         u8 cpumode = PERF_RECORD_MISC_USER;
439         struct addr_location tal;
440         struct ip_callchain *chain = sample->callchain;
441         FILE *f = open_memstream(&p, &p_len);
442
443         if (!f) {
444                 perror("open_memstream error");
445                 return NULL;
446         }
447
448         if (!chain)
449                 goto exit;
450
451         if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
452                 fprintf(stderr, "problem processing %d event, skipping it.\n",
453                         event->header.type);
454                 goto exit;
455         }
456
457         for (i = 0; i < chain->nr; i++) {
458                 u64 ip;
459
460                 if (callchain_param.order == ORDER_CALLEE)
461                         ip = chain->ips[i];
462                 else
463                         ip = chain->ips[chain->nr - i - 1];
464
465                 if (ip >= PERF_CONTEXT_MAX) {
466                         switch (ip) {
467                         case PERF_CONTEXT_HV:
468                                 cpumode = PERF_RECORD_MISC_HYPERVISOR;
469                                 break;
470                         case PERF_CONTEXT_KERNEL:
471                                 cpumode = PERF_RECORD_MISC_KERNEL;
472                                 break;
473                         case PERF_CONTEXT_USER:
474                                 cpumode = PERF_RECORD_MISC_USER;
475                                 break;
476                         default:
477                                 pr_debug("invalid callchain context: "
478                                          "%"PRId64"\n", (s64) ip);
479
480                                 /*
481                                  * It seems the callchain is corrupted.
482                                  * Discard all.
483                                  */
484                                 free(p);
485                                 p = NULL;
486                                 goto exit;
487                         }
488                         continue;
489                 }
490
491                 tal.filtered = false;
492                 thread__find_addr_location(al.thread, machine, cpumode,
493                                            MAP__FUNCTION, ip, &tal);
494
495                 if (tal.sym)
496                         fprintf(f, "..... %016" PRIx64 " %s\n", ip,
497                                 tal.sym->name);
498                 else
499                         fprintf(f, "..... %016" PRIx64 "\n", ip);
500         }
501
502 exit:
503         fclose(f);
504
505         return p;
506 }
507
508 typedef int (*tracepoint_handler)(struct timechart *tchart,
509                                   struct perf_evsel *evsel,
510                                   struct perf_sample *sample,
511                                   const char *backtrace);
512
513 static int process_sample_event(struct perf_tool *tool,
514                                 union perf_event *event,
515                                 struct perf_sample *sample,
516                                 struct perf_evsel *evsel,
517                                 struct machine *machine)
518 {
519         struct timechart *tchart = container_of(tool, struct timechart, tool);
520
521         if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
522                 if (!tchart->first_time || tchart->first_time > sample->time)
523                         tchart->first_time = sample->time;
524                 if (tchart->last_time < sample->time)
525                         tchart->last_time = sample->time;
526         }
527
528         if (sample->cpu > tchart->numcpus)
529                 tchart->numcpus = sample->cpu;
530
531         if (evsel->handler != NULL) {
532                 tracepoint_handler f = evsel->handler;
533                 return f(tchart, evsel, sample, cat_backtrace(event, sample, machine));
534         }
535
536         return 0;
537 }
538
539 static int
540 process_sample_cpu_idle(struct timechart *tchart __maybe_unused,
541                         struct perf_evsel *evsel,
542                         struct perf_sample *sample,
543                         const char *backtrace __maybe_unused)
544 {
545         u32 state = perf_evsel__intval(evsel, sample, "state");
546         u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
547
548         if (state == (u32)PWR_EVENT_EXIT)
549                 c_state_end(cpu_id, sample->time);
550         else
551                 c_state_start(cpu_id, sample->time, state);
552         return 0;
553 }
554
555 static int
556 process_sample_cpu_frequency(struct timechart *tchart,
557                              struct perf_evsel *evsel,
558                              struct perf_sample *sample,
559                              const char *backtrace __maybe_unused)
560 {
561         u32 state = perf_evsel__intval(evsel, sample, "state");
562         u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
563
564         p_state_change(tchart, cpu_id, sample->time, state);
565         return 0;
566 }
567
568 static int
569 process_sample_sched_wakeup(struct timechart *tchart __maybe_unused,
570                             struct perf_evsel *evsel,
571                             struct perf_sample *sample,
572                             const char *backtrace)
573 {
574         u8 flags = perf_evsel__intval(evsel, sample, "common_flags");
575         int waker = perf_evsel__intval(evsel, sample, "common_pid");
576         int wakee = perf_evsel__intval(evsel, sample, "pid");
577
578         sched_wakeup(sample->cpu, sample->time, waker, wakee, flags, backtrace);
579         return 0;
580 }
581
582 static int
583 process_sample_sched_switch(struct timechart *tchart __maybe_unused,
584                             struct perf_evsel *evsel,
585                             struct perf_sample *sample,
586                             const char *backtrace)
587 {
588         int prev_pid = perf_evsel__intval(evsel, sample, "prev_pid");
589         int next_pid = perf_evsel__intval(evsel, sample, "next_pid");
590         u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state");
591
592         sched_switch(sample->cpu, sample->time, prev_pid, next_pid, prev_state,
593                      backtrace);
594         return 0;
595 }
596
597 #ifdef SUPPORT_OLD_POWER_EVENTS
598 static int
599 process_sample_power_start(struct timechart *tchart __maybe_unused,
600                            struct perf_evsel *evsel,
601                            struct perf_sample *sample,
602                            const char *backtrace __maybe_unused)
603 {
604         u64 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
605         u64 value = perf_evsel__intval(evsel, sample, "value");
606
607         c_state_start(cpu_id, sample->time, value);
608         return 0;
609 }
610
611 static int
612 process_sample_power_end(struct timechart *tchart __maybe_unused,
613                          struct perf_evsel *evsel __maybe_unused,
614                          struct perf_sample *sample,
615                          const char *backtrace __maybe_unused)
616 {
617         c_state_end(sample->cpu, sample->time);
618         return 0;
619 }
620
621 static int
622 process_sample_power_frequency(struct timechart *tchart,
623                                struct perf_evsel *evsel,
624                                struct perf_sample *sample,
625                                const char *backtrace __maybe_unused)
626 {
627         u64 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
628         u64 value = perf_evsel__intval(evsel, sample, "value");
629
630         p_state_change(tchart, cpu_id, sample->time, value);
631         return 0;
632 }
633 #endif /* SUPPORT_OLD_POWER_EVENTS */
634
635 /*
636  * After the last sample we need to wrap up the current C/P state
637  * and close out each CPU for these.
638  */
639 static void end_sample_processing(struct timechart *tchart)
640 {
641         u64 cpu;
642         struct power_event *pwr;
643
644         for (cpu = 0; cpu <= tchart->numcpus; cpu++) {
645                 /* C state */
646 #if 0
647                 pwr = zalloc(sizeof(*pwr));
648                 if (!pwr)
649                         return;
650
651                 pwr->state = cpus_cstate_state[cpu];
652                 pwr->start_time = cpus_cstate_start_times[cpu];
653                 pwr->end_time = tchart->last_time;
654                 pwr->cpu = cpu;
655                 pwr->type = CSTATE;
656                 pwr->next = power_events;
657
658                 power_events = pwr;
659 #endif
660                 /* P state */
661
662                 pwr = zalloc(sizeof(*pwr));
663                 if (!pwr)
664                         return;
665
666                 pwr->state = cpus_pstate_state[cpu];
667                 pwr->start_time = cpus_pstate_start_times[cpu];
668                 pwr->end_time = tchart->last_time;
669                 pwr->cpu = cpu;
670                 pwr->type = PSTATE;
671                 pwr->next = power_events;
672
673                 if (!pwr->start_time)
674                         pwr->start_time = tchart->first_time;
675                 if (!pwr->state)
676                         pwr->state = tchart->min_freq;
677                 power_events = pwr;
678         }
679 }
680
681 /*
682  * Sort the pid datastructure
683  */
684 static void sort_pids(void)
685 {
686         struct per_pid *new_list, *p, *cursor, *prev;
687         /* sort by ppid first, then by pid, lowest to highest */
688
689         new_list = NULL;
690
691         while (all_data) {
692                 p = all_data;
693                 all_data = p->next;
694                 p->next = NULL;
695
696                 if (new_list == NULL) {
697                         new_list = p;
698                         p->next = NULL;
699                         continue;
700                 }
701                 prev = NULL;
702                 cursor = new_list;
703                 while (cursor) {
704                         if (cursor->ppid > p->ppid ||
705                                 (cursor->ppid == p->ppid && cursor->pid > p->pid)) {
706                                 /* must insert before */
707                                 if (prev) {
708                                         p->next = prev->next;
709                                         prev->next = p;
710                                         cursor = NULL;
711                                         continue;
712                                 } else {
713                                         p->next = new_list;
714                                         new_list = p;
715                                         cursor = NULL;
716                                         continue;
717                                 }
718                         }
719
720                         prev = cursor;
721                         cursor = cursor->next;
722                         if (!cursor)
723                                 prev->next = p;
724                 }
725         }
726         all_data = new_list;
727 }
728
729
730 static void draw_c_p_states(struct timechart *tchart)
731 {
732         struct power_event *pwr;
733         pwr = power_events;
734
735         /*
736          * two pass drawing so that the P state bars are on top of the C state blocks
737          */
738         while (pwr) {
739                 if (pwr->type == CSTATE)
740                         svg_cstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
741                 pwr = pwr->next;
742         }
743
744         pwr = power_events;
745         while (pwr) {
746                 if (pwr->type == PSTATE) {
747                         if (!pwr->state)
748                                 pwr->state = tchart->min_freq;
749                         svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
750                 }
751                 pwr = pwr->next;
752         }
753 }
754
755 static void draw_wakeups(void)
756 {
757         struct wake_event *we;
758         struct per_pid *p;
759         struct per_pidcomm *c;
760
761         we = wake_events;
762         while (we) {
763                 int from = 0, to = 0;
764                 char *task_from = NULL, *task_to = NULL;
765
766                 /* locate the column of the waker and wakee */
767                 p = all_data;
768                 while (p) {
769                         if (p->pid == we->waker || p->pid == we->wakee) {
770                                 c = p->all;
771                                 while (c) {
772                                         if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
773                                                 if (p->pid == we->waker && !from) {
774                                                         from = c->Y;
775                                                         task_from = strdup(c->comm);
776                                                 }
777                                                 if (p->pid == we->wakee && !to) {
778                                                         to = c->Y;
779                                                         task_to = strdup(c->comm);
780                                                 }
781                                         }
782                                         c = c->next;
783                                 }
784                                 c = p->all;
785                                 while (c) {
786                                         if (p->pid == we->waker && !from) {
787                                                 from = c->Y;
788                                                 task_from = strdup(c->comm);
789                                         }
790                                         if (p->pid == we->wakee && !to) {
791                                                 to = c->Y;
792                                                 task_to = strdup(c->comm);
793                                         }
794                                         c = c->next;
795                                 }
796                         }
797                         p = p->next;
798                 }
799
800                 if (!task_from) {
801                         task_from = malloc(40);
802                         sprintf(task_from, "[%i]", we->waker);
803                 }
804                 if (!task_to) {
805                         task_to = malloc(40);
806                         sprintf(task_to, "[%i]", we->wakee);
807                 }
808
809                 if (we->waker == -1)
810                         svg_interrupt(we->time, to, we->backtrace);
811                 else if (from && to && abs(from - to) == 1)
812                         svg_wakeline(we->time, from, to, we->backtrace);
813                 else
814                         svg_partial_wakeline(we->time, from, task_from, to,
815                                              task_to, we->backtrace);
816                 we = we->next;
817
818                 free(task_from);
819                 free(task_to);
820         }
821 }
822
823 static void draw_cpu_usage(void)
824 {
825         struct per_pid *p;
826         struct per_pidcomm *c;
827         struct cpu_sample *sample;
828         p = all_data;
829         while (p) {
830                 c = p->all;
831                 while (c) {
832                         sample = c->samples;
833                         while (sample) {
834                                 if (sample->type == TYPE_RUNNING)
835                                         svg_process(sample->cpu, sample->start_time, sample->end_time, "sample", c->comm);
836
837                                 sample = sample->next;
838                         }
839                         c = c->next;
840                 }
841                 p = p->next;
842         }
843 }
844
845 static void draw_process_bars(struct timechart *tchart)
846 {
847         struct per_pid *p;
848         struct per_pidcomm *c;
849         struct cpu_sample *sample;
850         int Y = 0;
851
852         Y = 2 * tchart->numcpus + 2;
853
854         p = all_data;
855         while (p) {
856                 c = p->all;
857                 while (c) {
858                         if (!c->display) {
859                                 c->Y = 0;
860                                 c = c->next;
861                                 continue;
862                         }
863
864                         svg_box(Y, c->start_time, c->end_time, "process");
865                         sample = c->samples;
866                         while (sample) {
867                                 if (sample->type == TYPE_RUNNING)
868                                         svg_running(Y, sample->cpu,
869                                                     sample->start_time,
870                                                     sample->end_time,
871                                                     sample->backtrace);
872                                 if (sample->type == TYPE_BLOCKED)
873                                         svg_blocked(Y, sample->cpu,
874                                                     sample->start_time,
875                                                     sample->end_time,
876                                                     sample->backtrace);
877                                 if (sample->type == TYPE_WAITING)
878                                         svg_waiting(Y, sample->cpu,
879                                                     sample->start_time,
880                                                     sample->end_time,
881                                                     sample->backtrace);
882                                 sample = sample->next;
883                         }
884
885                         if (c->comm) {
886                                 char comm[256];
887                                 if (c->total_time > 5000000000) /* 5 seconds */
888                                         sprintf(comm, "%s:%i (%2.2fs)", c->comm, p->pid, c->total_time / 1000000000.0);
889                                 else
890                                         sprintf(comm, "%s:%i (%3.1fms)", c->comm, p->pid, c->total_time / 1000000.0);
891
892                                 svg_text(Y, c->start_time, comm);
893                         }
894                         c->Y = Y;
895                         Y++;
896                         c = c->next;
897                 }
898                 p = p->next;
899         }
900 }
901
902 static void add_process_filter(const char *string)
903 {
904         int pid = strtoull(string, NULL, 10);
905         struct process_filter *filt = malloc(sizeof(*filt));
906
907         if (!filt)
908                 return;
909
910         filt->name = strdup(string);
911         filt->pid  = pid;
912         filt->next = process_filter;
913
914         process_filter = filt;
915 }
916
917 static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
918 {
919         struct process_filter *filt;
920         if (!process_filter)
921                 return 1;
922
923         filt = process_filter;
924         while (filt) {
925                 if (filt->pid && p->pid == filt->pid)
926                         return 1;
927                 if (strcmp(filt->name, c->comm) == 0)
928                         return 1;
929                 filt = filt->next;
930         }
931         return 0;
932 }
933
934 static int determine_display_tasks_filtered(struct timechart *tchart)
935 {
936         struct per_pid *p;
937         struct per_pidcomm *c;
938         int count = 0;
939
940         p = all_data;
941         while (p) {
942                 p->display = 0;
943                 if (p->start_time == 1)
944                         p->start_time = tchart->first_time;
945
946                 /* no exit marker, task kept running to the end */
947                 if (p->end_time == 0)
948                         p->end_time = tchart->last_time;
949
950                 c = p->all;
951
952                 while (c) {
953                         c->display = 0;
954
955                         if (c->start_time == 1)
956                                 c->start_time = tchart->first_time;
957
958                         if (passes_filter(p, c)) {
959                                 c->display = 1;
960                                 p->display = 1;
961                                 count++;
962                         }
963
964                         if (c->end_time == 0)
965                                 c->end_time = tchart->last_time;
966
967                         c = c->next;
968                 }
969                 p = p->next;
970         }
971         return count;
972 }
973
974 static int determine_display_tasks(struct timechart *tchart, u64 threshold)
975 {
976         struct per_pid *p;
977         struct per_pidcomm *c;
978         int count = 0;
979
980         if (process_filter)
981                 return determine_display_tasks_filtered(tchart);
982
983         p = all_data;
984         while (p) {
985                 p->display = 0;
986                 if (p->start_time == 1)
987                         p->start_time = tchart->first_time;
988
989                 /* no exit marker, task kept running to the end */
990                 if (p->end_time == 0)
991                         p->end_time = tchart->last_time;
992                 if (p->total_time >= threshold)
993                         p->display = 1;
994
995                 c = p->all;
996
997                 while (c) {
998                         c->display = 0;
999
1000                         if (c->start_time == 1)
1001                                 c->start_time = tchart->first_time;
1002
1003                         if (c->total_time >= threshold) {
1004                                 c->display = 1;
1005                                 count++;
1006                         }
1007
1008                         if (c->end_time == 0)
1009                                 c->end_time = tchart->last_time;
1010
1011                         c = c->next;
1012                 }
1013                 p = p->next;
1014         }
1015         return count;
1016 }
1017
1018
1019
1020 #define TIME_THRESH 10000000
1021
1022 static void write_svg_file(struct timechart *tchart, const char *filename)
1023 {
1024         u64 i;
1025         int count;
1026         int thresh = TIME_THRESH;
1027
1028         tchart->numcpus++;
1029
1030         if (tchart->power_only)
1031                 tchart->proc_num = 0;
1032
1033         /* We'd like to show at least proc_num tasks;
1034          * be less picky if we have fewer */
1035         do {
1036                 count = determine_display_tasks(tchart, thresh);
1037                 thresh /= 10;
1038         } while (!process_filter && thresh && count < tchart->proc_num);
1039
1040         open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time);
1041
1042         svg_time_grid();
1043         svg_legenda();
1044
1045         for (i = 0; i < tchart->numcpus; i++)
1046                 svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);
1047
1048         draw_cpu_usage();
1049         if (tchart->proc_num)
1050                 draw_process_bars(tchart);
1051         if (!tchart->tasks_only)
1052                 draw_c_p_states(tchart);
1053         if (tchart->proc_num)
1054                 draw_wakeups();
1055
1056         svg_close();
1057 }
1058
1059 static int __cmd_timechart(struct timechart *tchart, const char *output_name)
1060 {
1061         const struct perf_evsel_str_handler power_tracepoints[] = {
1062                 { "power:cpu_idle",             process_sample_cpu_idle },
1063                 { "power:cpu_frequency",        process_sample_cpu_frequency },
1064                 { "sched:sched_wakeup",         process_sample_sched_wakeup },
1065                 { "sched:sched_switch",         process_sample_sched_switch },
1066 #ifdef SUPPORT_OLD_POWER_EVENTS
1067                 { "power:power_start",          process_sample_power_start },
1068                 { "power:power_end",            process_sample_power_end },
1069                 { "power:power_frequency",      process_sample_power_frequency },
1070 #endif
1071         };
1072         struct perf_data_file file = {
1073                 .path = input_name,
1074                 .mode = PERF_DATA_MODE_READ,
1075         };
1076
1077         struct perf_session *session = perf_session__new(&file, false,
1078                                                          &tchart->tool);
1079         int ret = -EINVAL;
1080
1081         if (session == NULL)
1082                 return -ENOMEM;
1083
1084         if (!perf_session__has_traces(session, "timechart record"))
1085                 goto out_delete;
1086
1087         if (perf_session__set_tracepoints_handlers(session,
1088                                                    power_tracepoints)) {
1089                 pr_err("Initializing session tracepoint handlers failed\n");
1090                 goto out_delete;
1091         }
1092
1093         ret = perf_session__process_events(session, &tchart->tool);
1094         if (ret)
1095                 goto out_delete;
1096
1097         end_sample_processing(tchart);
1098
1099         sort_pids();
1100
1101         write_svg_file(tchart, output_name);
1102
1103         pr_info("Written %2.1f seconds of trace to %s.\n",
1104                 (tchart->last_time - tchart->first_time) / 1000000000.0, output_name);
1105 out_delete:
1106         perf_session__delete(session);
1107         return ret;
1108 }
1109
1110 static int timechart__record(struct timechart *tchart, int argc, const char **argv)
1111 {
1112         unsigned int rec_argc, i, j;
1113         const char **rec_argv;
1114         const char **p;
1115         unsigned int record_elems;
1116
1117         const char * const common_args[] = {
1118                 "record", "-a", "-R", "-c", "1",
1119         };
1120         unsigned int common_args_nr = ARRAY_SIZE(common_args);
1121
1122         const char * const backtrace_args[] = {
1123                 "-g",
1124         };
1125         unsigned int backtrace_args_no = ARRAY_SIZE(backtrace_args);
1126
1127         const char * const power_args[] = {
1128                 "-e", "power:cpu_frequency",
1129                 "-e", "power:cpu_idle",
1130         };
1131         unsigned int power_args_nr = ARRAY_SIZE(power_args);
1132
1133         const char * const old_power_args[] = {
1134 #ifdef SUPPORT_OLD_POWER_EVENTS
1135                 "-e", "power:power_start",
1136                 "-e", "power:power_end",
1137                 "-e", "power:power_frequency",
1138 #endif
1139         };
1140         unsigned int old_power_args_nr = ARRAY_SIZE(old_power_args);
1141
1142         const char * const tasks_args[] = {
1143                 "-e", "sched:sched_wakeup",
1144                 "-e", "sched:sched_switch",
1145         };
1146         unsigned int tasks_args_nr = ARRAY_SIZE(tasks_args);
1147
1148 #ifdef SUPPORT_OLD_POWER_EVENTS
1149         if (!is_valid_tracepoint("power:cpu_idle") &&
1150             is_valid_tracepoint("power:power_start")) {
1151                 use_old_power_events = 1;
1152                 power_args_nr = 0;
1153         } else {
1154                 old_power_args_nr = 0;
1155         }
1156 #endif
1157
1158         if (tchart->power_only)
1159                 tasks_args_nr = 0;
1160
1161         if (tchart->tasks_only) {
1162                 power_args_nr = 0;
1163                 old_power_args_nr = 0;
1164         }
1165
1166         if (!tchart->with_backtrace)
1167                 backtrace_args_no = 0;
1168
1169         record_elems = common_args_nr + tasks_args_nr +
1170                 power_args_nr + old_power_args_nr + backtrace_args_no;
1171
1172         rec_argc = record_elems + argc;
1173         rec_argv = calloc(rec_argc + 1, sizeof(char *));
1174
1175         if (rec_argv == NULL)
1176                 return -ENOMEM;
1177
1178         p = rec_argv;
1179         for (i = 0; i < common_args_nr; i++)
1180                 *p++ = strdup(common_args[i]);
1181
1182         for (i = 0; i < backtrace_args_no; i++)
1183                 *p++ = strdup(backtrace_args[i]);
1184
1185         for (i = 0; i < tasks_args_nr; i++)
1186                 *p++ = strdup(tasks_args[i]);
1187
1188         for (i = 0; i < power_args_nr; i++)
1189                 *p++ = strdup(power_args[i]);
1190
1191         for (i = 0; i < old_power_args_nr; i++)
1192                 *p++ = strdup(old_power_args[i]);
1193
1194         for (j = 1; j < (unsigned int)argc; j++)
1195                 *p++ = argv[j];
1196
1197         return cmd_record(rec_argc, rec_argv, NULL);
1198 }
1199
1200 static int
1201 parse_process(const struct option *opt __maybe_unused, const char *arg,
1202               int __maybe_unused unset)
1203 {
1204         if (arg)
1205                 add_process_filter(arg);
1206         return 0;
1207 }
1208
1209 int cmd_timechart(int argc, const char **argv,
1210                   const char *prefix __maybe_unused)
1211 {
1212         struct timechart tchart = {
1213                 .tool = {
1214                         .comm            = process_comm_event,
1215                         .fork            = process_fork_event,
1216                         .exit            = process_exit_event,
1217                         .sample          = process_sample_event,
1218                         .ordered_samples = true,
1219                 },
1220                 .proc_num = 15,
1221         };
1222         const char *output_name = "output.svg";
1223         const struct option timechart_options[] = {
1224         OPT_STRING('i', "input", &input_name, "file", "input file name"),
1225         OPT_STRING('o', "output", &output_name, "file", "output file name"),
1226         OPT_INTEGER('w', "width", &svg_page_width, "page width"),
1227         OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1228         OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1229                     "output processes data only"),
1230         OPT_CALLBACK('p', "process", NULL, "process",
1231                       "process selector. Pass a pid or process name.",
1232                        parse_process),
1233         OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
1234                     "Look for files with symbols relative to this directory"),
1235         OPT_INTEGER('n', "proc-num", &tchart.proc_num,
1236                     "min. number of tasks to print"),
1237         OPT_END()
1238         };
1239         const char * const timechart_usage[] = {
1240                 "perf timechart [<options>] {record}",
1241                 NULL
1242         };
1243
1244         const struct option record_options[] = {
1245         OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1246         OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1247                     "output processes data only"),
1248         OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"),
1249         OPT_END()
1250         };
1251         const char * const record_usage[] = {
1252                 "perf timechart record [<options>]",
1253                 NULL
1254         };
1255         argc = parse_options(argc, argv, timechart_options, timechart_usage,
1256                         PARSE_OPT_STOP_AT_NON_OPTION);
1257
1258         if (tchart.power_only && tchart.tasks_only) {
1259                 pr_err("-P and -T options cannot be used at the same time.\n");
1260                 return -1;
1261         }
1262
1263         symbol__init();
1264
1265         if (argc && !strncmp(argv[0], "rec", 3)) {
1266                 argc = parse_options(argc, argv, record_options, record_usage,
1267                                      PARSE_OPT_STOP_AT_NON_OPTION);
1268
1269                 if (tchart.power_only && tchart.tasks_only) {
1270                         pr_err("-P and -T options cannot be used at the same time.\n");
1271                         return -1;
1272                 }
1273
1274                 return timechart__record(&tchart, argc, argv);
1275         } else if (argc)
1276                 usage_with_options(timechart_usage, timechart_options);
1277
1278         setup_pager();
1279
1280         return __cmd_timechart(&tchart, output_name);
1281 }