summaryrefslogtreecommitdiff
path: root/tools/perf/builtin-timechart.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-timechart.c')
-rw-r--r--tools/perf/builtin-timechart.c212
1 files changed, 143 insertions, 69 deletions
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 85a9ad0455ae..3f9153d5ecfb 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -56,6 +56,7 @@ struct timechart {
struct per_pid *all_data;
struct power_event *power_events;
struct wake_event *wake_events;
+ struct perf_session *session;
int proc_num;
unsigned int numcpus;
u64 min_freq, /* Lowest CPU frequency seen */
@@ -299,7 +300,7 @@ static void pid_put_sample(struct timechart *tchart, int pid, int type,
sample->type = type;
sample->next = c->samples;
sample->cpu = cpu;
- sample->backtrace = backtrace ? strdup(backtrace) : NULL;
+ sample->backtrace = backtrace;
c->samples = sample;
if (sample->type == TYPE_RUNNING && end > start && start > 0) {
@@ -428,12 +429,14 @@ static void sched_wakeup(struct timechart *tchart, int cpu, u64 timestamp,
struct per_pid *p;
struct wake_event *we = zalloc(sizeof(*we));
- if (!we)
+ if (!we) {
+ free((char *)backtrace);
return;
+ }
we->time = timestamp;
we->waker = waker;
- we->backtrace = backtrace ? strdup(backtrace) : NULL;
+ we->backtrace = backtrace;
if ((flags & TRACE_FLAG_HARDIRQ) || (flags & TRACE_FLAG_SOFTIRQ))
we->waker = -1;
@@ -460,20 +463,28 @@ static void sched_switch(struct timechart *tchart, int cpu, u64 timestamp,
const char *backtrace)
{
struct per_pid *p = NULL, *prev_p;
+ bool backtrace_used = false;
prev_p = find_create_pid(tchart, prev_pid);
p = find_create_pid(tchart, next_pid);
- if (prev_p->current && prev_p->current->state != TYPE_NONE)
+ if (prev_p->current && prev_p->current->state != TYPE_NONE) {
pid_put_sample(tchart, prev_pid, TYPE_RUNNING, cpu,
prev_p->current->state_since, timestamp,
backtrace);
+ backtrace_used = true;
+ }
if (p && p->current) {
- if (p->current->state != TYPE_NONE)
+ if (p->current->state != TYPE_NONE) {
+ if (backtrace && backtrace_used)
+ backtrace = strdup(backtrace);
+
pid_put_sample(tchart, next_pid, p->current->state, cpu,
p->current->state_since, timestamp,
backtrace);
+ backtrace_used = true;
+ }
p->current->state_since = timestamp;
p->current->state = TYPE_RUNNING;
@@ -487,14 +498,16 @@ static void sched_switch(struct timechart *tchart, int cpu, u64 timestamp,
if (prev_state == 0)
prev_p->current->state = TYPE_WAITING;
}
+
+ if (!backtrace_used)
+ free((char *)backtrace);
}
/*
* Returns a malloc'd backtrace string built via open_memstream, or NULL
* on error. Caller must free() the returned pointer.
*/
-static char *cat_backtrace(union perf_event *event,
- struct perf_sample *sample,
+static char *cat_backtrace(struct perf_sample *sample,
struct machine *machine)
{
struct addr_location al;
@@ -516,9 +529,8 @@ static char *cat_backtrace(union perf_event *event,
goto exit;
if (machine__resolve(machine, &al, sample) < 0) {
- pr_err("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
- perf_event__name(event->header.type), event->header.type,
- sample->file_offset);
+ pr_err("problem processing SAMPLE (%u) event at offset %#" PRIx64 ", skipping it.\n",
+ PERF_RECORD_SAMPLE, sample->file_offset);
goto exit;
}
@@ -574,13 +586,12 @@ exit:
}
typedef int (*tracepoint_handler)(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace);
+ struct perf_sample *sample);
static int process_sample_event(const struct perf_tool *tool,
- union perf_event *event,
+ union perf_event *event __maybe_unused,
struct perf_sample *sample,
- struct machine *machine)
+ struct machine *machine __maybe_unused)
{
struct timechart *tchart = container_of(tool, struct timechart, tool);
struct evsel *evsel = sample->evsel;
@@ -595,10 +606,8 @@ static int process_sample_event(const struct perf_tool *tool,
if (evsel->handler != NULL) {
tracepoint_handler f = evsel->handler;
- char *backtrace = cat_backtrace(event, sample, machine);
- ret = f(tchart, sample, backtrace);
- free(backtrace);
+ ret = f(tchart, sample);
}
return ret;
@@ -606,8 +615,7 @@ static int process_sample_event(const struct perf_tool *tool,
static int
process_sample_cpu_idle(struct timechart *tchart __maybe_unused,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
u32 state = perf_sample__intval(sample, "state");
u32 cpu_id = perf_sample__intval(sample, "cpu_id");
@@ -627,8 +635,7 @@ process_sample_cpu_idle(struct timechart *tchart __maybe_unused,
static int
process_sample_cpu_frequency(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
u32 state = perf_sample__intval(sample, "state");
u32 cpu_id = perf_sample__intval(sample, "cpu_id");
@@ -645,12 +652,12 @@ process_sample_cpu_frequency(struct timechart *tchart,
static int
process_sample_sched_wakeup(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace)
+ struct perf_sample *sample)
{
u8 flags = perf_sample__intval(sample, "common_flags");
int waker = perf_sample__intval(sample, "common_pid");
int wakee = perf_sample__intval(sample, "pid");
+ char *backtrace;
/* perf.data is untrusted input — CPU may be absent or corrupted */
if (sample->cpu >= MAX_CPUS) {
@@ -658,18 +665,20 @@ process_sample_sched_wakeup(struct timechart *tchart,
sample->file_offset, sample->cpu);
return -1;
}
+
+ backtrace = cat_backtrace(sample, &tchart->session->machines.host);
sched_wakeup(tchart, sample->cpu, sample->time, waker, wakee, flags, backtrace);
return 0;
}
static int
process_sample_sched_switch(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace)
+ struct perf_sample *sample)
{
int prev_pid = perf_sample__intval(sample, "prev_pid");
int next_pid = perf_sample__intval(sample, "next_pid");
u64 prev_state = perf_sample__intval(sample, "prev_state");
+ char *backtrace;
/* perf.data is untrusted input — CPU may be absent or corrupted */
if (sample->cpu >= MAX_CPUS) {
@@ -677,6 +686,8 @@ process_sample_sched_switch(struct timechart *tchart,
sample->file_offset, sample->cpu);
return -1;
}
+
+ backtrace = cat_backtrace(sample, &tchart->session->machines.host);
sched_switch(tchart, sample->cpu, sample->time, prev_pid, next_pid,
prev_state, backtrace);
return 0;
@@ -685,8 +696,7 @@ process_sample_sched_switch(struct timechart *tchart,
#ifdef SUPPORT_OLD_POWER_EVENTS
static int
process_sample_power_start(struct timechart *tchart __maybe_unused,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
u64 cpu_id = perf_sample__intval(sample, "cpu_id");
u64 value = perf_sample__intval(sample, "value");
@@ -703,8 +713,7 @@ process_sample_power_start(struct timechart *tchart __maybe_unused,
static int
process_sample_power_end(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
/* perf.data is untrusted input — CPU may be absent or corrupted */
if (sample->cpu >= MAX_CPUS) {
@@ -718,8 +727,7 @@ process_sample_power_end(struct timechart *tchart,
static int
process_sample_power_frequency(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
u64 cpu_id = perf_sample__intval(sample, "cpu_id");
u64 value = perf_sample__intval(sample, "value");
@@ -892,8 +900,7 @@ static int pid_end_io_sample(struct timechart *tchart, int pid, int type,
static int
process_enter_read(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
long fd = perf_sample__intval(sample, "fd");
return pid_begin_io_sample(tchart, sample->tid, IOTYPE_READ,
@@ -902,8 +909,7 @@ process_enter_read(struct timechart *tchart,
static int
process_exit_read(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
long ret = perf_sample__intval(sample, "ret");
return pid_end_io_sample(tchart, sample->tid, IOTYPE_READ,
@@ -912,8 +918,7 @@ process_exit_read(struct timechart *tchart,
static int
process_enter_write(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
long fd = perf_sample__intval(sample, "fd");
return pid_begin_io_sample(tchart, sample->tid, IOTYPE_WRITE,
@@ -922,8 +927,7 @@ process_enter_write(struct timechart *tchart,
static int
process_exit_write(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
long ret = perf_sample__intval(sample, "ret");
return pid_end_io_sample(tchart, sample->tid, IOTYPE_WRITE,
@@ -932,8 +936,7 @@ process_exit_write(struct timechart *tchart,
static int
process_enter_sync(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
long fd = perf_sample__intval(sample, "fd");
return pid_begin_io_sample(tchart, sample->tid, IOTYPE_SYNC,
@@ -942,8 +945,7 @@ process_enter_sync(struct timechart *tchart,
static int
process_exit_sync(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
long ret = perf_sample__intval(sample, "ret");
return pid_end_io_sample(tchart, sample->tid, IOTYPE_SYNC,
@@ -952,8 +954,7 @@ process_exit_sync(struct timechart *tchart,
static int
process_enter_tx(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
long fd = perf_sample__intval(sample, "fd");
return pid_begin_io_sample(tchart, sample->tid, IOTYPE_TX,
@@ -962,8 +963,7 @@ process_enter_tx(struct timechart *tchart,
static int
process_exit_tx(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
long ret = perf_sample__intval(sample, "ret");
return pid_end_io_sample(tchart, sample->tid, IOTYPE_TX,
@@ -972,8 +972,7 @@ process_exit_tx(struct timechart *tchart,
static int
process_enter_rx(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
long fd = perf_sample__intval(sample, "fd");
return pid_begin_io_sample(tchart, sample->tid, IOTYPE_RX,
@@ -982,8 +981,7 @@ process_enter_rx(struct timechart *tchart,
static int
process_exit_rx(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
long ret = perf_sample__intval(sample, "ret");
return pid_end_io_sample(tchart, sample->tid, IOTYPE_RX,
@@ -992,8 +990,7 @@ process_exit_rx(struct timechart *tchart,
static int
process_enter_poll(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
long fd = perf_sample__intval(sample, "fd");
return pid_begin_io_sample(tchart, sample->tid, IOTYPE_POLL,
@@ -1002,8 +999,7 @@ process_enter_poll(struct timechart *tchart,
static int
process_exit_poll(struct timechart *tchart,
- struct perf_sample *sample,
- const char *backtrace __maybe_unused)
+ struct perf_sample *sample)
{
long ret = perf_sample__intval(sample, "ret");
return pid_end_io_sample(tchart, sample->tid, IOTYPE_POLL,
@@ -1114,12 +1110,12 @@ static void draw_wakeups(struct timechart *tchart)
c = c->next;
}
c = p->all;
- while (c) {
- if (p->pid == we->waker && !from) {
+ while (c && (!from || !to)) {
+ if (c->Y && p->pid == we->waker && !from) {
from = c->Y;
task_from = strdup(c->comm);
}
- if (p->pid == we->wakee && !to) {
+ if (c->Y && p->pid == we->wakee && !to) {
to = c->Y;
task_to = strdup(c->comm);
}
@@ -1552,6 +1548,73 @@ static void write_svg_file(struct timechart *tchart, const char *filename)
svg_close();
}
+static void timechart__release(struct timechart *tchart)
+{
+ struct per_pid *p = tchart->all_data;
+ struct power_event *pwr = tchart->power_events;
+ struct wake_event *we = tchart->wake_events;
+
+ while (p) {
+ struct per_pid *next_pid = p->next;
+ struct per_pidcomm *c = p->all;
+
+ while (c) {
+ struct per_pidcomm *next_comm = c->next;
+ struct cpu_sample *cs = c->samples;
+ struct io_sample *ios = c->io_samples;
+
+ while (cs) {
+ struct cpu_sample *next = cs->next;
+
+ zfree(&cs->backtrace);
+ cs->next = NULL;
+ free(cs);
+
+ cs = next;
+ }
+
+ while (ios) {
+ struct io_sample *next = ios->next;
+
+ ios->next = NULL;
+ free(ios);
+
+ ios = next;
+ }
+
+ zfree(&c->comm);
+ c->next = NULL;
+ free(c);
+
+ c = next_comm;
+ }
+
+ p->next = NULL;
+ free(p);
+
+ p = next_pid;
+ }
+
+ while (pwr) {
+ struct power_event *next = pwr->next;
+
+ pwr->next = NULL;
+ free(pwr);
+
+ pwr = next;
+ }
+
+ while (we) {
+ struct wake_event *next = we->next;
+
+ zfree(&we->backtrace);
+ we->next = NULL;
+ free(we);
+
+ we = next;
+ }
+}
+
static int process_header(struct perf_file_section *section __maybe_unused,
struct perf_header *ph,
int feat,
@@ -1663,6 +1726,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
if (IS_ERR(session))
return PTR_ERR(session);
+ tchart->session = session;
symbol__init(perf_session__env(session));
(void)perf_header__process_sections(&session->header,
@@ -1770,6 +1834,7 @@ static int timechart__io_record(int argc, const char **argv, const char *output_
"syscalls:sys_exit_select",
};
unsigned int poll_events_nr = ARRAY_SIZE(poll_events);
+ int ret;
rec_argc = common_args_nr +
disk_events_nr * 4 +
@@ -1788,7 +1853,7 @@ static int timechart__io_record(int argc, const char **argv, const char *output_
p = rec_argv;
for (i = 0; i < common_args_nr; i++)
- *p++ = strdup(common_args[i]);
+ *p++ = common_args[i];
for (i = 0; i < disk_events_nr; i++) {
if (!is_valid_tracepoint(disk_events[i])) {
@@ -1797,7 +1862,7 @@ static int timechart__io_record(int argc, const char **argv, const char *output_
}
*p++ = "-e";
- *p++ = strdup(disk_events[i]);
+ *p++ = disk_events[i];
*p++ = "--filter";
*p++ = filter;
}
@@ -1808,7 +1873,7 @@ static int timechart__io_record(int argc, const char **argv, const char *output_
}
*p++ = "-e";
- *p++ = strdup(net_events[i]);
+ *p++ = net_events[i];
*p++ = "--filter";
*p++ = filter;
}
@@ -1819,7 +1884,7 @@ static int timechart__io_record(int argc, const char **argv, const char *output_
}
*p++ = "-e";
- *p++ = strdup(poll_events[i]);
+ *p++ = poll_events[i];
*p++ = "--filter";
*p++ = filter;
}
@@ -1827,7 +1892,11 @@ static int timechart__io_record(int argc, const char **argv, const char *output_
for (i = 0; i < (unsigned int)argc; i++)
*p++ = argv[i];
- return cmd_record(rec_argc, rec_argv);
+ ret = cmd_record(rec_argc, rec_argv);
+
+ free(rec_argv);
+ free(filter);
+ return ret;
}
@@ -1838,6 +1907,7 @@ static int timechart__record(struct timechart *tchart, int argc, const char **ar
const char **rec_argv;
const char **p;
unsigned int record_elems;
+ int ret;
const char * const common_args[] = {
"record", "-a", "-R", "-c", "1", "-o", output_data,
@@ -1902,24 +1972,27 @@ static int timechart__record(struct timechart *tchart, int argc, const char **ar
p = rec_argv;
for (i = 0; i < common_args_nr; i++)
- *p++ = strdup(common_args[i]);
+ *p++ = common_args[i];
for (i = 0; i < backtrace_args_no; i++)
- *p++ = strdup(backtrace_args[i]);
+ *p++ = backtrace_args[i];
for (i = 0; i < tasks_args_nr; i++)
- *p++ = strdup(tasks_args[i]);
+ *p++ = tasks_args[i];
for (i = 0; i < power_args_nr; i++)
- *p++ = strdup(power_args[i]);
+ *p++ = power_args[i];
for (i = 0; i < old_power_args_nr; i++)
- *p++ = strdup(old_power_args[i]);
+ *p++ = old_power_args[i];
for (j = 0; j < (unsigned int)argc; j++)
*p++ = argv[j];
- return cmd_record(rec_argc, rec_argv);
+ ret = cmd_record(rec_argc, rec_argv);
+
+ free(rec_argv);
+ return ret;
}
static int
@@ -2082,6 +2155,7 @@ int cmd_timechart(int argc, const char **argv)
ret = __cmd_timechart(&tchart, output_name);
out:
+ timechart__release(&tchart);
zfree(&cpus_cstate_start_times);
zfree(&cpus_cstate_state);
zfree(&cpus_pstate_start_times);