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