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