Commit a9af6be5 authored by Namhyung Kim's avatar Namhyung Kim Committed by Arnaldo Carvalho de Melo

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: default avatarNamhyung Kim <namhyung@kernel.org>
Tested-by: default avatarArnaldo 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.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 7768f8da
...@@ -30,6 +30,10 @@ OPTIONS ...@@ -30,6 +30,10 @@ OPTIONS
--verbose=:: --verbose=::
Verbosity level. Verbosity level.
-p::
--pid=::
Trace on existing process id (comma separated list).
SEE ALSO SEE ALSO
-------- --------
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <fcntl.h>
#include "debug.h" #include "debug.h"
#include <subcmd/parse-options.h> #include <subcmd/parse-options.h>
...@@ -50,11 +51,12 @@ static void ftrace__workload_exec_failed_signal(int signo __maybe_unused, ...@@ -50,11 +51,12 @@ static void ftrace__workload_exec_failed_signal(int signo __maybe_unused,
done = true; 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; char *file;
int fd, ret = -1; int fd, ret = -1;
ssize_t size = strlen(val); ssize_t size = strlen(val);
int flags = O_WRONLY;
file = get_tracing_file(name); file = get_tracing_file(name);
if (!file) { if (!file) {
...@@ -62,7 +64,12 @@ static int write_tracing_file(const char *name, const char *val) ...@@ -62,7 +64,12 @@ static int write_tracing_file(const char *name, const char *val)
return -1; return -1;
} }
fd = open(file, O_WRONLY); if (append)
flags |= O_APPEND;
else
flags |= O_TRUNC;
fd = open(file, flags);
if (fd < 0) { if (fd < 0) {
pr_debug("cannot open tracing file: %s\n", name); pr_debug("cannot open tracing file: %s\n", name);
goto out; goto out;
...@@ -79,6 +86,16 @@ static int write_tracing_file(const char *name, const char *val) ...@@ -79,6 +86,16 @@ static int write_tracing_file(const char *name, const char *val)
return ret; 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) static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
{ {
if (write_tracing_file("tracing_on", "0") < 0) if (write_tracing_file("tracing_on", "0") < 0)
...@@ -93,11 +110,27 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) ...@@ -93,11 +110,27 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
return 0; 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) static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
{ {
char *trace_file; char *trace_file;
int trace_fd; int trace_fd;
char *trace_pid;
char buf[4096]; char buf[4096];
struct pollfd pollfd = { struct pollfd pollfd = {
.events = POLLIN, .events = POLLIN,
...@@ -108,42 +141,37 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) ...@@ -108,42 +141,37 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
return -1; return -1;
} }
if (argc < 1)
return -1;
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
signal(SIGUSR1, sig_handler); signal(SIGUSR1, sig_handler);
signal(SIGCHLD, sig_handler); signal(SIGCHLD, sig_handler);
reset_tracing_files(ftrace); if (reset_tracing_files(ftrace) < 0)
goto out;
/* reset ftrace buffer */ /* reset ftrace buffer */
if (write_tracing_file("trace", "0") < 0) if (write_tracing_file("trace", "0") < 0)
goto out; goto out;
if (perf_evlist__prepare_workload(ftrace->evlist, &ftrace->target, if (argc && perf_evlist__prepare_workload(ftrace->evlist,
argv, false, ftrace__workload_exec_failed_signal) < 0) &ftrace->target, argv, false,
goto out; ftrace__workload_exec_failed_signal) < 0) {
if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
goto out; goto out;
} }
if (asprintf(&trace_pid, "%d", thread_map__pid(ftrace->evlist->threads, 0)) < 0) { if (set_tracing_pid(ftrace) < 0) {
pr_err("failed to allocate pid string\n"); pr_err("failed to set ftrace pid\n");
goto out; goto out_reset;
} }
if (write_tracing_file("set_ftrace_pid", trace_pid) < 0) { if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
pr_err("failed to set pid: %s\n", trace_pid); pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
goto out_free_pid; goto out_reset;
} }
trace_file = get_tracing_file("trace_pipe"); trace_file = get_tracing_file("trace_pipe");
if (!trace_file) { if (!trace_file) {
pr_err("failed to open trace_pipe\n"); pr_err("failed to open trace_pipe\n");
goto out_free_pid; goto out_reset;
} }
trace_fd = open(trace_file, O_RDONLY); trace_fd = open(trace_file, O_RDONLY);
...@@ -152,7 +180,7 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) ...@@ -152,7 +180,7 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
if (trace_fd < 0) { if (trace_fd < 0) {
pr_err("failed to open trace_pipe\n"); pr_err("failed to open trace_pipe\n");
goto out_free_pid; goto out_reset;
} }
fcntl(trace_fd, F_SETFL, O_NONBLOCK); fcntl(trace_fd, F_SETFL, O_NONBLOCK);
...@@ -191,11 +219,9 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) ...@@ -191,11 +219,9 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
out_close_fd: out_close_fd:
close(trace_fd); close(trace_fd);
out_free_pid: out_reset:
free(trace_pid);
out:
reset_tracing_files(ftrace); reset_tracing_files(ftrace);
out:
return done ? 0 : -1; return done ? 0 : -1;
} }
...@@ -227,13 +253,15 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -227,13 +253,15 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
.target = { .uid = UINT_MAX, }, .target = { .uid = UINT_MAX, },
}; };
const char * const ftrace_usage[] = { const char * const ftrace_usage[] = {
"perf ftrace [<options>] <command>", "perf ftrace [<options>] [<command>]",
"perf ftrace [<options>] -- <command> [<options>]", "perf ftrace [<options>] -- <command> [<options>]",
NULL NULL
}; };
const struct option ftrace_options[] = { const struct option ftrace_options[] = {
OPT_STRING('t', "tracer", &ftrace.tracer, "tracer", OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
"tracer to use: function_graph(default) or function"), "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, OPT_INCR('v', "verbose", &verbose,
"be more verbose"), "be more verbose"),
OPT_END() OPT_END()
...@@ -245,9 +273,18 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -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, argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
PARSE_OPT_STOP_AT_NON_OPTION); PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc) if (!argc && target__none(&ftrace.target))
usage_with_options(ftrace_usage, ftrace_options); 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(); ftrace.evlist = perf_evlist__new();
if (ftrace.evlist == NULL) if (ftrace.evlist == NULL)
return -ENOMEM; return -ENOMEM;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment