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