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