11c6bec5bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2d01f4e8dSNamhyung Kim /* 3d01f4e8dSNamhyung Kim * builtin-ftrace.c 4d01f4e8dSNamhyung Kim * 5d01f4e8dSNamhyung Kim * Copyright (c) 2013 LG Electronics, Namhyung Kim <namhyung@kernel.org> 60094024aSChangbin Du * Copyright (c) 2020 Changbin Du <changbin.du@gmail.com>, significant enhancement. 7d01f4e8dSNamhyung Kim */ 8d01f4e8dSNamhyung Kim 9d01f4e8dSNamhyung Kim #include "builtin.h" 10d01f4e8dSNamhyung Kim 11a43783aeSArnaldo Carvalho de Melo #include <errno.h> 12d01f4e8dSNamhyung Kim #include <unistd.h> 13d01f4e8dSNamhyung Kim #include <signal.h> 14f2a39fe8SArnaldo Carvalho de Melo #include <stdlib.h> 15a9af6be5SNamhyung Kim #include <fcntl.h> 164208735dSArnaldo Carvalho de Melo #include <poll.h> 17c766f3dfSIgor Lubashev #include <linux/capability.h> 188520a98dSArnaldo Carvalho de Melo #include <linux/string.h> 19d01f4e8dSNamhyung Kim 20d01f4e8dSNamhyung Kim #include "debug.h" 218520a98dSArnaldo Carvalho de Melo #include <subcmd/pager.h> 22d01f4e8dSNamhyung Kim #include <subcmd/parse-options.h> 2320a9ed28SArnaldo Carvalho de Melo #include <api/fs/tracing_path.h> 24d01f4e8dSNamhyung Kim #include "evlist.h" 25d01f4e8dSNamhyung Kim #include "target.h" 26dc231032SNamhyung Kim #include "cpumap.h" 27d01f4e8dSNamhyung Kim #include "thread_map.h" 28*2ae05fe0SChangbin Du #include "strfilter.h" 29c766f3dfSIgor Lubashev #include "util/cap.h" 30b05d1093STaeung Song #include "util/config.h" 31846e1939SChangbin Du #include "util/units.h" 32b1d84af6SChangbin Du #include "util/parse-sublevel-options.h" 33d01f4e8dSNamhyung Kim 34d01f4e8dSNamhyung Kim #define DEFAULT_TRACER "function_graph" 35d01f4e8dSNamhyung Kim 36d01f4e8dSNamhyung Kim struct perf_ftrace { 3763503dbaSJiri Olsa struct evlist *evlist; 38d01f4e8dSNamhyung Kim struct target target; 39d01f4e8dSNamhyung Kim const char *tracer; 4078b83e8bSNamhyung Kim struct list_head filters; 4178b83e8bSNamhyung Kim struct list_head notrace; 4278b83e8bSNamhyung Kim struct list_head graph_funcs; 4378b83e8bSNamhyung Kim struct list_head nograph_funcs; 441096c35aSNamhyung Kim int graph_depth; 45846e1939SChangbin Du unsigned long percpu_buffer_size; 465b347472SChangbin Du bool inherit; 47b1d84af6SChangbin Du int func_stack_trace; 48c81fc34eSChangbin Du int func_irq_info; 4938988f2eSChangbin Du int graph_nosleep_time; 50d1bcf17cSChangbin Du int graph_noirqs; 5159486fb0SChangbin Du int graph_verbose; 5200c85d5fSChangbin Du int graph_thresh; 536555c2f6SChangbin Du unsigned int initial_delay; 5478b83e8bSNamhyung Kim }; 5578b83e8bSNamhyung Kim 5678b83e8bSNamhyung Kim struct filter_entry { 5778b83e8bSNamhyung Kim struct list_head list; 5878b83e8bSNamhyung Kim char name[]; 59d01f4e8dSNamhyung Kim }; 60d01f4e8dSNamhyung Kim 6151a09d8fSChangbin Du static volatile int workload_exec_errno; 62d01f4e8dSNamhyung Kim static bool done; 63d01f4e8dSNamhyung Kim 64d01f4e8dSNamhyung Kim static void sig_handler(int sig __maybe_unused) 65d01f4e8dSNamhyung Kim { 66d01f4e8dSNamhyung Kim done = true; 67d01f4e8dSNamhyung Kim } 68d01f4e8dSNamhyung Kim 69d01f4e8dSNamhyung Kim /* 70d01f4e8dSNamhyung Kim * perf_evlist__prepare_workload will send a SIGUSR1 if the fork fails, since 71d01f4e8dSNamhyung Kim * we asked by setting its exec_error to the function below, 72d01f4e8dSNamhyung Kim * ftrace__workload_exec_failed_signal. 73d01f4e8dSNamhyung Kim * 74d01f4e8dSNamhyung Kim * XXX We need to handle this more appropriately, emitting an error, etc. 75d01f4e8dSNamhyung Kim */ 76d01f4e8dSNamhyung Kim static void ftrace__workload_exec_failed_signal(int signo __maybe_unused, 77d01f4e8dSNamhyung Kim siginfo_t *info __maybe_unused, 78d01f4e8dSNamhyung Kim void *ucontext __maybe_unused) 79d01f4e8dSNamhyung Kim { 8051a09d8fSChangbin Du workload_exec_errno = info->si_value.sival_int; 81d01f4e8dSNamhyung Kim done = true; 82d01f4e8dSNamhyung Kim } 83d01f4e8dSNamhyung Kim 84a9af6be5SNamhyung Kim static int __write_tracing_file(const char *name, const char *val, bool append) 85d01f4e8dSNamhyung Kim { 86d01f4e8dSNamhyung Kim char *file; 87d01f4e8dSNamhyung Kim int fd, ret = -1; 88d01f4e8dSNamhyung Kim ssize_t size = strlen(val); 89a9af6be5SNamhyung Kim int flags = O_WRONLY; 90e7bd9ba2SNamhyung Kim char errbuf[512]; 9163cd02d8SChangbin Du char *val_copy; 92d01f4e8dSNamhyung Kim 93d01f4e8dSNamhyung Kim file = get_tracing_file(name); 94d01f4e8dSNamhyung Kim if (!file) { 95d01f4e8dSNamhyung Kim pr_debug("cannot get tracing file: %s\n", name); 96d01f4e8dSNamhyung Kim return -1; 97d01f4e8dSNamhyung Kim } 98d01f4e8dSNamhyung Kim 99a9af6be5SNamhyung Kim if (append) 100a9af6be5SNamhyung Kim flags |= O_APPEND; 101a9af6be5SNamhyung Kim else 102a9af6be5SNamhyung Kim flags |= O_TRUNC; 103a9af6be5SNamhyung Kim 104a9af6be5SNamhyung Kim fd = open(file, flags); 105d01f4e8dSNamhyung Kim if (fd < 0) { 106e7bd9ba2SNamhyung Kim pr_debug("cannot open tracing file: %s: %s\n", 107e7bd9ba2SNamhyung Kim name, str_error_r(errno, errbuf, sizeof(errbuf))); 108d01f4e8dSNamhyung Kim goto out; 109d01f4e8dSNamhyung Kim } 110d01f4e8dSNamhyung Kim 11163cd02d8SChangbin Du /* 11263cd02d8SChangbin Du * Copy the original value and append a '\n'. Without this, 11363cd02d8SChangbin Du * the kernel can hide possible errors. 11463cd02d8SChangbin Du */ 11563cd02d8SChangbin Du val_copy = strdup(val); 11663cd02d8SChangbin Du if (!val_copy) 11763cd02d8SChangbin Du goto out_close; 11863cd02d8SChangbin Du val_copy[size] = '\n'; 11963cd02d8SChangbin Du 12063cd02d8SChangbin Du if (write(fd, val_copy, size + 1) == size + 1) 121d01f4e8dSNamhyung Kim ret = 0; 122d01f4e8dSNamhyung Kim else 123e7bd9ba2SNamhyung Kim pr_debug("write '%s' to tracing/%s failed: %s\n", 124e7bd9ba2SNamhyung Kim val, name, str_error_r(errno, errbuf, sizeof(errbuf))); 125d01f4e8dSNamhyung Kim 12663cd02d8SChangbin Du free(val_copy); 12763cd02d8SChangbin Du out_close: 128d01f4e8dSNamhyung Kim close(fd); 129d01f4e8dSNamhyung Kim out: 130d01f4e8dSNamhyung Kim put_tracing_file(file); 131d01f4e8dSNamhyung Kim return ret; 132d01f4e8dSNamhyung Kim } 133d01f4e8dSNamhyung Kim 134a9af6be5SNamhyung Kim static int write_tracing_file(const char *name, const char *val) 135a9af6be5SNamhyung Kim { 136a9af6be5SNamhyung Kim return __write_tracing_file(name, val, false); 137a9af6be5SNamhyung Kim } 138a9af6be5SNamhyung Kim 139a9af6be5SNamhyung Kim static int append_tracing_file(const char *name, const char *val) 140a9af6be5SNamhyung Kim { 141a9af6be5SNamhyung Kim return __write_tracing_file(name, val, true); 142a9af6be5SNamhyung Kim } 143a9af6be5SNamhyung Kim 144d6d81bfeSChangbin Du static int read_tracing_file_to_stdout(const char *name) 145d6d81bfeSChangbin Du { 146d6d81bfeSChangbin Du char buf[4096]; 147d6d81bfeSChangbin Du char *file; 148d6d81bfeSChangbin Du int fd; 149d6d81bfeSChangbin Du int ret = -1; 150d6d81bfeSChangbin Du 151d6d81bfeSChangbin Du file = get_tracing_file(name); 152d6d81bfeSChangbin Du if (!file) { 153d6d81bfeSChangbin Du pr_debug("cannot get tracing file: %s\n", name); 154d6d81bfeSChangbin Du return -1; 155d6d81bfeSChangbin Du } 156d6d81bfeSChangbin Du 157d6d81bfeSChangbin Du fd = open(file, O_RDONLY); 158d6d81bfeSChangbin Du if (fd < 0) { 159d6d81bfeSChangbin Du pr_debug("cannot open tracing file: %s: %s\n", 160d6d81bfeSChangbin Du name, str_error_r(errno, buf, sizeof(buf))); 161d6d81bfeSChangbin Du goto out; 162d6d81bfeSChangbin Du } 163d6d81bfeSChangbin Du 164d6d81bfeSChangbin Du /* read contents to stdout */ 165d6d81bfeSChangbin Du while (true) { 166d6d81bfeSChangbin Du int n = read(fd, buf, sizeof(buf)); 167d6d81bfeSChangbin Du if (n == 0) 168d6d81bfeSChangbin Du break; 169d6d81bfeSChangbin Du else if (n < 0) 170d6d81bfeSChangbin Du goto out_close; 171d6d81bfeSChangbin Du 172d6d81bfeSChangbin Du if (fwrite(buf, n, 1, stdout) != 1) 173d6d81bfeSChangbin Du goto out_close; 174d6d81bfeSChangbin Du } 175d6d81bfeSChangbin Du ret = 0; 176d6d81bfeSChangbin Du 177d6d81bfeSChangbin Du out_close: 178d6d81bfeSChangbin Du close(fd); 179d6d81bfeSChangbin Du out: 180d6d81bfeSChangbin Du put_tracing_file(file); 181d6d81bfeSChangbin Du return ret; 182d6d81bfeSChangbin Du } 183d6d81bfeSChangbin Du 184*2ae05fe0SChangbin Du static int read_tracing_file_by_line(const char *name, 185*2ae05fe0SChangbin Du void (*cb)(char *str, void *arg), 186*2ae05fe0SChangbin Du void *cb_arg) 187*2ae05fe0SChangbin Du { 188*2ae05fe0SChangbin Du char *line = NULL; 189*2ae05fe0SChangbin Du size_t len = 0; 190*2ae05fe0SChangbin Du char *file; 191*2ae05fe0SChangbin Du FILE *fp; 192*2ae05fe0SChangbin Du 193*2ae05fe0SChangbin Du file = get_tracing_file(name); 194*2ae05fe0SChangbin Du if (!file) { 195*2ae05fe0SChangbin Du pr_debug("cannot get tracing file: %s\n", name); 196*2ae05fe0SChangbin Du return -1; 197*2ae05fe0SChangbin Du } 198*2ae05fe0SChangbin Du 199*2ae05fe0SChangbin Du fp = fopen(file, "r"); 200*2ae05fe0SChangbin Du if (fp == NULL) { 201*2ae05fe0SChangbin Du pr_debug("cannot open tracing file: %s\n", name); 202*2ae05fe0SChangbin Du put_tracing_file(file); 203*2ae05fe0SChangbin Du return -1; 204*2ae05fe0SChangbin Du } 205*2ae05fe0SChangbin Du 206*2ae05fe0SChangbin Du while (getline(&line, &len, fp) != -1) { 207*2ae05fe0SChangbin Du cb(line, cb_arg); 208*2ae05fe0SChangbin Du } 209*2ae05fe0SChangbin Du 210*2ae05fe0SChangbin Du if (line) 211*2ae05fe0SChangbin Du free(line); 212*2ae05fe0SChangbin Du 213*2ae05fe0SChangbin Du fclose(fp); 214*2ae05fe0SChangbin Du put_tracing_file(file); 215*2ae05fe0SChangbin Du return 0; 216*2ae05fe0SChangbin Du } 217*2ae05fe0SChangbin Du 21868faab0fSChangbin Du static int write_tracing_file_int(const char *name, int value) 21968faab0fSChangbin Du { 22068faab0fSChangbin Du char buf[16]; 22168faab0fSChangbin Du 22268faab0fSChangbin Du snprintf(buf, sizeof(buf), "%d", value); 22368faab0fSChangbin Du if (write_tracing_file(name, buf) < 0) 22468faab0fSChangbin Du return -1; 22568faab0fSChangbin Du 22668faab0fSChangbin Du return 0; 22768faab0fSChangbin Du } 22868faab0fSChangbin Du 2295b347472SChangbin Du static int write_tracing_option_file(const char *name, const char *val) 2305b347472SChangbin Du { 2315b347472SChangbin Du char *file; 2325b347472SChangbin Du int ret; 2335b347472SChangbin Du 2345b347472SChangbin Du if (asprintf(&file, "options/%s", name) < 0) 2355b347472SChangbin Du return -1; 2365b347472SChangbin Du 2375b347472SChangbin Du ret = __write_tracing_file(file, val, false); 2385b347472SChangbin Du free(file); 2395b347472SChangbin Du return ret; 2405b347472SChangbin Du } 2415b347472SChangbin Du 242dc231032SNamhyung Kim static int reset_tracing_cpu(void); 24378b83e8bSNamhyung Kim static void reset_tracing_filters(void); 244dc231032SNamhyung Kim 2455b347472SChangbin Du static void reset_tracing_options(struct perf_ftrace *ftrace __maybe_unused) 2465b347472SChangbin Du { 2475b347472SChangbin Du write_tracing_option_file("function-fork", "0"); 248b1d84af6SChangbin Du write_tracing_option_file("func_stack_trace", "0"); 24938988f2eSChangbin Du write_tracing_option_file("sleep-time", "1"); 250d1bcf17cSChangbin Du write_tracing_option_file("funcgraph-irqs", "1"); 25159486fb0SChangbin Du write_tracing_option_file("funcgraph-proc", "0"); 25259486fb0SChangbin Du write_tracing_option_file("funcgraph-abstime", "0"); 25359486fb0SChangbin Du write_tracing_option_file("latency-format", "0"); 254c81fc34eSChangbin Du write_tracing_option_file("irq-info", "0"); 2555b347472SChangbin Du } 2565b347472SChangbin Du 257d01f4e8dSNamhyung Kim static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) 258d01f4e8dSNamhyung Kim { 259d01f4e8dSNamhyung Kim if (write_tracing_file("tracing_on", "0") < 0) 260d01f4e8dSNamhyung Kim return -1; 261d01f4e8dSNamhyung Kim 262d01f4e8dSNamhyung Kim if (write_tracing_file("current_tracer", "nop") < 0) 263d01f4e8dSNamhyung Kim return -1; 264d01f4e8dSNamhyung Kim 265d01f4e8dSNamhyung Kim if (write_tracing_file("set_ftrace_pid", " ") < 0) 266d01f4e8dSNamhyung Kim return -1; 267d01f4e8dSNamhyung Kim 268dc231032SNamhyung Kim if (reset_tracing_cpu() < 0) 269dc231032SNamhyung Kim return -1; 270dc231032SNamhyung Kim 2711096c35aSNamhyung Kim if (write_tracing_file("max_graph_depth", "0") < 0) 2721096c35aSNamhyung Kim return -1; 2731096c35aSNamhyung Kim 27400c85d5fSChangbin Du if (write_tracing_file("tracing_thresh", "0") < 0) 27500c85d5fSChangbin Du return -1; 27600c85d5fSChangbin Du 27778b83e8bSNamhyung Kim reset_tracing_filters(); 2785b347472SChangbin Du reset_tracing_options(ftrace); 279d01f4e8dSNamhyung Kim return 0; 280d01f4e8dSNamhyung Kim } 281d01f4e8dSNamhyung Kim 282a9af6be5SNamhyung Kim static int set_tracing_pid(struct perf_ftrace *ftrace) 283a9af6be5SNamhyung Kim { 284a9af6be5SNamhyung Kim int i; 285a9af6be5SNamhyung Kim char buf[16]; 286a9af6be5SNamhyung Kim 287a9af6be5SNamhyung Kim if (target__has_cpu(&ftrace->target)) 288a9af6be5SNamhyung Kim return 0; 289a9af6be5SNamhyung Kim 290a2f354e3SJiri Olsa for (i = 0; i < perf_thread_map__nr(ftrace->evlist->core.threads); i++) { 291a9af6be5SNamhyung Kim scnprintf(buf, sizeof(buf), "%d", 29203617c22SJiri Olsa ftrace->evlist->core.threads->map[i]); 293a9af6be5SNamhyung Kim if (append_tracing_file("set_ftrace_pid", buf) < 0) 294a9af6be5SNamhyung Kim return -1; 295a9af6be5SNamhyung Kim } 296a9af6be5SNamhyung Kim return 0; 297a9af6be5SNamhyung Kim } 298a9af6be5SNamhyung Kim 299f854839bSJiri Olsa static int set_tracing_cpumask(struct perf_cpu_map *cpumap) 300dc231032SNamhyung Kim { 301dc231032SNamhyung Kim char *cpumask; 302dc231032SNamhyung Kim size_t mask_size; 303dc231032SNamhyung Kim int ret; 304dc231032SNamhyung Kim int last_cpu; 305dc231032SNamhyung Kim 306dc231032SNamhyung Kim last_cpu = cpu_map__cpu(cpumap, cpumap->nr - 1); 307cf30ae72SHe Zhe mask_size = last_cpu / 4 + 2; /* one more byte for EOS */ 308dc231032SNamhyung Kim mask_size += last_cpu / 32; /* ',' is needed for every 32th cpus */ 309dc231032SNamhyung Kim 310dc231032SNamhyung Kim cpumask = malloc(mask_size); 311dc231032SNamhyung Kim if (cpumask == NULL) { 312dc231032SNamhyung Kim pr_debug("failed to allocate cpu mask\n"); 313dc231032SNamhyung Kim return -1; 314dc231032SNamhyung Kim } 315dc231032SNamhyung Kim 316dc231032SNamhyung Kim cpu_map__snprint_mask(cpumap, cpumask, mask_size); 317dc231032SNamhyung Kim 318dc231032SNamhyung Kim ret = write_tracing_file("tracing_cpumask", cpumask); 319dc231032SNamhyung Kim 320dc231032SNamhyung Kim free(cpumask); 321dc231032SNamhyung Kim return ret; 322dc231032SNamhyung Kim } 323dc231032SNamhyung Kim 324dc231032SNamhyung Kim static int set_tracing_cpu(struct perf_ftrace *ftrace) 325dc231032SNamhyung Kim { 326f72f901dSJiri Olsa struct perf_cpu_map *cpumap = ftrace->evlist->core.cpus; 327dc231032SNamhyung Kim 328dc231032SNamhyung Kim if (!target__has_cpu(&ftrace->target)) 329dc231032SNamhyung Kim return 0; 330dc231032SNamhyung Kim 331dc231032SNamhyung Kim return set_tracing_cpumask(cpumap); 332dc231032SNamhyung Kim } 333dc231032SNamhyung Kim 334b1d84af6SChangbin Du static int set_tracing_func_stack_trace(struct perf_ftrace *ftrace) 335b1d84af6SChangbin Du { 336b1d84af6SChangbin Du if (!ftrace->func_stack_trace) 337b1d84af6SChangbin Du return 0; 338b1d84af6SChangbin Du 339b1d84af6SChangbin Du if (write_tracing_option_file("func_stack_trace", "1") < 0) 340b1d84af6SChangbin Du return -1; 341b1d84af6SChangbin Du 342b1d84af6SChangbin Du return 0; 343b1d84af6SChangbin Du } 344b1d84af6SChangbin Du 345c81fc34eSChangbin Du static int set_tracing_func_irqinfo(struct perf_ftrace *ftrace) 346c81fc34eSChangbin Du { 347c81fc34eSChangbin Du if (!ftrace->func_irq_info) 348c81fc34eSChangbin Du return 0; 349c81fc34eSChangbin Du 350c81fc34eSChangbin Du if (write_tracing_option_file("irq-info", "1") < 0) 351c81fc34eSChangbin Du return -1; 352c81fc34eSChangbin Du 353c81fc34eSChangbin Du return 0; 354c81fc34eSChangbin Du } 355c81fc34eSChangbin Du 356dc231032SNamhyung Kim static int reset_tracing_cpu(void) 357dc231032SNamhyung Kim { 3589c3516d1SJiri Olsa struct perf_cpu_map *cpumap = perf_cpu_map__new(NULL); 359dc231032SNamhyung Kim int ret; 360dc231032SNamhyung Kim 361dc231032SNamhyung Kim ret = set_tracing_cpumask(cpumap); 36238f01d8dSJiri Olsa perf_cpu_map__put(cpumap); 363dc231032SNamhyung Kim return ret; 364dc231032SNamhyung Kim } 365dc231032SNamhyung Kim 36678b83e8bSNamhyung Kim static int __set_tracing_filter(const char *filter_file, struct list_head *funcs) 36778b83e8bSNamhyung Kim { 36878b83e8bSNamhyung Kim struct filter_entry *pos; 36978b83e8bSNamhyung Kim 37078b83e8bSNamhyung Kim list_for_each_entry(pos, funcs, list) { 37178b83e8bSNamhyung Kim if (append_tracing_file(filter_file, pos->name) < 0) 37278b83e8bSNamhyung Kim return -1; 37378b83e8bSNamhyung Kim } 37478b83e8bSNamhyung Kim 37578b83e8bSNamhyung Kim return 0; 37678b83e8bSNamhyung Kim } 37778b83e8bSNamhyung Kim 37878b83e8bSNamhyung Kim static int set_tracing_filters(struct perf_ftrace *ftrace) 37978b83e8bSNamhyung Kim { 38078b83e8bSNamhyung Kim int ret; 38178b83e8bSNamhyung Kim 38278b83e8bSNamhyung Kim ret = __set_tracing_filter("set_ftrace_filter", &ftrace->filters); 38378b83e8bSNamhyung Kim if (ret < 0) 38478b83e8bSNamhyung Kim return ret; 38578b83e8bSNamhyung Kim 38678b83e8bSNamhyung Kim ret = __set_tracing_filter("set_ftrace_notrace", &ftrace->notrace); 38778b83e8bSNamhyung Kim if (ret < 0) 38878b83e8bSNamhyung Kim return ret; 38978b83e8bSNamhyung Kim 39078b83e8bSNamhyung Kim ret = __set_tracing_filter("set_graph_function", &ftrace->graph_funcs); 39178b83e8bSNamhyung Kim if (ret < 0) 39278b83e8bSNamhyung Kim return ret; 39378b83e8bSNamhyung Kim 39478b83e8bSNamhyung Kim /* old kernels do not have this filter */ 39578b83e8bSNamhyung Kim __set_tracing_filter("set_graph_notrace", &ftrace->nograph_funcs); 39678b83e8bSNamhyung Kim 39778b83e8bSNamhyung Kim return ret; 39878b83e8bSNamhyung Kim } 39978b83e8bSNamhyung Kim 40078b83e8bSNamhyung Kim static void reset_tracing_filters(void) 40178b83e8bSNamhyung Kim { 40278b83e8bSNamhyung Kim write_tracing_file("set_ftrace_filter", " "); 40378b83e8bSNamhyung Kim write_tracing_file("set_ftrace_notrace", " "); 40478b83e8bSNamhyung Kim write_tracing_file("set_graph_function", " "); 40578b83e8bSNamhyung Kim write_tracing_file("set_graph_notrace", " "); 40678b83e8bSNamhyung Kim } 40778b83e8bSNamhyung Kim 4081096c35aSNamhyung Kim static int set_tracing_depth(struct perf_ftrace *ftrace) 4091096c35aSNamhyung Kim { 4101096c35aSNamhyung Kim if (ftrace->graph_depth == 0) 4111096c35aSNamhyung Kim return 0; 4121096c35aSNamhyung Kim 4131096c35aSNamhyung Kim if (ftrace->graph_depth < 0) { 4141096c35aSNamhyung Kim pr_err("invalid graph depth: %d\n", ftrace->graph_depth); 4151096c35aSNamhyung Kim return -1; 4161096c35aSNamhyung Kim } 4171096c35aSNamhyung Kim 41868faab0fSChangbin Du if (write_tracing_file_int("max_graph_depth", ftrace->graph_depth) < 0) 4191096c35aSNamhyung Kim return -1; 4201096c35aSNamhyung Kim 4211096c35aSNamhyung Kim return 0; 4221096c35aSNamhyung Kim } 4231096c35aSNamhyung Kim 424846e1939SChangbin Du static int set_tracing_percpu_buffer_size(struct perf_ftrace *ftrace) 425846e1939SChangbin Du { 426846e1939SChangbin Du int ret; 427846e1939SChangbin Du 428846e1939SChangbin Du if (ftrace->percpu_buffer_size == 0) 429846e1939SChangbin Du return 0; 430846e1939SChangbin Du 431846e1939SChangbin Du ret = write_tracing_file_int("buffer_size_kb", 432846e1939SChangbin Du ftrace->percpu_buffer_size / 1024); 433846e1939SChangbin Du if (ret < 0) 434846e1939SChangbin Du return ret; 435846e1939SChangbin Du 436846e1939SChangbin Du return 0; 437846e1939SChangbin Du } 438846e1939SChangbin Du 4395b347472SChangbin Du static int set_tracing_trace_inherit(struct perf_ftrace *ftrace) 4405b347472SChangbin Du { 4415b347472SChangbin Du if (!ftrace->inherit) 4425b347472SChangbin Du return 0; 4435b347472SChangbin Du 4445b347472SChangbin Du if (write_tracing_option_file("function-fork", "1") < 0) 4455b347472SChangbin Du return -1; 4465b347472SChangbin Du 4475b347472SChangbin Du return 0; 4485b347472SChangbin Du } 4495b347472SChangbin Du 45038988f2eSChangbin Du static int set_tracing_sleep_time(struct perf_ftrace *ftrace) 45138988f2eSChangbin Du { 45238988f2eSChangbin Du if (!ftrace->graph_nosleep_time) 45338988f2eSChangbin Du return 0; 45438988f2eSChangbin Du 45538988f2eSChangbin Du if (write_tracing_option_file("sleep-time", "0") < 0) 45638988f2eSChangbin Du return -1; 45738988f2eSChangbin Du 45838988f2eSChangbin Du return 0; 45938988f2eSChangbin Du } 46038988f2eSChangbin Du 461d1bcf17cSChangbin Du static int set_tracing_funcgraph_irqs(struct perf_ftrace *ftrace) 462d1bcf17cSChangbin Du { 463d1bcf17cSChangbin Du if (!ftrace->graph_noirqs) 464d1bcf17cSChangbin Du return 0; 465d1bcf17cSChangbin Du 466d1bcf17cSChangbin Du if (write_tracing_option_file("funcgraph-irqs", "0") < 0) 467d1bcf17cSChangbin Du return -1; 468d1bcf17cSChangbin Du 469d1bcf17cSChangbin Du return 0; 470d1bcf17cSChangbin Du } 471d1bcf17cSChangbin Du 47259486fb0SChangbin Du static int set_tracing_funcgraph_verbose(struct perf_ftrace *ftrace) 47359486fb0SChangbin Du { 47459486fb0SChangbin Du if (!ftrace->graph_verbose) 47559486fb0SChangbin Du return 0; 47659486fb0SChangbin Du 47759486fb0SChangbin Du if (write_tracing_option_file("funcgraph-proc", "1") < 0) 47859486fb0SChangbin Du return -1; 47959486fb0SChangbin Du 48059486fb0SChangbin Du if (write_tracing_option_file("funcgraph-abstime", "1") < 0) 48159486fb0SChangbin Du return -1; 48259486fb0SChangbin Du 48359486fb0SChangbin Du if (write_tracing_option_file("latency-format", "1") < 0) 48459486fb0SChangbin Du return -1; 48559486fb0SChangbin Du 48659486fb0SChangbin Du return 0; 48759486fb0SChangbin Du } 48859486fb0SChangbin Du 48900c85d5fSChangbin Du static int set_tracing_thresh(struct perf_ftrace *ftrace) 49000c85d5fSChangbin Du { 49100c85d5fSChangbin Du int ret; 49200c85d5fSChangbin Du 49300c85d5fSChangbin Du if (ftrace->graph_thresh == 0) 49400c85d5fSChangbin Du return 0; 49500c85d5fSChangbin Du 49600c85d5fSChangbin Du ret = write_tracing_file_int("tracing_thresh", ftrace->graph_thresh); 49700c85d5fSChangbin Du if (ret < 0) 49800c85d5fSChangbin Du return ret; 49900c85d5fSChangbin Du 50000c85d5fSChangbin Du return 0; 50100c85d5fSChangbin Du } 50200c85d5fSChangbin Du 5033c4dc21bSChangbin Du static int set_tracing_options(struct perf_ftrace *ftrace) 5043c4dc21bSChangbin Du { 5053c4dc21bSChangbin Du if (set_tracing_pid(ftrace) < 0) { 5063c4dc21bSChangbin Du pr_err("failed to set ftrace pid\n"); 5073c4dc21bSChangbin Du return -1; 5083c4dc21bSChangbin Du } 5093c4dc21bSChangbin Du 5103c4dc21bSChangbin Du if (set_tracing_cpu(ftrace) < 0) { 5113c4dc21bSChangbin Du pr_err("failed to set tracing cpumask\n"); 5123c4dc21bSChangbin Du return -1; 5133c4dc21bSChangbin Du } 5143c4dc21bSChangbin Du 5153c4dc21bSChangbin Du if (set_tracing_func_stack_trace(ftrace) < 0) { 5163c4dc21bSChangbin Du pr_err("failed to set tracing option func_stack_trace\n"); 5173c4dc21bSChangbin Du return -1; 5183c4dc21bSChangbin Du } 5193c4dc21bSChangbin Du 5203c4dc21bSChangbin Du if (set_tracing_func_irqinfo(ftrace) < 0) { 5213c4dc21bSChangbin Du pr_err("failed to set tracing option irq-info\n"); 5223c4dc21bSChangbin Du return -1; 5233c4dc21bSChangbin Du } 5243c4dc21bSChangbin Du 5253c4dc21bSChangbin Du if (set_tracing_filters(ftrace) < 0) { 5263c4dc21bSChangbin Du pr_err("failed to set tracing filters\n"); 5273c4dc21bSChangbin Du return -1; 5283c4dc21bSChangbin Du } 5293c4dc21bSChangbin Du 5303c4dc21bSChangbin Du if (set_tracing_depth(ftrace) < 0) { 5313c4dc21bSChangbin Du pr_err("failed to set graph depth\n"); 5323c4dc21bSChangbin Du return -1; 5333c4dc21bSChangbin Du } 5343c4dc21bSChangbin Du 5353c4dc21bSChangbin Du if (set_tracing_percpu_buffer_size(ftrace) < 0) { 5363c4dc21bSChangbin Du pr_err("failed to set tracing per-cpu buffer size\n"); 5373c4dc21bSChangbin Du return -1; 5383c4dc21bSChangbin Du } 5393c4dc21bSChangbin Du 5403c4dc21bSChangbin Du if (set_tracing_trace_inherit(ftrace) < 0) { 5413c4dc21bSChangbin Du pr_err("failed to set tracing option function-fork\n"); 5423c4dc21bSChangbin Du return -1; 5433c4dc21bSChangbin Du } 5443c4dc21bSChangbin Du 5453c4dc21bSChangbin Du if (set_tracing_sleep_time(ftrace) < 0) { 5463c4dc21bSChangbin Du pr_err("failed to set tracing option sleep-time\n"); 5473c4dc21bSChangbin Du return -1; 5483c4dc21bSChangbin Du } 5493c4dc21bSChangbin Du 5503c4dc21bSChangbin Du if (set_tracing_funcgraph_irqs(ftrace) < 0) { 5513c4dc21bSChangbin Du pr_err("failed to set tracing option funcgraph-irqs\n"); 5523c4dc21bSChangbin Du return -1; 5533c4dc21bSChangbin Du } 5543c4dc21bSChangbin Du 5553c4dc21bSChangbin Du if (set_tracing_funcgraph_verbose(ftrace) < 0) { 5563c4dc21bSChangbin Du pr_err("failed to set tracing option funcgraph-proc/funcgraph-abstime\n"); 5573c4dc21bSChangbin Du return -1; 5583c4dc21bSChangbin Du } 5593c4dc21bSChangbin Du 5603c4dc21bSChangbin Du if (set_tracing_thresh(ftrace) < 0) { 5613c4dc21bSChangbin Du pr_err("failed to set tracing thresh\n"); 5623c4dc21bSChangbin Du return -1; 5633c4dc21bSChangbin Du } 5643c4dc21bSChangbin Du 5653c4dc21bSChangbin Du return 0; 5663c4dc21bSChangbin Du } 5673c4dc21bSChangbin Du 568d01f4e8dSNamhyung Kim static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) 569d01f4e8dSNamhyung Kim { 570d01f4e8dSNamhyung Kim char *trace_file; 571d01f4e8dSNamhyung Kim int trace_fd; 572d01f4e8dSNamhyung Kim char buf[4096]; 573d01f4e8dSNamhyung Kim struct pollfd pollfd = { 574d01f4e8dSNamhyung Kim .events = POLLIN, 575d01f4e8dSNamhyung Kim }; 576d01f4e8dSNamhyung Kim 5776b3e0e2eSAlexey Budankov if (!(perf_cap__capable(CAP_PERFMON) || 5786b3e0e2eSAlexey Budankov perf_cap__capable(CAP_SYS_ADMIN))) { 57973e5de70SArnaldo Carvalho de Melo pr_err("ftrace only works for %s!\n", 58073e5de70SArnaldo Carvalho de Melo #ifdef HAVE_LIBCAP_SUPPORT 5816b3e0e2eSAlexey Budankov "users with the CAP_PERFMON or CAP_SYS_ADMIN capability" 58273e5de70SArnaldo Carvalho de Melo #else 58373e5de70SArnaldo Carvalho de Melo "root" 58473e5de70SArnaldo Carvalho de Melo #endif 58573e5de70SArnaldo Carvalho de Melo ); 586d01f4e8dSNamhyung Kim return -1; 587d01f4e8dSNamhyung Kim } 588d01f4e8dSNamhyung Kim 589d01f4e8dSNamhyung Kim signal(SIGINT, sig_handler); 590d01f4e8dSNamhyung Kim signal(SIGUSR1, sig_handler); 591d01f4e8dSNamhyung Kim signal(SIGCHLD, sig_handler); 59258335964SNamhyung Kim signal(SIGPIPE, sig_handler); 593d01f4e8dSNamhyung Kim 59463cd02d8SChangbin Du if (reset_tracing_files(ftrace) < 0) { 59563cd02d8SChangbin Du pr_err("failed to reset ftrace\n"); 596a9af6be5SNamhyung Kim goto out; 59763cd02d8SChangbin Du } 598d01f4e8dSNamhyung Kim 599d01f4e8dSNamhyung Kim /* reset ftrace buffer */ 600d01f4e8dSNamhyung Kim if (write_tracing_file("trace", "0") < 0) 601d01f4e8dSNamhyung Kim goto out; 602d01f4e8dSNamhyung Kim 603a9af6be5SNamhyung Kim if (argc && perf_evlist__prepare_workload(ftrace->evlist, 604a9af6be5SNamhyung Kim &ftrace->target, argv, false, 605a9af6be5SNamhyung Kim ftrace__workload_exec_failed_signal) < 0) { 606d01f4e8dSNamhyung Kim goto out; 607a9af6be5SNamhyung Kim } 608a9af6be5SNamhyung Kim 6093c4dc21bSChangbin Du if (set_tracing_options(ftrace) < 0) 610a9af6be5SNamhyung Kim goto out_reset; 61100c85d5fSChangbin Du 612d01f4e8dSNamhyung Kim if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { 613d01f4e8dSNamhyung Kim pr_err("failed to set current_tracer to %s\n", ftrace->tracer); 614a9af6be5SNamhyung Kim goto out_reset; 615d01f4e8dSNamhyung Kim } 616d01f4e8dSNamhyung Kim 61729681bc5SNamhyung Kim setup_pager(); 61829681bc5SNamhyung Kim 619d01f4e8dSNamhyung Kim trace_file = get_tracing_file("trace_pipe"); 620d01f4e8dSNamhyung Kim if (!trace_file) { 621d01f4e8dSNamhyung Kim pr_err("failed to open trace_pipe\n"); 622a9af6be5SNamhyung Kim goto out_reset; 623d01f4e8dSNamhyung Kim } 624d01f4e8dSNamhyung Kim 625d01f4e8dSNamhyung Kim trace_fd = open(trace_file, O_RDONLY); 626d01f4e8dSNamhyung Kim 627d01f4e8dSNamhyung Kim put_tracing_file(trace_file); 628d01f4e8dSNamhyung Kim 629d01f4e8dSNamhyung Kim if (trace_fd < 0) { 630d01f4e8dSNamhyung Kim pr_err("failed to open trace_pipe\n"); 631a9af6be5SNamhyung Kim goto out_reset; 632d01f4e8dSNamhyung Kim } 633d01f4e8dSNamhyung Kim 634d01f4e8dSNamhyung Kim fcntl(trace_fd, F_SETFL, O_NONBLOCK); 635d01f4e8dSNamhyung Kim pollfd.fd = trace_fd; 636d01f4e8dSNamhyung Kim 63781523c1eSChangbin Du /* display column headers */ 63881523c1eSChangbin Du read_tracing_file_to_stdout("trace"); 63981523c1eSChangbin Du 6406555c2f6SChangbin Du if (!ftrace->initial_delay) { 641d01f4e8dSNamhyung Kim if (write_tracing_file("tracing_on", "1") < 0) { 642d01f4e8dSNamhyung Kim pr_err("can't enable tracing\n"); 643d01f4e8dSNamhyung Kim goto out_close_fd; 644d01f4e8dSNamhyung Kim } 6456555c2f6SChangbin Du } 646d01f4e8dSNamhyung Kim 647d01f4e8dSNamhyung Kim perf_evlist__start_workload(ftrace->evlist); 648d01f4e8dSNamhyung Kim 6496555c2f6SChangbin Du if (ftrace->initial_delay) { 6506555c2f6SChangbin Du usleep(ftrace->initial_delay * 1000); 6516555c2f6SChangbin Du if (write_tracing_file("tracing_on", "1") < 0) { 6526555c2f6SChangbin Du pr_err("can't enable tracing\n"); 6536555c2f6SChangbin Du goto out_close_fd; 6546555c2f6SChangbin Du } 6556555c2f6SChangbin Du } 6566555c2f6SChangbin Du 657d01f4e8dSNamhyung Kim while (!done) { 658d01f4e8dSNamhyung Kim if (poll(&pollfd, 1, -1) < 0) 659d01f4e8dSNamhyung Kim break; 660d01f4e8dSNamhyung Kim 661d01f4e8dSNamhyung Kim if (pollfd.revents & POLLIN) { 662d01f4e8dSNamhyung Kim int n = read(trace_fd, buf, sizeof(buf)); 663d01f4e8dSNamhyung Kim if (n < 0) 664d01f4e8dSNamhyung Kim break; 665d01f4e8dSNamhyung Kim if (fwrite(buf, n, 1, stdout) != 1) 666d01f4e8dSNamhyung Kim break; 667d01f4e8dSNamhyung Kim } 668d01f4e8dSNamhyung Kim } 669d01f4e8dSNamhyung Kim 670d01f4e8dSNamhyung Kim write_tracing_file("tracing_on", "0"); 671d01f4e8dSNamhyung Kim 67251a09d8fSChangbin Du if (workload_exec_errno) { 67351a09d8fSChangbin Du const char *emsg = str_error_r(workload_exec_errno, buf, sizeof(buf)); 67451a09d8fSChangbin Du /* flush stdout first so below error msg appears at the end. */ 67551a09d8fSChangbin Du fflush(stdout); 67651a09d8fSChangbin Du pr_err("workload failed: %s\n", emsg); 67751a09d8fSChangbin Du goto out_close_fd; 67851a09d8fSChangbin Du } 67951a09d8fSChangbin Du 680d01f4e8dSNamhyung Kim /* read remaining buffer contents */ 681d01f4e8dSNamhyung Kim while (true) { 682d01f4e8dSNamhyung Kim int n = read(trace_fd, buf, sizeof(buf)); 683d01f4e8dSNamhyung Kim if (n <= 0) 684d01f4e8dSNamhyung Kim break; 685d01f4e8dSNamhyung Kim if (fwrite(buf, n, 1, stdout) != 1) 686d01f4e8dSNamhyung Kim break; 687d01f4e8dSNamhyung Kim } 688d01f4e8dSNamhyung Kim 689d01f4e8dSNamhyung Kim out_close_fd: 690d01f4e8dSNamhyung Kim close(trace_fd); 691a9af6be5SNamhyung Kim out_reset: 692d01f4e8dSNamhyung Kim reset_tracing_files(ftrace); 693a9af6be5SNamhyung Kim out: 69451a09d8fSChangbin Du return (done && !workload_exec_errno) ? 0 : -1; 695d01f4e8dSNamhyung Kim } 696d01f4e8dSNamhyung Kim 697b05d1093STaeung Song static int perf_ftrace_config(const char *var, const char *value, void *cb) 698b05d1093STaeung Song { 699b05d1093STaeung Song struct perf_ftrace *ftrace = cb; 700b05d1093STaeung Song 7018e99b6d4SArnaldo Carvalho de Melo if (!strstarts(var, "ftrace.")) 702b05d1093STaeung Song return 0; 703b05d1093STaeung Song 704b05d1093STaeung Song if (strcmp(var, "ftrace.tracer")) 705b05d1093STaeung Song return -1; 706b05d1093STaeung Song 707b05d1093STaeung Song if (!strcmp(value, "function_graph") || 708b05d1093STaeung Song !strcmp(value, "function")) { 709b05d1093STaeung Song ftrace->tracer = value; 710b05d1093STaeung Song return 0; 711b05d1093STaeung Song } 712b05d1093STaeung Song 713b05d1093STaeung Song pr_err("Please select \"function_graph\" (default) or \"function\"\n"); 714b05d1093STaeung Song return -1; 715b05d1093STaeung Song } 716b05d1093STaeung Song 717*2ae05fe0SChangbin Du static void list_function_cb(char *str, void *arg) 718*2ae05fe0SChangbin Du { 719*2ae05fe0SChangbin Du struct strfilter *filter = (struct strfilter *)arg; 720*2ae05fe0SChangbin Du 721*2ae05fe0SChangbin Du if (strfilter__compare(filter, str)) 722*2ae05fe0SChangbin Du printf("%s", str); 723*2ae05fe0SChangbin Du } 724*2ae05fe0SChangbin Du 725*2ae05fe0SChangbin Du static int opt_list_avail_functions(const struct option *opt __maybe_unused, 726*2ae05fe0SChangbin Du const char *str, int unset) 727*2ae05fe0SChangbin Du { 728*2ae05fe0SChangbin Du struct strfilter *filter; 729*2ae05fe0SChangbin Du const char *err = NULL; 730*2ae05fe0SChangbin Du int ret; 731*2ae05fe0SChangbin Du 732*2ae05fe0SChangbin Du if (unset || !str) 733*2ae05fe0SChangbin Du return -1; 734*2ae05fe0SChangbin Du 735*2ae05fe0SChangbin Du filter = strfilter__new(str, &err); 736*2ae05fe0SChangbin Du if (!filter) 737*2ae05fe0SChangbin Du return err ? -EINVAL : -ENOMEM; 738*2ae05fe0SChangbin Du 739*2ae05fe0SChangbin Du ret = strfilter__or(filter, str, &err); 740*2ae05fe0SChangbin Du if (ret == -EINVAL) { 741*2ae05fe0SChangbin Du pr_err("Filter parse error at %td.\n", err - str + 1); 742*2ae05fe0SChangbin Du pr_err("Source: \"%s\"\n", str); 743*2ae05fe0SChangbin Du pr_err(" %*c\n", (int)(err - str + 1), '^'); 744*2ae05fe0SChangbin Du strfilter__delete(filter); 745*2ae05fe0SChangbin Du return ret; 746*2ae05fe0SChangbin Du } 747*2ae05fe0SChangbin Du 748*2ae05fe0SChangbin Du ret = read_tracing_file_by_line("available_filter_functions", 749*2ae05fe0SChangbin Du list_function_cb, filter); 750*2ae05fe0SChangbin Du strfilter__delete(filter); 751*2ae05fe0SChangbin Du if (ret < 0) 752*2ae05fe0SChangbin Du return ret; 753*2ae05fe0SChangbin Du 754*2ae05fe0SChangbin Du exit(0); 755*2ae05fe0SChangbin Du } 756*2ae05fe0SChangbin Du 75778b83e8bSNamhyung Kim static int parse_filter_func(const struct option *opt, const char *str, 75878b83e8bSNamhyung Kim int unset __maybe_unused) 75978b83e8bSNamhyung Kim { 76078b83e8bSNamhyung Kim struct list_head *head = opt->value; 76178b83e8bSNamhyung Kim struct filter_entry *entry; 76278b83e8bSNamhyung Kim 76378b83e8bSNamhyung Kim entry = malloc(sizeof(*entry) + strlen(str) + 1); 76478b83e8bSNamhyung Kim if (entry == NULL) 76578b83e8bSNamhyung Kim return -ENOMEM; 76678b83e8bSNamhyung Kim 76778b83e8bSNamhyung Kim strcpy(entry->name, str); 76878b83e8bSNamhyung Kim list_add_tail(&entry->list, head); 76978b83e8bSNamhyung Kim 77078b83e8bSNamhyung Kim return 0; 77178b83e8bSNamhyung Kim } 77278b83e8bSNamhyung Kim 77378b83e8bSNamhyung Kim static void delete_filter_func(struct list_head *head) 77478b83e8bSNamhyung Kim { 77578b83e8bSNamhyung Kim struct filter_entry *pos, *tmp; 77678b83e8bSNamhyung Kim 77778b83e8bSNamhyung Kim list_for_each_entry_safe(pos, tmp, head, list) { 778e56fbc9dSArnaldo Carvalho de Melo list_del_init(&pos->list); 77978b83e8bSNamhyung Kim free(pos); 78078b83e8bSNamhyung Kim } 78178b83e8bSNamhyung Kim } 78278b83e8bSNamhyung Kim 783846e1939SChangbin Du static int parse_buffer_size(const struct option *opt, 784846e1939SChangbin Du const char *str, int unset) 785846e1939SChangbin Du { 786846e1939SChangbin Du unsigned long *s = (unsigned long *)opt->value; 787846e1939SChangbin Du static struct parse_tag tags_size[] = { 788846e1939SChangbin Du { .tag = 'B', .mult = 1 }, 789846e1939SChangbin Du { .tag = 'K', .mult = 1 << 10 }, 790846e1939SChangbin Du { .tag = 'M', .mult = 1 << 20 }, 791846e1939SChangbin Du { .tag = 'G', .mult = 1 << 30 }, 792846e1939SChangbin Du { .tag = 0 }, 793846e1939SChangbin Du }; 794846e1939SChangbin Du unsigned long val; 795846e1939SChangbin Du 796846e1939SChangbin Du if (unset) { 797846e1939SChangbin Du *s = 0; 798846e1939SChangbin Du return 0; 799846e1939SChangbin Du } 800846e1939SChangbin Du 801846e1939SChangbin Du val = parse_tag_value(str, tags_size); 802846e1939SChangbin Du if (val != (unsigned long) -1) { 803846e1939SChangbin Du if (val < 1024) { 804846e1939SChangbin Du pr_err("buffer size too small, must larger than 1KB."); 805846e1939SChangbin Du return -1; 806846e1939SChangbin Du } 807846e1939SChangbin Du *s = val; 808846e1939SChangbin Du return 0; 809846e1939SChangbin Du } 810846e1939SChangbin Du 811846e1939SChangbin Du return -1; 812846e1939SChangbin Du } 813846e1939SChangbin Du 814b1d84af6SChangbin Du static int parse_func_tracer_opts(const struct option *opt, 815b1d84af6SChangbin Du const char *str, int unset) 816b1d84af6SChangbin Du { 817b1d84af6SChangbin Du int ret; 818b1d84af6SChangbin Du struct perf_ftrace *ftrace = (struct perf_ftrace *) opt->value; 819b1d84af6SChangbin Du struct sublevel_option func_tracer_opts[] = { 820b1d84af6SChangbin Du { .name = "call-graph", .value_ptr = &ftrace->func_stack_trace }, 821c81fc34eSChangbin Du { .name = "irq-info", .value_ptr = &ftrace->func_irq_info }, 822b1d84af6SChangbin Du { .name = NULL, } 823b1d84af6SChangbin Du }; 824b1d84af6SChangbin Du 825b1d84af6SChangbin Du if (unset) 826b1d84af6SChangbin Du return 0; 827b1d84af6SChangbin Du 828b1d84af6SChangbin Du ret = perf_parse_sublevel_options(str, func_tracer_opts); 829b1d84af6SChangbin Du if (ret) 830b1d84af6SChangbin Du return ret; 831b1d84af6SChangbin Du 832b1d84af6SChangbin Du return 0; 833b1d84af6SChangbin Du } 834b1d84af6SChangbin Du 83538988f2eSChangbin Du static int parse_graph_tracer_opts(const struct option *opt, 83638988f2eSChangbin Du const char *str, int unset) 83738988f2eSChangbin Du { 83838988f2eSChangbin Du int ret; 83938988f2eSChangbin Du struct perf_ftrace *ftrace = (struct perf_ftrace *) opt->value; 84038988f2eSChangbin Du struct sublevel_option graph_tracer_opts[] = { 84138988f2eSChangbin Du { .name = "nosleep-time", .value_ptr = &ftrace->graph_nosleep_time }, 842d1bcf17cSChangbin Du { .name = "noirqs", .value_ptr = &ftrace->graph_noirqs }, 84359486fb0SChangbin Du { .name = "verbose", .value_ptr = &ftrace->graph_verbose }, 84400c85d5fSChangbin Du { .name = "thresh", .value_ptr = &ftrace->graph_thresh }, 845a8f87a5cSChangbin Du { .name = "depth", .value_ptr = &ftrace->graph_depth }, 84638988f2eSChangbin Du { .name = NULL, } 84738988f2eSChangbin Du }; 84838988f2eSChangbin Du 84938988f2eSChangbin Du if (unset) 85038988f2eSChangbin Du return 0; 85138988f2eSChangbin Du 85238988f2eSChangbin Du ret = perf_parse_sublevel_options(str, graph_tracer_opts); 85338988f2eSChangbin Du if (ret) 85438988f2eSChangbin Du return ret; 85538988f2eSChangbin Du 85638988f2eSChangbin Du return 0; 85738988f2eSChangbin Du } 85838988f2eSChangbin Du 859eb6d31aeSChangbin Du static void select_tracer(struct perf_ftrace *ftrace) 860eb6d31aeSChangbin Du { 861eb6d31aeSChangbin Du bool graph = !list_empty(&ftrace->graph_funcs) || 862eb6d31aeSChangbin Du !list_empty(&ftrace->nograph_funcs); 863eb6d31aeSChangbin Du bool func = !list_empty(&ftrace->filters) || 864eb6d31aeSChangbin Du !list_empty(&ftrace->notrace); 865eb6d31aeSChangbin Du 866eb6d31aeSChangbin Du /* The function_graph has priority over function tracer. */ 867eb6d31aeSChangbin Du if (graph) 868eb6d31aeSChangbin Du ftrace->tracer = "function_graph"; 869eb6d31aeSChangbin Du else if (func) 870eb6d31aeSChangbin Du ftrace->tracer = "function"; 871eb6d31aeSChangbin Du /* Otherwise, the default tracer is used. */ 872eb6d31aeSChangbin Du 873eb6d31aeSChangbin Du pr_debug("%s tracer is used\n", ftrace->tracer); 874eb6d31aeSChangbin Du } 875eb6d31aeSChangbin Du 876b0ad8ea6SArnaldo Carvalho de Melo int cmd_ftrace(int argc, const char **argv) 877d01f4e8dSNamhyung Kim { 878d01f4e8dSNamhyung Kim int ret; 879d01f4e8dSNamhyung Kim struct perf_ftrace ftrace = { 880bf062bd2STaeung Song .tracer = DEFAULT_TRACER, 881d01f4e8dSNamhyung Kim .target = { .uid = UINT_MAX, }, 882d01f4e8dSNamhyung Kim }; 883d01f4e8dSNamhyung Kim const char * const ftrace_usage[] = { 884a9af6be5SNamhyung Kim "perf ftrace [<options>] [<command>]", 885d01f4e8dSNamhyung Kim "perf ftrace [<options>] -- <command> [<options>]", 886d01f4e8dSNamhyung Kim NULL 887d01f4e8dSNamhyung Kim }; 888d01f4e8dSNamhyung Kim const struct option ftrace_options[] = { 889d01f4e8dSNamhyung Kim OPT_STRING('t', "tracer", &ftrace.tracer, "tracer", 890492e4edbSArnaldo Carvalho de Melo "Tracer to use: function_graph(default) or function"), 891*2ae05fe0SChangbin Du OPT_CALLBACK_DEFAULT('F', "funcs", NULL, "[FILTER]", 892*2ae05fe0SChangbin Du "Show available functions to filter", 893*2ae05fe0SChangbin Du opt_list_avail_functions, "*"), 894a9af6be5SNamhyung Kim OPT_STRING('p', "pid", &ftrace.target.pid, "pid", 895492e4edbSArnaldo Carvalho de Melo "Trace on existing process id"), 89642145d71SChangbin Du /* TODO: Add short option -t after -t/--tracer can be removed. */ 89742145d71SChangbin Du OPT_STRING(0, "tid", &ftrace.target.tid, "tid", 898492e4edbSArnaldo Carvalho de Melo "Trace on existing thread id (exclusive to --pid)"), 899d01f4e8dSNamhyung Kim OPT_INCR('v', "verbose", &verbose, 900492e4edbSArnaldo Carvalho de Melo "Be more verbose"), 901dc231032SNamhyung Kim OPT_BOOLEAN('a', "all-cpus", &ftrace.target.system_wide, 902492e4edbSArnaldo Carvalho de Melo "System-wide collection from all CPUs"), 903dc231032SNamhyung Kim OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu", 904492e4edbSArnaldo Carvalho de Melo "List of cpus to monitor"), 90578b83e8bSNamhyung Kim OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func", 906492e4edbSArnaldo Carvalho de Melo "Trace given functions using function tracer", 907eb6d31aeSChangbin Du parse_filter_func), 90878b83e8bSNamhyung Kim OPT_CALLBACK('N', "notrace-funcs", &ftrace.notrace, "func", 909492e4edbSArnaldo Carvalho de Melo "Do not trace given functions", parse_filter_func), 910b1d84af6SChangbin Du OPT_CALLBACK(0, "func-opts", &ftrace, "options", 911492e4edbSArnaldo Carvalho de Melo "Function tracer options, available options: call-graph,irq-info", 912b1d84af6SChangbin Du parse_func_tracer_opts), 91378b83e8bSNamhyung Kim OPT_CALLBACK('G', "graph-funcs", &ftrace.graph_funcs, "func", 914492e4edbSArnaldo Carvalho de Melo "Trace given functions using function_graph tracer", 915eb6d31aeSChangbin Du parse_filter_func), 91678b83e8bSNamhyung Kim OPT_CALLBACK('g', "nograph-funcs", &ftrace.nograph_funcs, "func", 91778b83e8bSNamhyung Kim "Set nograph filter on given functions", parse_filter_func), 91838988f2eSChangbin Du OPT_CALLBACK(0, "graph-opts", &ftrace, "options", 919492e4edbSArnaldo Carvalho de Melo "Graph tracer options, available options: nosleep-time,noirqs,verbose,thresh=<n>,depth=<n>", 92038988f2eSChangbin Du parse_graph_tracer_opts), 921846e1939SChangbin Du OPT_CALLBACK('m', "buffer-size", &ftrace.percpu_buffer_size, "size", 922492e4edbSArnaldo Carvalho de Melo "Size of per cpu buffer, needs to use a B, K, M or G suffix.", parse_buffer_size), 9235b347472SChangbin Du OPT_BOOLEAN(0, "inherit", &ftrace.inherit, 924492e4edbSArnaldo Carvalho de Melo "Trace children processes"), 9256555c2f6SChangbin Du OPT_UINTEGER('D', "delay", &ftrace.initial_delay, 926492e4edbSArnaldo Carvalho de Melo "Number of milliseconds to wait before starting tracing after program start"), 927d01f4e8dSNamhyung Kim OPT_END() 928d01f4e8dSNamhyung Kim }; 929d01f4e8dSNamhyung Kim 93078b83e8bSNamhyung Kim INIT_LIST_HEAD(&ftrace.filters); 93178b83e8bSNamhyung Kim INIT_LIST_HEAD(&ftrace.notrace); 93278b83e8bSNamhyung Kim INIT_LIST_HEAD(&ftrace.graph_funcs); 93378b83e8bSNamhyung Kim INIT_LIST_HEAD(&ftrace.nograph_funcs); 93478b83e8bSNamhyung Kim 935b05d1093STaeung Song ret = perf_config(perf_ftrace_config, &ftrace); 936b05d1093STaeung Song if (ret < 0) 937b05d1093STaeung Song return -1; 938b05d1093STaeung Song 939d01f4e8dSNamhyung Kim argc = parse_options(argc, argv, ftrace_options, ftrace_usage, 940d01f4e8dSNamhyung Kim PARSE_OPT_STOP_AT_NON_OPTION); 941a9af6be5SNamhyung Kim if (!argc && target__none(&ftrace.target)) 942452b0d16SChangbin Du ftrace.target.system_wide = true; 943d01f4e8dSNamhyung Kim 944eb6d31aeSChangbin Du select_tracer(&ftrace); 945eb6d31aeSChangbin Du 946a9af6be5SNamhyung Kim ret = target__validate(&ftrace.target); 947a9af6be5SNamhyung Kim if (ret) { 948a9af6be5SNamhyung Kim char errbuf[512]; 949a9af6be5SNamhyung Kim 950a9af6be5SNamhyung Kim target__strerror(&ftrace.target, ret, errbuf, 512); 951a9af6be5SNamhyung Kim pr_err("%s\n", errbuf); 95278b83e8bSNamhyung Kim goto out_delete_filters; 953a9af6be5SNamhyung Kim } 954a9af6be5SNamhyung Kim 9550f98b11cSJiri Olsa ftrace.evlist = evlist__new(); 95678b83e8bSNamhyung Kim if (ftrace.evlist == NULL) { 95778b83e8bSNamhyung Kim ret = -ENOMEM; 95878b83e8bSNamhyung Kim goto out_delete_filters; 95978b83e8bSNamhyung Kim } 960d01f4e8dSNamhyung Kim 961d01f4e8dSNamhyung Kim ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target); 962d01f4e8dSNamhyung Kim if (ret < 0) 963d01f4e8dSNamhyung Kim goto out_delete_evlist; 964d01f4e8dSNamhyung Kim 965d01f4e8dSNamhyung Kim ret = __cmd_ftrace(&ftrace, argc, argv); 966d01f4e8dSNamhyung Kim 967d01f4e8dSNamhyung Kim out_delete_evlist: 968c12995a5SJiri Olsa evlist__delete(ftrace.evlist); 969d01f4e8dSNamhyung Kim 97078b83e8bSNamhyung Kim out_delete_filters: 97178b83e8bSNamhyung Kim delete_filter_func(&ftrace.filters); 97278b83e8bSNamhyung Kim delete_filter_func(&ftrace.notrace); 97378b83e8bSNamhyung Kim delete_filter_func(&ftrace.graph_funcs); 97478b83e8bSNamhyung Kim delete_filter_func(&ftrace.nograph_funcs); 97578b83e8bSNamhyung Kim 976d01f4e8dSNamhyung Kim return ret; 977d01f4e8dSNamhyung Kim } 978