1 /* 2 * builtin-ftrace.c 3 * 4 * Copyright (c) 2013 LG Electronics, Namhyung Kim <namhyung@kernel.org> 5 * 6 * Released under the GPL v2. 7 */ 8 9 #include "builtin.h" 10 #include "perf.h" 11 12 #include <unistd.h> 13 #include <signal.h> 14 15 #include "debug.h" 16 #include <subcmd/parse-options.h> 17 #include "evlist.h" 18 #include "target.h" 19 #include "thread_map.h" 20 #include "util/config.h" 21 22 23 #define DEFAULT_TRACER "function_graph" 24 25 struct perf_ftrace { 26 struct perf_evlist *evlist; 27 struct target target; 28 const char *tracer; 29 }; 30 31 static bool done; 32 33 static void sig_handler(int sig __maybe_unused) 34 { 35 done = true; 36 } 37 38 /* 39 * perf_evlist__prepare_workload will send a SIGUSR1 if the fork fails, since 40 * we asked by setting its exec_error to the function below, 41 * ftrace__workload_exec_failed_signal. 42 * 43 * XXX We need to handle this more appropriately, emitting an error, etc. 44 */ 45 static void ftrace__workload_exec_failed_signal(int signo __maybe_unused, 46 siginfo_t *info __maybe_unused, 47 void *ucontext __maybe_unused) 48 { 49 /* workload_exec_errno = info->si_value.sival_int; */ 50 done = true; 51 } 52 53 static int write_tracing_file(const char *name, const char *val) 54 { 55 char *file; 56 int fd, ret = -1; 57 ssize_t size = strlen(val); 58 59 file = get_tracing_file(name); 60 if (!file) { 61 pr_debug("cannot get tracing file: %s\n", name); 62 return -1; 63 } 64 65 fd = open(file, O_WRONLY); 66 if (fd < 0) { 67 pr_debug("cannot open tracing file: %s\n", name); 68 goto out; 69 } 70 71 if (write(fd, val, size) == size) 72 ret = 0; 73 else 74 pr_debug("write '%s' to tracing/%s failed\n", val, name); 75 76 close(fd); 77 out: 78 put_tracing_file(file); 79 return ret; 80 } 81 82 static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) 83 { 84 if (write_tracing_file("tracing_on", "0") < 0) 85 return -1; 86 87 if (write_tracing_file("current_tracer", "nop") < 0) 88 return -1; 89 90 if (write_tracing_file("set_ftrace_pid", " ") < 0) 91 return -1; 92 93 return 0; 94 } 95 96 static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) 97 { 98 char *trace_file; 99 int trace_fd; 100 char *trace_pid; 101 char buf[4096]; 102 struct pollfd pollfd = { 103 .events = POLLIN, 104 }; 105 106 if (geteuid() != 0) { 107 pr_err("ftrace only works for root!\n"); 108 return -1; 109 } 110 111 if (argc < 1) 112 return -1; 113 114 signal(SIGINT, sig_handler); 115 signal(SIGUSR1, sig_handler); 116 signal(SIGCHLD, sig_handler); 117 118 reset_tracing_files(ftrace); 119 120 /* reset ftrace buffer */ 121 if (write_tracing_file("trace", "0") < 0) 122 goto out; 123 124 if (perf_evlist__prepare_workload(ftrace->evlist, &ftrace->target, 125 argv, false, ftrace__workload_exec_failed_signal) < 0) 126 goto out; 127 128 if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { 129 pr_err("failed to set current_tracer to %s\n", ftrace->tracer); 130 goto out; 131 } 132 133 if (asprintf(&trace_pid, "%d", thread_map__pid(ftrace->evlist->threads, 0)) < 0) { 134 pr_err("failed to allocate pid string\n"); 135 goto out; 136 } 137 138 if (write_tracing_file("set_ftrace_pid", trace_pid) < 0) { 139 pr_err("failed to set pid: %s\n", trace_pid); 140 goto out_free_pid; 141 } 142 143 trace_file = get_tracing_file("trace_pipe"); 144 if (!trace_file) { 145 pr_err("failed to open trace_pipe\n"); 146 goto out_free_pid; 147 } 148 149 trace_fd = open(trace_file, O_RDONLY); 150 151 put_tracing_file(trace_file); 152 153 if (trace_fd < 0) { 154 pr_err("failed to open trace_pipe\n"); 155 goto out_free_pid; 156 } 157 158 fcntl(trace_fd, F_SETFL, O_NONBLOCK); 159 pollfd.fd = trace_fd; 160 161 if (write_tracing_file("tracing_on", "1") < 0) { 162 pr_err("can't enable tracing\n"); 163 goto out_close_fd; 164 } 165 166 perf_evlist__start_workload(ftrace->evlist); 167 168 while (!done) { 169 if (poll(&pollfd, 1, -1) < 0) 170 break; 171 172 if (pollfd.revents & POLLIN) { 173 int n = read(trace_fd, buf, sizeof(buf)); 174 if (n < 0) 175 break; 176 if (fwrite(buf, n, 1, stdout) != 1) 177 break; 178 } 179 } 180 181 write_tracing_file("tracing_on", "0"); 182 183 /* read remaining buffer contents */ 184 while (true) { 185 int n = read(trace_fd, buf, sizeof(buf)); 186 if (n <= 0) 187 break; 188 if (fwrite(buf, n, 1, stdout) != 1) 189 break; 190 } 191 192 out_close_fd: 193 close(trace_fd); 194 out_free_pid: 195 free(trace_pid); 196 out: 197 reset_tracing_files(ftrace); 198 199 return done ? 0 : -1; 200 } 201 202 static int perf_ftrace_config(const char *var, const char *value, void *cb) 203 { 204 struct perf_ftrace *ftrace = cb; 205 206 if (prefixcmp(var, "ftrace.")) 207 return 0; 208 209 if (strcmp(var, "ftrace.tracer")) 210 return -1; 211 212 if (!strcmp(value, "function_graph") || 213 !strcmp(value, "function")) { 214 ftrace->tracer = value; 215 return 0; 216 } 217 218 pr_err("Please select \"function_graph\" (default) or \"function\"\n"); 219 return -1; 220 } 221 222 int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused) 223 { 224 int ret; 225 struct perf_ftrace ftrace = { 226 .tracer = DEFAULT_TRACER, 227 .target = { .uid = UINT_MAX, }, 228 }; 229 const char * const ftrace_usage[] = { 230 "perf ftrace [<options>] <command>", 231 "perf ftrace [<options>] -- <command> [<options>]", 232 NULL 233 }; 234 const struct option ftrace_options[] = { 235 OPT_STRING('t', "tracer", &ftrace.tracer, "tracer", 236 "tracer to use: function_graph(default) or function"), 237 OPT_INCR('v', "verbose", &verbose, 238 "be more verbose"), 239 OPT_END() 240 }; 241 242 ret = perf_config(perf_ftrace_config, &ftrace); 243 if (ret < 0) 244 return -1; 245 246 argc = parse_options(argc, argv, ftrace_options, ftrace_usage, 247 PARSE_OPT_STOP_AT_NON_OPTION); 248 if (!argc) 249 usage_with_options(ftrace_usage, ftrace_options); 250 251 ftrace.evlist = perf_evlist__new(); 252 if (ftrace.evlist == NULL) 253 return -ENOMEM; 254 255 ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target); 256 if (ret < 0) 257 goto out_delete_evlist; 258 259 ret = __cmd_ftrace(&ftrace, argc, argv); 260 261 out_delete_evlist: 262 perf_evlist__delete(ftrace.evlist); 263 264 return ret; 265 } 266