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:
parent
7768f8dada
commit
a9af6be5bc
|
@ -30,6 +30,10 @@ OPTIONS
|
|||
--verbose=::
|
||||
Verbosity level.
|
||||
|
||||
-p::
|
||||
--pid=::
|
||||
Trace on existing process id (comma separated list).
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue