diff options
Diffstat (limited to 'tools/perf/builtin-timechart.c')
-rw-r--r-- | tools/perf/builtin-timechart.c | 134 |
1 files changed, 86 insertions, 48 deletions
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 4e380e7b5230..19d4542ea18a 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -24,7 +24,6 @@ #include "util/thread.h" #include "util/callchain.h" -#include "perf.h" #include "util/header.h" #include <subcmd/pager.h> #include <subcmd/parse-options.h> @@ -35,7 +34,11 @@ #include "util/tool.h" #include "util/data.h" #include "util/debug.h" +#include "util/string2.h" +#include "util/tracepoint.h" +#include "util/util.h" #include <linux/err.h> +#include <traceevent/event-parse.h> #ifdef LACKS_OPEN_MEMSTREAM_PROTOTYPE FILE *open_memstream(char **ptr, size_t *sizeloc); @@ -213,6 +216,19 @@ static struct per_pid *find_create_pid(struct timechart *tchart, int pid) return cursor; } +static struct per_pidcomm *create_pidcomm(struct per_pid *p) +{ + struct per_pidcomm *c; + + c = zalloc(sizeof(*c)); + if (!c) + return NULL; + p->current = c; + c->next = p->all; + p->all = c; + return c; +} + static void pid_set_comm(struct timechart *tchart, int pid, char *comm) { struct per_pid *p; @@ -231,12 +247,9 @@ static void pid_set_comm(struct timechart *tchart, int pid, char *comm) } c = c->next; } - c = zalloc(sizeof(*c)); + c = create_pidcomm(p); assert(c != NULL); c->comm = strdup(comm); - p->current = c; - c->next = p->all; - p->all = c; } static void pid_fork(struct timechart *tchart, int pid, int ppid, u64 timestamp) @@ -275,11 +288,8 @@ static void pid_put_sample(struct timechart *tchart, int pid, int type, p = find_create_pid(tchart, pid); c = p->current; if (!c) { - c = zalloc(sizeof(*c)); + c = create_pidcomm(p); assert(c != NULL); - p->current = c; - c->next = p->all; - p->all = c; } sample = zalloc(sizeof(*sample)); @@ -305,10 +315,10 @@ static void pid_put_sample(struct timechart *tchart, int pid, int type, #define MAX_CPUS 4096 -static u64 cpus_cstate_start_times[MAX_CPUS]; -static int cpus_cstate_state[MAX_CPUS]; -static u64 cpus_pstate_start_times[MAX_CPUS]; -static u64 cpus_pstate_state[MAX_CPUS]; +static u64 *cpus_cstate_start_times; +static int *cpus_cstate_state; +static u64 *cpus_pstate_start_times; +static u64 *cpus_pstate_state; static int process_comm_event(struct perf_tool *tool, union perf_event *event, @@ -367,16 +377,13 @@ static void c_state_end(struct timechart *tchart, int cpu, u64 timestamp) tchart->power_events = pwr; } -static void p_state_change(struct timechart *tchart, int cpu, u64 timestamp, u64 new_freq) +static struct power_event *p_state_end(struct timechart *tchart, int cpu, + u64 timestamp) { - struct power_event *pwr; - - if (new_freq > 8000000) /* detect invalid data */ - return; + struct power_event *pwr = zalloc(sizeof(*pwr)); - pwr = zalloc(sizeof(*pwr)); if (!pwr) - return; + return NULL; pwr->state = cpus_pstate_state[cpu]; pwr->start_time = cpus_pstate_start_times[cpu]; @@ -384,11 +391,23 @@ static void p_state_change(struct timechart *tchart, int cpu, u64 timestamp, u64 pwr->cpu = cpu; pwr->type = PSTATE; pwr->next = tchart->power_events; - if (!pwr->start_time) pwr->start_time = tchart->first_time; tchart->power_events = pwr; + return pwr; +} + +static void p_state_change(struct timechart *tchart, int cpu, u64 timestamp, u64 new_freq) +{ + struct power_event *pwr; + + if (new_freq > 8000000) /* detect invalid data */ + return; + + pwr = p_state_end(tchart, cpu, timestamp); + if (!pwr) + return; cpus_pstate_state[cpu] = new_freq; cpus_pstate_start_times[cpu] = timestamp; @@ -479,7 +498,6 @@ static const char *cat_backtrace(union perf_event *event, char *p = NULL; size_t p_len; u8 cpumode = PERF_RECORD_MISC_USER; - struct addr_location tal; struct ip_callchain *chain = sample->callchain; FILE *f = open_memstream(&p, &p_len); @@ -488,6 +506,7 @@ static const char *cat_backtrace(union perf_event *event, return NULL; } + addr_location__init(&al); if (!chain) goto exit; @@ -499,6 +518,7 @@ static const char *cat_backtrace(union perf_event *event, for (i = 0; i < chain->nr; i++) { u64 ip; + struct addr_location tal; if (callchain_param.order == ORDER_CALLEE) ip = chain->ips[i]; @@ -525,20 +545,22 @@ static const char *cat_backtrace(union perf_event *event, * Discard all. */ zfree(&p); - goto exit_put; + goto exit; } continue; } + addr_location__init(&tal); tal.filtered = 0; if (thread__find_symbol(al.thread, cpumode, ip, &tal)) fprintf(f, "..... %016" PRIx64 " %s\n", ip, tal.sym->name); else fprintf(f, "..... %016" PRIx64 "\n", ip); + + addr_location__exit(&tal); } -exit_put: - addr_location__put(&al); exit: + addr_location__exit(&al); fclose(f); return p; @@ -696,22 +718,12 @@ static void end_sample_processing(struct timechart *tchart) #endif /* P state */ - pwr = zalloc(sizeof(*pwr)); + pwr = p_state_end(tchart, cpu, tchart->last_time); if (!pwr) return; - pwr->state = cpus_pstate_state[cpu]; - pwr->start_time = cpus_pstate_start_times[cpu]; - pwr->end_time = tchart->last_time; - pwr->cpu = cpu; - pwr->type = PSTATE; - pwr->next = tchart->power_events; - - if (!pwr->start_time) - pwr->start_time = tchart->first_time; if (!pwr->state) pwr->state = tchart->min_freq; - tchart->power_events = pwr; } } @@ -724,12 +736,9 @@ static int pid_begin_io_sample(struct timechart *tchart, int pid, int type, struct io_sample *prev; if (!c) { - c = zalloc(sizeof(*c)); + c = create_pidcomm(p); if (!c) return -ENOMEM; - p->current = c; - c->next = p->all; - p->all = c; } prev = c->io_samples; @@ -1598,8 +1607,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) .force = tchart->force, }; - struct perf_session *session = perf_session__new(&data, false, - &tchart->tool); + struct perf_session *session = perf_session__new(&data, &tchart->tool); int ret = -EINVAL; if (IS_ERR(session)) @@ -1976,32 +1984,62 @@ int cmd_timechart(int argc, const char **argv) "perf timechart record [<options>]", NULL }; + int ret; + + cpus_cstate_start_times = calloc(MAX_CPUS, sizeof(*cpus_cstate_start_times)); + if (!cpus_cstate_start_times) + return -ENOMEM; + cpus_cstate_state = calloc(MAX_CPUS, sizeof(*cpus_cstate_state)); + if (!cpus_cstate_state) { + ret = -ENOMEM; + goto out; + } + cpus_pstate_start_times = calloc(MAX_CPUS, sizeof(*cpus_pstate_start_times)); + if (!cpus_pstate_start_times) { + ret = -ENOMEM; + goto out; + } + cpus_pstate_state = calloc(MAX_CPUS, sizeof(*cpus_pstate_state)); + if (!cpus_pstate_state) { + ret = -ENOMEM; + goto out; + } + argc = parse_options_subcommand(argc, argv, timechart_options, timechart_subcommands, timechart_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (tchart.power_only && tchart.tasks_only) { pr_err("-P and -T options cannot be used at the same time.\n"); - return -1; + ret = -1; + goto out; } - if (argc && !strncmp(argv[0], "rec", 3)) { + if (argc && strlen(argv[0]) > 2 && strstarts("record", argv[0])) { argc = parse_options(argc, argv, timechart_record_options, timechart_record_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (tchart.power_only && tchart.tasks_only) { pr_err("-P and -T options cannot be used at the same time.\n"); - return -1; + ret = -1; + goto out; } if (tchart.io_only) - return timechart__io_record(argc, argv); + ret = timechart__io_record(argc, argv); else - return timechart__record(&tchart, argc, argv); + ret = timechart__record(&tchart, argc, argv); + goto out; } else if (argc) usage_with_options(timechart_usage, timechart_options); setup_pager(); - return __cmd_timechart(&tchart, output_name); + ret = __cmd_timechart(&tchart, output_name); +out: + zfree(&cpus_cstate_start_times); + zfree(&cpus_cstate_state); + zfree(&cpus_pstate_start_times); + zfree(&cpus_pstate_state); + return ret; } |