18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * builtin-ftrace.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2013 LG Electronics, Namhyung Kim <namhyung@kernel.org> 68c2ecf20Sopenharmony_ci * Copyright (c) 2020 Changbin Du <changbin.du@gmail.com>, significant enhancement. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "builtin.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <errno.h> 128c2ecf20Sopenharmony_ci#include <unistd.h> 138c2ecf20Sopenharmony_ci#include <signal.h> 148c2ecf20Sopenharmony_ci#include <stdlib.h> 158c2ecf20Sopenharmony_ci#include <fcntl.h> 168c2ecf20Sopenharmony_ci#include <poll.h> 178c2ecf20Sopenharmony_ci#include <linux/capability.h> 188c2ecf20Sopenharmony_ci#include <linux/string.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "debug.h" 218c2ecf20Sopenharmony_ci#include <subcmd/pager.h> 228c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h> 238c2ecf20Sopenharmony_ci#include <api/fs/tracing_path.h> 248c2ecf20Sopenharmony_ci#include "evlist.h" 258c2ecf20Sopenharmony_ci#include "target.h" 268c2ecf20Sopenharmony_ci#include "cpumap.h" 278c2ecf20Sopenharmony_ci#include "thread_map.h" 288c2ecf20Sopenharmony_ci#include "strfilter.h" 298c2ecf20Sopenharmony_ci#include "util/cap.h" 308c2ecf20Sopenharmony_ci#include "util/config.h" 318c2ecf20Sopenharmony_ci#include "util/units.h" 328c2ecf20Sopenharmony_ci#include "util/parse-sublevel-options.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define DEFAULT_TRACER "function_graph" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct perf_ftrace { 378c2ecf20Sopenharmony_ci struct evlist *evlist; 388c2ecf20Sopenharmony_ci struct target target; 398c2ecf20Sopenharmony_ci const char *tracer; 408c2ecf20Sopenharmony_ci struct list_head filters; 418c2ecf20Sopenharmony_ci struct list_head notrace; 428c2ecf20Sopenharmony_ci struct list_head graph_funcs; 438c2ecf20Sopenharmony_ci struct list_head nograph_funcs; 448c2ecf20Sopenharmony_ci int graph_depth; 458c2ecf20Sopenharmony_ci unsigned long percpu_buffer_size; 468c2ecf20Sopenharmony_ci bool inherit; 478c2ecf20Sopenharmony_ci int func_stack_trace; 488c2ecf20Sopenharmony_ci int func_irq_info; 498c2ecf20Sopenharmony_ci int graph_nosleep_time; 508c2ecf20Sopenharmony_ci int graph_noirqs; 518c2ecf20Sopenharmony_ci int graph_verbose; 528c2ecf20Sopenharmony_ci int graph_thresh; 538c2ecf20Sopenharmony_ci unsigned int initial_delay; 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistruct filter_entry { 578c2ecf20Sopenharmony_ci struct list_head list; 588c2ecf20Sopenharmony_ci char name[]; 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic volatile int workload_exec_errno; 628c2ecf20Sopenharmony_cistatic bool done; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void sig_handler(int sig __maybe_unused) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci done = true; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* 708c2ecf20Sopenharmony_ci * perf_evlist__prepare_workload will send a SIGUSR1 if the fork fails, since 718c2ecf20Sopenharmony_ci * we asked by setting its exec_error to the function below, 728c2ecf20Sopenharmony_ci * ftrace__workload_exec_failed_signal. 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * XXX We need to handle this more appropriately, emitting an error, etc. 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_cistatic void ftrace__workload_exec_failed_signal(int signo __maybe_unused, 778c2ecf20Sopenharmony_ci siginfo_t *info __maybe_unused, 788c2ecf20Sopenharmony_ci void *ucontext __maybe_unused) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci workload_exec_errno = info->si_value.sival_int; 818c2ecf20Sopenharmony_ci done = true; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int __write_tracing_file(const char *name, const char *val, bool append) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci char *file; 878c2ecf20Sopenharmony_ci int fd, ret = -1; 888c2ecf20Sopenharmony_ci ssize_t size = strlen(val); 898c2ecf20Sopenharmony_ci int flags = O_WRONLY; 908c2ecf20Sopenharmony_ci char errbuf[512]; 918c2ecf20Sopenharmony_ci char *val_copy; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci file = get_tracing_file(name); 948c2ecf20Sopenharmony_ci if (!file) { 958c2ecf20Sopenharmony_ci pr_debug("cannot get tracing file: %s\n", name); 968c2ecf20Sopenharmony_ci return -1; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (append) 1008c2ecf20Sopenharmony_ci flags |= O_APPEND; 1018c2ecf20Sopenharmony_ci else 1028c2ecf20Sopenharmony_ci flags |= O_TRUNC; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci fd = open(file, flags); 1058c2ecf20Sopenharmony_ci if (fd < 0) { 1068c2ecf20Sopenharmony_ci pr_debug("cannot open tracing file: %s: %s\n", 1078c2ecf20Sopenharmony_ci name, str_error_r(errno, errbuf, sizeof(errbuf))); 1088c2ecf20Sopenharmony_ci goto out; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* 1128c2ecf20Sopenharmony_ci * Copy the original value and append a '\n'. Without this, 1138c2ecf20Sopenharmony_ci * the kernel can hide possible errors. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ci val_copy = strdup(val); 1168c2ecf20Sopenharmony_ci if (!val_copy) 1178c2ecf20Sopenharmony_ci goto out_close; 1188c2ecf20Sopenharmony_ci val_copy[size] = '\n'; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (write(fd, val_copy, size + 1) == size + 1) 1218c2ecf20Sopenharmony_ci ret = 0; 1228c2ecf20Sopenharmony_ci else 1238c2ecf20Sopenharmony_ci pr_debug("write '%s' to tracing/%s failed: %s\n", 1248c2ecf20Sopenharmony_ci val, name, str_error_r(errno, errbuf, sizeof(errbuf))); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci free(val_copy); 1278c2ecf20Sopenharmony_ciout_close: 1288c2ecf20Sopenharmony_ci close(fd); 1298c2ecf20Sopenharmony_ciout: 1308c2ecf20Sopenharmony_ci put_tracing_file(file); 1318c2ecf20Sopenharmony_ci return ret; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int write_tracing_file(const char *name, const char *val) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci return __write_tracing_file(name, val, false); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int append_tracing_file(const char *name, const char *val) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci return __write_tracing_file(name, val, true); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int read_tracing_file_to_stdout(const char *name) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci char buf[4096]; 1478c2ecf20Sopenharmony_ci char *file; 1488c2ecf20Sopenharmony_ci int fd; 1498c2ecf20Sopenharmony_ci int ret = -1; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci file = get_tracing_file(name); 1528c2ecf20Sopenharmony_ci if (!file) { 1538c2ecf20Sopenharmony_ci pr_debug("cannot get tracing file: %s\n", name); 1548c2ecf20Sopenharmony_ci return -1; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci fd = open(file, O_RDONLY); 1588c2ecf20Sopenharmony_ci if (fd < 0) { 1598c2ecf20Sopenharmony_ci pr_debug("cannot open tracing file: %s: %s\n", 1608c2ecf20Sopenharmony_ci name, str_error_r(errno, buf, sizeof(buf))); 1618c2ecf20Sopenharmony_ci goto out; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* read contents to stdout */ 1658c2ecf20Sopenharmony_ci while (true) { 1668c2ecf20Sopenharmony_ci int n = read(fd, buf, sizeof(buf)); 1678c2ecf20Sopenharmony_ci if (n == 0) 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci else if (n < 0) 1708c2ecf20Sopenharmony_ci goto out_close; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (fwrite(buf, n, 1, stdout) != 1) 1738c2ecf20Sopenharmony_ci goto out_close; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci ret = 0; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ciout_close: 1788c2ecf20Sopenharmony_ci close(fd); 1798c2ecf20Sopenharmony_ciout: 1808c2ecf20Sopenharmony_ci put_tracing_file(file); 1818c2ecf20Sopenharmony_ci return ret; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int read_tracing_file_by_line(const char *name, 1858c2ecf20Sopenharmony_ci void (*cb)(char *str, void *arg), 1868c2ecf20Sopenharmony_ci void *cb_arg) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci char *line = NULL; 1898c2ecf20Sopenharmony_ci size_t len = 0; 1908c2ecf20Sopenharmony_ci char *file; 1918c2ecf20Sopenharmony_ci FILE *fp; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci file = get_tracing_file(name); 1948c2ecf20Sopenharmony_ci if (!file) { 1958c2ecf20Sopenharmony_ci pr_debug("cannot get tracing file: %s\n", name); 1968c2ecf20Sopenharmony_ci return -1; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci fp = fopen(file, "r"); 2008c2ecf20Sopenharmony_ci if (fp == NULL) { 2018c2ecf20Sopenharmony_ci pr_debug("cannot open tracing file: %s\n", name); 2028c2ecf20Sopenharmony_ci put_tracing_file(file); 2038c2ecf20Sopenharmony_ci return -1; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci while (getline(&line, &len, fp) != -1) { 2078c2ecf20Sopenharmony_ci cb(line, cb_arg); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (line) 2118c2ecf20Sopenharmony_ci free(line); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci fclose(fp); 2148c2ecf20Sopenharmony_ci put_tracing_file(file); 2158c2ecf20Sopenharmony_ci return 0; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int write_tracing_file_int(const char *name, int value) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci char buf[16]; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "%d", value); 2238c2ecf20Sopenharmony_ci if (write_tracing_file(name, buf) < 0) 2248c2ecf20Sopenharmony_ci return -1; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int write_tracing_option_file(const char *name, const char *val) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci char *file; 2328c2ecf20Sopenharmony_ci int ret; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (asprintf(&file, "options/%s", name) < 0) 2358c2ecf20Sopenharmony_ci return -1; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci ret = __write_tracing_file(file, val, false); 2388c2ecf20Sopenharmony_ci free(file); 2398c2ecf20Sopenharmony_ci return ret; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic int reset_tracing_cpu(void); 2438c2ecf20Sopenharmony_cistatic void reset_tracing_filters(void); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic void reset_tracing_options(struct perf_ftrace *ftrace __maybe_unused) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci write_tracing_option_file("function-fork", "0"); 2488c2ecf20Sopenharmony_ci write_tracing_option_file("func_stack_trace", "0"); 2498c2ecf20Sopenharmony_ci write_tracing_option_file("sleep-time", "1"); 2508c2ecf20Sopenharmony_ci write_tracing_option_file("funcgraph-irqs", "1"); 2518c2ecf20Sopenharmony_ci write_tracing_option_file("funcgraph-proc", "0"); 2528c2ecf20Sopenharmony_ci write_tracing_option_file("funcgraph-abstime", "0"); 2538c2ecf20Sopenharmony_ci write_tracing_option_file("latency-format", "0"); 2548c2ecf20Sopenharmony_ci write_tracing_option_file("irq-info", "0"); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci if (write_tracing_file("tracing_on", "0") < 0) 2608c2ecf20Sopenharmony_ci return -1; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (write_tracing_file("current_tracer", "nop") < 0) 2638c2ecf20Sopenharmony_ci return -1; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (write_tracing_file("set_ftrace_pid", " ") < 0) 2668c2ecf20Sopenharmony_ci return -1; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (reset_tracing_cpu() < 0) 2698c2ecf20Sopenharmony_ci return -1; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (write_tracing_file("max_graph_depth", "0") < 0) 2728c2ecf20Sopenharmony_ci return -1; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (write_tracing_file("tracing_thresh", "0") < 0) 2758c2ecf20Sopenharmony_ci return -1; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci reset_tracing_filters(); 2788c2ecf20Sopenharmony_ci reset_tracing_options(ftrace); 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int set_tracing_pid(struct perf_ftrace *ftrace) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci int i; 2858c2ecf20Sopenharmony_ci char buf[16]; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (target__has_cpu(&ftrace->target)) 2888c2ecf20Sopenharmony_ci return 0; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci for (i = 0; i < perf_thread_map__nr(ftrace->evlist->core.threads); i++) { 2918c2ecf20Sopenharmony_ci scnprintf(buf, sizeof(buf), "%d", 2928c2ecf20Sopenharmony_ci perf_thread_map__pid(ftrace->evlist->core.threads, i)); 2938c2ecf20Sopenharmony_ci if (append_tracing_file("set_ftrace_pid", buf) < 0) 2948c2ecf20Sopenharmony_ci return -1; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic int set_tracing_cpumask(struct perf_cpu_map *cpumap) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci char *cpumask; 3028c2ecf20Sopenharmony_ci size_t mask_size; 3038c2ecf20Sopenharmony_ci int ret; 3048c2ecf20Sopenharmony_ci int last_cpu; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci last_cpu = cpu_map__cpu(cpumap, cpumap->nr - 1); 3078c2ecf20Sopenharmony_ci mask_size = last_cpu / 4 + 2; /* one more byte for EOS */ 3088c2ecf20Sopenharmony_ci mask_size += last_cpu / 32; /* ',' is needed for every 32th cpus */ 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci cpumask = malloc(mask_size); 3118c2ecf20Sopenharmony_ci if (cpumask == NULL) { 3128c2ecf20Sopenharmony_ci pr_debug("failed to allocate cpu mask\n"); 3138c2ecf20Sopenharmony_ci return -1; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci cpu_map__snprint_mask(cpumap, cpumask, mask_size); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci ret = write_tracing_file("tracing_cpumask", cpumask); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci free(cpumask); 3218c2ecf20Sopenharmony_ci return ret; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic int set_tracing_cpu(struct perf_ftrace *ftrace) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct perf_cpu_map *cpumap = ftrace->evlist->core.cpus; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (!target__has_cpu(&ftrace->target)) 3298c2ecf20Sopenharmony_ci return 0; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return set_tracing_cpumask(cpumap); 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic int set_tracing_func_stack_trace(struct perf_ftrace *ftrace) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci if (!ftrace->func_stack_trace) 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (write_tracing_option_file("func_stack_trace", "1") < 0) 3408c2ecf20Sopenharmony_ci return -1; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic int set_tracing_func_irqinfo(struct perf_ftrace *ftrace) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci if (!ftrace->func_irq_info) 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (write_tracing_option_file("irq-info", "1") < 0) 3518c2ecf20Sopenharmony_ci return -1; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return 0; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic int reset_tracing_cpu(void) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct perf_cpu_map *cpumap = perf_cpu_map__new(NULL); 3598c2ecf20Sopenharmony_ci int ret; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci ret = set_tracing_cpumask(cpumap); 3628c2ecf20Sopenharmony_ci perf_cpu_map__put(cpumap); 3638c2ecf20Sopenharmony_ci return ret; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int __set_tracing_filter(const char *filter_file, struct list_head *funcs) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct filter_entry *pos; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci list_for_each_entry(pos, funcs, list) { 3718c2ecf20Sopenharmony_ci if (append_tracing_file(filter_file, pos->name) < 0) 3728c2ecf20Sopenharmony_ci return -1; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return 0; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic int set_tracing_filters(struct perf_ftrace *ftrace) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci int ret; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci ret = __set_tracing_filter("set_ftrace_filter", &ftrace->filters); 3838c2ecf20Sopenharmony_ci if (ret < 0) 3848c2ecf20Sopenharmony_ci return ret; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci ret = __set_tracing_filter("set_ftrace_notrace", &ftrace->notrace); 3878c2ecf20Sopenharmony_ci if (ret < 0) 3888c2ecf20Sopenharmony_ci return ret; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci ret = __set_tracing_filter("set_graph_function", &ftrace->graph_funcs); 3918c2ecf20Sopenharmony_ci if (ret < 0) 3928c2ecf20Sopenharmony_ci return ret; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* old kernels do not have this filter */ 3958c2ecf20Sopenharmony_ci __set_tracing_filter("set_graph_notrace", &ftrace->nograph_funcs); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return ret; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic void reset_tracing_filters(void) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci write_tracing_file("set_ftrace_filter", " "); 4038c2ecf20Sopenharmony_ci write_tracing_file("set_ftrace_notrace", " "); 4048c2ecf20Sopenharmony_ci write_tracing_file("set_graph_function", " "); 4058c2ecf20Sopenharmony_ci write_tracing_file("set_graph_notrace", " "); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic int set_tracing_depth(struct perf_ftrace *ftrace) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci if (ftrace->graph_depth == 0) 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (ftrace->graph_depth < 0) { 4148c2ecf20Sopenharmony_ci pr_err("invalid graph depth: %d\n", ftrace->graph_depth); 4158c2ecf20Sopenharmony_ci return -1; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (write_tracing_file_int("max_graph_depth", ftrace->graph_depth) < 0) 4198c2ecf20Sopenharmony_ci return -1; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic int set_tracing_percpu_buffer_size(struct perf_ftrace *ftrace) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci int ret; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (ftrace->percpu_buffer_size == 0) 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci ret = write_tracing_file_int("buffer_size_kb", 4328c2ecf20Sopenharmony_ci ftrace->percpu_buffer_size / 1024); 4338c2ecf20Sopenharmony_ci if (ret < 0) 4348c2ecf20Sopenharmony_ci return ret; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int set_tracing_trace_inherit(struct perf_ftrace *ftrace) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci if (!ftrace->inherit) 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (write_tracing_option_file("function-fork", "1") < 0) 4458c2ecf20Sopenharmony_ci return -1; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic int set_tracing_sleep_time(struct perf_ftrace *ftrace) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci if (!ftrace->graph_nosleep_time) 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (write_tracing_option_file("sleep-time", "0") < 0) 4568c2ecf20Sopenharmony_ci return -1; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return 0; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int set_tracing_funcgraph_irqs(struct perf_ftrace *ftrace) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci if (!ftrace->graph_noirqs) 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (write_tracing_option_file("funcgraph-irqs", "0") < 0) 4678c2ecf20Sopenharmony_ci return -1; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic int set_tracing_funcgraph_verbose(struct perf_ftrace *ftrace) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci if (!ftrace->graph_verbose) 4758c2ecf20Sopenharmony_ci return 0; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (write_tracing_option_file("funcgraph-proc", "1") < 0) 4788c2ecf20Sopenharmony_ci return -1; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (write_tracing_option_file("funcgraph-abstime", "1") < 0) 4818c2ecf20Sopenharmony_ci return -1; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (write_tracing_option_file("latency-format", "1") < 0) 4848c2ecf20Sopenharmony_ci return -1; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic int set_tracing_thresh(struct perf_ftrace *ftrace) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci int ret; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (ftrace->graph_thresh == 0) 4948c2ecf20Sopenharmony_ci return 0; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci ret = write_tracing_file_int("tracing_thresh", ftrace->graph_thresh); 4978c2ecf20Sopenharmony_ci if (ret < 0) 4988c2ecf20Sopenharmony_ci return ret; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic int set_tracing_options(struct perf_ftrace *ftrace) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci if (set_tracing_pid(ftrace) < 0) { 5068c2ecf20Sopenharmony_ci pr_err("failed to set ftrace pid\n"); 5078c2ecf20Sopenharmony_ci return -1; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (set_tracing_cpu(ftrace) < 0) { 5118c2ecf20Sopenharmony_ci pr_err("failed to set tracing cpumask\n"); 5128c2ecf20Sopenharmony_ci return -1; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (set_tracing_func_stack_trace(ftrace) < 0) { 5168c2ecf20Sopenharmony_ci pr_err("failed to set tracing option func_stack_trace\n"); 5178c2ecf20Sopenharmony_ci return -1; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (set_tracing_func_irqinfo(ftrace) < 0) { 5218c2ecf20Sopenharmony_ci pr_err("failed to set tracing option irq-info\n"); 5228c2ecf20Sopenharmony_ci return -1; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (set_tracing_filters(ftrace) < 0) { 5268c2ecf20Sopenharmony_ci pr_err("failed to set tracing filters\n"); 5278c2ecf20Sopenharmony_ci return -1; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (set_tracing_depth(ftrace) < 0) { 5318c2ecf20Sopenharmony_ci pr_err("failed to set graph depth\n"); 5328c2ecf20Sopenharmony_ci return -1; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (set_tracing_percpu_buffer_size(ftrace) < 0) { 5368c2ecf20Sopenharmony_ci pr_err("failed to set tracing per-cpu buffer size\n"); 5378c2ecf20Sopenharmony_ci return -1; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (set_tracing_trace_inherit(ftrace) < 0) { 5418c2ecf20Sopenharmony_ci pr_err("failed to set tracing option function-fork\n"); 5428c2ecf20Sopenharmony_ci return -1; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (set_tracing_sleep_time(ftrace) < 0) { 5468c2ecf20Sopenharmony_ci pr_err("failed to set tracing option sleep-time\n"); 5478c2ecf20Sopenharmony_ci return -1; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (set_tracing_funcgraph_irqs(ftrace) < 0) { 5518c2ecf20Sopenharmony_ci pr_err("failed to set tracing option funcgraph-irqs\n"); 5528c2ecf20Sopenharmony_ci return -1; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (set_tracing_funcgraph_verbose(ftrace) < 0) { 5568c2ecf20Sopenharmony_ci pr_err("failed to set tracing option funcgraph-proc/funcgraph-abstime\n"); 5578c2ecf20Sopenharmony_ci return -1; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (set_tracing_thresh(ftrace) < 0) { 5618c2ecf20Sopenharmony_ci pr_err("failed to set tracing thresh\n"); 5628c2ecf20Sopenharmony_ci return -1; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return 0; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci char *trace_file; 5718c2ecf20Sopenharmony_ci int trace_fd; 5728c2ecf20Sopenharmony_ci char buf[4096]; 5738c2ecf20Sopenharmony_ci struct pollfd pollfd = { 5748c2ecf20Sopenharmony_ci .events = POLLIN, 5758c2ecf20Sopenharmony_ci }; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (!(perf_cap__capable(CAP_PERFMON) || 5788c2ecf20Sopenharmony_ci perf_cap__capable(CAP_SYS_ADMIN))) { 5798c2ecf20Sopenharmony_ci pr_err("ftrace only works for %s!\n", 5808c2ecf20Sopenharmony_ci#ifdef HAVE_LIBCAP_SUPPORT 5818c2ecf20Sopenharmony_ci "users with the CAP_PERFMON or CAP_SYS_ADMIN capability" 5828c2ecf20Sopenharmony_ci#else 5838c2ecf20Sopenharmony_ci "root" 5848c2ecf20Sopenharmony_ci#endif 5858c2ecf20Sopenharmony_ci ); 5868c2ecf20Sopenharmony_ci return -1; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci signal(SIGINT, sig_handler); 5908c2ecf20Sopenharmony_ci signal(SIGUSR1, sig_handler); 5918c2ecf20Sopenharmony_ci signal(SIGCHLD, sig_handler); 5928c2ecf20Sopenharmony_ci signal(SIGPIPE, sig_handler); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (reset_tracing_files(ftrace) < 0) { 5958c2ecf20Sopenharmony_ci pr_err("failed to reset ftrace\n"); 5968c2ecf20Sopenharmony_ci goto out; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* reset ftrace buffer */ 6008c2ecf20Sopenharmony_ci if (write_tracing_file("trace", "0") < 0) 6018c2ecf20Sopenharmony_ci goto out; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (argc && perf_evlist__prepare_workload(ftrace->evlist, 6048c2ecf20Sopenharmony_ci &ftrace->target, argv, false, 6058c2ecf20Sopenharmony_ci ftrace__workload_exec_failed_signal) < 0) { 6068c2ecf20Sopenharmony_ci goto out; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (set_tracing_options(ftrace) < 0) 6108c2ecf20Sopenharmony_ci goto out_reset; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { 6138c2ecf20Sopenharmony_ci pr_err("failed to set current_tracer to %s\n", ftrace->tracer); 6148c2ecf20Sopenharmony_ci goto out_reset; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci setup_pager(); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci trace_file = get_tracing_file("trace_pipe"); 6208c2ecf20Sopenharmony_ci if (!trace_file) { 6218c2ecf20Sopenharmony_ci pr_err("failed to open trace_pipe\n"); 6228c2ecf20Sopenharmony_ci goto out_reset; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci trace_fd = open(trace_file, O_RDONLY); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci put_tracing_file(trace_file); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (trace_fd < 0) { 6308c2ecf20Sopenharmony_ci pr_err("failed to open trace_pipe\n"); 6318c2ecf20Sopenharmony_ci goto out_reset; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci fcntl(trace_fd, F_SETFL, O_NONBLOCK); 6358c2ecf20Sopenharmony_ci pollfd.fd = trace_fd; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* display column headers */ 6388c2ecf20Sopenharmony_ci read_tracing_file_to_stdout("trace"); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (!ftrace->initial_delay) { 6418c2ecf20Sopenharmony_ci if (write_tracing_file("tracing_on", "1") < 0) { 6428c2ecf20Sopenharmony_ci pr_err("can't enable tracing\n"); 6438c2ecf20Sopenharmony_ci goto out_close_fd; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci perf_evlist__start_workload(ftrace->evlist); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci if (ftrace->initial_delay) { 6508c2ecf20Sopenharmony_ci usleep(ftrace->initial_delay * 1000); 6518c2ecf20Sopenharmony_ci if (write_tracing_file("tracing_on", "1") < 0) { 6528c2ecf20Sopenharmony_ci pr_err("can't enable tracing\n"); 6538c2ecf20Sopenharmony_ci goto out_close_fd; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci while (!done) { 6588c2ecf20Sopenharmony_ci if (poll(&pollfd, 1, -1) < 0) 6598c2ecf20Sopenharmony_ci break; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (pollfd.revents & POLLIN) { 6628c2ecf20Sopenharmony_ci int n = read(trace_fd, buf, sizeof(buf)); 6638c2ecf20Sopenharmony_ci if (n < 0) 6648c2ecf20Sopenharmony_ci break; 6658c2ecf20Sopenharmony_ci if (fwrite(buf, n, 1, stdout) != 1) 6668c2ecf20Sopenharmony_ci break; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci write_tracing_file("tracing_on", "0"); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (workload_exec_errno) { 6738c2ecf20Sopenharmony_ci const char *emsg = str_error_r(workload_exec_errno, buf, sizeof(buf)); 6748c2ecf20Sopenharmony_ci /* flush stdout first so below error msg appears at the end. */ 6758c2ecf20Sopenharmony_ci fflush(stdout); 6768c2ecf20Sopenharmony_ci pr_err("workload failed: %s\n", emsg); 6778c2ecf20Sopenharmony_ci goto out_close_fd; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* read remaining buffer contents */ 6818c2ecf20Sopenharmony_ci while (true) { 6828c2ecf20Sopenharmony_ci int n = read(trace_fd, buf, sizeof(buf)); 6838c2ecf20Sopenharmony_ci if (n <= 0) 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci if (fwrite(buf, n, 1, stdout) != 1) 6868c2ecf20Sopenharmony_ci break; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ciout_close_fd: 6908c2ecf20Sopenharmony_ci close(trace_fd); 6918c2ecf20Sopenharmony_ciout_reset: 6928c2ecf20Sopenharmony_ci reset_tracing_files(ftrace); 6938c2ecf20Sopenharmony_ciout: 6948c2ecf20Sopenharmony_ci return (done && !workload_exec_errno) ? 0 : -1; 6958c2ecf20Sopenharmony_ci} 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cistatic int perf_ftrace_config(const char *var, const char *value, void *cb) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci struct perf_ftrace *ftrace = cb; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (!strstarts(var, "ftrace.")) 7028c2ecf20Sopenharmony_ci return 0; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci if (strcmp(var, "ftrace.tracer")) 7058c2ecf20Sopenharmony_ci return -1; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (!strcmp(value, "function_graph") || 7088c2ecf20Sopenharmony_ci !strcmp(value, "function")) { 7098c2ecf20Sopenharmony_ci ftrace->tracer = value; 7108c2ecf20Sopenharmony_ci return 0; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci pr_err("Please select \"function_graph\" (default) or \"function\"\n"); 7148c2ecf20Sopenharmony_ci return -1; 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_cistatic void list_function_cb(char *str, void *arg) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci struct strfilter *filter = (struct strfilter *)arg; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (strfilter__compare(filter, str)) 7228c2ecf20Sopenharmony_ci printf("%s", str); 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic int opt_list_avail_functions(const struct option *opt __maybe_unused, 7268c2ecf20Sopenharmony_ci const char *str, int unset) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci struct strfilter *filter; 7298c2ecf20Sopenharmony_ci const char *err = NULL; 7308c2ecf20Sopenharmony_ci int ret; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci if (unset || !str) 7338c2ecf20Sopenharmony_ci return -1; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci filter = strfilter__new(str, &err); 7368c2ecf20Sopenharmony_ci if (!filter) 7378c2ecf20Sopenharmony_ci return err ? -EINVAL : -ENOMEM; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci ret = strfilter__or(filter, str, &err); 7408c2ecf20Sopenharmony_ci if (ret == -EINVAL) { 7418c2ecf20Sopenharmony_ci pr_err("Filter parse error at %td.\n", err - str + 1); 7428c2ecf20Sopenharmony_ci pr_err("Source: \"%s\"\n", str); 7438c2ecf20Sopenharmony_ci pr_err(" %*c\n", (int)(err - str + 1), '^'); 7448c2ecf20Sopenharmony_ci strfilter__delete(filter); 7458c2ecf20Sopenharmony_ci return ret; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci ret = read_tracing_file_by_line("available_filter_functions", 7498c2ecf20Sopenharmony_ci list_function_cb, filter); 7508c2ecf20Sopenharmony_ci strfilter__delete(filter); 7518c2ecf20Sopenharmony_ci if (ret < 0) 7528c2ecf20Sopenharmony_ci return ret; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci exit(0); 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic int parse_filter_func(const struct option *opt, const char *str, 7588c2ecf20Sopenharmony_ci int unset __maybe_unused) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct list_head *head = opt->value; 7618c2ecf20Sopenharmony_ci struct filter_entry *entry; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci entry = malloc(sizeof(*entry) + strlen(str) + 1); 7648c2ecf20Sopenharmony_ci if (entry == NULL) 7658c2ecf20Sopenharmony_ci return -ENOMEM; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci strcpy(entry->name, str); 7688c2ecf20Sopenharmony_ci list_add_tail(&entry->list, head); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci return 0; 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_cistatic void delete_filter_func(struct list_head *head) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci struct filter_entry *pos, *tmp; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci list_for_each_entry_safe(pos, tmp, head, list) { 7788c2ecf20Sopenharmony_ci list_del_init(&pos->list); 7798c2ecf20Sopenharmony_ci free(pos); 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic int parse_buffer_size(const struct option *opt, 7848c2ecf20Sopenharmony_ci const char *str, int unset) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci unsigned long *s = (unsigned long *)opt->value; 7878c2ecf20Sopenharmony_ci static struct parse_tag tags_size[] = { 7888c2ecf20Sopenharmony_ci { .tag = 'B', .mult = 1 }, 7898c2ecf20Sopenharmony_ci { .tag = 'K', .mult = 1 << 10 }, 7908c2ecf20Sopenharmony_ci { .tag = 'M', .mult = 1 << 20 }, 7918c2ecf20Sopenharmony_ci { .tag = 'G', .mult = 1 << 30 }, 7928c2ecf20Sopenharmony_ci { .tag = 0 }, 7938c2ecf20Sopenharmony_ci }; 7948c2ecf20Sopenharmony_ci unsigned long val; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (unset) { 7978c2ecf20Sopenharmony_ci *s = 0; 7988c2ecf20Sopenharmony_ci return 0; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci val = parse_tag_value(str, tags_size); 8028c2ecf20Sopenharmony_ci if (val != (unsigned long) -1) { 8038c2ecf20Sopenharmony_ci if (val < 1024) { 8048c2ecf20Sopenharmony_ci pr_err("buffer size too small, must larger than 1KB."); 8058c2ecf20Sopenharmony_ci return -1; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci *s = val; 8088c2ecf20Sopenharmony_ci return 0; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci return -1; 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic int parse_func_tracer_opts(const struct option *opt, 8158c2ecf20Sopenharmony_ci const char *str, int unset) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci int ret; 8188c2ecf20Sopenharmony_ci struct perf_ftrace *ftrace = (struct perf_ftrace *) opt->value; 8198c2ecf20Sopenharmony_ci struct sublevel_option func_tracer_opts[] = { 8208c2ecf20Sopenharmony_ci { .name = "call-graph", .value_ptr = &ftrace->func_stack_trace }, 8218c2ecf20Sopenharmony_ci { .name = "irq-info", .value_ptr = &ftrace->func_irq_info }, 8228c2ecf20Sopenharmony_ci { .name = NULL, } 8238c2ecf20Sopenharmony_ci }; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci if (unset) 8268c2ecf20Sopenharmony_ci return 0; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci ret = perf_parse_sublevel_options(str, func_tracer_opts); 8298c2ecf20Sopenharmony_ci if (ret) 8308c2ecf20Sopenharmony_ci return ret; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci return 0; 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cistatic int parse_graph_tracer_opts(const struct option *opt, 8368c2ecf20Sopenharmony_ci const char *str, int unset) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci int ret; 8398c2ecf20Sopenharmony_ci struct perf_ftrace *ftrace = (struct perf_ftrace *) opt->value; 8408c2ecf20Sopenharmony_ci struct sublevel_option graph_tracer_opts[] = { 8418c2ecf20Sopenharmony_ci { .name = "nosleep-time", .value_ptr = &ftrace->graph_nosleep_time }, 8428c2ecf20Sopenharmony_ci { .name = "noirqs", .value_ptr = &ftrace->graph_noirqs }, 8438c2ecf20Sopenharmony_ci { .name = "verbose", .value_ptr = &ftrace->graph_verbose }, 8448c2ecf20Sopenharmony_ci { .name = "thresh", .value_ptr = &ftrace->graph_thresh }, 8458c2ecf20Sopenharmony_ci { .name = "depth", .value_ptr = &ftrace->graph_depth }, 8468c2ecf20Sopenharmony_ci { .name = NULL, } 8478c2ecf20Sopenharmony_ci }; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (unset) 8508c2ecf20Sopenharmony_ci return 0; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci ret = perf_parse_sublevel_options(str, graph_tracer_opts); 8538c2ecf20Sopenharmony_ci if (ret) 8548c2ecf20Sopenharmony_ci return ret; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci return 0; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cistatic void select_tracer(struct perf_ftrace *ftrace) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci bool graph = !list_empty(&ftrace->graph_funcs) || 8628c2ecf20Sopenharmony_ci !list_empty(&ftrace->nograph_funcs); 8638c2ecf20Sopenharmony_ci bool func = !list_empty(&ftrace->filters) || 8648c2ecf20Sopenharmony_ci !list_empty(&ftrace->notrace); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* The function_graph has priority over function tracer. */ 8678c2ecf20Sopenharmony_ci if (graph) 8688c2ecf20Sopenharmony_ci ftrace->tracer = "function_graph"; 8698c2ecf20Sopenharmony_ci else if (func) 8708c2ecf20Sopenharmony_ci ftrace->tracer = "function"; 8718c2ecf20Sopenharmony_ci /* Otherwise, the default tracer is used. */ 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci pr_debug("%s tracer is used\n", ftrace->tracer); 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ciint cmd_ftrace(int argc, const char **argv) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci int ret; 8798c2ecf20Sopenharmony_ci struct perf_ftrace ftrace = { 8808c2ecf20Sopenharmony_ci .tracer = DEFAULT_TRACER, 8818c2ecf20Sopenharmony_ci .target = { .uid = UINT_MAX, }, 8828c2ecf20Sopenharmony_ci }; 8838c2ecf20Sopenharmony_ci const char * const ftrace_usage[] = { 8848c2ecf20Sopenharmony_ci "perf ftrace [<options>] [<command>]", 8858c2ecf20Sopenharmony_ci "perf ftrace [<options>] -- <command> [<options>]", 8868c2ecf20Sopenharmony_ci NULL 8878c2ecf20Sopenharmony_ci }; 8888c2ecf20Sopenharmony_ci const struct option ftrace_options[] = { 8898c2ecf20Sopenharmony_ci OPT_STRING('t', "tracer", &ftrace.tracer, "tracer", 8908c2ecf20Sopenharmony_ci "Tracer to use: function_graph(default) or function"), 8918c2ecf20Sopenharmony_ci OPT_CALLBACK_DEFAULT('F', "funcs", NULL, "[FILTER]", 8928c2ecf20Sopenharmony_ci "Show available functions to filter", 8938c2ecf20Sopenharmony_ci opt_list_avail_functions, "*"), 8948c2ecf20Sopenharmony_ci OPT_STRING('p', "pid", &ftrace.target.pid, "pid", 8958c2ecf20Sopenharmony_ci "Trace on existing process id"), 8968c2ecf20Sopenharmony_ci /* TODO: Add short option -t after -t/--tracer can be removed. */ 8978c2ecf20Sopenharmony_ci OPT_STRING(0, "tid", &ftrace.target.tid, "tid", 8988c2ecf20Sopenharmony_ci "Trace on existing thread id (exclusive to --pid)"), 8998c2ecf20Sopenharmony_ci OPT_INCR('v', "verbose", &verbose, 9008c2ecf20Sopenharmony_ci "Be more verbose"), 9018c2ecf20Sopenharmony_ci OPT_BOOLEAN('a', "all-cpus", &ftrace.target.system_wide, 9028c2ecf20Sopenharmony_ci "System-wide collection from all CPUs"), 9038c2ecf20Sopenharmony_ci OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu", 9048c2ecf20Sopenharmony_ci "List of cpus to monitor"), 9058c2ecf20Sopenharmony_ci OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func", 9068c2ecf20Sopenharmony_ci "Trace given functions using function tracer", 9078c2ecf20Sopenharmony_ci parse_filter_func), 9088c2ecf20Sopenharmony_ci OPT_CALLBACK('N', "notrace-funcs", &ftrace.notrace, "func", 9098c2ecf20Sopenharmony_ci "Do not trace given functions", parse_filter_func), 9108c2ecf20Sopenharmony_ci OPT_CALLBACK(0, "func-opts", &ftrace, "options", 9118c2ecf20Sopenharmony_ci "Function tracer options, available options: call-graph,irq-info", 9128c2ecf20Sopenharmony_ci parse_func_tracer_opts), 9138c2ecf20Sopenharmony_ci OPT_CALLBACK('G', "graph-funcs", &ftrace.graph_funcs, "func", 9148c2ecf20Sopenharmony_ci "Trace given functions using function_graph tracer", 9158c2ecf20Sopenharmony_ci parse_filter_func), 9168c2ecf20Sopenharmony_ci OPT_CALLBACK('g', "nograph-funcs", &ftrace.nograph_funcs, "func", 9178c2ecf20Sopenharmony_ci "Set nograph filter on given functions", parse_filter_func), 9188c2ecf20Sopenharmony_ci OPT_CALLBACK(0, "graph-opts", &ftrace, "options", 9198c2ecf20Sopenharmony_ci "Graph tracer options, available options: nosleep-time,noirqs,verbose,thresh=<n>,depth=<n>", 9208c2ecf20Sopenharmony_ci parse_graph_tracer_opts), 9218c2ecf20Sopenharmony_ci OPT_CALLBACK('m', "buffer-size", &ftrace.percpu_buffer_size, "size", 9228c2ecf20Sopenharmony_ci "Size of per cpu buffer, needs to use a B, K, M or G suffix.", parse_buffer_size), 9238c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "inherit", &ftrace.inherit, 9248c2ecf20Sopenharmony_ci "Trace children processes"), 9258c2ecf20Sopenharmony_ci OPT_UINTEGER('D', "delay", &ftrace.initial_delay, 9268c2ecf20Sopenharmony_ci "Number of milliseconds to wait before starting tracing after program start"), 9278c2ecf20Sopenharmony_ci OPT_END() 9288c2ecf20Sopenharmony_ci }; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ftrace.filters); 9318c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ftrace.notrace); 9328c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ftrace.graph_funcs); 9338c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ftrace.nograph_funcs); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci ret = perf_config(perf_ftrace_config, &ftrace); 9368c2ecf20Sopenharmony_ci if (ret < 0) 9378c2ecf20Sopenharmony_ci return -1; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci argc = parse_options(argc, argv, ftrace_options, ftrace_usage, 9408c2ecf20Sopenharmony_ci PARSE_OPT_STOP_AT_NON_OPTION); 9418c2ecf20Sopenharmony_ci if (!argc && target__none(&ftrace.target)) 9428c2ecf20Sopenharmony_ci ftrace.target.system_wide = true; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci select_tracer(&ftrace); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci ret = target__validate(&ftrace.target); 9478c2ecf20Sopenharmony_ci if (ret) { 9488c2ecf20Sopenharmony_ci char errbuf[512]; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci target__strerror(&ftrace.target, ret, errbuf, 512); 9518c2ecf20Sopenharmony_ci pr_err("%s\n", errbuf); 9528c2ecf20Sopenharmony_ci goto out_delete_filters; 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci ftrace.evlist = evlist__new(); 9568c2ecf20Sopenharmony_ci if (ftrace.evlist == NULL) { 9578c2ecf20Sopenharmony_ci ret = -ENOMEM; 9588c2ecf20Sopenharmony_ci goto out_delete_filters; 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target); 9628c2ecf20Sopenharmony_ci if (ret < 0) 9638c2ecf20Sopenharmony_ci goto out_delete_evlist; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci ret = __cmd_ftrace(&ftrace, argc, argv); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ciout_delete_evlist: 9688c2ecf20Sopenharmony_ci evlist__delete(ftrace.evlist); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ciout_delete_filters: 9718c2ecf20Sopenharmony_ci delete_filter_func(&ftrace.filters); 9728c2ecf20Sopenharmony_ci delete_filter_func(&ftrace.notrace); 9738c2ecf20Sopenharmony_ci delete_filter_func(&ftrace.graph_funcs); 9748c2ecf20Sopenharmony_ci delete_filter_func(&ftrace.nograph_funcs); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci return ret; 9778c2ecf20Sopenharmony_ci} 978