-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
perf ftrace: Introduce new 'ftrace' tool
The 'perf ftrace' command is a simple wrapper of kernel's ftrace functionality. It only supports single thread tracing currently and just reads trace_pipe in text and then write it to stdout. Committer notes: Testing it: # perf ftrace -f function_graph usleep 123456 <SNIP> 2) | SyS_nanosleep() { 2) | _copy_from_user() { <SNIP> 2) 0.900 us | } 2) 1.354 us | } 2) | hrtimer_nanosleep() { 2) 0.062 us | __hrtimer_init(); 2) | do_nanosleep() { 2) | hrtimer_start_range_ns() { <SNIP> 2) 5.025 us | } 2) | schedule() { 2) 0.125 us | rcu_note_context_switch(); 2) 0.057 us | _raw_spin_lock(); 2) | deactivate_task() { 2) 0.369 us | update_rq_clock.part.77(); 2) | dequeue_task_fair() { <SNIP> 2) + 22.453 us | } 2) + 23.736 us | } 2) | pick_next_task_fair() { <SNIP> 2) + 47.167 us | } 2) | pick_next_task_idle() { <SNIP> 2) 4.462 us | } ------------------------------------------ 2) usleep-20387 => <idle>-0 ------------------------------------------ 2) 0.806 us | switch_mm_irqs_off(); ------------------------------------------ 2) <idle>-0 => usleep-20387 ------------------------------------------ 2) 0.151 us | finish_task_switch(); 2) @ 123597.2 us | } 2) 0.037 us | _cond_resched(); 2) | hrtimer_try_to_cancel() { 2) 0.064 us | hrtimer_active(); 2) 0.353 us | } 2) @ 123605.3 us | } 2) @ 123606.2 us | } 2) @ 123608.3 us | } /* SyS_nanosleep */ 2) | __do_page_fault() { <SNIP> Signed-off-by: Namhyung Kim <namhyung@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Tested-by: Masami Hiramatsu <mhiramat@kernel.org> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jeremy Eder <jeder@redhat.com> Cc: Jiri Olsa <jolsa@redhat.com>, Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Stephane Eranian <eranian@google.com> Cc: Steven Rostedt <rostedt@goodmis.org> Link: http://lkml.kernel.org/n/tip-r1hgmsj4dxny8arn3o9mw512@git.kernel.org [ Various foward port fixes, add man page ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
- Loading branch information
Namhyung Kim
authored and
Arnaldo Carvalho de Melo
committed
Jan 26, 2017
1 parent
a7619ae
commit d01f4e8
Showing
6 changed files
with
282 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
perf-ftrace(1) | ||
============= | ||
|
||
NAME | ||
---- | ||
perf-ftrace - simple wrapper for kernel's ftrace functionality | ||
|
||
|
||
SYNOPSIS | ||
-------- | ||
[verse] | ||
'perf ftrace' <command> | ||
|
||
DESCRIPTION | ||
----------- | ||
The 'perf ftrace' command is a simple wrapper of kernel's ftrace | ||
functionality. It only supports single thread tracing currently and | ||
just reads trace_pipe in text and then write it to stdout. | ||
|
||
The following options apply to perf ftrace. | ||
|
||
OPTIONS | ||
------- | ||
|
||
-t:: | ||
--tracer=:: | ||
Tracer to use: function_graph or function. | ||
|
||
-v:: | ||
--verbose=:: | ||
Verbosity level. | ||
|
||
|
||
SEE ALSO | ||
-------- | ||
linkperf:perf-record[1], linkperf:perf-trace[1] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
/* | ||
* builtin-ftrace.c | ||
* | ||
* Copyright (c) 2013 LG Electronics, Namhyung Kim <namhyung@kernel.org> | ||
* | ||
* Released under the GPL v2. | ||
*/ | ||
|
||
#include "builtin.h" | ||
#include "perf.h" | ||
|
||
#include <unistd.h> | ||
#include <signal.h> | ||
|
||
#include "debug.h" | ||
#include <subcmd/parse-options.h> | ||
#include "evlist.h" | ||
#include "target.h" | ||
#include "thread_map.h" | ||
|
||
|
||
#define DEFAULT_TRACER "function_graph" | ||
|
||
struct perf_ftrace { | ||
struct perf_evlist *evlist; | ||
struct target target; | ||
const char *tracer; | ||
}; | ||
|
||
static bool done; | ||
|
||
static void sig_handler(int sig __maybe_unused) | ||
{ | ||
done = true; | ||
} | ||
|
||
/* | ||
* perf_evlist__prepare_workload will send a SIGUSR1 if the fork fails, since | ||
* we asked by setting its exec_error to the function below, | ||
* ftrace__workload_exec_failed_signal. | ||
* | ||
* XXX We need to handle this more appropriately, emitting an error, etc. | ||
*/ | ||
static void ftrace__workload_exec_failed_signal(int signo __maybe_unused, | ||
siginfo_t *info __maybe_unused, | ||
void *ucontext __maybe_unused) | ||
{ | ||
/* workload_exec_errno = info->si_value.sival_int; */ | ||
done = true; | ||
} | ||
|
||
static int write_tracing_file(const char *name, const char *val) | ||
{ | ||
char *file; | ||
int fd, ret = -1; | ||
ssize_t size = strlen(val); | ||
|
||
file = get_tracing_file(name); | ||
if (!file) { | ||
pr_debug("cannot get tracing file: %s\n", name); | ||
return -1; | ||
} | ||
|
||
fd = open(file, O_WRONLY); | ||
if (fd < 0) { | ||
pr_debug("cannot open tracing file: %s\n", name); | ||
goto out; | ||
} | ||
|
||
if (write(fd, val, size) == size) | ||
ret = 0; | ||
else | ||
pr_debug("write '%s' to tracing/%s failed\n", val, name); | ||
|
||
close(fd); | ||
out: | ||
put_tracing_file(file); | ||
return ret; | ||
} | ||
|
||
static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) | ||
{ | ||
if (write_tracing_file("tracing_on", "0") < 0) | ||
return -1; | ||
|
||
if (write_tracing_file("current_tracer", "nop") < 0) | ||
return -1; | ||
|
||
if (write_tracing_file("set_ftrace_pid", " ") < 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, | ||
}; | ||
|
||
if (geteuid() != 0) { | ||
pr_err("ftrace only works for root!\n"); | ||
return -1; | ||
} | ||
|
||
if (argc < 1) | ||
return -1; | ||
|
||
signal(SIGINT, sig_handler); | ||
signal(SIGUSR1, sig_handler); | ||
signal(SIGCHLD, sig_handler); | ||
|
||
reset_tracing_files(ftrace); | ||
|
||
/* 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) | ||
goto out; | ||
|
||
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; | ||
} | ||
|
||
trace_file = get_tracing_file("trace_pipe"); | ||
if (!trace_file) { | ||
pr_err("failed to open trace_pipe\n"); | ||
goto out_free_pid; | ||
} | ||
|
||
trace_fd = open(trace_file, O_RDONLY); | ||
|
||
put_tracing_file(trace_file); | ||
|
||
if (trace_fd < 0) { | ||
pr_err("failed to open trace_pipe\n"); | ||
goto out_free_pid; | ||
} | ||
|
||
fcntl(trace_fd, F_SETFL, O_NONBLOCK); | ||
pollfd.fd = trace_fd; | ||
|
||
if (write_tracing_file("tracing_on", "1") < 0) { | ||
pr_err("can't enable tracing\n"); | ||
goto out_close_fd; | ||
} | ||
|
||
perf_evlist__start_workload(ftrace->evlist); | ||
|
||
while (!done) { | ||
if (poll(&pollfd, 1, -1) < 0) | ||
break; | ||
|
||
if (pollfd.revents & POLLIN) { | ||
int n = read(trace_fd, buf, sizeof(buf)); | ||
if (n < 0) | ||
break; | ||
if (fwrite(buf, n, 1, stdout) != 1) | ||
break; | ||
} | ||
} | ||
|
||
write_tracing_file("tracing_on", "0"); | ||
|
||
/* read remaining buffer contents */ | ||
while (true) { | ||
int n = read(trace_fd, buf, sizeof(buf)); | ||
if (n <= 0) | ||
break; | ||
if (fwrite(buf, n, 1, stdout) != 1) | ||
break; | ||
} | ||
|
||
out_close_fd: | ||
close(trace_fd); | ||
out_free_pid: | ||
free(trace_pid); | ||
out: | ||
reset_tracing_files(ftrace); | ||
|
||
return done ? 0 : -1; | ||
} | ||
|
||
int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused) | ||
{ | ||
int ret; | ||
struct perf_ftrace ftrace = { | ||
.target = { .uid = UINT_MAX, }, | ||
}; | ||
const char * const ftrace_usage[] = { | ||
"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 or function"), | ||
OPT_INCR('v', "verbose", &verbose, | ||
"be more verbose"), | ||
OPT_END() | ||
}; | ||
|
||
argc = parse_options(argc, argv, ftrace_options, ftrace_usage, | ||
PARSE_OPT_STOP_AT_NON_OPTION); | ||
if (!argc) | ||
usage_with_options(ftrace_usage, ftrace_options); | ||
|
||
ftrace.evlist = perf_evlist__new(); | ||
if (ftrace.evlist == NULL) | ||
return -ENOMEM; | ||
|
||
ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target); | ||
if (ret < 0) | ||
goto out_delete_evlist; | ||
|
||
if (ftrace.tracer == NULL) | ||
ftrace.tracer = DEFAULT_TRACER; | ||
|
||
ret = __cmd_ftrace(&ftrace, argc, argv); | ||
|
||
out_delete_evlist: | ||
perf_evlist__delete(ftrace.evlist); | ||
|
||
return ret; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters