diff options
Diffstat (limited to 'tools/perf/builtin-timechart.c')
| -rw-r--r-- | tools/perf/builtin-timechart.c | 212 |
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); |
