xref: /openbmc/linux/tools/perf/builtin-timechart.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
210274989SArjan van de Ven /*
310274989SArjan van de Ven  * builtin-timechart.c - make an svg timechart of system activity
410274989SArjan van de Ven  *
510274989SArjan van de Ven  * (C) Copyright 2009 Intel Corporation
610274989SArjan van de Ven  *
710274989SArjan van de Ven  * Authors:
810274989SArjan van de Ven  *     Arjan van de Ven <arjan@linux.intel.com>
910274989SArjan van de Ven  */
1010274989SArjan van de Ven 
11a43783aeSArnaldo Carvalho de Melo #include <errno.h>
12fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
13c85cffa5SJiri Olsa 
1410274989SArjan van de Ven #include "builtin.h"
1510274989SArjan van de Ven #include "util/color.h"
1610274989SArjan van de Ven #include <linux/list.h>
177ae811b1SArnaldo Carvalho de Melo #include "util/evlist.h" // for struct evsel_str_handler
18e3f42609SArnaldo Carvalho de Melo #include "util/evsel.h"
19877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h>
2010274989SArjan van de Ven #include <linux/rbtree.h>
21af4b2c97SArnaldo Carvalho de Melo #include <linux/time64.h>
227f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
2310274989SArjan van de Ven #include "util/symbol.h"
24e7ff8920SArnaldo Carvalho de Melo #include "util/thread.h"
2510274989SArjan van de Ven #include "util/callchain.h"
2610274989SArjan van de Ven 
2710274989SArjan van de Ven #include "util/header.h"
28fa0d9846SArnaldo Carvalho de Melo #include <subcmd/pager.h>
294b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h>
3010274989SArjan van de Ven #include "util/parse-events.h"
315cbd0805SLi Zefan #include "util/event.h"
32301a0b02SArnaldo Carvalho de Melo #include "util/session.h"
3310274989SArjan van de Ven #include "util/svghelper.h"
3445694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
35f5fc1412SJiri Olsa #include "util/data.h"
3684f5d36fSJiri Olsa #include "util/debug.h"
37ae0f4eb3SWei Li #include "util/string2.h"
389b7c7728SIan Rogers #include "util/tracepoint.h"
39*f12ad272SIan Rogers #include "util/util.h"
406ef81c55SMamatha Inamdar #include <linux/err.h>
41378ef0f5SIan Rogers #include <traceevent/event-parse.h>
4210274989SArjan van de Ven 
43d7a8c4a6SArnaldo Carvalho de Melo #ifdef LACKS_OPEN_MEMSTREAM_PROTOTYPE
44d7a8c4a6SArnaldo Carvalho de Melo FILE *open_memstream(char **ptr, size_t *sizeloc);
45d7a8c4a6SArnaldo Carvalho de Melo #endif
46d7a8c4a6SArnaldo Carvalho de Melo 
4720c457b8SThomas Renninger #define SUPPORT_OLD_POWER_EVENTS 1
4820c457b8SThomas Renninger #define PWR_EVENT_EXIT -1
4920c457b8SThomas Renninger 
505e22f6d2SArnaldo Carvalho de Melo struct per_pid;
5166cc3adaSArnaldo Carvalho de Melo struct power_event;
52436b0da0SArnaldo Carvalho de Melo struct wake_event;
535e22f6d2SArnaldo Carvalho de Melo 
54985b12e6SArnaldo Carvalho de Melo struct timechart {
55985b12e6SArnaldo Carvalho de Melo 	struct perf_tool	tool;
565e22f6d2SArnaldo Carvalho de Melo 	struct per_pid		*all_data;
5766cc3adaSArnaldo Carvalho de Melo 	struct power_event	*power_events;
58436b0da0SArnaldo Carvalho de Melo 	struct wake_event	*wake_events;
59985b12e6SArnaldo Carvalho de Melo 	int			proc_num;
60985b12e6SArnaldo Carvalho de Melo 	unsigned int		numcpus;
61985b12e6SArnaldo Carvalho de Melo 	u64			min_freq,	/* Lowest CPU frequency seen */
62985b12e6SArnaldo Carvalho de Melo 				max_freq,	/* Highest CPU frequency seen */
63985b12e6SArnaldo Carvalho de Melo 				turbo_frequency,
64985b12e6SArnaldo Carvalho de Melo 				first_time, last_time;
65985b12e6SArnaldo Carvalho de Melo 	bool			power_only,
66985b12e6SArnaldo Carvalho de Melo 				tasks_only,
67c5079997SStanislav Fomichev 				with_backtrace,
68c5079997SStanislav Fomichev 				topology;
6986066064SArnaldo Carvalho de Melo 	bool			force;
70b97b59b9SStanislav Fomichev 	/* IO related settings */
71d243144aSStanislav Fomichev 	bool			io_only,
72d243144aSStanislav Fomichev 				skip_eagain;
7386066064SArnaldo Carvalho de Melo 	u64			io_events;
74d243144aSStanislav Fomichev 	u64			min_time,
75d243144aSStanislav Fomichev 				merge_dist;
76985b12e6SArnaldo Carvalho de Melo };
7710274989SArjan van de Ven 
7810274989SArjan van de Ven struct per_pidcomm;
7910274989SArjan van de Ven struct cpu_sample;
80b97b59b9SStanislav Fomichev struct io_sample;
8110274989SArjan van de Ven 
8210274989SArjan van de Ven /*
8310274989SArjan van de Ven  * Datastructure layout:
8410274989SArjan van de Ven  * We keep an list of "pid"s, matching the kernels notion of a task struct.
8510274989SArjan van de Ven  * Each "pid" entry, has a list of "comm"s.
8610274989SArjan van de Ven  *	this is because we want to track different programs different, while
8710274989SArjan van de Ven  *	exec will reuse the original pid (by design).
8810274989SArjan van de Ven  * Each comm has a list of samples that will be used to draw
8910274989SArjan van de Ven  * final graph.
9010274989SArjan van de Ven  */
9110274989SArjan van de Ven 
9210274989SArjan van de Ven struct per_pid {
9310274989SArjan van de Ven 	struct per_pid *next;
9410274989SArjan van de Ven 
9510274989SArjan van de Ven 	int		pid;
9610274989SArjan van de Ven 	int		ppid;
9710274989SArjan van de Ven 
9810274989SArjan van de Ven 	u64		start_time;
9910274989SArjan van de Ven 	u64		end_time;
10010274989SArjan van de Ven 	u64		total_time;
101b97b59b9SStanislav Fomichev 	u64		total_bytes;
10210274989SArjan van de Ven 	int		display;
10310274989SArjan van de Ven 
10410274989SArjan van de Ven 	struct per_pidcomm *all;
10510274989SArjan van de Ven 	struct per_pidcomm *current;
10610274989SArjan van de Ven };
10710274989SArjan van de Ven 
10810274989SArjan van de Ven 
10910274989SArjan van de Ven struct per_pidcomm {
11010274989SArjan van de Ven 	struct per_pidcomm *next;
11110274989SArjan van de Ven 
11210274989SArjan van de Ven 	u64		start_time;
11310274989SArjan van de Ven 	u64		end_time;
11410274989SArjan van de Ven 	u64		total_time;
115b97b59b9SStanislav Fomichev 	u64		max_bytes;
116b97b59b9SStanislav Fomichev 	u64		total_bytes;
11710274989SArjan van de Ven 
11810274989SArjan van de Ven 	int		Y;
11910274989SArjan van de Ven 	int		display;
12010274989SArjan van de Ven 
12110274989SArjan van de Ven 	long		state;
12210274989SArjan van de Ven 	u64		state_since;
12310274989SArjan van de Ven 
12410274989SArjan van de Ven 	char		*comm;
12510274989SArjan van de Ven 
12610274989SArjan van de Ven 	struct cpu_sample *samples;
127b97b59b9SStanislav Fomichev 	struct io_sample  *io_samples;
12810274989SArjan van de Ven };
12910274989SArjan van de Ven 
13010274989SArjan van de Ven struct sample_wrapper {
13110274989SArjan van de Ven 	struct sample_wrapper *next;
13210274989SArjan van de Ven 
13310274989SArjan van de Ven 	u64		timestamp;
1346549a8c0SGustavo A. R. Silva 	unsigned char	data[];
13510274989SArjan van de Ven };
13610274989SArjan van de Ven 
13710274989SArjan van de Ven #define TYPE_NONE	0
13810274989SArjan van de Ven #define TYPE_RUNNING	1
13910274989SArjan van de Ven #define TYPE_WAITING	2
14010274989SArjan van de Ven #define TYPE_BLOCKED	3
14110274989SArjan van de Ven 
14210274989SArjan van de Ven struct cpu_sample {
14310274989SArjan van de Ven 	struct cpu_sample *next;
14410274989SArjan van de Ven 
14510274989SArjan van de Ven 	u64 start_time;
14610274989SArjan van de Ven 	u64 end_time;
14710274989SArjan van de Ven 	int type;
14810274989SArjan van de Ven 	int cpu;
1496f8d67faSStanislav Fomichev 	const char *backtrace;
15010274989SArjan van de Ven };
15110274989SArjan van de Ven 
152b97b59b9SStanislav Fomichev enum {
153b97b59b9SStanislav Fomichev 	IOTYPE_READ,
154b97b59b9SStanislav Fomichev 	IOTYPE_WRITE,
155b97b59b9SStanislav Fomichev 	IOTYPE_SYNC,
156b97b59b9SStanislav Fomichev 	IOTYPE_TX,
157b97b59b9SStanislav Fomichev 	IOTYPE_RX,
158b97b59b9SStanislav Fomichev 	IOTYPE_POLL,
159b97b59b9SStanislav Fomichev };
160b97b59b9SStanislav Fomichev 
161b97b59b9SStanislav Fomichev struct io_sample {
162b97b59b9SStanislav Fomichev 	struct io_sample *next;
163b97b59b9SStanislav Fomichev 
164b97b59b9SStanislav Fomichev 	u64 start_time;
165b97b59b9SStanislav Fomichev 	u64 end_time;
166b97b59b9SStanislav Fomichev 	u64 bytes;
167b97b59b9SStanislav Fomichev 	int type;
168b97b59b9SStanislav Fomichev 	int fd;
169b97b59b9SStanislav Fomichev 	int err;
170b97b59b9SStanislav Fomichev 	int merges;
171b97b59b9SStanislav Fomichev };
172b97b59b9SStanislav Fomichev 
17310274989SArjan van de Ven #define CSTATE 1
17410274989SArjan van de Ven #define PSTATE 2
17510274989SArjan van de Ven 
17610274989SArjan van de Ven struct power_event {
17710274989SArjan van de Ven 	struct power_event *next;
17810274989SArjan van de Ven 	int type;
17910274989SArjan van de Ven 	int state;
18010274989SArjan van de Ven 	u64 start_time;
18110274989SArjan van de Ven 	u64 end_time;
18210274989SArjan van de Ven 	int cpu;
18310274989SArjan van de Ven };
18410274989SArjan van de Ven 
18510274989SArjan van de Ven struct wake_event {
18610274989SArjan van de Ven 	struct wake_event *next;
18710274989SArjan van de Ven 	int waker;
18810274989SArjan van de Ven 	int wakee;
18910274989SArjan van de Ven 	u64 time;
1906f8d67faSStanislav Fomichev 	const char *backtrace;
19110274989SArjan van de Ven };
19210274989SArjan van de Ven 
193bbe2987bSArjan van de Ven struct process_filter {
194bbe2987bSArjan van de Ven 	char			*name;
195bbe2987bSArjan van de Ven 	int			pid;
196bbe2987bSArjan van de Ven 	struct process_filter	*next;
197bbe2987bSArjan van de Ven };
198bbe2987bSArjan van de Ven 
199bbe2987bSArjan van de Ven static struct process_filter *process_filter;
200bbe2987bSArjan van de Ven 
201bbe2987bSArjan van de Ven 
find_create_pid(struct timechart * tchart,int pid)2025e22f6d2SArnaldo Carvalho de Melo static struct per_pid *find_create_pid(struct timechart *tchart, int pid)
20310274989SArjan van de Ven {
2045e22f6d2SArnaldo Carvalho de Melo 	struct per_pid *cursor = tchart->all_data;
20510274989SArjan van de Ven 
20610274989SArjan van de Ven 	while (cursor) {
20710274989SArjan van de Ven 		if (cursor->pid == pid)
20810274989SArjan van de Ven 			return cursor;
20910274989SArjan van de Ven 		cursor = cursor->next;
21010274989SArjan van de Ven 	}
211e0dcd6fbSArnaldo Carvalho de Melo 	cursor = zalloc(sizeof(*cursor));
21210274989SArjan van de Ven 	assert(cursor != NULL);
21310274989SArjan van de Ven 	cursor->pid = pid;
2145e22f6d2SArnaldo Carvalho de Melo 	cursor->next = tchart->all_data;
2155e22f6d2SArnaldo Carvalho de Melo 	tchart->all_data = cursor;
21610274989SArjan van de Ven 	return cursor;
21710274989SArjan van de Ven }
21810274989SArjan van de Ven 
create_pidcomm(struct per_pid * p)219569c746bSShang XiaoJing static struct per_pidcomm *create_pidcomm(struct per_pid *p)
220569c746bSShang XiaoJing {
221569c746bSShang XiaoJing 	struct per_pidcomm *c;
222569c746bSShang XiaoJing 
223569c746bSShang XiaoJing 	c = zalloc(sizeof(*c));
224569c746bSShang XiaoJing 	if (!c)
225569c746bSShang XiaoJing 		return NULL;
226569c746bSShang XiaoJing 	p->current = c;
227569c746bSShang XiaoJing 	c->next = p->all;
228569c746bSShang XiaoJing 	p->all = c;
229569c746bSShang XiaoJing 	return c;
230569c746bSShang XiaoJing }
231569c746bSShang XiaoJing 
pid_set_comm(struct timechart * tchart,int pid,char * comm)2325e22f6d2SArnaldo Carvalho de Melo static void pid_set_comm(struct timechart *tchart, int pid, char *comm)
23310274989SArjan van de Ven {
23410274989SArjan van de Ven 	struct per_pid *p;
23510274989SArjan van de Ven 	struct per_pidcomm *c;
2365e22f6d2SArnaldo Carvalho de Melo 	p = find_create_pid(tchart, pid);
23710274989SArjan van de Ven 	c = p->all;
23810274989SArjan van de Ven 	while (c) {
23910274989SArjan van de Ven 		if (c->comm && strcmp(c->comm, comm) == 0) {
24010274989SArjan van de Ven 			p->current = c;
24110274989SArjan van de Ven 			return;
24210274989SArjan van de Ven 		}
24310274989SArjan van de Ven 		if (!c->comm) {
24410274989SArjan van de Ven 			c->comm = strdup(comm);
24510274989SArjan van de Ven 			p->current = c;
24610274989SArjan van de Ven 			return;
24710274989SArjan van de Ven 		}
24810274989SArjan van de Ven 		c = c->next;
24910274989SArjan van de Ven 	}
250569c746bSShang XiaoJing 	c = create_pidcomm(p);
25110274989SArjan van de Ven 	assert(c != NULL);
25210274989SArjan van de Ven 	c->comm = strdup(comm);
25310274989SArjan van de Ven }
25410274989SArjan van de Ven 
pid_fork(struct timechart * tchart,int pid,int ppid,u64 timestamp)2555e22f6d2SArnaldo Carvalho de Melo static void pid_fork(struct timechart *tchart, int pid, int ppid, u64 timestamp)
25610274989SArjan van de Ven {
25710274989SArjan van de Ven 	struct per_pid *p, *pp;
2585e22f6d2SArnaldo Carvalho de Melo 	p = find_create_pid(tchart, pid);
2595e22f6d2SArnaldo Carvalho de Melo 	pp = find_create_pid(tchart, ppid);
26010274989SArjan van de Ven 	p->ppid = ppid;
26110274989SArjan van de Ven 	if (pp->current && pp->current->comm && !p->current)
2625e22f6d2SArnaldo Carvalho de Melo 		pid_set_comm(tchart, pid, pp->current->comm);
26310274989SArjan van de Ven 
26410274989SArjan van de Ven 	p->start_time = timestamp;
265962e310aSStanislav Fomichev 	if (p->current && !p->current->start_time) {
26610274989SArjan van de Ven 		p->current->start_time = timestamp;
26710274989SArjan van de Ven 		p->current->state_since = timestamp;
26810274989SArjan van de Ven 	}
26910274989SArjan van de Ven }
27010274989SArjan van de Ven 
pid_exit(struct timechart * tchart,int pid,u64 timestamp)2715e22f6d2SArnaldo Carvalho de Melo static void pid_exit(struct timechart *tchart, int pid, u64 timestamp)
27210274989SArjan van de Ven {
27310274989SArjan van de Ven 	struct per_pid *p;
2745e22f6d2SArnaldo Carvalho de Melo 	p = find_create_pid(tchart, pid);
27510274989SArjan van de Ven 	p->end_time = timestamp;
27610274989SArjan van de Ven 	if (p->current)
27710274989SArjan van de Ven 		p->current->end_time = timestamp;
27810274989SArjan van de Ven }
27910274989SArjan van de Ven 
pid_put_sample(struct timechart * tchart,int pid,int type,unsigned int cpu,u64 start,u64 end,const char * backtrace)2805e22f6d2SArnaldo Carvalho de Melo static void pid_put_sample(struct timechart *tchart, int pid, int type,
2815e22f6d2SArnaldo Carvalho de Melo 			   unsigned int cpu, u64 start, u64 end,
2826f8d67faSStanislav Fomichev 			   const char *backtrace)
28310274989SArjan van de Ven {
28410274989SArjan van de Ven 	struct per_pid *p;
28510274989SArjan van de Ven 	struct per_pidcomm *c;
28610274989SArjan van de Ven 	struct cpu_sample *sample;
28710274989SArjan van de Ven 
2885e22f6d2SArnaldo Carvalho de Melo 	p = find_create_pid(tchart, pid);
28910274989SArjan van de Ven 	c = p->current;
29010274989SArjan van de Ven 	if (!c) {
291569c746bSShang XiaoJing 		c = create_pidcomm(p);
29210274989SArjan van de Ven 		assert(c != NULL);
29310274989SArjan van de Ven 	}
29410274989SArjan van de Ven 
295e0dcd6fbSArnaldo Carvalho de Melo 	sample = zalloc(sizeof(*sample));
29610274989SArjan van de Ven 	assert(sample != NULL);
29710274989SArjan van de Ven 	sample->start_time = start;
29810274989SArjan van de Ven 	sample->end_time = end;
29910274989SArjan van de Ven 	sample->type = type;
30010274989SArjan van de Ven 	sample->next = c->samples;
30110274989SArjan van de Ven 	sample->cpu = cpu;
3026f8d67faSStanislav Fomichev 	sample->backtrace = backtrace;
30310274989SArjan van de Ven 	c->samples = sample;
30410274989SArjan van de Ven 
30510274989SArjan van de Ven 	if (sample->type == TYPE_RUNNING && end > start && start > 0) {
30610274989SArjan van de Ven 		c->total_time += (end-start);
30710274989SArjan van de Ven 		p->total_time += (end-start);
30810274989SArjan van de Ven 	}
30910274989SArjan van de Ven 
31010274989SArjan van de Ven 	if (c->start_time == 0 || c->start_time > start)
31110274989SArjan van de Ven 		c->start_time = start;
31210274989SArjan van de Ven 	if (p->start_time == 0 || p->start_time > start)
31310274989SArjan van de Ven 		p->start_time = start;
31410274989SArjan van de Ven }
31510274989SArjan van de Ven 
31610274989SArjan van de Ven #define MAX_CPUS 4096
31710274989SArjan van de Ven 
31810274989SArjan van de Ven static u64 *cpus_cstate_start_times;
31910274989SArjan van de Ven static int *cpus_cstate_state;
32010274989SArjan van de Ven static u64 *cpus_pstate_start_times;
32110274989SArjan van de Ven static u64 *cpus_pstate_state;
32210274989SArjan van de Ven 
process_comm_event(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine __maybe_unused)3235e22f6d2SArnaldo Carvalho de Melo static int process_comm_event(struct perf_tool *tool,
324d20deb64SArnaldo Carvalho de Melo 			      union perf_event *event,
3251d037ca1SIrina Tirdea 			      struct perf_sample *sample __maybe_unused,
3261d037ca1SIrina Tirdea 			      struct machine *machine __maybe_unused)
32710274989SArjan van de Ven {
3285e22f6d2SArnaldo Carvalho de Melo 	struct timechart *tchart = container_of(tool, struct timechart, tool);
3295e22f6d2SArnaldo Carvalho de Melo 	pid_set_comm(tchart, event->comm.tid, event->comm.comm);
33010274989SArjan van de Ven 	return 0;
33110274989SArjan van de Ven }
332d8f66248SArnaldo Carvalho de Melo 
process_fork_event(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine __maybe_unused)3335e22f6d2SArnaldo Carvalho de Melo static int process_fork_event(struct perf_tool *tool,
334d20deb64SArnaldo Carvalho de Melo 			      union perf_event *event,
3351d037ca1SIrina Tirdea 			      struct perf_sample *sample __maybe_unused,
3361d037ca1SIrina Tirdea 			      struct machine *machine __maybe_unused)
33710274989SArjan van de Ven {
3385e22f6d2SArnaldo Carvalho de Melo 	struct timechart *tchart = container_of(tool, struct timechart, tool);
3395e22f6d2SArnaldo Carvalho de Melo 	pid_fork(tchart, event->fork.pid, event->fork.ppid, event->fork.time);
34010274989SArjan van de Ven 	return 0;
34110274989SArjan van de Ven }
34210274989SArjan van de Ven 
process_exit_event(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine __maybe_unused)3435e22f6d2SArnaldo Carvalho de Melo static int process_exit_event(struct perf_tool *tool,
344d20deb64SArnaldo Carvalho de Melo 			      union perf_event *event,
3451d037ca1SIrina Tirdea 			      struct perf_sample *sample __maybe_unused,
3461d037ca1SIrina Tirdea 			      struct machine *machine __maybe_unused)
34710274989SArjan van de Ven {
3485e22f6d2SArnaldo Carvalho de Melo 	struct timechart *tchart = container_of(tool, struct timechart, tool);
3495e22f6d2SArnaldo Carvalho de Melo 	pid_exit(tchart, event->fork.pid, event->fork.time);
35010274989SArjan van de Ven 	return 0;
35110274989SArjan van de Ven }
35210274989SArjan van de Ven 
35320c457b8SThomas Renninger #ifdef SUPPORT_OLD_POWER_EVENTS
35420c457b8SThomas Renninger static int use_old_power_events;
35520c457b8SThomas Renninger #endif
35620c457b8SThomas Renninger 
c_state_start(int cpu,u64 timestamp,int state)35710274989SArjan van de Ven static void c_state_start(int cpu, u64 timestamp, int state)
35810274989SArjan van de Ven {
35910274989SArjan van de Ven 	cpus_cstate_start_times[cpu] = timestamp;
36010274989SArjan van de Ven 	cpus_cstate_state[cpu] = state;
36110274989SArjan van de Ven }
36210274989SArjan van de Ven 
c_state_end(struct timechart * tchart,int cpu,u64 timestamp)36366cc3adaSArnaldo Carvalho de Melo static void c_state_end(struct timechart *tchart, int cpu, u64 timestamp)
36410274989SArjan van de Ven {
365e0dcd6fbSArnaldo Carvalho de Melo 	struct power_event *pwr = zalloc(sizeof(*pwr));
366e0dcd6fbSArnaldo Carvalho de Melo 
36710274989SArjan van de Ven 	if (!pwr)
36810274989SArjan van de Ven 		return;
36910274989SArjan van de Ven 
37010274989SArjan van de Ven 	pwr->state = cpus_cstate_state[cpu];
37110274989SArjan van de Ven 	pwr->start_time = cpus_cstate_start_times[cpu];
37210274989SArjan van de Ven 	pwr->end_time = timestamp;
37310274989SArjan van de Ven 	pwr->cpu = cpu;
37410274989SArjan van de Ven 	pwr->type = CSTATE;
37566cc3adaSArnaldo Carvalho de Melo 	pwr->next = tchart->power_events;
37610274989SArjan van de Ven 
37766cc3adaSArnaldo Carvalho de Melo 	tchart->power_events = pwr;
37810274989SArjan van de Ven }
37910274989SArjan van de Ven 
p_state_end(struct timechart * tchart,int cpu,u64 timestamp)3803e8d21b9SShang XiaoJing static struct power_event *p_state_end(struct timechart *tchart, int cpu,
3813e8d21b9SShang XiaoJing 					u64 timestamp)
38210274989SArjan van de Ven {
3833e8d21b9SShang XiaoJing 	struct power_event *pwr = zalloc(sizeof(*pwr));
38410274989SArjan van de Ven 
38510274989SArjan van de Ven 	if (!pwr)
3863e8d21b9SShang XiaoJing 		return NULL;
38710274989SArjan van de Ven 
38810274989SArjan van de Ven 	pwr->state = cpus_pstate_state[cpu];
38910274989SArjan van de Ven 	pwr->start_time = cpus_pstate_start_times[cpu];
39010274989SArjan van de Ven 	pwr->end_time = timestamp;
39110274989SArjan van de Ven 	pwr->cpu = cpu;
39210274989SArjan van de Ven 	pwr->type = PSTATE;
39366cc3adaSArnaldo Carvalho de Melo 	pwr->next = tchart->power_events;
39410274989SArjan van de Ven 	if (!pwr->start_time)
395985b12e6SArnaldo Carvalho de Melo 		pwr->start_time = tchart->first_time;
39610274989SArjan van de Ven 
39766cc3adaSArnaldo Carvalho de Melo 	tchart->power_events = pwr;
3983e8d21b9SShang XiaoJing 	return pwr;
3993e8d21b9SShang XiaoJing }
4003e8d21b9SShang XiaoJing 
p_state_change(struct timechart * tchart,int cpu,u64 timestamp,u64 new_freq)4013e8d21b9SShang XiaoJing static void p_state_change(struct timechart *tchart, int cpu, u64 timestamp, u64 new_freq)
4023e8d21b9SShang XiaoJing {
4033e8d21b9SShang XiaoJing 	struct power_event *pwr;
4043e8d21b9SShang XiaoJing 
4053e8d21b9SShang XiaoJing 	if (new_freq > 8000000) /* detect invalid data */
4063e8d21b9SShang XiaoJing 		return;
4073e8d21b9SShang XiaoJing 
4083e8d21b9SShang XiaoJing 	pwr = p_state_end(tchart, cpu, timestamp);
4093e8d21b9SShang XiaoJing 	if (!pwr)
4103e8d21b9SShang XiaoJing 		return;
41110274989SArjan van de Ven 
41210274989SArjan van de Ven 	cpus_pstate_state[cpu] = new_freq;
41310274989SArjan van de Ven 	cpus_pstate_start_times[cpu] = timestamp;
41410274989SArjan van de Ven 
415985b12e6SArnaldo Carvalho de Melo 	if ((u64)new_freq > tchart->max_freq)
416985b12e6SArnaldo Carvalho de Melo 		tchart->max_freq = new_freq;
41710274989SArjan van de Ven 
418985b12e6SArnaldo Carvalho de Melo 	if (new_freq < tchart->min_freq || tchart->min_freq == 0)
419985b12e6SArnaldo Carvalho de Melo 		tchart->min_freq = new_freq;
42010274989SArjan van de Ven 
421985b12e6SArnaldo Carvalho de Melo 	if (new_freq == tchart->max_freq - 1000)
422985b12e6SArnaldo Carvalho de Melo 		tchart->turbo_frequency = tchart->max_freq;
42310274989SArjan van de Ven }
42410274989SArjan van de Ven 
sched_wakeup(struct timechart * tchart,int cpu,u64 timestamp,int waker,int wakee,u8 flags,const char * backtrace)4255e22f6d2SArnaldo Carvalho de Melo static void sched_wakeup(struct timechart *tchart, int cpu, u64 timestamp,
4265e22f6d2SArnaldo Carvalho de Melo 			 int waker, int wakee, u8 flags, const char *backtrace)
42710274989SArjan van de Ven {
42810274989SArjan van de Ven 	struct per_pid *p;
429e0dcd6fbSArnaldo Carvalho de Melo 	struct wake_event *we = zalloc(sizeof(*we));
43010274989SArjan van de Ven 
43110274989SArjan van de Ven 	if (!we)
43210274989SArjan van de Ven 		return;
43310274989SArjan van de Ven 
43410274989SArjan van de Ven 	we->time = timestamp;
4353ed0d21eSStanislav Fomichev 	we->waker = waker;
4366f8d67faSStanislav Fomichev 	we->backtrace = backtrace;
43710274989SArjan van de Ven 
4383ed0d21eSStanislav Fomichev 	if ((flags & TRACE_FLAG_HARDIRQ) || (flags & TRACE_FLAG_SOFTIRQ))
43910274989SArjan van de Ven 		we->waker = -1;
44010274989SArjan van de Ven 
4413ed0d21eSStanislav Fomichev 	we->wakee = wakee;
442436b0da0SArnaldo Carvalho de Melo 	we->next = tchart->wake_events;
443436b0da0SArnaldo Carvalho de Melo 	tchart->wake_events = we;
4445e22f6d2SArnaldo Carvalho de Melo 	p = find_create_pid(tchart, we->wakee);
44510274989SArjan van de Ven 
44610274989SArjan van de Ven 	if (p && p->current && p->current->state == TYPE_NONE) {
44710274989SArjan van de Ven 		p->current->state_since = timestamp;
44810274989SArjan van de Ven 		p->current->state = TYPE_WAITING;
44910274989SArjan van de Ven 	}
45010274989SArjan van de Ven 	if (p && p->current && p->current->state == TYPE_BLOCKED) {
4515e22f6d2SArnaldo Carvalho de Melo 		pid_put_sample(tchart, p->pid, p->current->state, cpu,
4526f8d67faSStanislav Fomichev 			       p->current->state_since, timestamp, NULL);
45310274989SArjan van de Ven 		p->current->state_since = timestamp;
45410274989SArjan van de Ven 		p->current->state = TYPE_WAITING;
45510274989SArjan van de Ven 	}
45610274989SArjan van de Ven }
45710274989SArjan van de Ven 
sched_switch(struct timechart * tchart,int cpu,u64 timestamp,int prev_pid,int next_pid,u64 prev_state,const char * backtrace)4585e22f6d2SArnaldo Carvalho de Melo static void sched_switch(struct timechart *tchart, int cpu, u64 timestamp,
4595e22f6d2SArnaldo Carvalho de Melo 			 int prev_pid, int next_pid, u64 prev_state,
4605e22f6d2SArnaldo Carvalho de Melo 			 const char *backtrace)
46110274989SArjan van de Ven {
46210274989SArjan van de Ven 	struct per_pid *p = NULL, *prev_p;
46310274989SArjan van de Ven 
4645e22f6d2SArnaldo Carvalho de Melo 	prev_p = find_create_pid(tchart, prev_pid);
46510274989SArjan van de Ven 
4665e22f6d2SArnaldo Carvalho de Melo 	p = find_create_pid(tchart, next_pid);
46710274989SArjan van de Ven 
46810274989SArjan van de Ven 	if (prev_p->current && prev_p->current->state != TYPE_NONE)
4695e22f6d2SArnaldo Carvalho de Melo 		pid_put_sample(tchart, prev_pid, TYPE_RUNNING, cpu,
4706f8d67faSStanislav Fomichev 			       prev_p->current->state_since, timestamp,
4716f8d67faSStanislav Fomichev 			       backtrace);
47210274989SArjan van de Ven 	if (p && p->current) {
47310274989SArjan van de Ven 		if (p->current->state != TYPE_NONE)
4745e22f6d2SArnaldo Carvalho de Melo 			pid_put_sample(tchart, next_pid, p->current->state, cpu,
4756f8d67faSStanislav Fomichev 				       p->current->state_since, timestamp,
4766f8d67faSStanislav Fomichev 				       backtrace);
47710274989SArjan van de Ven 
47810274989SArjan van de Ven 		p->current->state_since = timestamp;
47910274989SArjan van de Ven 		p->current->state = TYPE_RUNNING;
48010274989SArjan van de Ven 	}
48110274989SArjan van de Ven 
48210274989SArjan van de Ven 	if (prev_p->current) {
48310274989SArjan van de Ven 		prev_p->current->state = TYPE_NONE;
48410274989SArjan van de Ven 		prev_p->current->state_since = timestamp;
4853ed0d21eSStanislav Fomichev 		if (prev_state & 2)
48610274989SArjan van de Ven 			prev_p->current->state = TYPE_BLOCKED;
4873ed0d21eSStanislav Fomichev 		if (prev_state == 0)
48810274989SArjan van de Ven 			prev_p->current->state = TYPE_WAITING;
48910274989SArjan van de Ven 	}
49010274989SArjan van de Ven }
49110274989SArjan van de Ven 
cat_backtrace(union perf_event * event,struct perf_sample * sample,struct machine * machine)4926f8d67faSStanislav Fomichev static const char *cat_backtrace(union perf_event *event,
4936f8d67faSStanislav Fomichev 				 struct perf_sample *sample,
4946f8d67faSStanislav Fomichev 				 struct machine *machine)
4956f8d67faSStanislav Fomichev {
4966f8d67faSStanislav Fomichev 	struct addr_location al;
4976f8d67faSStanislav Fomichev 	unsigned int i;
4986f8d67faSStanislav Fomichev 	char *p = NULL;
4996f8d67faSStanislav Fomichev 	size_t p_len;
5006f8d67faSStanislav Fomichev 	u8 cpumode = PERF_RECORD_MISC_USER;
5016f8d67faSStanislav Fomichev 	struct ip_callchain *chain = sample->callchain;
5026f8d67faSStanislav Fomichev 	FILE *f = open_memstream(&p, &p_len);
5036f8d67faSStanislav Fomichev 
5046f8d67faSStanislav Fomichev 	if (!f) {
5056f8d67faSStanislav Fomichev 		perror("open_memstream error");
5066f8d67faSStanislav Fomichev 		return NULL;
5076f8d67faSStanislav Fomichev 	}
5086f8d67faSStanislav Fomichev 
5096f8d67faSStanislav Fomichev 	addr_location__init(&al);
5106f8d67faSStanislav Fomichev 	if (!chain)
5116f8d67faSStanislav Fomichev 		goto exit;
5126f8d67faSStanislav Fomichev 
513bb3eb566SArnaldo Carvalho de Melo 	if (machine__resolve(machine, &al, sample) < 0) {
5146f8d67faSStanislav Fomichev 		fprintf(stderr, "problem processing %d event, skipping it.\n",
5156f8d67faSStanislav Fomichev 			event->header.type);
5166f8d67faSStanislav Fomichev 		goto exit;
5176f8d67faSStanislav Fomichev 	}
5186f8d67faSStanislav Fomichev 
5196f8d67faSStanislav Fomichev 	for (i = 0; i < chain->nr; i++) {
5206f8d67faSStanislav Fomichev 		u64 ip;
5216f8d67faSStanislav Fomichev 		struct addr_location tal;
5226f8d67faSStanislav Fomichev 
5236f8d67faSStanislav Fomichev 		if (callchain_param.order == ORDER_CALLEE)
5246f8d67faSStanislav Fomichev 			ip = chain->ips[i];
5256f8d67faSStanislav Fomichev 		else
5266f8d67faSStanislav Fomichev 			ip = chain->ips[chain->nr - i - 1];
5276f8d67faSStanislav Fomichev 
5286f8d67faSStanislav Fomichev 		if (ip >= PERF_CONTEXT_MAX) {
5296f8d67faSStanislav Fomichev 			switch (ip) {
5306f8d67faSStanislav Fomichev 			case PERF_CONTEXT_HV:
5316f8d67faSStanislav Fomichev 				cpumode = PERF_RECORD_MISC_HYPERVISOR;
5326f8d67faSStanislav Fomichev 				break;
5336f8d67faSStanislav Fomichev 			case PERF_CONTEXT_KERNEL:
5346f8d67faSStanislav Fomichev 				cpumode = PERF_RECORD_MISC_KERNEL;
5356f8d67faSStanislav Fomichev 				break;
5366f8d67faSStanislav Fomichev 			case PERF_CONTEXT_USER:
5376f8d67faSStanislav Fomichev 				cpumode = PERF_RECORD_MISC_USER;
5386f8d67faSStanislav Fomichev 				break;
5396f8d67faSStanislav Fomichev 			default:
5406f8d67faSStanislav Fomichev 				pr_debug("invalid callchain context: "
5416f8d67faSStanislav Fomichev 					 "%"PRId64"\n", (s64) ip);
5426f8d67faSStanislav Fomichev 
5436f8d67faSStanislav Fomichev 				/*
5446f8d67faSStanislav Fomichev 				 * It seems the callchain is corrupted.
5456f8d67faSStanislav Fomichev 				 * Discard all.
54604662523SArnaldo Carvalho de Melo 				 */
547b91fc39fSArnaldo Carvalho de Melo 				zfree(&p);
5486f8d67faSStanislav Fomichev 				goto exit;
5496f8d67faSStanislav Fomichev 			}
5506f8d67faSStanislav Fomichev 			continue;
5516f8d67faSStanislav Fomichev 		}
552b3cef7f6SNamhyung Kim 
553d9a5f274SArnaldo Carvalho de Melo 		addr_location__init(&tal);
554d9a5f274SArnaldo Carvalho de Melo 		tal.filtered = 0;
5556f8d67faSStanislav Fomichev 		if (thread__find_symbol(al.thread, cpumode, ip, &tal))
5566f8d67faSStanislav Fomichev 			fprintf(f, "..... %016" PRIx64 " %s\n", ip, tal.sym->name);
5576f8d67faSStanislav Fomichev 		else
558b91fc39fSArnaldo Carvalho de Melo 			fprintf(f, "..... %016" PRIx64 "\n", ip);
559b91fc39fSArnaldo Carvalho de Melo 
5606f8d67faSStanislav Fomichev 		addr_location__exit(&tal);
5616f8d67faSStanislav Fomichev 	}
5626f8d67faSStanislav Fomichev exit:
5636f8d67faSStanislav Fomichev 	addr_location__exit(&al);
5646f8d67faSStanislav Fomichev 	fclose(f);
5656f8d67faSStanislav Fomichev 
566985b12e6SArnaldo Carvalho de Melo 	return p;
56732dcd021SJiri Olsa }
5686f8d67faSStanislav Fomichev 
5696f8d67faSStanislav Fomichev typedef int (*tracepoint_handler)(struct timechart *tchart,
57010274989SArjan van de Ven 				  struct evsel *evsel,
571985b12e6SArnaldo Carvalho de Melo 				  struct perf_sample *sample,
572972ec653SArnaldo Carvalho de Melo 				  const char *backtrace);
5738d50e5b4SArnaldo Carvalho de Melo 
process_sample_event(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct evsel * evsel,struct machine * machine)57432dcd021SJiri Olsa static int process_sample_event(struct perf_tool *tool,
575985b12e6SArnaldo Carvalho de Melo 				union perf_event *event,
57610274989SArjan van de Ven 				struct perf_sample *sample,
577985b12e6SArnaldo Carvalho de Melo 				struct evsel *evsel,
578985b12e6SArnaldo Carvalho de Melo 				struct machine *machine)
5791fc632ceSJiri Olsa {
580985b12e6SArnaldo Carvalho de Melo 	struct timechart *tchart = container_of(tool, struct timechart, tool);
581985b12e6SArnaldo Carvalho de Melo 
582985b12e6SArnaldo Carvalho de Melo 	if (evsel->core.attr.sample_type & PERF_SAMPLE_TIME) {
583985b12e6SArnaldo Carvalho de Melo 		if (!tchart->first_time || tchart->first_time > sample->time)
58410274989SArjan van de Ven 			tchart->first_time = sample->time;
58510274989SArjan van de Ven 		if (tchart->last_time < sample->time)
586744a9719SArnaldo Carvalho de Melo 			tchart->last_time = sample->time;
587744a9719SArnaldo Carvalho de Melo 	}
58858b9a18eSStanislav Fomichev 
58958b9a18eSStanislav Fomichev 	if (evsel->handler != NULL) {
5905936678eSJiri Olsa 		tracepoint_handler f = evsel->handler;
5915936678eSJiri Olsa 		return f(tchart, evsel, sample,
5925936678eSJiri Olsa 			 cat_backtrace(event, sample, machine));
5935936678eSJiri Olsa 	}
5945936678eSJiri Olsa 
5955936678eSJiri Olsa 	return 0;
596985b12e6SArnaldo Carvalho de Melo }
59732dcd021SJiri Olsa 
5986f8d67faSStanislav Fomichev static int
process_sample_cpu_idle(struct timechart * tchart __maybe_unused,struct evsel * evsel,struct perf_sample * sample,const char * backtrace __maybe_unused)5996f8d67faSStanislav Fomichev process_sample_cpu_idle(struct timechart *tchart __maybe_unused,
6005936678eSJiri Olsa 			struct evsel *evsel,
601efc0cdc9SArnaldo Carvalho de Melo 			struct perf_sample *sample,
602efc0cdc9SArnaldo Carvalho de Melo 			const char *backtrace __maybe_unused)
6035936678eSJiri Olsa {
6043ed0d21eSStanislav Fomichev 	u32 state  = evsel__intval(evsel, sample, "state");
60566cc3adaSArnaldo Carvalho de Melo 	u32 cpu_id = evsel__intval(evsel, sample, "cpu_id");
60620c457b8SThomas Renninger 
6073ed0d21eSStanislav Fomichev 	if (state == (u32)PWR_EVENT_EXIT)
60810274989SArjan van de Ven 		c_state_end(tchart, cpu_id, sample->time);
60910274989SArjan van de Ven 	else
61010274989SArjan van de Ven 		c_state_start(cpu_id, sample->time, state);
6115936678eSJiri Olsa 	return 0;
612985b12e6SArnaldo Carvalho de Melo }
61332dcd021SJiri Olsa 
6146f8d67faSStanislav Fomichev static int
process_sample_cpu_frequency(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample,const char * backtrace __maybe_unused)6156f8d67faSStanislav Fomichev process_sample_cpu_frequency(struct timechart *tchart,
6165936678eSJiri Olsa 			     struct evsel *evsel,
617efc0cdc9SArnaldo Carvalho de Melo 			     struct perf_sample *sample,
618efc0cdc9SArnaldo Carvalho de Melo 			     const char *backtrace __maybe_unused)
6195936678eSJiri Olsa {
620985b12e6SArnaldo Carvalho de Melo 	u32 state  = evsel__intval(evsel, sample, "state");
6215936678eSJiri Olsa 	u32 cpu_id = evsel__intval(evsel, sample, "cpu_id");
6225936678eSJiri Olsa 
6235936678eSJiri Olsa 	p_state_change(tchart, cpu_id, sample->time, state);
6245936678eSJiri Olsa 	return 0;
6255e22f6d2SArnaldo Carvalho de Melo }
62632dcd021SJiri Olsa 
6276f8d67faSStanislav Fomichev static int
process_sample_sched_wakeup(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample,const char * backtrace)6286f8d67faSStanislav Fomichev process_sample_sched_wakeup(struct timechart *tchart,
6295936678eSJiri Olsa 			    struct evsel *evsel,
630efc0cdc9SArnaldo Carvalho de Melo 			    struct perf_sample *sample,
631efc0cdc9SArnaldo Carvalho de Melo 			    const char *backtrace)
632efc0cdc9SArnaldo Carvalho de Melo {
6335936678eSJiri Olsa 	u8 flags  = evsel__intval(evsel, sample, "common_flags");
6345e22f6d2SArnaldo Carvalho de Melo 	int waker = evsel__intval(evsel, sample, "common_pid");
6355936678eSJiri Olsa 	int wakee = evsel__intval(evsel, sample, "pid");
6365936678eSJiri Olsa 
6375936678eSJiri Olsa 	sched_wakeup(tchart, sample->cpu, sample->time, waker, wakee, flags, backtrace);
6385936678eSJiri Olsa 	return 0;
6395e22f6d2SArnaldo Carvalho de Melo }
64032dcd021SJiri Olsa 
6416f8d67faSStanislav Fomichev static int
process_sample_sched_switch(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample,const char * backtrace)6426f8d67faSStanislav Fomichev process_sample_sched_switch(struct timechart *tchart,
6435936678eSJiri Olsa 			    struct evsel *evsel,
644efc0cdc9SArnaldo Carvalho de Melo 			    struct perf_sample *sample,
645efc0cdc9SArnaldo Carvalho de Melo 			    const char *backtrace)
646efc0cdc9SArnaldo Carvalho de Melo {
6475936678eSJiri Olsa 	int prev_pid   = evsel__intval(evsel, sample, "prev_pid");
6485e22f6d2SArnaldo Carvalho de Melo 	int next_pid   = evsel__intval(evsel, sample, "next_pid");
6495e22f6d2SArnaldo Carvalho de Melo 	u64 prev_state = evsel__intval(evsel, sample, "prev_state");
6505936678eSJiri Olsa 
6515936678eSJiri Olsa 	sched_switch(tchart, sample->cpu, sample->time, prev_pid, next_pid,
6525936678eSJiri Olsa 		     prev_state, backtrace);
6535936678eSJiri Olsa 	return 0;
6545936678eSJiri Olsa }
655985b12e6SArnaldo Carvalho de Melo 
65632dcd021SJiri Olsa #ifdef SUPPORT_OLD_POWER_EVENTS
6576f8d67faSStanislav Fomichev static int
process_sample_power_start(struct timechart * tchart __maybe_unused,struct evsel * evsel,struct perf_sample * sample,const char * backtrace __maybe_unused)6586f8d67faSStanislav Fomichev process_sample_power_start(struct timechart *tchart __maybe_unused,
6595936678eSJiri Olsa 			   struct evsel *evsel,
660efc0cdc9SArnaldo Carvalho de Melo 			   struct perf_sample *sample,
661efc0cdc9SArnaldo Carvalho de Melo 			   const char *backtrace __maybe_unused)
6625936678eSJiri Olsa {
6633ed0d21eSStanislav Fomichev 	u64 cpu_id = evsel__intval(evsel, sample, "cpu_id");
6645936678eSJiri Olsa 	u64 value  = evsel__intval(evsel, sample, "value");
6655936678eSJiri Olsa 
6665936678eSJiri Olsa 	c_state_start(cpu_id, sample->time, value);
6675936678eSJiri Olsa 	return 0;
66866cc3adaSArnaldo Carvalho de Melo }
66932dcd021SJiri Olsa 
6706f8d67faSStanislav Fomichev static int
process_sample_power_end(struct timechart * tchart,struct evsel * evsel __maybe_unused,struct perf_sample * sample,const char * backtrace __maybe_unused)6716f8d67faSStanislav Fomichev process_sample_power_end(struct timechart *tchart,
6725936678eSJiri Olsa 			 struct evsel *evsel __maybe_unused,
67366cc3adaSArnaldo Carvalho de Melo 			 struct perf_sample *sample,
6745936678eSJiri Olsa 			 const char *backtrace __maybe_unused)
6755936678eSJiri Olsa {
6765936678eSJiri Olsa 	c_state_end(tchart, sample->cpu, sample->time);
6775936678eSJiri Olsa 	return 0;
678985b12e6SArnaldo Carvalho de Melo }
67932dcd021SJiri Olsa 
6806f8d67faSStanislav Fomichev static int
process_sample_power_frequency(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample,const char * backtrace __maybe_unused)6816f8d67faSStanislav Fomichev process_sample_power_frequency(struct timechart *tchart,
6825936678eSJiri Olsa 			       struct evsel *evsel,
683efc0cdc9SArnaldo Carvalho de Melo 			       struct perf_sample *sample,
684efc0cdc9SArnaldo Carvalho de Melo 			       const char *backtrace __maybe_unused)
6855936678eSJiri Olsa {
686985b12e6SArnaldo Carvalho de Melo 	u64 cpu_id = evsel__intval(evsel, sample, "cpu_id");
6875936678eSJiri Olsa 	u64 value  = evsel__intval(evsel, sample, "value");
6885936678eSJiri Olsa 
6895936678eSJiri Olsa 	p_state_change(tchart, cpu_id, sample->time, value);
6905936678eSJiri Olsa 	return 0;
69110274989SArjan van de Ven }
69210274989SArjan van de Ven #endif /* SUPPORT_OLD_POWER_EVENTS */
69310274989SArjan van de Ven 
69410274989SArjan van de Ven /*
695985b12e6SArnaldo Carvalho de Melo  * After the last sample we need to wrap up the current C/P state
69610274989SArjan van de Ven  * and close out each CPU for these.
69710274989SArjan van de Ven  */
end_sample_processing(struct timechart * tchart)69810274989SArjan van de Ven static void end_sample_processing(struct timechart *tchart)
69910274989SArjan van de Ven {
700985b12e6SArnaldo Carvalho de Melo 	u64 cpu;
70110274989SArjan van de Ven 	struct power_event *pwr;
70210274989SArjan van de Ven 
703e0dcd6fbSArnaldo Carvalho de Melo 	for (cpu = 0; cpu <= tchart->numcpus; cpu++) {
704e0dcd6fbSArnaldo Carvalho de Melo 		/* C state */
705e0dcd6fbSArnaldo Carvalho de Melo #if 0
706e0dcd6fbSArnaldo Carvalho de Melo 		pwr = zalloc(sizeof(*pwr));
70710274989SArjan van de Ven 		if (!pwr)
70810274989SArjan van de Ven 			return;
709985b12e6SArnaldo Carvalho de Melo 
71010274989SArjan van de Ven 		pwr->state = cpus_cstate_state[cpu];
71110274989SArjan van de Ven 		pwr->start_time = cpus_cstate_start_times[cpu];
71266cc3adaSArnaldo Carvalho de Melo 		pwr->end_time = tchart->last_time;
71310274989SArjan van de Ven 		pwr->cpu = cpu;
71466cc3adaSArnaldo Carvalho de Melo 		pwr->type = CSTATE;
71510274989SArjan van de Ven 		pwr->next = tchart->power_events;
71610274989SArjan van de Ven 
71710274989SArjan van de Ven 		tchart->power_events = pwr;
7183e8d21b9SShang XiaoJing #endif
71910274989SArjan van de Ven 		/* P state */
72010274989SArjan van de Ven 
72110274989SArjan van de Ven 		pwr = p_state_end(tchart, cpu, tchart->last_time);
72210274989SArjan van de Ven 		if (!pwr)
723985b12e6SArnaldo Carvalho de Melo 			return;
72410274989SArjan van de Ven 
72510274989SArjan van de Ven 		if (!pwr->state)
72610274989SArjan van de Ven 			pwr->state = tchart->min_freq;
727b97b59b9SStanislav Fomichev 	}
728b97b59b9SStanislav Fomichev }
729b97b59b9SStanislav Fomichev 
pid_begin_io_sample(struct timechart * tchart,int pid,int type,u64 start,int fd)730b97b59b9SStanislav Fomichev static int pid_begin_io_sample(struct timechart *tchart, int pid, int type,
731b97b59b9SStanislav Fomichev 			       u64 start, int fd)
732b97b59b9SStanislav Fomichev {
733b97b59b9SStanislav Fomichev 	struct per_pid *p = find_create_pid(tchart, pid);
734b97b59b9SStanislav Fomichev 	struct per_pidcomm *c = p->current;
735b97b59b9SStanislav Fomichev 	struct io_sample *sample;
736569c746bSShang XiaoJing 	struct io_sample *prev;
737b97b59b9SStanislav Fomichev 
738b97b59b9SStanislav Fomichev 	if (!c) {
739b97b59b9SStanislav Fomichev 		c = create_pidcomm(p);
740b97b59b9SStanislav Fomichev 		if (!c)
741b97b59b9SStanislav Fomichev 			return -ENOMEM;
742b97b59b9SStanislav Fomichev 	}
743b97b59b9SStanislav Fomichev 
744b97b59b9SStanislav Fomichev 	prev = c->io_samples;
745b97b59b9SStanislav Fomichev 
746b97b59b9SStanislav Fomichev 	if (prev && prev->start_time && !prev->end_time) {
747b97b59b9SStanislav Fomichev 		pr_warning("Skip invalid start event: "
748b97b59b9SStanislav Fomichev 			   "previous event already started!\n");
749b97b59b9SStanislav Fomichev 
750b97b59b9SStanislav Fomichev 		/* remove previous event that has been started,
751b97b59b9SStanislav Fomichev 		 * we are not sure we will ever get an end for it */
752b97b59b9SStanislav Fomichev 		c->io_samples = prev->next;
753b97b59b9SStanislav Fomichev 		free(prev);
754b97b59b9SStanislav Fomichev 		return 0;
755b97b59b9SStanislav Fomichev 	}
756b97b59b9SStanislav Fomichev 
757b97b59b9SStanislav Fomichev 	sample = zalloc(sizeof(*sample));
758b97b59b9SStanislav Fomichev 	if (!sample)
759b97b59b9SStanislav Fomichev 		return -ENOMEM;
760b97b59b9SStanislav Fomichev 	sample->start_time = start;
761b97b59b9SStanislav Fomichev 	sample->type = type;
762b97b59b9SStanislav Fomichev 	sample->fd = fd;
763b97b59b9SStanislav Fomichev 	sample->next = c->io_samples;
764b97b59b9SStanislav Fomichev 	c->io_samples = sample;
765b97b59b9SStanislav Fomichev 
766b97b59b9SStanislav Fomichev 	if (c->start_time == 0 || c->start_time > start)
767b97b59b9SStanislav Fomichev 		c->start_time = start;
768b97b59b9SStanislav Fomichev 
769b97b59b9SStanislav Fomichev 	return 0;
770b97b59b9SStanislav Fomichev }
771b97b59b9SStanislav Fomichev 
pid_end_io_sample(struct timechart * tchart,int pid,int type,u64 end,long ret)772b97b59b9SStanislav Fomichev static int pid_end_io_sample(struct timechart *tchart, int pid, int type,
773b97b59b9SStanislav Fomichev 			     u64 end, long ret)
774d243144aSStanislav Fomichev {
775b97b59b9SStanislav Fomichev 	struct per_pid *p = find_create_pid(tchart, pid);
776b97b59b9SStanislav Fomichev 	struct per_pidcomm *c = p->current;
777b97b59b9SStanislav Fomichev 	struct io_sample *sample, *prev;
778b97b59b9SStanislav Fomichev 
779b97b59b9SStanislav Fomichev 	if (!c) {
780b97b59b9SStanislav Fomichev 		pr_warning("Invalid pidcomm!\n");
781b97b59b9SStanislav Fomichev 		return -1;
782b97b59b9SStanislav Fomichev 	}
783b97b59b9SStanislav Fomichev 
784b97b59b9SStanislav Fomichev 	sample = c->io_samples;
785b97b59b9SStanislav Fomichev 
786b97b59b9SStanislav Fomichev 	if (!sample) /* skip partially captured events */
787b97b59b9SStanislav Fomichev 		return 0;
788b97b59b9SStanislav Fomichev 
789b97b59b9SStanislav Fomichev 	if (sample->end_time) {
790b97b59b9SStanislav Fomichev 		pr_warning("Skip invalid end event: "
791b97b59b9SStanislav Fomichev 			   "previous event already ended!\n");
792b97b59b9SStanislav Fomichev 		return 0;
793b97b59b9SStanislav Fomichev 	}
794b97b59b9SStanislav Fomichev 
795b97b59b9SStanislav Fomichev 	if (sample->type != type) {
796b97b59b9SStanislav Fomichev 		pr_warning("Skip invalid end event: invalid event type!\n");
797b97b59b9SStanislav Fomichev 		return 0;
798d243144aSStanislav Fomichev 	}
799d243144aSStanislav Fomichev 
800d243144aSStanislav Fomichev 	sample->end_time = end;
801d243144aSStanislav Fomichev 	prev = sample->next;
802d243144aSStanislav Fomichev 
803d243144aSStanislav Fomichev 	/* we want to be able to see small and fast transfers, so make them
804d243144aSStanislav Fomichev 	 * at least min_time long, but don't overlap them */
805d243144aSStanislav Fomichev 	if (sample->end_time - sample->start_time < tchart->min_time)
806d243144aSStanislav Fomichev 		sample->end_time = sample->start_time + tchart->min_time;
807d243144aSStanislav Fomichev 	if (prev && sample->start_time < prev->end_time) {
808d243144aSStanislav Fomichev 		if (prev->err) /* try to make errors more visible */
809d243144aSStanislav Fomichev 			sample->start_time = prev->end_time;
810b97b59b9SStanislav Fomichev 		else
811b97b59b9SStanislav Fomichev 			prev->end_time = sample->start_time;
812b97b59b9SStanislav Fomichev 	}
813b97b59b9SStanislav Fomichev 
814b97b59b9SStanislav Fomichev 	if (ret < 0) {
815b97b59b9SStanislav Fomichev 		sample->err = ret;
816b97b59b9SStanislav Fomichev 	} else if (type == IOTYPE_READ || type == IOTYPE_WRITE ||
817b97b59b9SStanislav Fomichev 		   type == IOTYPE_TX || type == IOTYPE_RX) {
818b97b59b9SStanislav Fomichev 
819b97b59b9SStanislav Fomichev 		if ((u64)ret > c->max_bytes)
820b97b59b9SStanislav Fomichev 			c->max_bytes = ret;
821b97b59b9SStanislav Fomichev 
822b97b59b9SStanislav Fomichev 		c->total_bytes += ret;
823b97b59b9SStanislav Fomichev 		p->total_bytes += ret;
824d243144aSStanislav Fomichev 		sample->bytes = ret;
825d243144aSStanislav Fomichev 	}
826d243144aSStanislav Fomichev 
827d243144aSStanislav Fomichev 	/* merge two requests to make svg smaller and render-friendly */
828d243144aSStanislav Fomichev 	if (prev &&
829d243144aSStanislav Fomichev 	    prev->type == sample->type &&
830d243144aSStanislav Fomichev 	    prev->err == sample->err &&
831d243144aSStanislav Fomichev 	    prev->fd == sample->fd &&
832d243144aSStanislav Fomichev 	    prev->end_time + tchart->merge_dist >= sample->start_time) {
833d243144aSStanislav Fomichev 
834d243144aSStanislav Fomichev 		sample->bytes += prev->bytes;
835d243144aSStanislav Fomichev 		sample->merges += prev->merges + 1;
836d243144aSStanislav Fomichev 
837d243144aSStanislav Fomichev 		sample->start_time = prev->start_time;
838d243144aSStanislav Fomichev 		sample->next = prev->next;
839d243144aSStanislav Fomichev 		free(prev);
840d243144aSStanislav Fomichev 
841d243144aSStanislav Fomichev 		if (!sample->err && sample->bytes > c->max_bytes)
842b97b59b9SStanislav Fomichev 			c->max_bytes = sample->bytes;
843b97b59b9SStanislav Fomichev 	}
844b97b59b9SStanislav Fomichev 
845b97b59b9SStanislav Fomichev 	tchart->io_events++;
846b97b59b9SStanislav Fomichev 
847b97b59b9SStanislav Fomichev 	return 0;
848b97b59b9SStanislav Fomichev }
84932dcd021SJiri Olsa 
850b97b59b9SStanislav Fomichev static int
process_enter_read(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample)851b97b59b9SStanislav Fomichev process_enter_read(struct timechart *tchart,
852efc0cdc9SArnaldo Carvalho de Melo 		   struct evsel *evsel,
853b97b59b9SStanislav Fomichev 		   struct perf_sample *sample)
854b97b59b9SStanislav Fomichev {
855b97b59b9SStanislav Fomichev 	long fd = evsel__intval(evsel, sample, "fd");
856b97b59b9SStanislav Fomichev 	return pid_begin_io_sample(tchart, sample->tid, IOTYPE_READ,
857b97b59b9SStanislav Fomichev 				   sample->time, fd);
858b97b59b9SStanislav Fomichev }
85932dcd021SJiri Olsa 
860b97b59b9SStanislav Fomichev static int
process_exit_read(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample)861b97b59b9SStanislav Fomichev process_exit_read(struct timechart *tchart,
862efc0cdc9SArnaldo Carvalho de Melo 		  struct evsel *evsel,
863b97b59b9SStanislav Fomichev 		  struct perf_sample *sample)
864b97b59b9SStanislav Fomichev {
865b97b59b9SStanislav Fomichev 	long ret = evsel__intval(evsel, sample, "ret");
866b97b59b9SStanislav Fomichev 	return pid_end_io_sample(tchart, sample->tid, IOTYPE_READ,
867b97b59b9SStanislav Fomichev 				 sample->time, ret);
868b97b59b9SStanislav Fomichev }
86932dcd021SJiri Olsa 
870b97b59b9SStanislav Fomichev static int
process_enter_write(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample)871b97b59b9SStanislav Fomichev process_enter_write(struct timechart *tchart,
872efc0cdc9SArnaldo Carvalho de Melo 		    struct evsel *evsel,
873b97b59b9SStanislav Fomichev 		    struct perf_sample *sample)
874b97b59b9SStanislav Fomichev {
875b97b59b9SStanislav Fomichev 	long fd = evsel__intval(evsel, sample, "fd");
876b97b59b9SStanislav Fomichev 	return pid_begin_io_sample(tchart, sample->tid, IOTYPE_WRITE,
877b97b59b9SStanislav Fomichev 				   sample->time, fd);
878b97b59b9SStanislav Fomichev }
87932dcd021SJiri Olsa 
880b97b59b9SStanislav Fomichev static int
process_exit_write(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample)881b97b59b9SStanislav Fomichev process_exit_write(struct timechart *tchart,
882efc0cdc9SArnaldo Carvalho de Melo 		   struct evsel *evsel,
883b97b59b9SStanislav Fomichev 		   struct perf_sample *sample)
884b97b59b9SStanislav Fomichev {
885b97b59b9SStanislav Fomichev 	long ret = evsel__intval(evsel, sample, "ret");
886b97b59b9SStanislav Fomichev 	return pid_end_io_sample(tchart, sample->tid, IOTYPE_WRITE,
887b97b59b9SStanislav Fomichev 				 sample->time, ret);
888b97b59b9SStanislav Fomichev }
88932dcd021SJiri Olsa 
890b97b59b9SStanislav Fomichev static int
process_enter_sync(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample)891b97b59b9SStanislav Fomichev process_enter_sync(struct timechart *tchart,
892efc0cdc9SArnaldo Carvalho de Melo 		   struct evsel *evsel,
893b97b59b9SStanislav Fomichev 		   struct perf_sample *sample)
894b97b59b9SStanislav Fomichev {
895b97b59b9SStanislav Fomichev 	long fd = evsel__intval(evsel, sample, "fd");
896b97b59b9SStanislav Fomichev 	return pid_begin_io_sample(tchart, sample->tid, IOTYPE_SYNC,
897b97b59b9SStanislav Fomichev 				   sample->time, fd);
898b97b59b9SStanislav Fomichev }
89932dcd021SJiri Olsa 
900b97b59b9SStanislav Fomichev static int
process_exit_sync(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample)901b97b59b9SStanislav Fomichev process_exit_sync(struct timechart *tchart,
902efc0cdc9SArnaldo Carvalho de Melo 		  struct evsel *evsel,
903b97b59b9SStanislav Fomichev 		  struct perf_sample *sample)
904b97b59b9SStanislav Fomichev {
905b97b59b9SStanislav Fomichev 	long ret = evsel__intval(evsel, sample, "ret");
906b97b59b9SStanislav Fomichev 	return pid_end_io_sample(tchart, sample->tid, IOTYPE_SYNC,
907b97b59b9SStanislav Fomichev 				 sample->time, ret);
908b97b59b9SStanislav Fomichev }
90932dcd021SJiri Olsa 
910b97b59b9SStanislav Fomichev static int
process_enter_tx(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample)911b97b59b9SStanislav Fomichev process_enter_tx(struct timechart *tchart,
912efc0cdc9SArnaldo Carvalho de Melo 		 struct evsel *evsel,
913b97b59b9SStanislav Fomichev 		 struct perf_sample *sample)
914b97b59b9SStanislav Fomichev {
915b97b59b9SStanislav Fomichev 	long fd = evsel__intval(evsel, sample, "fd");
916b97b59b9SStanislav Fomichev 	return pid_begin_io_sample(tchart, sample->tid, IOTYPE_TX,
917b97b59b9SStanislav Fomichev 				   sample->time, fd);
918b97b59b9SStanislav Fomichev }
91932dcd021SJiri Olsa 
920b97b59b9SStanislav Fomichev static int
process_exit_tx(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample)921b97b59b9SStanislav Fomichev process_exit_tx(struct timechart *tchart,
922efc0cdc9SArnaldo Carvalho de Melo 		struct evsel *evsel,
923b97b59b9SStanislav Fomichev 		struct perf_sample *sample)
924b97b59b9SStanislav Fomichev {
925b97b59b9SStanislav Fomichev 	long ret = evsel__intval(evsel, sample, "ret");
926b97b59b9SStanislav Fomichev 	return pid_end_io_sample(tchart, sample->tid, IOTYPE_TX,
927b97b59b9SStanislav Fomichev 				 sample->time, ret);
928b97b59b9SStanislav Fomichev }
92932dcd021SJiri Olsa 
930b97b59b9SStanislav Fomichev static int
process_enter_rx(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample)931b97b59b9SStanislav Fomichev process_enter_rx(struct timechart *tchart,
932efc0cdc9SArnaldo Carvalho de Melo 		 struct evsel *evsel,
933b97b59b9SStanislav Fomichev 		 struct perf_sample *sample)
934b97b59b9SStanislav Fomichev {
935b97b59b9SStanislav Fomichev 	long fd = evsel__intval(evsel, sample, "fd");
936b97b59b9SStanislav Fomichev 	return pid_begin_io_sample(tchart, sample->tid, IOTYPE_RX,
937b97b59b9SStanislav Fomichev 				   sample->time, fd);
938b97b59b9SStanislav Fomichev }
93932dcd021SJiri Olsa 
940b97b59b9SStanislav Fomichev static int
process_exit_rx(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample)941b97b59b9SStanislav Fomichev process_exit_rx(struct timechart *tchart,
942efc0cdc9SArnaldo Carvalho de Melo 		struct evsel *evsel,
943b97b59b9SStanislav Fomichev 		struct perf_sample *sample)
944b97b59b9SStanislav Fomichev {
945b97b59b9SStanislav Fomichev 	long ret = evsel__intval(evsel, sample, "ret");
946b97b59b9SStanislav Fomichev 	return pid_end_io_sample(tchart, sample->tid, IOTYPE_RX,
947b97b59b9SStanislav Fomichev 				 sample->time, ret);
948b97b59b9SStanislav Fomichev }
94932dcd021SJiri Olsa 
950b97b59b9SStanislav Fomichev static int
process_enter_poll(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample)951b97b59b9SStanislav Fomichev process_enter_poll(struct timechart *tchart,
952efc0cdc9SArnaldo Carvalho de Melo 		   struct evsel *evsel,
953b97b59b9SStanislav Fomichev 		   struct perf_sample *sample)
954b97b59b9SStanislav Fomichev {
955b97b59b9SStanislav Fomichev 	long fd = evsel__intval(evsel, sample, "fd");
956b97b59b9SStanislav Fomichev 	return pid_begin_io_sample(tchart, sample->tid, IOTYPE_POLL,
957b97b59b9SStanislav Fomichev 				   sample->time, fd);
958b97b59b9SStanislav Fomichev }
95932dcd021SJiri Olsa 
960b97b59b9SStanislav Fomichev static int
process_exit_poll(struct timechart * tchart,struct evsel * evsel,struct perf_sample * sample)961b97b59b9SStanislav Fomichev process_exit_poll(struct timechart *tchart,
962efc0cdc9SArnaldo Carvalho de Melo 		  struct evsel *evsel,
963b97b59b9SStanislav Fomichev 		  struct perf_sample *sample)
964b97b59b9SStanislav Fomichev {
965b97b59b9SStanislav Fomichev 	long ret = evsel__intval(evsel, sample, "ret");
966b97b59b9SStanislav Fomichev 	return pid_end_io_sample(tchart, sample->tid, IOTYPE_POLL,
96710274989SArjan van de Ven 				 sample->time, ret);
96810274989SArjan van de Ven }
96910274989SArjan van de Ven 
9705e22f6d2SArnaldo Carvalho de Melo /*
97110274989SArjan van de Ven  * Sort the pid datastructure
97210274989SArjan van de Ven  */
sort_pids(struct timechart * tchart)97310274989SArjan van de Ven static void sort_pids(struct timechart *tchart)
97410274989SArjan van de Ven {
97510274989SArjan van de Ven 	struct per_pid *new_list, *p, *cursor, *prev;
97610274989SArjan van de Ven 	/* sort by ppid first, then by pid, lowest to highest */
9775e22f6d2SArnaldo Carvalho de Melo 
9785e22f6d2SArnaldo Carvalho de Melo 	new_list = NULL;
9795e22f6d2SArnaldo Carvalho de Melo 
98010274989SArjan van de Ven 	while (tchart->all_data) {
98110274989SArjan van de Ven 		p = tchart->all_data;
98210274989SArjan van de Ven 		tchart->all_data = p->next;
98310274989SArjan van de Ven 		p->next = NULL;
98410274989SArjan van de Ven 
98510274989SArjan van de Ven 		if (new_list == NULL) {
98610274989SArjan van de Ven 			new_list = p;
98710274989SArjan van de Ven 			p->next = NULL;
98810274989SArjan van de Ven 			continue;
98910274989SArjan van de Ven 		}
99010274989SArjan van de Ven 		prev = NULL;
99110274989SArjan van de Ven 		cursor = new_list;
99210274989SArjan van de Ven 		while (cursor) {
99310274989SArjan van de Ven 			if (cursor->ppid > p->ppid ||
99410274989SArjan van de Ven 				(cursor->ppid == p->ppid && cursor->pid > p->pid)) {
99510274989SArjan van de Ven 				/* must insert before */
99610274989SArjan van de Ven 				if (prev) {
99710274989SArjan van de Ven 					p->next = prev->next;
99810274989SArjan van de Ven 					prev->next = p;
99910274989SArjan van de Ven 					cursor = NULL;
100010274989SArjan van de Ven 					continue;
100110274989SArjan van de Ven 				} else {
100210274989SArjan van de Ven 					p->next = new_list;
100310274989SArjan van de Ven 					new_list = p;
100410274989SArjan van de Ven 					cursor = NULL;
100510274989SArjan van de Ven 					continue;
100610274989SArjan van de Ven 				}
100710274989SArjan van de Ven 			}
100810274989SArjan van de Ven 
100910274989SArjan van de Ven 			prev = cursor;
101010274989SArjan van de Ven 			cursor = cursor->next;
101110274989SArjan van de Ven 			if (!cursor)
10125e22f6d2SArnaldo Carvalho de Melo 				prev->next = p;
101310274989SArjan van de Ven 		}
101410274989SArjan van de Ven 	}
101510274989SArjan van de Ven 	tchart->all_data = new_list;
1016985b12e6SArnaldo Carvalho de Melo }
101710274989SArjan van de Ven 
101810274989SArjan van de Ven 
draw_c_p_states(struct timechart * tchart)101966cc3adaSArnaldo Carvalho de Melo static void draw_c_p_states(struct timechart *tchart)
102010274989SArjan van de Ven {
102110274989SArjan van de Ven 	struct power_event *pwr;
102210274989SArjan van de Ven 	pwr = tchart->power_events;
102310274989SArjan van de Ven 
102410274989SArjan van de Ven 	/*
102510274989SArjan van de Ven 	 * two pass drawing so that the P state bars are on top of the C state blocks
102610274989SArjan van de Ven 	 */
102710274989SArjan van de Ven 	while (pwr) {
102810274989SArjan van de Ven 		if (pwr->type == CSTATE)
102910274989SArjan van de Ven 			svg_cstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
103066cc3adaSArnaldo Carvalho de Melo 		pwr = pwr->next;
103110274989SArjan van de Ven 	}
103210274989SArjan van de Ven 
103310274989SArjan van de Ven 	pwr = tchart->power_events;
1034985b12e6SArnaldo Carvalho de Melo 	while (pwr) {
103510274989SArjan van de Ven 		if (pwr->type == PSTATE) {
103610274989SArjan van de Ven 			if (!pwr->state)
103710274989SArjan van de Ven 				pwr->state = tchart->min_freq;
103810274989SArjan van de Ven 			svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
103910274989SArjan van de Ven 		}
104010274989SArjan van de Ven 		pwr = pwr->next;
10415e22f6d2SArnaldo Carvalho de Melo 	}
104210274989SArjan van de Ven }
104310274989SArjan van de Ven 
draw_wakeups(struct timechart * tchart)104410274989SArjan van de Ven static void draw_wakeups(struct timechart *tchart)
104510274989SArjan van de Ven {
104610274989SArjan van de Ven 	struct wake_event *we;
1047436b0da0SArnaldo Carvalho de Melo 	struct per_pid *p;
104810274989SArjan van de Ven 	struct per_pidcomm *c;
104910274989SArjan van de Ven 
10504f1202c8SArjan van de Ven 	we = tchart->wake_events;
105110274989SArjan van de Ven 	while (we) {
105210274989SArjan van de Ven 		int from = 0, to = 0;
10535e22f6d2SArnaldo Carvalho de Melo 		char *task_from = NULL, *task_to = NULL;
105410274989SArjan van de Ven 
105510274989SArjan van de Ven 		/* locate the column of the waker and wakee */
105610274989SArjan van de Ven 		p = tchart->all_data;
105710274989SArjan van de Ven 		while (p) {
105810274989SArjan van de Ven 			if (p->pid == we->waker || p->pid == we->wakee) {
1059bbe2987bSArjan van de Ven 				c = p->all;
106010274989SArjan van de Ven 				while (c) {
10613bc2a39cSArjan van de Ven 					if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
10624f1202c8SArjan van de Ven 						if (p->pid == we->waker && !from) {
1063bbe2987bSArjan van de Ven 							from = c->Y;
106410274989SArjan van de Ven 							task_from = strdup(c->comm);
10653bc2a39cSArjan van de Ven 						}
10664f1202c8SArjan van de Ven 						if (p->pid == we->wakee && !to) {
106710274989SArjan van de Ven 							to = c->Y;
106810274989SArjan van de Ven 							task_to = strdup(c->comm);
106910274989SArjan van de Ven 						}
10703bc2a39cSArjan van de Ven 					}
10713bc2a39cSArjan van de Ven 					c = c->next;
10723bc2a39cSArjan van de Ven 				}
10733bc2a39cSArjan van de Ven 				c = p->all;
10743bc2a39cSArjan van de Ven 				while (c) {
10753bc2a39cSArjan van de Ven 					if (p->pid == we->waker && !from) {
10763bc2a39cSArjan van de Ven 						from = c->Y;
10773bc2a39cSArjan van de Ven 						task_from = strdup(c->comm);
10783bc2a39cSArjan van de Ven 					}
10793bc2a39cSArjan van de Ven 					if (p->pid == we->wakee && !to) {
10803bc2a39cSArjan van de Ven 						to = c->Y;
10813bc2a39cSArjan van de Ven 						task_to = strdup(c->comm);
108210274989SArjan van de Ven 					}
108310274989SArjan van de Ven 					c = c->next;
108410274989SArjan van de Ven 				}
108510274989SArjan van de Ven 			}
10863bc2a39cSArjan van de Ven 			p = p->next;
10873bc2a39cSArjan van de Ven 		}
10883bc2a39cSArjan van de Ven 
10893bc2a39cSArjan van de Ven 		if (!task_from) {
10903bc2a39cSArjan van de Ven 			task_from = malloc(40);
10913bc2a39cSArjan van de Ven 			sprintf(task_from, "[%i]", we->waker);
10923bc2a39cSArjan van de Ven 		}
10933bc2a39cSArjan van de Ven 		if (!task_to) {
10943bc2a39cSArjan van de Ven 			task_to = malloc(40);
109510274989SArjan van de Ven 			sprintf(task_to, "[%i]", we->wakee);
10966f8d67faSStanislav Fomichev 		}
109710274989SArjan van de Ven 
10986f8d67faSStanislav Fomichev 		if (we->waker == -1)
109910274989SArjan van de Ven 			svg_interrupt(we->time, to, we->backtrace);
11006f8d67faSStanislav Fomichev 		else if (from && to && abs(from - to) == 1)
11016f8d67faSStanislav Fomichev 			svg_wakeline(we->time, from, to, we->backtrace);
110210274989SArjan van de Ven 		else
11033bc2a39cSArjan van de Ven 			svg_partial_wakeline(we->time, from, task_from, to,
11043bc2a39cSArjan van de Ven 					     task_to, we->backtrace);
11053bc2a39cSArjan van de Ven 		we = we->next;
110610274989SArjan van de Ven 
110710274989SArjan van de Ven 		free(task_from);
110810274989SArjan van de Ven 		free(task_to);
11095e22f6d2SArnaldo Carvalho de Melo 	}
111010274989SArjan van de Ven }
111110274989SArjan van de Ven 
draw_cpu_usage(struct timechart * tchart)111210274989SArjan van de Ven static void draw_cpu_usage(struct timechart *tchart)
111310274989SArjan van de Ven {
11145e22f6d2SArnaldo Carvalho de Melo 	struct per_pid *p;
111510274989SArjan van de Ven 	struct per_pidcomm *c;
111610274989SArjan van de Ven 	struct cpu_sample *sample;
111710274989SArjan van de Ven 	p = tchart->all_data;
111810274989SArjan van de Ven 	while (p) {
111910274989SArjan van de Ven 		c = p->all;
11208b6dcca0SStanislav Fomichev 		while (c) {
11218b6dcca0SStanislav Fomichev 			sample = c->samples;
11228b6dcca0SStanislav Fomichev 			while (sample) {
11238b6dcca0SStanislav Fomichev 				if (sample->type == TYPE_RUNNING) {
1124de996228SStanislav Fomichev 					svg_process(sample->cpu,
11258b6dcca0SStanislav Fomichev 						    sample->start_time,
11268b6dcca0SStanislav Fomichev 						    sample->end_time,
11278b6dcca0SStanislav Fomichev 						    p->pid,
112810274989SArjan van de Ven 						    c->comm,
112910274989SArjan van de Ven 						    sample->backtrace);
113010274989SArjan van de Ven 				}
113110274989SArjan van de Ven 
113210274989SArjan van de Ven 				sample = sample->next;
113310274989SArjan van de Ven 			}
113410274989SArjan van de Ven 			c = c->next;
113510274989SArjan van de Ven 		}
113610274989SArjan van de Ven 		p = p->next;
1137b97b59b9SStanislav Fomichev 	}
1138b97b59b9SStanislav Fomichev }
1139b97b59b9SStanislav Fomichev 
draw_io_bars(struct timechart * tchart)1140b97b59b9SStanislav Fomichev static void draw_io_bars(struct timechart *tchart)
1141b97b59b9SStanislav Fomichev {
1142b97b59b9SStanislav Fomichev 	const char *suf;
1143b97b59b9SStanislav Fomichev 	double bytes;
1144b97b59b9SStanislav Fomichev 	char comm[256];
1145b97b59b9SStanislav Fomichev 	struct per_pid *p;
1146b97b59b9SStanislav Fomichev 	struct per_pidcomm *c;
1147b97b59b9SStanislav Fomichev 	struct io_sample *sample;
1148b97b59b9SStanislav Fomichev 	int Y = 1;
1149b97b59b9SStanislav Fomichev 
1150b97b59b9SStanislav Fomichev 	p = tchart->all_data;
1151b97b59b9SStanislav Fomichev 	while (p) {
1152b97b59b9SStanislav Fomichev 		c = p->all;
1153b97b59b9SStanislav Fomichev 		while (c) {
1154b97b59b9SStanislav Fomichev 			if (!c->display) {
1155b97b59b9SStanislav Fomichev 				c->Y = 0;
1156b97b59b9SStanislav Fomichev 				c = c->next;
1157b97b59b9SStanislav Fomichev 				continue;
1158b97b59b9SStanislav Fomichev 			}
1159b97b59b9SStanislav Fomichev 
1160b97b59b9SStanislav Fomichev 			svg_box(Y, c->start_time, c->end_time, "process3");
1161b97b59b9SStanislav Fomichev 			sample = c->io_samples;
1162d243144aSStanislav Fomichev 			for (sample = c->io_samples; sample; sample = sample->next) {
1163d243144aSStanislav Fomichev 				double h = (double)sample->bytes / c->max_bytes;
1164d243144aSStanislav Fomichev 
1165d243144aSStanislav Fomichev 				if (tchart->skip_eagain &&
1166b97b59b9SStanislav Fomichev 				    sample->err == -EAGAIN)
1167b97b59b9SStanislav Fomichev 					continue;
1168b97b59b9SStanislav Fomichev 
1169b97b59b9SStanislav Fomichev 				if (sample->err)
1170b97b59b9SStanislav Fomichev 					h = 1;
1171b97b59b9SStanislav Fomichev 
1172b97b59b9SStanislav Fomichev 				if (sample->type == IOTYPE_SYNC)
1173b97b59b9SStanislav Fomichev 					svg_fbox(Y,
1174b97b59b9SStanislav Fomichev 						sample->start_time,
1175b97b59b9SStanislav Fomichev 						sample->end_time,
1176b97b59b9SStanislav Fomichev 						1,
1177b97b59b9SStanislav Fomichev 						sample->err ? "error" : "sync",
1178b97b59b9SStanislav Fomichev 						sample->fd,
1179b97b59b9SStanislav Fomichev 						sample->err,
1180b97b59b9SStanislav Fomichev 						sample->merges);
1181b97b59b9SStanislav Fomichev 				else if (sample->type == IOTYPE_POLL)
1182b97b59b9SStanislav Fomichev 					svg_fbox(Y,
1183b97b59b9SStanislav Fomichev 						sample->start_time,
1184b97b59b9SStanislav Fomichev 						sample->end_time,
1185b97b59b9SStanislav Fomichev 						1,
1186b97b59b9SStanislav Fomichev 						sample->err ? "error" : "poll",
1187b97b59b9SStanislav Fomichev 						sample->fd,
1188b97b59b9SStanislav Fomichev 						sample->err,
1189b97b59b9SStanislav Fomichev 						sample->merges);
1190b97b59b9SStanislav Fomichev 				else if (sample->type == IOTYPE_READ)
1191b97b59b9SStanislav Fomichev 					svg_ubox(Y,
1192b97b59b9SStanislav Fomichev 						sample->start_time,
1193b97b59b9SStanislav Fomichev 						sample->end_time,
1194b97b59b9SStanislav Fomichev 						h,
1195b97b59b9SStanislav Fomichev 						sample->err ? "error" : "disk",
1196b97b59b9SStanislav Fomichev 						sample->fd,
1197b97b59b9SStanislav Fomichev 						sample->err,
1198b97b59b9SStanislav Fomichev 						sample->merges);
1199b97b59b9SStanislav Fomichev 				else if (sample->type == IOTYPE_WRITE)
1200b97b59b9SStanislav Fomichev 					svg_lbox(Y,
1201b97b59b9SStanislav Fomichev 						sample->start_time,
1202b97b59b9SStanislav Fomichev 						sample->end_time,
1203b97b59b9SStanislav Fomichev 						h,
1204b97b59b9SStanislav Fomichev 						sample->err ? "error" : "disk",
1205b97b59b9SStanislav Fomichev 						sample->fd,
1206b97b59b9SStanislav Fomichev 						sample->err,
1207b97b59b9SStanislav Fomichev 						sample->merges);
1208b97b59b9SStanislav Fomichev 				else if (sample->type == IOTYPE_RX)
1209b97b59b9SStanislav Fomichev 					svg_ubox(Y,
1210b97b59b9SStanislav Fomichev 						sample->start_time,
1211b97b59b9SStanislav Fomichev 						sample->end_time,
1212b97b59b9SStanislav Fomichev 						h,
1213b97b59b9SStanislav Fomichev 						sample->err ? "error" : "net",
1214b97b59b9SStanislav Fomichev 						sample->fd,
1215b97b59b9SStanislav Fomichev 						sample->err,
1216b97b59b9SStanislav Fomichev 						sample->merges);
1217b97b59b9SStanislav Fomichev 				else if (sample->type == IOTYPE_TX)
1218b97b59b9SStanislav Fomichev 					svg_lbox(Y,
1219b97b59b9SStanislav Fomichev 						sample->start_time,
1220b97b59b9SStanislav Fomichev 						sample->end_time,
1221b97b59b9SStanislav Fomichev 						h,
1222b97b59b9SStanislav Fomichev 						sample->err ? "error" : "net",
1223b97b59b9SStanislav Fomichev 						sample->fd,
1224b97b59b9SStanislav Fomichev 						sample->err,
1225b97b59b9SStanislav Fomichev 						sample->merges);
1226b97b59b9SStanislav Fomichev 			}
1227b97b59b9SStanislav Fomichev 
1228b97b59b9SStanislav Fomichev 			suf = "";
1229b97b59b9SStanislav Fomichev 			bytes = c->total_bytes;
1230b97b59b9SStanislav Fomichev 			if (bytes > 1024) {
1231b97b59b9SStanislav Fomichev 				bytes = bytes / 1024;
1232b97b59b9SStanislav Fomichev 				suf = "K";
1233b97b59b9SStanislav Fomichev 			}
1234b97b59b9SStanislav Fomichev 			if (bytes > 1024) {
1235b97b59b9SStanislav Fomichev 				bytes = bytes / 1024;
1236b97b59b9SStanislav Fomichev 				suf = "M";
1237b97b59b9SStanislav Fomichev 			}
1238b97b59b9SStanislav Fomichev 			if (bytes > 1024) {
1239b97b59b9SStanislav Fomichev 				bytes = bytes / 1024;
1240b97b59b9SStanislav Fomichev 				suf = "G";
1241b97b59b9SStanislav Fomichev 			}
1242b97b59b9SStanislav Fomichev 
1243b97b59b9SStanislav Fomichev 
1244b97b59b9SStanislav Fomichev 			sprintf(comm, "%s:%i (%3.1f %sbytes)", c->comm ?: "", p->pid, bytes, suf);
1245b97b59b9SStanislav Fomichev 			svg_text(Y, c->start_time, comm);
1246b97b59b9SStanislav Fomichev 
1247b97b59b9SStanislav Fomichev 			c->Y = Y;
1248b97b59b9SStanislav Fomichev 			Y++;
1249b97b59b9SStanislav Fomichev 			c = c->next;
1250b97b59b9SStanislav Fomichev 		}
1251b97b59b9SStanislav Fomichev 		p = p->next;
1252985b12e6SArnaldo Carvalho de Melo 	}
125310274989SArjan van de Ven }
125410274989SArjan van de Ven 
draw_process_bars(struct timechart * tchart)125510274989SArjan van de Ven static void draw_process_bars(struct timechart *tchart)
125610274989SArjan van de Ven {
125710274989SArjan van de Ven 	struct per_pid *p;
125810274989SArjan van de Ven 	struct per_pidcomm *c;
1259985b12e6SArnaldo Carvalho de Melo 	struct cpu_sample *sample;
126010274989SArjan van de Ven 	int Y = 0;
12615e22f6d2SArnaldo Carvalho de Melo 
126210274989SArjan van de Ven 	Y = 2 * tchart->numcpus + 2;
126310274989SArjan van de Ven 
126410274989SArjan van de Ven 	p = tchart->all_data;
126510274989SArjan van de Ven 	while (p) {
126610274989SArjan van de Ven 		c = p->all;
126710274989SArjan van de Ven 		while (c) {
126810274989SArjan van de Ven 			if (!c->display) {
126910274989SArjan van de Ven 				c->Y = 0;
127010274989SArjan van de Ven 				c = c->next;
1271a92fe7b3SArjan van de Ven 				continue;
127210274989SArjan van de Ven 			}
127310274989SArjan van de Ven 
127410274989SArjan van de Ven 			svg_box(Y, c->start_time, c->end_time, "process");
12756f8d67faSStanislav Fomichev 			sample = c->samples;
12766f8d67faSStanislav Fomichev 			while (sample) {
12776f8d67faSStanislav Fomichev 				if (sample->type == TYPE_RUNNING)
12786f8d67faSStanislav Fomichev 					svg_running(Y, sample->cpu,
127910274989SArjan van de Ven 						    sample->start_time,
12806f8d67faSStanislav Fomichev 						    sample->end_time,
12816f8d67faSStanislav Fomichev 						    sample->backtrace);
12826f8d67faSStanislav Fomichev 				if (sample->type == TYPE_BLOCKED)
12836f8d67faSStanislav Fomichev 					svg_blocked(Y, sample->cpu,
128410274989SArjan van de Ven 						    sample->start_time,
12856f8d67faSStanislav Fomichev 						    sample->end_time,
12866f8d67faSStanislav Fomichev 						    sample->backtrace);
12876f8d67faSStanislav Fomichev 				if (sample->type == TYPE_WAITING)
12886f8d67faSStanislav Fomichev 					svg_waiting(Y, sample->cpu,
128910274989SArjan van de Ven 						    sample->start_time,
129010274989SArjan van de Ven 						    sample->end_time,
129110274989SArjan van de Ven 						    sample->backtrace);
129210274989SArjan van de Ven 				sample = sample->next;
129310274989SArjan van de Ven 			}
129410274989SArjan van de Ven 
1295af4b2c97SArnaldo Carvalho de Melo 			if (c->comm) {
129610274989SArjan van de Ven 				char comm[256];
1297af4b2c97SArnaldo Carvalho de Melo 				if (c->total_time > 5000000000) /* 5 seconds */
129810274989SArjan van de Ven 					sprintf(comm, "%s:%i (%2.2fs)", c->comm, p->pid, c->total_time / (double)NSEC_PER_SEC);
129910274989SArjan van de Ven 				else
130010274989SArjan van de Ven 					sprintf(comm, "%s:%i (%3.1fms)", c->comm, p->pid, c->total_time / (double)NSEC_PER_MSEC);
130110274989SArjan van de Ven 
130210274989SArjan van de Ven 				svg_text(Y, c->start_time, comm);
130310274989SArjan van de Ven 			}
130410274989SArjan van de Ven 			c->Y = Y;
130510274989SArjan van de Ven 			Y++;
130610274989SArjan van de Ven 			c = c->next;
130710274989SArjan van de Ven 		}
130810274989SArjan van de Ven 		p = p->next;
1309bbe2987bSArjan van de Ven 	}
1310bbe2987bSArjan van de Ven }
1311e0dcd6fbSArnaldo Carvalho de Melo 
add_process_filter(const char * string)1312e0dcd6fbSArnaldo Carvalho de Melo static void add_process_filter(const char *string)
1313bbe2987bSArjan van de Ven {
1314bbe2987bSArjan van de Ven 	int pid = strtoull(string, NULL, 10);
1315bbe2987bSArjan van de Ven 	struct process_filter *filt = malloc(sizeof(*filt));
1316bbe2987bSArjan van de Ven 
1317bbe2987bSArjan van de Ven 	if (!filt)
1318bbe2987bSArjan van de Ven 		return;
1319bbe2987bSArjan van de Ven 
1320bbe2987bSArjan van de Ven 	filt->name = strdup(string);
1321bbe2987bSArjan van de Ven 	filt->pid  = pid;
1322bbe2987bSArjan van de Ven 	filt->next = process_filter;
1323bbe2987bSArjan van de Ven 
1324bbe2987bSArjan van de Ven 	process_filter = filt;
1325bbe2987bSArjan van de Ven }
1326bbe2987bSArjan van de Ven 
passes_filter(struct per_pid * p,struct per_pidcomm * c)1327bbe2987bSArjan van de Ven static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
1328bbe2987bSArjan van de Ven {
1329bbe2987bSArjan van de Ven 	struct process_filter *filt;
1330bbe2987bSArjan van de Ven 	if (!process_filter)
1331bbe2987bSArjan van de Ven 		return 1;
1332bbe2987bSArjan van de Ven 
1333bbe2987bSArjan van de Ven 	filt = process_filter;
1334bbe2987bSArjan van de Ven 	while (filt) {
1335bbe2987bSArjan van de Ven 		if (filt->pid && p->pid == filt->pid)
1336bbe2987bSArjan van de Ven 			return 1;
1337bbe2987bSArjan van de Ven 		if (strcmp(filt->name, c->comm) == 0)
1338bbe2987bSArjan van de Ven 			return 1;
1339bbe2987bSArjan van de Ven 		filt = filt->next;
1340bbe2987bSArjan van de Ven 	}
1341985b12e6SArnaldo Carvalho de Melo 	return 0;
1342bbe2987bSArjan van de Ven }
1343bbe2987bSArjan van de Ven 
determine_display_tasks_filtered(struct timechart * tchart)1344bbe2987bSArjan van de Ven static int determine_display_tasks_filtered(struct timechart *tchart)
1345bbe2987bSArjan van de Ven {
1346bbe2987bSArjan van de Ven 	struct per_pid *p;
13475e22f6d2SArnaldo Carvalho de Melo 	struct per_pidcomm *c;
1348bbe2987bSArjan van de Ven 	int count = 0;
1349bbe2987bSArjan van de Ven 
1350bbe2987bSArjan van de Ven 	p = tchart->all_data;
1351985b12e6SArnaldo Carvalho de Melo 	while (p) {
1352bbe2987bSArjan van de Ven 		p->display = 0;
1353bbe2987bSArjan van de Ven 		if (p->start_time == 1)
1354bbe2987bSArjan van de Ven 			p->start_time = tchart->first_time;
1355985b12e6SArnaldo Carvalho de Melo 
1356bbe2987bSArjan van de Ven 		/* no exit marker, task kept running to the end */
1357bbe2987bSArjan van de Ven 		if (p->end_time == 0)
1358bbe2987bSArjan van de Ven 			p->end_time = tchart->last_time;
1359bbe2987bSArjan van de Ven 
1360bbe2987bSArjan van de Ven 		c = p->all;
1361bbe2987bSArjan van de Ven 
1362bbe2987bSArjan van de Ven 		while (c) {
1363985b12e6SArnaldo Carvalho de Melo 			c->display = 0;
1364bbe2987bSArjan van de Ven 
1365bbe2987bSArjan van de Ven 			if (c->start_time == 1)
1366bbe2987bSArjan van de Ven 				c->start_time = tchart->first_time;
1367bbe2987bSArjan van de Ven 
1368bbe2987bSArjan van de Ven 			if (passes_filter(p, c)) {
1369bbe2987bSArjan van de Ven 				c->display = 1;
1370bbe2987bSArjan van de Ven 				p->display = 1;
1371bbe2987bSArjan van de Ven 				count++;
1372985b12e6SArnaldo Carvalho de Melo 			}
1373bbe2987bSArjan van de Ven 
1374bbe2987bSArjan van de Ven 			if (c->end_time == 0)
1375bbe2987bSArjan van de Ven 				c->end_time = tchart->last_time;
1376bbe2987bSArjan van de Ven 
1377bbe2987bSArjan van de Ven 			c = c->next;
1378bbe2987bSArjan van de Ven 		}
1379bbe2987bSArjan van de Ven 		p = p->next;
1380bbe2987bSArjan van de Ven 	}
1381985b12e6SArnaldo Carvalho de Melo 	return count;
138210274989SArjan van de Ven }
138310274989SArjan van de Ven 
determine_display_tasks(struct timechart * tchart,u64 threshold)138410274989SArjan van de Ven static int determine_display_tasks(struct timechart *tchart, u64 threshold)
138510274989SArjan van de Ven {
138610274989SArjan van de Ven 	struct per_pid *p;
13875e22f6d2SArnaldo Carvalho de Melo 	struct per_pidcomm *c;
138810274989SArjan van de Ven 	int count = 0;
138910274989SArjan van de Ven 
139010274989SArjan van de Ven 	p = tchart->all_data;
1391985b12e6SArnaldo Carvalho de Melo 	while (p) {
139210274989SArjan van de Ven 		p->display = 0;
139310274989SArjan van de Ven 		if (p->start_time == 1)
139410274989SArjan van de Ven 			p->start_time = tchart->first_time;
1395985b12e6SArnaldo Carvalho de Melo 
1396753c505dSStanislav Fomichev 		/* no exit marker, task kept running to the end */
139710274989SArjan van de Ven 		if (p->end_time == 0)
139810274989SArjan van de Ven 			p->end_time = tchart->last_time;
139910274989SArjan van de Ven 		if (p->total_time >= threshold)
140010274989SArjan van de Ven 			p->display = 1;
140110274989SArjan van de Ven 
140210274989SArjan van de Ven 		c = p->all;
140310274989SArjan van de Ven 
140410274989SArjan van de Ven 		while (c) {
1405985b12e6SArnaldo Carvalho de Melo 			c->display = 0;
140610274989SArjan van de Ven 
1407753c505dSStanislav Fomichev 			if (c->start_time == 1)
140810274989SArjan van de Ven 				c->start_time = tchart->first_time;
140910274989SArjan van de Ven 
141010274989SArjan van de Ven 			if (c->total_time >= threshold) {
141110274989SArjan van de Ven 				c->display = 1;
141210274989SArjan van de Ven 				count++;
1413985b12e6SArnaldo Carvalho de Melo 			}
141410274989SArjan van de Ven 
141510274989SArjan van de Ven 			if (c->end_time == 0)
141610274989SArjan van de Ven 				c->end_time = tchart->last_time;
141710274989SArjan van de Ven 
141810274989SArjan van de Ven 			c = c->next;
141910274989SArjan van de Ven 		}
142010274989SArjan van de Ven 		p = p->next;
142110274989SArjan van de Ven 	}
1422b97b59b9SStanislav Fomichev 	return count;
1423b97b59b9SStanislav Fomichev }
1424b97b59b9SStanislav Fomichev 
determine_display_io_tasks(struct timechart * timechart,u64 threshold)1425b97b59b9SStanislav Fomichev static int determine_display_io_tasks(struct timechart *timechart, u64 threshold)
1426b97b59b9SStanislav Fomichev {
142710274989SArjan van de Ven 	struct per_pid *p;
1428b97b59b9SStanislav Fomichev 	struct per_pidcomm *c;
1429b97b59b9SStanislav Fomichev 	int count = 0;
1430b97b59b9SStanislav Fomichev 
1431b97b59b9SStanislav Fomichev 	p = timechart->all_data;
1432b97b59b9SStanislav Fomichev 	while (p) {
143310274989SArjan van de Ven 		/* no exit marker, task kept running to the end */
1434b97b59b9SStanislav Fomichev 		if (p->end_time == 0)
1435b97b59b9SStanislav Fomichev 			p->end_time = timechart->last_time;
1436b97b59b9SStanislav Fomichev 
1437b97b59b9SStanislav Fomichev 		c = p->all;
1438b97b59b9SStanislav Fomichev 
1439b97b59b9SStanislav Fomichev 		while (c) {
1440b97b59b9SStanislav Fomichev 			c->display = 0;
1441b97b59b9SStanislav Fomichev 
1442b97b59b9SStanislav Fomichev 			if (c->total_bytes >= threshold) {
1443b97b59b9SStanislav Fomichev 				c->display = 1;
1444b97b59b9SStanislav Fomichev 				count++;
1445b97b59b9SStanislav Fomichev 			}
1446b97b59b9SStanislav Fomichev 
1447b97b59b9SStanislav Fomichev 			if (c->end_time == 0)
1448b97b59b9SStanislav Fomichev 				c->end_time = timechart->last_time;
1449b97b59b9SStanislav Fomichev 
1450b97b59b9SStanislav Fomichev 			c = c->next;
1451b97b59b9SStanislav Fomichev 		}
1452b97b59b9SStanislav Fomichev 		p = p->next;
1453b97b59b9SStanislav Fomichev 	}
1454b97b59b9SStanislav Fomichev 	return count;
145510274989SArjan van de Ven }
145610274989SArjan van de Ven 
1457985b12e6SArnaldo Carvalho de Melo #define BYTES_THRESH (1 * 1024 * 1024)
145810274989SArjan van de Ven #define TIME_THRESH 10000000
145910274989SArjan van de Ven 
write_svg_file(struct timechart * tchart,const char * filename)146010274989SArjan van de Ven static void write_svg_file(struct timechart *tchart, const char *filename)
1461b97b59b9SStanislav Fomichev {
146210274989SArjan van de Ven 	u64 i;
1463985b12e6SArnaldo Carvalho de Melo 	int count;
1464985b12e6SArnaldo Carvalho de Melo 	int thresh = tchart->io_events ? BYTES_THRESH : TIME_THRESH;
146510274989SArjan van de Ven 
14660a8eb275SStanislav Fomichev 	if (tchart->power_only)
14670a8eb275SStanislav Fomichev 		tchart->proc_num = 0;
14680a8eb275SStanislav Fomichev 
1469b97b59b9SStanislav Fomichev 	/* We'd like to show at least proc_num tasks;
1470b97b59b9SStanislav Fomichev 	 * be less picky if we have fewer */
1471b97b59b9SStanislav Fomichev 	do {
1472b97b59b9SStanislav Fomichev 		if (process_filter)
1473b97b59b9SStanislav Fomichev 			count = determine_display_tasks_filtered(tchart);
1474985b12e6SArnaldo Carvalho de Melo 		else if (tchart->io_events)
14750a8eb275SStanislav Fomichev 			count = determine_display_io_tasks(tchart, thresh);
1476985b12e6SArnaldo Carvalho de Melo 		else
147710274989SArjan van de Ven 			count = determine_display_tasks(tchart, thresh);
14783415d8b8SStanislav Fomichev 		thresh /= 10;
14793415d8b8SStanislav Fomichev 	} while (!process_filter && thresh && count < tchart->proc_num);
14803415d8b8SStanislav Fomichev 
1481b97b59b9SStanislav Fomichev 	if (!tchart->proc_num)
1482b97b59b9SStanislav Fomichev 		count = 0;
1483b97b59b9SStanislav Fomichev 
1484b97b59b9SStanislav Fomichev 	if (tchart->io_events) {
1485b97b59b9SStanislav Fomichev 		open_svg(filename, 0, count, tchart->first_time, tchart->last_time);
1486b97b59b9SStanislav Fomichev 
1487b97b59b9SStanislav Fomichev 		svg_time_grid(0.5);
1488b97b59b9SStanislav Fomichev 		svg_io_legenda();
1489985b12e6SArnaldo Carvalho de Melo 
149010274989SArjan van de Ven 		draw_io_bars(tchart);
1491b97b59b9SStanislav Fomichev 	} else {
1492b97b59b9SStanislav Fomichev 		open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time);
149310274989SArjan van de Ven 
149410274989SArjan van de Ven 		svg_time_grid(0);
1495985b12e6SArnaldo Carvalho de Melo 
1496985b12e6SArnaldo Carvalho de Melo 		svg_legenda();
149710274989SArjan van de Ven 
14985e22f6d2SArnaldo Carvalho de Melo 		for (i = 0; i < tchart->numcpus; i++)
1499985b12e6SArnaldo Carvalho de Melo 			svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);
1500985b12e6SArnaldo Carvalho de Melo 
1501985b12e6SArnaldo Carvalho de Melo 		draw_cpu_usage(tchart);
1502985b12e6SArnaldo Carvalho de Melo 		if (tchart->proc_num)
1503985b12e6SArnaldo Carvalho de Melo 			draw_process_bars(tchart);
15045e22f6d2SArnaldo Carvalho de Melo 		if (!tchart->tasks_only)
1505b97b59b9SStanislav Fomichev 			draw_c_p_states(tchart);
150610274989SArjan van de Ven 		if (tchart->proc_num)
150710274989SArjan van de Ven 			draw_wakeups(tchart);
150810274989SArjan van de Ven 	}
150910274989SArjan van de Ven 
151058b9a18eSStanislav Fomichev 	svg_close();
151158b9a18eSStanislav Fomichev }
151258b9a18eSStanislav Fomichev 
process_header(struct perf_file_section * section __maybe_unused,struct perf_header * ph,int feat,int fd __maybe_unused,void * data)151358b9a18eSStanislav Fomichev static int process_header(struct perf_file_section *section __maybe_unused,
151458b9a18eSStanislav Fomichev 			  struct perf_header *ph,
151558b9a18eSStanislav Fomichev 			  int feat,
151658b9a18eSStanislav Fomichev 			  int fd __maybe_unused,
151758b9a18eSStanislav Fomichev 			  void *data)
151858b9a18eSStanislav Fomichev {
151958b9a18eSStanislav Fomichev 	struct timechart *tchart = data;
152058b9a18eSStanislav Fomichev 
152158b9a18eSStanislav Fomichev 	switch (feat) {
1522c5079997SStanislav Fomichev 	case HEADER_NRCPUS:
1523c5079997SStanislav Fomichev 		tchart->numcpus = ph->env.nr_cpus_avail;
1524c5079997SStanislav Fomichev 		break;
1525c5079997SStanislav Fomichev 
1526c5079997SStanislav Fomichev 	case HEADER_CPU_TOPOLOGY:
15270ac1dd5bSKyle Meyer 		if (!tchart->topology)
1528c5079997SStanislav Fomichev 			break;
1529c5079997SStanislav Fomichev 
1530c5079997SStanislav Fomichev 		if (svg_build_topology_map(&ph->env))
153158b9a18eSStanislav Fomichev 			fprintf(stderr, "problem building topology\n");
153258b9a18eSStanislav Fomichev 		break;
153358b9a18eSStanislav Fomichev 
153458b9a18eSStanislav Fomichev 	default:
153558b9a18eSStanislav Fomichev 		break;
153658b9a18eSStanislav Fomichev 	}
153758b9a18eSStanislav Fomichev 
1538985b12e6SArnaldo Carvalho de Melo 	return 0;
153973bdc715SArnaldo Carvalho de Melo }
154032dcd021SJiri Olsa 
__cmd_timechart(struct timechart * tchart,const char * output_name)15415936678eSJiri Olsa static int __cmd_timechart(struct timechart *tchart, const char *output_name)
15425936678eSJiri Olsa {
15435936678eSJiri Olsa 	const struct evsel_str_handler power_tracepoints[] = {
15445936678eSJiri Olsa 		{ "power:cpu_idle",		process_sample_cpu_idle },
15455936678eSJiri Olsa 		{ "power:cpu_frequency",	process_sample_cpu_frequency },
15465936678eSJiri Olsa 		{ "sched:sched_wakeup",		process_sample_sched_wakeup },
15475936678eSJiri Olsa 		{ "sched:sched_switch",		process_sample_sched_switch },
15485936678eSJiri Olsa #ifdef SUPPORT_OLD_POWER_EVENTS
15495936678eSJiri Olsa 		{ "power:power_start",		process_sample_power_start },
1550b97b59b9SStanislav Fomichev 		{ "power:power_end",		process_sample_power_end },
1551b97b59b9SStanislav Fomichev 		{ "power:power_frequency",	process_sample_power_frequency },
1552b97b59b9SStanislav Fomichev #endif
1553b97b59b9SStanislav Fomichev 
1554b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_read",		process_enter_read },
1555b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_pread64",		process_enter_read },
1556b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_readv",		process_enter_read },
1557b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_preadv",		process_enter_read },
1558b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_write",		process_enter_write },
1559b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_pwrite64",	process_enter_write },
1560b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_writev",		process_enter_write },
1561b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_pwritev",		process_enter_write },
1562b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_sync",		process_enter_sync },
1563b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_sync_file_range",	process_enter_sync },
1564b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_fsync",		process_enter_sync },
1565b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_msync",		process_enter_sync },
1566b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_recvfrom",	process_enter_rx },
1567b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_recvmmsg",	process_enter_rx },
1568b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_recvmsg",		process_enter_rx },
1569b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_sendto",		process_enter_tx },
1570b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_sendmsg",		process_enter_tx },
1571b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_sendmmsg",	process_enter_tx },
1572b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_epoll_pwait",	process_enter_poll },
1573b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_epoll_wait",	process_enter_poll },
1574b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_poll",		process_enter_poll },
1575b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_ppoll",		process_enter_poll },
1576b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_pselect6",	process_enter_poll },
1577b97b59b9SStanislav Fomichev 		{ "syscalls:sys_enter_select",		process_enter_poll },
1578b97b59b9SStanislav Fomichev 
1579b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_read",		process_exit_read },
1580b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_pread64",		process_exit_read },
1581b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_readv",		process_exit_read },
1582b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_preadv",		process_exit_read },
1583b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_write",		process_exit_write },
1584b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_pwrite64",		process_exit_write },
1585b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_writev",		process_exit_write },
1586b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_pwritev",		process_exit_write },
1587b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_sync",		process_exit_sync },
1588b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_sync_file_range",	process_exit_sync },
1589b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_fsync",		process_exit_sync },
1590b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_msync",		process_exit_sync },
1591b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_recvfrom",		process_exit_rx },
1592b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_recvmmsg",		process_exit_rx },
1593b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_recvmsg",		process_exit_rx },
1594b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_sendto",		process_exit_tx },
1595b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_sendmsg",		process_exit_tx },
1596b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_sendmmsg",		process_exit_tx },
1597b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_epoll_pwait",	process_exit_poll },
1598b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_epoll_wait",	process_exit_poll },
1599b97b59b9SStanislav Fomichev 		{ "syscalls:sys_exit_poll",		process_exit_poll },
16005936678eSJiri Olsa 		{ "syscalls:sys_exit_ppoll",		process_exit_poll },
16018ceb41d7SJiri Olsa 		{ "syscalls:sys_exit_pselect6",		process_exit_poll },
1602f5fc1412SJiri Olsa 		{ "syscalls:sys_exit_select",		process_exit_poll },
1603f5fc1412SJiri Olsa 	};
160444f7e432SYunlong Song 	struct perf_data data = {
1605f5fc1412SJiri Olsa 		.path  = input_name,
1606f5fc1412SJiri Olsa 		.mode  = PERF_DATA_MODE_READ,
16072681bd85SNamhyung Kim 		.force = tchart->force,
1608d549c769SArnaldo Carvalho de Melo 	};
160910274989SArjan van de Ven 
16106ef81c55SMamatha Inamdar 	struct perf_session *session = perf_session__new(&data, &tchart->tool);
16116ef81c55SMamatha Inamdar 	int ret = -EINVAL;
161294c744b6SArnaldo Carvalho de Melo 
16130a7e6d1bSNamhyung Kim 	if (IS_ERR(session))
1614dc5c8190SNamhyung Kim 		return PTR_ERR(session);
161558b9a18eSStanislav Fomichev 
16168ceb41d7SJiri Olsa 	symbol__init(&session->header.env);
161758b9a18eSStanislav Fomichev 
161858b9a18eSStanislav Fomichev 	(void)perf_header__process_sections(&session->header,
161958b9a18eSStanislav Fomichev 					    perf_data__fd(session->data),
1620d549c769SArnaldo Carvalho de Melo 					    tchart,
1621d549c769SArnaldo Carvalho de Melo 					    process_header);
1622d549c769SArnaldo Carvalho de Melo 
16235936678eSJiri Olsa 	if (!perf_session__has_traces(session, "timechart record"))
16245936678eSJiri Olsa 		goto out_delete;
16255936678eSJiri Olsa 
16265936678eSJiri Olsa 	if (perf_session__set_tracepoints_handlers(session,
16275936678eSJiri Olsa 						   power_tracepoints)) {
16285936678eSJiri Olsa 		pr_err("Initializing session tracepoint handlers failed\n");
1629b7b61cbeSArnaldo Carvalho de Melo 		goto out_delete;
16305cbd0805SLi Zefan 	}
163194c744b6SArnaldo Carvalho de Melo 
163210274989SArjan van de Ven 	ret = perf_session__process_events(session);
1633985b12e6SArnaldo Carvalho de Melo 	if (ret)
163410274989SArjan van de Ven 		goto out_delete;
16355e22f6d2SArnaldo Carvalho de Melo 
163610274989SArjan van de Ven 	end_sample_processing(tchart);
1637985b12e6SArnaldo Carvalho de Melo 
163810274989SArjan van de Ven 	sort_pids(tchart);
16396beba7adSArnaldo Carvalho de Melo 
1640af4b2c97SArnaldo Carvalho de Melo 	write_svg_file(tchart, output_name);
164194c744b6SArnaldo Carvalho de Melo 
164294c744b6SArnaldo Carvalho de Melo 	pr_info("Written %2.1f seconds of trace to %s.\n",
164394c744b6SArnaldo Carvalho de Melo 		(tchart->last_time - tchart->first_time) / (double)NSEC_PER_SEC, output_name);
164410274989SArjan van de Ven out_delete:
164510274989SArjan van de Ven 	perf_session__delete(session);
1646b97b59b9SStanislav Fomichev 	return ret;
1647b97b59b9SStanislav Fomichev }
1648b97b59b9SStanislav Fomichev 
timechart__io_record(int argc,const char ** argv)1649b97b59b9SStanislav Fomichev static int timechart__io_record(int argc, const char **argv)
1650b97b59b9SStanislav Fomichev {
1651b97b59b9SStanislav Fomichev 	unsigned int rec_argc, i;
1652b97b59b9SStanislav Fomichev 	const char **rec_argv;
1653b97b59b9SStanislav Fomichev 	const char **p;
1654b97b59b9SStanislav Fomichev 	char *filter = NULL;
1655b97b59b9SStanislav Fomichev 
1656b97b59b9SStanislav Fomichev 	const char * const common_args[] = {
1657b97b59b9SStanislav Fomichev 		"record", "-a", "-R", "-c", "1",
1658b97b59b9SStanislav Fomichev 	};
1659b97b59b9SStanislav Fomichev 	unsigned int common_args_nr = ARRAY_SIZE(common_args);
1660b97b59b9SStanislav Fomichev 
1661b97b59b9SStanislav Fomichev 	const char * const disk_events[] = {
1662b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_read",
1663b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_pread64",
1664b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_readv",
1665b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_preadv",
1666b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_write",
1667b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_pwrite64",
1668b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_writev",
1669b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_pwritev",
1670b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_sync",
1671b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_sync_file_range",
1672b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_fsync",
1673b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_msync",
1674b97b59b9SStanislav Fomichev 
1675b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_read",
1676b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_pread64",
1677b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_readv",
1678b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_preadv",
1679b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_write",
1680b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_pwrite64",
1681b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_writev",
1682b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_pwritev",
1683b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_sync",
1684b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_sync_file_range",
1685b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_fsync",
1686b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_msync",
1687b97b59b9SStanislav Fomichev 	};
1688b97b59b9SStanislav Fomichev 	unsigned int disk_events_nr = ARRAY_SIZE(disk_events);
1689b97b59b9SStanislav Fomichev 
1690b97b59b9SStanislav Fomichev 	const char * const net_events[] = {
1691b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_recvfrom",
1692b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_recvmmsg",
1693b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_recvmsg",
1694b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_sendto",
1695b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_sendmsg",
1696b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_sendmmsg",
1697b97b59b9SStanislav Fomichev 
1698b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_recvfrom",
1699b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_recvmmsg",
1700b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_recvmsg",
1701b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_sendto",
1702b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_sendmsg",
1703b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_sendmmsg",
1704b97b59b9SStanislav Fomichev 	};
1705b97b59b9SStanislav Fomichev 	unsigned int net_events_nr = ARRAY_SIZE(net_events);
1706b97b59b9SStanislav Fomichev 
1707b97b59b9SStanislav Fomichev 	const char * const poll_events[] = {
1708b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_epoll_pwait",
1709b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_epoll_wait",
1710b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_poll",
1711b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_ppoll",
1712b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_pselect6",
1713b97b59b9SStanislav Fomichev 		"syscalls:sys_enter_select",
1714b97b59b9SStanislav Fomichev 
1715b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_epoll_pwait",
1716b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_epoll_wait",
1717b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_poll",
1718b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_ppoll",
1719b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_pselect6",
1720b97b59b9SStanislav Fomichev 		"syscalls:sys_exit_select",
1721b97b59b9SStanislav Fomichev 	};
1722b97b59b9SStanislav Fomichev 	unsigned int poll_events_nr = ARRAY_SIZE(poll_events);
1723b97b59b9SStanislav Fomichev 
1724b97b59b9SStanislav Fomichev 	rec_argc = common_args_nr +
1725b97b59b9SStanislav Fomichev 		disk_events_nr * 4 +
1726b97b59b9SStanislav Fomichev 		net_events_nr * 4 +
1727b97b59b9SStanislav Fomichev 		poll_events_nr * 4 +
1728b97b59b9SStanislav Fomichev 		argc;
1729b97b59b9SStanislav Fomichev 	rec_argv = calloc(rec_argc + 1, sizeof(char *));
1730b97b59b9SStanislav Fomichev 
1731c896f85aSMartin Kepplinger 	if (rec_argv == NULL)
1732c896f85aSMartin Kepplinger 		return -ENOMEM;
1733b97b59b9SStanislav Fomichev 
1734c896f85aSMartin Kepplinger 	if (asprintf(&filter, "common_pid != %d", getpid()) < 0) {
1735b97b59b9SStanislav Fomichev 		free(rec_argv);
1736b97b59b9SStanislav Fomichev 		return -ENOMEM;
1737b97b59b9SStanislav Fomichev 	}
1738b97b59b9SStanislav Fomichev 
1739b97b59b9SStanislav Fomichev 	p = rec_argv;
1740b97b59b9SStanislav Fomichev 	for (i = 0; i < common_args_nr; i++)
1741b97b59b9SStanislav Fomichev 		*p++ = strdup(common_args[i]);
1742b97b59b9SStanislav Fomichev 
1743b97b59b9SStanislav Fomichev 	for (i = 0; i < disk_events_nr; i++) {
1744b97b59b9SStanislav Fomichev 		if (!is_valid_tracepoint(disk_events[i])) {
1745b97b59b9SStanislav Fomichev 			rec_argc -= 4;
1746b97b59b9SStanislav Fomichev 			continue;
1747b97b59b9SStanislav Fomichev 		}
1748b97b59b9SStanislav Fomichev 
1749b97b59b9SStanislav Fomichev 		*p++ = "-e";
1750b97b59b9SStanislav Fomichev 		*p++ = strdup(disk_events[i]);
1751b97b59b9SStanislav Fomichev 		*p++ = "--filter";
1752b97b59b9SStanislav Fomichev 		*p++ = filter;
1753b97b59b9SStanislav Fomichev 	}
1754b97b59b9SStanislav Fomichev 	for (i = 0; i < net_events_nr; i++) {
1755b97b59b9SStanislav Fomichev 		if (!is_valid_tracepoint(net_events[i])) {
1756b97b59b9SStanislav Fomichev 			rec_argc -= 4;
1757b97b59b9SStanislav Fomichev 			continue;
1758b97b59b9SStanislav Fomichev 		}
1759b97b59b9SStanislav Fomichev 
1760b97b59b9SStanislav Fomichev 		*p++ = "-e";
1761b97b59b9SStanislav Fomichev 		*p++ = strdup(net_events[i]);
1762b97b59b9SStanislav Fomichev 		*p++ = "--filter";
1763b97b59b9SStanislav Fomichev 		*p++ = filter;
1764b97b59b9SStanislav Fomichev 	}
1765b97b59b9SStanislav Fomichev 	for (i = 0; i < poll_events_nr; i++) {
1766b97b59b9SStanislav Fomichev 		if (!is_valid_tracepoint(poll_events[i])) {
1767b97b59b9SStanislav Fomichev 			rec_argc -= 4;
1768b97b59b9SStanislav Fomichev 			continue;
1769b97b59b9SStanislav Fomichev 		}
1770b97b59b9SStanislav Fomichev 
1771b97b59b9SStanislav Fomichev 		*p++ = "-e";
1772b97b59b9SStanislav Fomichev 		*p++ = strdup(poll_events[i]);
1773b97b59b9SStanislav Fomichev 		*p++ = "--filter";
1774b97b59b9SStanislav Fomichev 		*p++ = filter;
1775b97b59b9SStanislav Fomichev 	}
1776b97b59b9SStanislav Fomichev 
1777b0ad8ea6SArnaldo Carvalho de Melo 	for (i = 0; i < (unsigned int)argc; i++)
1778b97b59b9SStanislav Fomichev 		*p++ = argv[i];
1779b97b59b9SStanislav Fomichev 
1780b97b59b9SStanislav Fomichev 	return cmd_record(rec_argc, rec_argv);
1781985b12e6SArnaldo Carvalho de Melo }
178273bdc715SArnaldo Carvalho de Melo 
1783367b3152SStanislav Fomichev 
timechart__record(struct timechart * tchart,int argc,const char ** argv)1784367b3152SStanislav Fomichev static int timechart__record(struct timechart *tchart, int argc, const char **argv)
1785367b3152SStanislav Fomichev {
1786367b3152SStanislav Fomichev 	unsigned int rec_argc, i, j;
1787367b3152SStanislav Fomichev 	const char **rec_argv;
1788367b3152SStanislav Fomichev 	const char **p;
17894a4d371aSJiri Olsa 	unsigned int record_elems;
1790367b3152SStanislav Fomichev 
1791367b3152SStanislav Fomichev 	const char * const common_args[] = {
1792367b3152SStanislav Fomichev 		"record", "-a", "-R", "-c", "1",
17936f8d67faSStanislav Fomichev 	};
17946f8d67faSStanislav Fomichev 	unsigned int common_args_nr = ARRAY_SIZE(common_args);
17956f8d67faSStanislav Fomichev 
17966f8d67faSStanislav Fomichev 	const char * const backtrace_args[] = {
17976f8d67faSStanislav Fomichev 		"-g",
1798367b3152SStanislav Fomichev 	};
1799367b3152SStanislav Fomichev 	unsigned int backtrace_args_no = ARRAY_SIZE(backtrace_args);
1800367b3152SStanislav Fomichev 
1801367b3152SStanislav Fomichev 	const char * const power_args[] = {
1802367b3152SStanislav Fomichev 		"-e", "power:cpu_frequency",
1803367b3152SStanislav Fomichev 		"-e", "power:cpu_idle",
1804367b3152SStanislav Fomichev 	};
1805367b3152SStanislav Fomichev 	unsigned int power_args_nr = ARRAY_SIZE(power_args);
18063c09eebdSArjan van de Ven 
18073c09eebdSArjan van de Ven 	const char * const old_power_args[] = {
18083c09eebdSArjan van de Ven #ifdef SUPPORT_OLD_POWER_EVENTS
180920c457b8SThomas Renninger 		"-e", "power:power_start",
1810367b3152SStanislav Fomichev 		"-e", "power:power_end",
1811367b3152SStanislav Fomichev 		"-e", "power:power_frequency",
1812367b3152SStanislav Fomichev #endif
1813367b3152SStanislav Fomichev 	};
181420c457b8SThomas Renninger 	unsigned int old_power_args_nr = ARRAY_SIZE(old_power_args);
181520c457b8SThomas Renninger 
181620c457b8SThomas Renninger 	const char * const tasks_args[] = {
1817367b3152SStanislav Fomichev 		"-e", "sched:sched_wakeup",
18183c09eebdSArjan van de Ven 		"-e", "sched:sched_switch",
181920c457b8SThomas Renninger 	};
182020c457b8SThomas Renninger 	unsigned int tasks_args_nr = ARRAY_SIZE(tasks_args);
182120c457b8SThomas Renninger 
182220c457b8SThomas Renninger #ifdef SUPPORT_OLD_POWER_EVENTS
1823367b3152SStanislav Fomichev 	if (!is_valid_tracepoint("power:cpu_idle") &&
1824367b3152SStanislav Fomichev 	    is_valid_tracepoint("power:power_start")) {
1825367b3152SStanislav Fomichev 		use_old_power_events = 1;
182620c457b8SThomas Renninger 		power_args_nr = 0;
182720c457b8SThomas Renninger 	} else {
182820c457b8SThomas Renninger 		old_power_args_nr = 0;
1829985b12e6SArnaldo Carvalho de Melo 	}
1830367b3152SStanislav Fomichev #endif
1831367b3152SStanislav Fomichev 
1832985b12e6SArnaldo Carvalho de Melo 	if (tchart->power_only)
1833367b3152SStanislav Fomichev 		tasks_args_nr = 0;
1834367b3152SStanislav Fomichev 
1835367b3152SStanislav Fomichev 	if (tchart->tasks_only) {
1836367b3152SStanislav Fomichev 		power_args_nr = 0;
1837985b12e6SArnaldo Carvalho de Melo 		old_power_args_nr = 0;
18386f8d67faSStanislav Fomichev 	}
18396f8d67faSStanislav Fomichev 
1840367b3152SStanislav Fomichev 	if (!tchart->with_backtrace)
18416f8d67faSStanislav Fomichev 		backtrace_args_no = 0;
1842367b3152SStanislav Fomichev 
1843367b3152SStanislav Fomichev 	record_elems = common_args_nr + tasks_args_nr +
18443c09eebdSArjan van de Ven 		power_args_nr + old_power_args_nr + backtrace_args_no;
18453c09eebdSArjan van de Ven 
1846ce47dc56SChris Samuel 	rec_argc = record_elems + argc;
1847ce47dc56SChris Samuel 	rec_argv = calloc(rec_argc + 1, sizeof(char *));
1848ce47dc56SChris Samuel 
1849367b3152SStanislav Fomichev 	if (rec_argv == NULL)
1850367b3152SStanislav Fomichev 		return -ENOMEM;
1851367b3152SStanislav Fomichev 
18523c09eebdSArjan van de Ven 	p = rec_argv;
18536f8d67faSStanislav Fomichev 	for (i = 0; i < common_args_nr; i++)
18546f8d67faSStanislav Fomichev 		*p++ = strdup(common_args[i]);
18556f8d67faSStanislav Fomichev 
1856367b3152SStanislav Fomichev 	for (i = 0; i < backtrace_args_no; i++)
1857367b3152SStanislav Fomichev 		*p++ = strdup(backtrace_args[i]);
18583c09eebdSArjan van de Ven 
1859367b3152SStanislav Fomichev 	for (i = 0; i < tasks_args_nr; i++)
1860367b3152SStanislav Fomichev 		*p++ = strdup(tasks_args[i]);
1861367b3152SStanislav Fomichev 
1862367b3152SStanislav Fomichev 	for (i = 0; i < power_args_nr; i++)
1863367b3152SStanislav Fomichev 		*p++ = strdup(power_args[i]);
1864367b3152SStanislav Fomichev 
1865263f89bfSRamkumar Ramachandra 	for (i = 0; i < old_power_args_nr; i++)
1866367b3152SStanislav Fomichev 		*p++ = strdup(old_power_args[i]);
1867367b3152SStanislav Fomichev 
1868b0ad8ea6SArnaldo Carvalho de Melo 	for (j = 0; j < (unsigned int)argc; j++)
18693c09eebdSArjan van de Ven 		*p++ = argv[j];
18703c09eebdSArjan van de Ven 
1871bbe2987bSArjan van de Ven 	return cmd_record(rec_argc, rec_argv);
18721d037ca1SIrina Tirdea }
18731d037ca1SIrina Tirdea 
1874bbe2987bSArjan van de Ven static int
parse_process(const struct option * opt __maybe_unused,const char * arg,int __maybe_unused unset)1875bbe2987bSArjan van de Ven parse_process(const struct option *opt __maybe_unused, const char *arg,
1876bbe2987bSArjan van de Ven 	      int __maybe_unused unset)
1877bbe2987bSArjan van de Ven {
1878bbe2987bSArjan van de Ven 	if (arg)
1879bbe2987bSArjan van de Ven 		add_process_filter(arg);
1880e57a2dffSStanislav Fomichev 	return 0;
1881e57a2dffSStanislav Fomichev }
1882e57a2dffSStanislav Fomichev 
1883e57a2dffSStanislav Fomichev static int
parse_highlight(const struct option * opt __maybe_unused,const char * arg,int __maybe_unused unset)1884e57a2dffSStanislav Fomichev parse_highlight(const struct option *opt __maybe_unused, const char *arg,
1885e57a2dffSStanislav Fomichev 		int __maybe_unused unset)
1886e57a2dffSStanislav Fomichev {
1887e57a2dffSStanislav Fomichev 	unsigned long duration = strtoul(arg, NULL, 0);
1888e57a2dffSStanislav Fomichev 
1889e57a2dffSStanislav Fomichev 	if (svg_highlight || svg_highlight_name)
1890e57a2dffSStanislav Fomichev 		return -1;
1891e57a2dffSStanislav Fomichev 
1892e57a2dffSStanislav Fomichev 	if (duration)
1893e57a2dffSStanislav Fomichev 		svg_highlight = duration;
1894e57a2dffSStanislav Fomichev 	else
1895e57a2dffSStanislav Fomichev 		svg_highlight_name = strdup(arg);
1896e57a2dffSStanislav Fomichev 
1897d243144aSStanislav Fomichev 	return 0;
1898d243144aSStanislav Fomichev }
1899d243144aSStanislav Fomichev 
1900d243144aSStanislav Fomichev static int
parse_time(const struct option * opt,const char * arg,int __maybe_unused unset)1901d243144aSStanislav Fomichev parse_time(const struct option *opt, const char *arg, int __maybe_unused unset)
1902d243144aSStanislav Fomichev {
1903d243144aSStanislav Fomichev 	char unit = 'n';
1904d243144aSStanislav Fomichev 	u64 *value = opt->value;
1905d243144aSStanislav Fomichev 
1906af4b2c97SArnaldo Carvalho de Melo 	if (sscanf(arg, "%" PRIu64 "%cs", value, &unit) > 0) {
1907d243144aSStanislav Fomichev 		switch (unit) {
1908d243144aSStanislav Fomichev 		case 'm':
1909af4b2c97SArnaldo Carvalho de Melo 			*value *= NSEC_PER_MSEC;
1910d243144aSStanislav Fomichev 			break;
1911d243144aSStanislav Fomichev 		case 'u':
1912d243144aSStanislav Fomichev 			*value *= NSEC_PER_USEC;
1913d243144aSStanislav Fomichev 			break;
1914d243144aSStanislav Fomichev 		case 'n':
1915d243144aSStanislav Fomichev 			break;
1916d243144aSStanislav Fomichev 		default:
1917d243144aSStanislav Fomichev 			return -1;
1918d243144aSStanislav Fomichev 		}
1919d243144aSStanislav Fomichev 	}
1920d243144aSStanislav Fomichev 
1921b0ad8ea6SArnaldo Carvalho de Melo 	return 0;
192273bdc715SArnaldo Carvalho de Melo }
1923985b12e6SArnaldo Carvalho de Melo 
cmd_timechart(int argc,const char ** argv)1924985b12e6SArnaldo Carvalho de Melo int cmd_timechart(int argc, const char **argv)
1925985b12e6SArnaldo Carvalho de Melo {
1926985b12e6SArnaldo Carvalho de Melo 	struct timechart tchart = {
1927985b12e6SArnaldo Carvalho de Melo 		.tool = {
1928985b12e6SArnaldo Carvalho de Melo 			.comm		 = process_comm_event,
19290a8cb85cSJiri Olsa 			.fork		 = process_fork_event,
1930985b12e6SArnaldo Carvalho de Melo 			.exit		 = process_exit_event,
1931985b12e6SArnaldo Carvalho de Melo 			.sample		 = process_sample_event,
1932af4b2c97SArnaldo Carvalho de Melo 			.ordered_events	 = true,
1933d243144aSStanislav Fomichev 		},
1934985b12e6SArnaldo Carvalho de Melo 		.proc_num = 15,
193573bdc715SArnaldo Carvalho de Melo 		.min_time = NSEC_PER_MSEC,
1936f371594aSArnaldo Carvalho de Melo 		.merge_dist = 1000,
1937f371594aSArnaldo Carvalho de Melo 	};
1938f371594aSArnaldo Carvalho de Melo 	const char *output_name = "output.svg";
1939f371594aSArnaldo Carvalho de Melo 	const struct option timechart_common_options[] = {
1940f371594aSArnaldo Carvalho de Melo 	OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1941367b3152SStanislav Fomichev 	OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, "output processes data only"),
194273bdc715SArnaldo Carvalho de Melo 	OPT_END()
194373bdc715SArnaldo Carvalho de Melo 	};
194473bdc715SArnaldo Carvalho de Melo 	const struct option timechart_options[] = {
1945e57a2dffSStanislav Fomichev 	OPT_STRING('i', "input", &input_name, "file", "input file name"),
1946e57a2dffSStanislav Fomichev 	OPT_STRING('o', "output", &output_name, "file", "output file name"),
1947e57a2dffSStanislav Fomichev 	OPT_INTEGER('w', "width", &svg_page_width, "page width"),
1948bbe2987bSArjan van de Ven 	OPT_CALLBACK(0, "highlight", NULL, "duration or task name",
1949bbe2987bSArjan van de Ven 		      "highlight tasks. Pass duration in ns or process name.",
1950bbe2987bSArjan van de Ven 		       parse_highlight),
1951a7066709SHe Kuang 	OPT_CALLBACK('p', "process", NULL, "process",
1952a7066709SHe Kuang 		      "process selector. Pass a pid or process name.",
1953a7066709SHe Kuang 		       parse_process),
1954985b12e6SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "symfs", NULL, "directory",
195554874e32SStanislav Fomichev 		     "Look for files with symbols relative to this directory",
1956c5079997SStanislav Fomichev 		     symbol__config_symfs),
1957c5079997SStanislav Fomichev 	OPT_INTEGER('n', "proc-num", &tchart.proc_num,
1958d243144aSStanislav Fomichev 		    "min. number of tasks to print"),
1959d243144aSStanislav Fomichev 	OPT_BOOLEAN('t', "topology", &tchart.topology,
1960d243144aSStanislav Fomichev 		    "sort CPUs according to topology"),
1961d243144aSStanislav Fomichev 	OPT_BOOLEAN(0, "io-skip-eagain", &tchart.skip_eagain,
1962d243144aSStanislav Fomichev 		    "skip EAGAIN errors"),
1963d243144aSStanislav Fomichev 	OPT_CALLBACK(0, "io-min-time", &tchart.min_time, "time",
1964d243144aSStanislav Fomichev 		     "all IO faster than min-time will visually appear longer",
1965d243144aSStanislav Fomichev 		     parse_time),
196644f7e432SYunlong Song 	OPT_CALLBACK(0, "io-merge-dist", &tchart.merge_dist, "time",
1967f371594aSArnaldo Carvalho de Melo 		     "merge events that are merge-dist us apart",
196810274989SArjan van de Ven 		     parse_time),
196933ec0cafSYunlong Song 	OPT_BOOLEAN('f', "force", &tchart.force, "don't complain, do it"),
197033ec0cafSYunlong Song 	OPT_PARENT(timechart_common_options),
197173bdc715SArnaldo Carvalho de Melo 	};
197273bdc715SArnaldo Carvalho de Melo 	const char * const timechart_subcommands[] = { "record", NULL };
197373bdc715SArnaldo Carvalho de Melo 	const char *timechart_usage[] = {
1974e5b2c207SNamhyung Kim 		"perf timechart [<options>] {record}",
1975b97b59b9SStanislav Fomichev 		NULL
1976b97b59b9SStanislav Fomichev 	};
1977985b12e6SArnaldo Carvalho de Melo 	const struct option timechart_record_options[] = {
1978f371594aSArnaldo Carvalho de Melo 	OPT_BOOLEAN('I', "io-only", &tchart.io_only,
1979367b3152SStanislav Fomichev 		    "record only IO data"),
1980e5b2c207SNamhyung Kim 	OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"),
1981367b3152SStanislav Fomichev 	OPT_PARENT(timechart_common_options),
1982367b3152SStanislav Fomichev 	};
1983367b3152SStanislav Fomichev 	const char * const timechart_record_usage[] = {
198433ec0cafSYunlong Song 		"perf timechart record [<options>]",
198533ec0cafSYunlong Song 		NULL
198610274989SArjan van de Ven 	};
1987985b12e6SArnaldo Carvalho de Melo 	int ret;
1988c87097d3SStanislav Fomichev 
1989c87097d3SStanislav Fomichev 	cpus_cstate_start_times = calloc(MAX_CPUS, sizeof(*cpus_cstate_start_times));
1990c87097d3SStanislav Fomichev 	if (!cpus_cstate_start_times)
1991c87097d3SStanislav Fomichev 		return -ENOMEM;
1992ae0f4eb3SWei Li 	cpus_cstate_state = calloc(MAX_CPUS, sizeof(*cpus_cstate_state));
1993e5b2c207SNamhyung Kim 	if (!cpus_cstate_state) {
1994e5b2c207SNamhyung Kim 		ret = -ENOMEM;
1995367b3152SStanislav Fomichev 		goto out;
1996367b3152SStanislav Fomichev 	}
1997985b12e6SArnaldo Carvalho de Melo 	cpus_pstate_start_times = calloc(MAX_CPUS, sizeof(*cpus_pstate_start_times));
1998367b3152SStanislav Fomichev 	if (!cpus_pstate_start_times) {
1999367b3152SStanislav Fomichev 		ret = -ENOMEM;
2000367b3152SStanislav Fomichev 		goto out;
2001367b3152SStanislav Fomichev 	}
2002b97b59b9SStanislav Fomichev 	cpus_pstate_state = calloc(MAX_CPUS, sizeof(*cpus_pstate_state));
2003b97b59b9SStanislav Fomichev 	if (!cpus_pstate_state) {
2004b97b59b9SStanislav Fomichev 		ret = -ENOMEM;
2005985b12e6SArnaldo Carvalho de Melo 		goto out;
2006367b3152SStanislav Fomichev 	}
2007367b3152SStanislav Fomichev 
200810274989SArjan van de Ven 	argc = parse_options_subcommand(argc, argv, timechart_options, timechart_subcommands,
200910274989SArjan van de Ven 			timechart_usage, PARSE_OPT_STOP_AT_NON_OPTION);
201010274989SArjan van de Ven 
2011985b12e6SArnaldo Carvalho de Melo 	if (tchart.power_only && tchart.tasks_only) {
201210274989SArjan van de Ven 		pr_err("-P and -T options cannot be used at the same time.\n");
2013 		ret = -1;
2014 		goto out;
2015 	}
2016 
2017 	if (argc && strlen(argv[0]) > 2 && strstarts("record", argv[0])) {
2018 		argc = parse_options(argc, argv, timechart_record_options,
2019 				     timechart_record_usage,
2020 				     PARSE_OPT_STOP_AT_NON_OPTION);
2021 
2022 		if (tchart.power_only && tchart.tasks_only) {
2023 			pr_err("-P and -T options cannot be used at the same time.\n");
2024 			ret = -1;
2025 			goto out;
2026 		}
2027 
2028 		if (tchart.io_only)
2029 			ret = timechart__io_record(argc, argv);
2030 		else
2031 			ret = timechart__record(&tchart, argc, argv);
2032 		goto out;
2033 	} else if (argc)
2034 		usage_with_options(timechart_usage, timechart_options);
2035 
2036 	setup_pager();
2037 
2038 	ret = __cmd_timechart(&tchart, output_name);
2039 out:
2040 	zfree(&cpus_cstate_start_times);
2041 	zfree(&cpus_cstate_state);
2042 	zfree(&cpus_pstate_start_times);
2043 	zfree(&cpus_pstate_state);
2044 	return ret;
2045 }
2046