Blame view
tools/perf/builtin-ftrace.c
7.57 KB
d01f4e8db perf ftrace: Intr... |
1 2 3 4 5 6 7 8 9 10 |
/* * builtin-ftrace.c * * Copyright (c) 2013 LG Electronics, Namhyung Kim <namhyung@kernel.org> * * Released under the GPL v2. */ #include "builtin.h" #include "perf.h" |
a43783aee perf tools: Inclu... |
11 |
#include <errno.h> |
d01f4e8db perf ftrace: Intr... |
12 13 |
#include <unistd.h> #include <signal.h> |
a9af6be5b perf ftrace: Add ... |
14 |
#include <fcntl.h> |
4208735d8 perf tools: Remov... |
15 |
#include <poll.h> |
d01f4e8db perf ftrace: Intr... |
16 17 18 |
#include "debug.h" #include <subcmd/parse-options.h> |
20a9ed280 perf tools: Use a... |
19 |
#include <api/fs/tracing_path.h> |
d01f4e8db perf ftrace: Intr... |
20 21 |
#include "evlist.h" #include "target.h" |
dc2310327 perf ftrace: Add ... |
22 |
#include "cpumap.h" |
d01f4e8db perf ftrace: Intr... |
23 |
#include "thread_map.h" |
b05d10939 perf ftrace: Add ... |
24 |
#include "util/config.h" |
d01f4e8db perf ftrace: Intr... |
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#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; } |
a9af6be5b perf ftrace: Add ... |
56 |
static int __write_tracing_file(const char *name, const char *val, bool append) |
d01f4e8db perf ftrace: Intr... |
57 58 59 60 |
{ char *file; int fd, ret = -1; ssize_t size = strlen(val); |
a9af6be5b perf ftrace: Add ... |
61 |
int flags = O_WRONLY; |
d01f4e8db perf ftrace: Intr... |
62 63 64 65 66 67 68 |
file = get_tracing_file(name); if (!file) { pr_debug("cannot get tracing file: %s ", name); return -1; } |
a9af6be5b perf ftrace: Add ... |
69 70 71 72 73 74 |
if (append) flags |= O_APPEND; else flags |= O_TRUNC; fd = open(file, flags); |
d01f4e8db perf ftrace: Intr... |
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
if (fd < 0) { pr_debug("cannot open tracing file: %s ", name); goto out; } if (write(fd, val, size) == size) ret = 0; else pr_debug("write '%s' to tracing/%s failed ", val, name); close(fd); out: put_tracing_file(file); return ret; } |
a9af6be5b perf ftrace: Add ... |
92 93 94 95 96 97 98 99 100 |
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); } |
dc2310327 perf ftrace: Add ... |
101 |
static int reset_tracing_cpu(void); |
d01f4e8db perf ftrace: Intr... |
102 103 104 105 106 107 108 109 110 111 |
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; |
dc2310327 perf ftrace: Add ... |
112 113 |
if (reset_tracing_cpu() < 0) return -1; |
d01f4e8db perf ftrace: Intr... |
114 115 |
return 0; } |
a9af6be5b perf ftrace: Add ... |
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
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; } |
dc2310327 perf ftrace: Add ... |
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
static int set_tracing_cpumask(struct cpu_map *cpumap) { char *cpumask; size_t mask_size; int ret; int last_cpu; last_cpu = cpu_map__cpu(cpumap, cpumap->nr - 1); mask_size = (last_cpu + 3) / 4 + 1; mask_size += last_cpu / 32; /* ',' is needed for every 32th cpus */ cpumask = malloc(mask_size); if (cpumask == NULL) { pr_debug("failed to allocate cpu mask "); return -1; } cpu_map__snprint_mask(cpumap, cpumask, mask_size); ret = write_tracing_file("tracing_cpumask", cpumask); free(cpumask); return ret; } static int set_tracing_cpu(struct perf_ftrace *ftrace) { struct cpu_map *cpumap = ftrace->evlist->cpus; if (!target__has_cpu(&ftrace->target)) return 0; return set_tracing_cpumask(cpumap); } static int reset_tracing_cpu(void) { struct cpu_map *cpumap = cpu_map__new(NULL); int ret; ret = set_tracing_cpumask(cpumap); cpu_map__put(cpumap); return ret; } |
d01f4e8db perf ftrace: Intr... |
177 178 179 180 |
static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) { char *trace_file; int trace_fd; |
d01f4e8db perf ftrace: Intr... |
181 182 183 184 185 186 187 188 189 190 |
char buf[4096]; struct pollfd pollfd = { .events = POLLIN, }; if (geteuid() != 0) { pr_err("ftrace only works for root! "); return -1; } |
d01f4e8db perf ftrace: Intr... |
191 192 193 |
signal(SIGINT, sig_handler); signal(SIGUSR1, sig_handler); signal(SIGCHLD, sig_handler); |
583359646 perf ftrace: Use ... |
194 |
signal(SIGPIPE, sig_handler); |
d01f4e8db perf ftrace: Intr... |
195 |
|
a9af6be5b perf ftrace: Add ... |
196 197 |
if (reset_tracing_files(ftrace) < 0) goto out; |
d01f4e8db perf ftrace: Intr... |
198 199 200 201 |
/* reset ftrace buffer */ if (write_tracing_file("trace", "0") < 0) goto out; |
a9af6be5b perf ftrace: Add ... |
202 203 204 |
if (argc && perf_evlist__prepare_workload(ftrace->evlist, &ftrace->target, argv, false, ftrace__workload_exec_failed_signal) < 0) { |
d01f4e8db perf ftrace: Intr... |
205 206 |
goto out; } |
a9af6be5b perf ftrace: Add ... |
207 208 209 210 |
if (set_tracing_pid(ftrace) < 0) { pr_err("failed to set ftrace pid "); goto out_reset; |
d01f4e8db perf ftrace: Intr... |
211 |
} |
dc2310327 perf ftrace: Add ... |
212 213 214 215 216 |
if (set_tracing_cpu(ftrace) < 0) { pr_err("failed to set tracing cpumask "); goto out_reset; } |
a9af6be5b perf ftrace: Add ... |
217 218 219 220 |
if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { pr_err("failed to set current_tracer to %s ", ftrace->tracer); goto out_reset; |
d01f4e8db perf ftrace: Intr... |
221 222 223 224 225 226 |
} trace_file = get_tracing_file("trace_pipe"); if (!trace_file) { pr_err("failed to open trace_pipe "); |
a9af6be5b perf ftrace: Add ... |
227 |
goto out_reset; |
d01f4e8db perf ftrace: Intr... |
228 229 230 231 232 233 234 235 236 |
} trace_fd = open(trace_file, O_RDONLY); put_tracing_file(trace_file); if (trace_fd < 0) { pr_err("failed to open trace_pipe "); |
a9af6be5b perf ftrace: Add ... |
237 |
goto out_reset; |
d01f4e8db perf ftrace: Intr... |
238 239 240 241 242 243 244 245 246 247 |
} 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 "); goto out_close_fd; } |
583359646 perf ftrace: Use ... |
248 |
setup_pager(); |
d01f4e8db perf ftrace: Intr... |
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
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); |
a9af6be5b perf ftrace: Add ... |
277 |
out_reset: |
d01f4e8db perf ftrace: Intr... |
278 |
reset_tracing_files(ftrace); |
a9af6be5b perf ftrace: Add ... |
279 |
out: |
d01f4e8db perf ftrace: Intr... |
280 281 |
return done ? 0 : -1; } |
b05d10939 perf ftrace: Add ... |
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
static int perf_ftrace_config(const char *var, const char *value, void *cb) { struct perf_ftrace *ftrace = cb; if (prefixcmp(var, "ftrace.")) return 0; if (strcmp(var, "ftrace.tracer")) return -1; if (!strcmp(value, "function_graph") || !strcmp(value, "function")) { ftrace->tracer = value; return 0; } pr_err("Please select \"function_graph\" (default) or \"function\" "); return -1; } |
b0ad8ea66 perf tools: Remov... |
302 |
int cmd_ftrace(int argc, const char **argv) |
d01f4e8db perf ftrace: Intr... |
303 304 305 |
{ int ret; struct perf_ftrace ftrace = { |
bf062bd20 perf ftrace: Remo... |
306 |
.tracer = DEFAULT_TRACER, |
d01f4e8db perf ftrace: Intr... |
307 308 309 |
.target = { .uid = UINT_MAX, }, }; const char * const ftrace_usage[] = { |
a9af6be5b perf ftrace: Add ... |
310 |
"perf ftrace [<options>] [<command>]", |
d01f4e8db perf ftrace: Intr... |
311 312 313 314 315 |
"perf ftrace [<options>] -- <command> [<options>]", NULL }; const struct option ftrace_options[] = { OPT_STRING('t', "tracer", &ftrace.tracer, "tracer", |
ec347870a perf ftrace: Make... |
316 |
"tracer to use: function_graph(default) or function"), |
a9af6be5b perf ftrace: Add ... |
317 318 |
OPT_STRING('p', "pid", &ftrace.target.pid, "pid", "trace on existing process id"), |
d01f4e8db perf ftrace: Intr... |
319 320 |
OPT_INCR('v', "verbose", &verbose, "be more verbose"), |
dc2310327 perf ftrace: Add ... |
321 322 323 324 |
OPT_BOOLEAN('a', "all-cpus", &ftrace.target.system_wide, "system-wide collection from all CPUs"), OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu", "list of cpus to monitor"), |
d01f4e8db perf ftrace: Intr... |
325 326 |
OPT_END() }; |
b05d10939 perf ftrace: Add ... |
327 328 329 |
ret = perf_config(perf_ftrace_config, &ftrace); if (ret < 0) return -1; |
d01f4e8db perf ftrace: Intr... |
330 331 |
argc = parse_options(argc, argv, ftrace_options, ftrace_usage, PARSE_OPT_STOP_AT_NON_OPTION); |
a9af6be5b perf ftrace: Add ... |
332 |
if (!argc && target__none(&ftrace.target)) |
d01f4e8db perf ftrace: Intr... |
333 |
usage_with_options(ftrace_usage, ftrace_options); |
a9af6be5b perf ftrace: Add ... |
334 335 336 337 338 339 340 341 342 |
ret = target__validate(&ftrace.target); if (ret) { char errbuf[512]; target__strerror(&ftrace.target, ret, errbuf, 512); pr_err("%s ", errbuf); return -EINVAL; } |
d01f4e8db perf ftrace: Intr... |
343 344 345 346 347 348 349 |
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; |
d01f4e8db perf ftrace: Intr... |
350 351 352 353 354 355 356 |
ret = __cmd_ftrace(&ftrace, argc, argv); out_delete_evlist: perf_evlist__delete(ftrace.evlist); return ret; } |