Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf ftrace: Use process/session specific trace settings

Executing 'perf ftrace' commands 'ftrace', 'profile' and 'latency' leave
tracing disabled as can seen in this output:

# echo 1 > /sys/kernel/debug/tracing/tracing_on
# cat /sys/kernel/debug/tracing/tracing_on
1
# perf ftrace trace --graph-opts depth=5 sleep 0.1 > /dev/null
# cat /sys/kernel/debug/tracing/tracing_on
0
#

The 'tracing_on' file is not restored to its value before the command.

To fix that this patch uses the .../tracing/instances/XXX subdirectory
feature.

Each 'perf ftrace' invocation creates its own session/process
specific subdirectory and does not change the global state
in the .../tracing directory itself.

Use rmdir(../tracing/instances/dir) to stop process/session specific
tracing and delete all process/session specific setings.

Reported-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Suggested-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Sumanth Korikkar <sumanthk@linux.ibm.com>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Link: https://lore.kernel.org/r/20250520093726.2009696-1-tmricht@linux.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Thomas Richter and committed by
Arnaldo Carvalho de Melo
ba5f102e e48b92f9

+87 -14
+87 -14
tools/perf/builtin-ftrace.c
··· 19 19 #include <ctype.h> 20 20 #include <linux/capability.h> 21 21 #include <linux/string.h> 22 + #include <sys/stat.h> 22 23 23 24 #include "debug.h" 24 25 #include <subcmd/pager.h> ··· 45 44 static volatile sig_atomic_t done; 46 45 47 46 static struct stats latency_stats; /* for tracepoints */ 47 + 48 + static char tracing_instance[PATH_MAX]; /* Trace instance directory */ 48 49 49 50 static void sig_handler(int sig __maybe_unused) 50 51 { ··· 103 100 return supported; 104 101 } 105 102 103 + /* 104 + * Wrapper to test if a file in directory .../tracing/instances/XXX 105 + * exists. If so return the .../tracing/instances/XXX file for use. 106 + * Otherwise the file exists only in directory .../tracing and 107 + * is applicable to all instances, for example file available_filter_functions. 108 + * Return that file name in this case. 109 + * 110 + * This functions works similar to get_tracing_file() and expects its caller 111 + * to free the returned file name. 112 + * 113 + * The global variable tracing_instance is set in init_tracing_instance() 114 + * called at the beginning to a process specific tracing subdirectory. 115 + */ 116 + static char *get_tracing_instance_file(const char *name) 117 + { 118 + char *file; 119 + 120 + if (asprintf(&file, "%s/%s", tracing_instance, name) < 0) 121 + return NULL; 122 + 123 + if (!access(file, F_OK)) 124 + return file; 125 + 126 + free(file); 127 + file = get_tracing_file(name); 128 + return file; 129 + } 130 + 106 131 static int __write_tracing_file(const char *name, const char *val, bool append) 107 132 { 108 133 char *file; ··· 140 109 char errbuf[512]; 141 110 char *val_copy; 142 111 143 - file = get_tracing_file(name); 112 + file = get_tracing_instance_file(name); 144 113 if (!file) { 145 114 pr_debug("cannot get tracing file: %s\n", name); 146 115 return -1; ··· 198 167 int fd; 199 168 int ret = -1; 200 169 201 - file = get_tracing_file(name); 170 + file = get_tracing_instance_file(name); 202 171 if (!file) { 203 172 pr_debug("cannot get tracing file: %s\n", name); 204 173 return -1; ··· 240 209 char *file; 241 210 FILE *fp; 242 211 243 - file = get_tracing_file(name); 212 + file = get_tracing_instance_file(name); 244 213 if (!file) { 245 214 pr_debug("cannot get tracing file: %s\n", name); 246 215 return -1; ··· 328 297 reset_tracing_filters(); 329 298 reset_tracing_options(ftrace); 330 299 return 0; 300 + } 301 + 302 + /* Remove .../tracing/instances/XXX subdirectory created with 303 + * init_tracing_instance(). 304 + */ 305 + static void exit_tracing_instance(void) 306 + { 307 + if (rmdir(tracing_instance)) 308 + pr_err("failed to delete tracing/instances directory\n"); 309 + } 310 + 311 + /* Create subdirectory within .../tracing/instances/XXX to have session 312 + * or process specific setup. To delete this setup, simply remove the 313 + * subdirectory. 314 + */ 315 + static int init_tracing_instance(void) 316 + { 317 + char dirname[] = "instances/perf-ftrace-XXXXXX"; 318 + char *path; 319 + 320 + path = get_tracing_file(dirname); 321 + if (!path) 322 + goto error; 323 + strncpy(tracing_instance, path, sizeof(tracing_instance) - 1); 324 + put_tracing_file(path); 325 + path = mkdtemp(tracing_instance); 326 + if (!path) 327 + goto error; 328 + return 0; 329 + 330 + error: 331 + pr_err("failed to create tracing/instances directory\n"); 332 + return -1; 331 333 } 332 334 333 335 static int set_tracing_pid(struct perf_ftrace *ftrace) ··· 693 629 694 630 select_tracer(ftrace); 695 631 632 + if (init_tracing_instance() < 0) 633 + goto out; 634 + 696 635 if (reset_tracing_files(ftrace) < 0) { 697 636 pr_err("failed to reset ftrace\n"); 698 - goto out; 637 + goto out_reset; 699 638 } 700 639 701 640 /* reset ftrace buffer */ 702 641 if (write_tracing_file("trace", "0") < 0) 703 - goto out; 642 + goto out_reset; 704 643 705 644 if (set_tracing_options(ftrace) < 0) 706 645 goto out_reset; ··· 715 648 716 649 setup_pager(); 717 650 718 - trace_file = get_tracing_file("trace_pipe"); 651 + trace_file = get_tracing_instance_file("trace_pipe"); 719 652 if (!trace_file) { 720 653 pr_err("failed to open trace_pipe\n"); 721 654 goto out_reset; ··· 790 723 out_close_fd: 791 724 close(trace_fd); 792 725 out_reset: 793 - reset_tracing_files(ftrace); 726 + exit_tracing_instance(); 794 727 out: 795 728 return (done && !workload_exec_errno) ? 0 : -1; 796 729 } ··· 991 924 if (ftrace->target.use_bpf) 992 925 return perf_ftrace__latency_prepare_bpf(ftrace); 993 926 927 + if (init_tracing_instance() < 0) 928 + return -1; 929 + 994 930 if (reset_tracing_files(ftrace) < 0) { 995 931 pr_err("failed to reset ftrace\n"); 996 932 return -1; ··· 1012 942 return -1; 1013 943 } 1014 944 1015 - trace_file = get_tracing_file("trace_pipe"); 945 + trace_file = get_tracing_instance_file("trace_pipe"); 1016 946 if (!trace_file) { 1017 947 pr_err("failed to open trace_pipe\n"); 1018 948 return -1; ··· 1063 993 if (ftrace->target.use_bpf) 1064 994 return perf_ftrace__latency_cleanup_bpf(ftrace); 1065 995 1066 - reset_tracing_files(ftrace); 996 + exit_tracing_instance(); 1067 997 return 0; 1068 998 } 1069 999 ··· 1374 1304 goto out; 1375 1305 } 1376 1306 1307 + if (init_tracing_instance() < 0) 1308 + goto out; 1309 + 1377 1310 if (reset_tracing_files(ftrace) < 0) { 1378 1311 pr_err("failed to reset ftrace\n"); 1379 - goto out; 1312 + goto out_reset; 1380 1313 } 1381 1314 1382 1315 /* reset ftrace buffer */ 1383 1316 if (write_tracing_file("trace", "0") < 0) 1384 - goto out; 1317 + goto out_reset; 1385 1318 1386 1319 if (set_tracing_options(ftrace) < 0) 1387 - return -1; 1320 + goto out_reset; 1388 1321 1389 1322 if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { 1390 1323 pr_err("failed to set current_tracer to %s\n", ftrace->tracer); ··· 1396 1323 1397 1324 setup_pager(); 1398 1325 1399 - trace_file = get_tracing_file("trace_pipe"); 1326 + trace_file = get_tracing_instance_file("trace_pipe"); 1400 1327 if (!trace_file) { 1401 1328 pr_err("failed to open trace_pipe\n"); 1402 1329 goto out_reset; ··· 1458 1385 out_close_fd: 1459 1386 close(trace_fd); 1460 1387 out_reset: 1461 - reset_tracing_files(ftrace); 1388 + exit_tracing_instance(); 1462 1389 out: 1463 1390 return (done && !workload_exec_errno) ? 0 : -1; 1464 1391 }