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