perf ftrace: Add support for --pid option

The -p (--pid) option enables to trace existing process by its pid.

Committer notes:

Testing it:

Using the function_graph tracer on a process that is just waiting for user
input and thus will make 'perf ftrace' sit there waiting for that, then press
any key on that mutt session and see what happens:

  # perf ftrace -t function_graph -p `pidof mutt` | head -40
  2)   1.038 us    |  switch_mm_irqs_off();
  ------------------------------------------
  2)    <idle>-0    =>   mutt-3595
  ------------------------------------------

  2)               |              finish_task_switch() {
  2)               |                smp_irq_work_interrupt() {
  2)               |                  irq_enter() {
  2)   0.180 us    |                    rcu_irq_enter();
  2)   1.248 us    |                  }
  2)               |                  __wake_up() {
  2)   0.126 us    |                    _raw_spin_lock_irqsave();
  2)               |                    __wake_up_common() {
  2)               |                      pollwake() {
  2)               |                        default_wake_function() {
  2)               |                          try_to_wake_up() {
  2)   0.662 us    |                            _raw_spin_lock_irqsave();
  2)               |                            select_task_rq_fair() {
  2)   1.719 us    |                              effective_load.isra.41();
  2)   1.343 us    |                              effective_load.isra.41();
  2)               |                              select_idle_sibling() {
  2)   0.331 us    |                                idle_cpu();
  2)   1.458 us    |                              }
  2)   8.350 us    |                            }
  2)   0.200 us    |                            _raw_spin_lock();
  2)               |                            ttwu_do_activate() {
  2)               |                              activate_task() {
  2)   0.136 us    |                                update_rq_clock.part.77();
  2)               |                                enqueue_task_fair() {
  2)               |                                  enqueue_entity() {
  2)   0.146 us    |                                    update_curr();
  2)   0.330 us    |                                    account_entity_enqueue();
  2)   0.280 us    |                                    update_cfs_shares();
  2)   0.321 us    |                                    place_entity();
  2)   0.206 us    |                                    __enqueue_entity();
  2)   6.926 us    |                                  }
  2)               |                                  enqueue_entity() {
  2)   0.105 us    |                                    update_curr();
  2)   0.175 us    |                                    account_entity_enqueue();
  2)   0.531 us    |                                    update_cfs_shares();
 #

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: kernel-team@lge.com
Link: http://lkml.kernel.org/r/20170224011251.14946-1-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Namhyung Kim 2017-02-24 10:12:48 +09:00 committed by Arnaldo Carvalho de Melo
parent 7768f8dada
commit a9af6be5bc
2 changed files with 69 additions and 28 deletions

View File

@ -30,6 +30,10 @@ OPTIONS
--verbose=::
Verbosity level.
-p::
--pid=::
Trace on existing process id (comma separated list).
SEE ALSO
--------

View File

@ -11,6 +11,7 @@
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include "debug.h"
#include <subcmd/parse-options.h>
@ -50,11 +51,12 @@ static void ftrace__workload_exec_failed_signal(int signo __maybe_unused,
done = true;
}
static int write_tracing_file(const char *name, const char *val)
static int __write_tracing_file(const char *name, const char *val, bool append)
{
char *file;
int fd, ret = -1;
ssize_t size = strlen(val);
int flags = O_WRONLY;
file = get_tracing_file(name);
if (!file) {
@ -62,7 +64,12 @@ static int write_tracing_file(const char *name, const char *val)
return -1;
}
fd = open(file, O_WRONLY);
if (append)
flags |= O_APPEND;
else
flags |= O_TRUNC;
fd = open(file, flags);
if (fd < 0) {
pr_debug("cannot open tracing file: %s\n", name);
goto out;
@ -79,6 +86,16 @@ out:
return ret;
}
static int write_tracing_file(const char *name, const char *val)
{
return __write_tracing_file(name, val, false);
}
static int append_tracing_file(const char *name, const char *val)
{
return __write_tracing_file(name, val, true);
}
static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
{
if (write_tracing_file("tracing_on", "0") < 0)
@ -93,11 +110,27 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
return 0;
}
static int set_tracing_pid(struct perf_ftrace *ftrace)
{
int i;
char buf[16];
if (target__has_cpu(&ftrace->target))
return 0;
for (i = 0; i < thread_map__nr(ftrace->evlist->threads); i++) {
scnprintf(buf, sizeof(buf), "%d",
ftrace->evlist->threads->map[i]);
if (append_tracing_file("set_ftrace_pid", buf) < 0)
return -1;
}
return 0;
}
static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
{
char *trace_file;
int trace_fd;
char *trace_pid;
char buf[4096];
struct pollfd pollfd = {
.events = POLLIN,
@ -108,42 +141,37 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
return -1;
}
if (argc < 1)
return -1;
signal(SIGINT, sig_handler);
signal(SIGUSR1, sig_handler);
signal(SIGCHLD, sig_handler);
reset_tracing_files(ftrace);
if (reset_tracing_files(ftrace) < 0)
goto out;
/* reset ftrace buffer */
if (write_tracing_file("trace", "0") < 0)
goto out;
if (perf_evlist__prepare_workload(ftrace->evlist, &ftrace->target,
argv, false, ftrace__workload_exec_failed_signal) < 0)
if (argc && perf_evlist__prepare_workload(ftrace->evlist,
&ftrace->target, argv, false,
ftrace__workload_exec_failed_signal) < 0) {
goto out;
}
if (set_tracing_pid(ftrace) < 0) {
pr_err("failed to set ftrace pid\n");
goto out_reset;
}
if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
goto out;
}
if (asprintf(&trace_pid, "%d", thread_map__pid(ftrace->evlist->threads, 0)) < 0) {
pr_err("failed to allocate pid string\n");
goto out;
}
if (write_tracing_file("set_ftrace_pid", trace_pid) < 0) {
pr_err("failed to set pid: %s\n", trace_pid);
goto out_free_pid;
goto out_reset;
}
trace_file = get_tracing_file("trace_pipe");
if (!trace_file) {
pr_err("failed to open trace_pipe\n");
goto out_free_pid;
goto out_reset;
}
trace_fd = open(trace_file, O_RDONLY);
@ -152,7 +180,7 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
if (trace_fd < 0) {
pr_err("failed to open trace_pipe\n");
goto out_free_pid;
goto out_reset;
}
fcntl(trace_fd, F_SETFL, O_NONBLOCK);
@ -191,11 +219,9 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
out_close_fd:
close(trace_fd);
out_free_pid:
free(trace_pid);
out:
out_reset:
reset_tracing_files(ftrace);
out:
return done ? 0 : -1;
}
@ -227,13 +253,15 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
.target = { .uid = UINT_MAX, },
};
const char * const ftrace_usage[] = {
"perf ftrace [<options>] <command>",
"perf ftrace [<options>] [<command>]",
"perf ftrace [<options>] -- <command> [<options>]",
NULL
};
const struct option ftrace_options[] = {
OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
"tracer to use: function_graph(default) or function"),
OPT_STRING('p', "pid", &ftrace.target.pid, "pid",
"trace on existing process id"),
OPT_INCR('v', "verbose", &verbose,
"be more verbose"),
OPT_END()
@ -245,9 +273,18 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc)
if (!argc && target__none(&ftrace.target))
usage_with_options(ftrace_usage, ftrace_options);
ret = target__validate(&ftrace.target);
if (ret) {
char errbuf[512];
target__strerror(&ftrace.target, ret, errbuf, 512);
pr_err("%s\n", errbuf);
return -EINVAL;
}
ftrace.evlist = perf_evlist__new();
if (ftrace.evlist == NULL)
return -ENOMEM;