public inbox for linux-s390@vger.kernel.org
 help / color / mirror / Atom feed
From: Thomas Richter <tmricht@linux.ibm.com>
To: linux-kernel@vger.kernel.org, linux-s390@vger.kernel.org,
	linux-perf-users@vger.kernel.org, acme@kernel.org,
	namhyung@kernel.org
Cc: agordeev@linux.ibm.com, gor@linux.ibm.com,
	sumanthk@linux.ibm.com, hca@linux.ibm.com,
	Thomas Richter <tmricht@linux.ibm.com>,
	Alexander Egorenkov <egorenar@linux.ibm.com>
Subject: [PATCH] perf ftrace: Restore to original trace settings on exit
Date: Thu, 15 May 2025 08:34:07 +0200	[thread overview]
Message-ID: <20250515063407.3025338-1-tmricht@linux.ibm.com> (raw)

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.
Fix this behavior and restore the trace setting to what
is was before the invocation of the command.
On Fedora 41 and 42 tracing is turned on by default.

The root cause is function reset_tracing_files() which
writes zero (0) into file tracing_on.

Read tracing files on start of the program and
restore these values just before exit.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Suggested-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Reviewed-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Reported-by: Alexander Egorenkov <egorenar@linux.ibm.com>
---
 tools/perf/builtin-ftrace.c | 226 ++++++++++++++++++++++++++++++++++++
 1 file changed, 226 insertions(+)

diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 7caa18d5ffc3..11ead75fe0f7 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -299,6 +299,228 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
 	return 0;
 }
 
+static int read_tracing_file(const char *name, char *buf, size_t size)
+{
+	int ret = -1;
+	char *file;
+	int fd;
+
+	file = get_tracing_file(name);
+	if (!file) {
+		pr_debug("cannot get tracing file: %s\n", name);
+		return -1;
+	}
+
+	fd = open(file, O_RDONLY);
+	if (fd < 0) {
+		pr_debug("cannot open tracing file: %s: %s\n",
+			 name, str_error_r(errno, buf, size));
+		goto out;
+	}
+
+	/* read contents to stdout */
+	while (true) {
+		int n = read(fd, buf, size);
+
+		if (n == 0)
+			break;
+		else if (n < 0)
+			goto out_close;
+		buf += n;
+		size -= n;
+	}
+	ret = 0;
+
+out_close:
+	close(fd);
+out:
+	put_tracing_file(file);
+	return ret;
+}
+
+static int read_tracing_option_file(const char *name, char *val, size_t size)
+{
+	char *file;
+	int ret;
+
+	if (asprintf(&file, "options/%s", name) < 0)
+		return -1;
+
+	ret = read_tracing_file(file, val, size);
+	free(file);
+	return ret;
+}
+
+/*
+ * Save the initial trace file setting to restore them after the tests.
+ * This ensures the setting are the same as before the invocation
+ * of the program.
+ */
+static struct trace_file_list {		/* List of tracing files */
+	const char *filename;		/* File name */
+	char *contents;			/* Contents to restore */
+	int (*read_fct)(const char *fn, char *buf, size_t buf_sz);		/* Read function */
+	int (*write_fct)(const char *fn, const char *buf);		/* Write function */
+} trace_file_list[] = {
+	[0] = {
+		.filename = "tracing_on",
+		.read_fct = read_tracing_file,
+		.write_fct = write_tracing_file,
+	},
+	[1] = {
+		.filename = "current_tracer",
+		.read_fct = read_tracing_file,
+		.write_fct = write_tracing_file,
+	},
+	[2] = {
+		.filename = "set_ftrace_pid",
+		.read_fct = read_tracing_file,
+		.write_fct = write_tracing_file,
+	},
+	[3] = {
+		.write_fct = write_tracing_file,
+		.read_fct = read_tracing_file,
+		.filename = "max_graph_depth",
+	},
+	[4] = {
+		.filename = "tracing_thresh",
+		.read_fct = read_tracing_file,
+		.write_fct = write_tracing_file,
+	},
+	[5] = {
+		.filename = "tracing_cpumask",
+		.read_fct = read_tracing_file,
+		.write_fct = write_tracing_file,
+	},
+	[6] = {
+		.filename = "set_ftrace_filter",
+		.read_fct = read_tracing_file,
+		.write_fct = write_tracing_file,
+	},
+	[7] = {
+		.filename = "set_ftrace_notrace",
+		.read_fct = read_tracing_file,
+		.write_fct = write_tracing_file,
+	},
+	[8] = {
+		.filename = "set_graph_function",
+		.read_fct = read_tracing_file,
+		.write_fct = write_tracing_file,
+	},
+	[9] = {
+		.filename = "set_graph_notrace",
+		.read_fct = read_tracing_file,
+		.write_fct = write_tracing_file,
+	},
+			/* Files in .../options/ directory */
+	[10] = {
+		.filename = "function-fork",
+		.read_fct = read_tracing_option_file,
+		.write_fct = write_tracing_option_file,
+	},
+	[11] = {
+		.filename = "func_stack_trace",
+		.read_fct = read_tracing_option_file,
+		.write_fct = write_tracing_option_file,
+	},
+	[12] = {
+		.filename = "sleep-time",
+		.read_fct = read_tracing_option_file,
+		.write_fct = write_tracing_option_file,
+	},
+	[13] = {
+		.filename = "funcgraph-irqs",
+		.read_fct = read_tracing_option_file,
+		.write_fct = write_tracing_option_file,
+	},
+	[14] = {
+		.filename = "funcgraph-proc",
+		.read_fct = read_tracing_option_file,
+		.write_fct = write_tracing_option_file,
+	},
+	[15] = {
+		.filename = "funcgraph-abstime",
+		.read_fct = read_tracing_option_file,
+		.write_fct = write_tracing_option_file,
+	},
+	[16] = {
+		.filename = "funcgraph-tail",
+		.read_fct = read_tracing_option_file,
+		.write_fct = write_tracing_option_file,
+	},
+	[17] = {
+		.filename = "latency-format",
+		.read_fct = read_tracing_option_file,
+		.write_fct = write_tracing_option_file,
+	},
+	[18] = {
+		.filename = "irq-info",
+		.read_fct = read_tracing_option_file,
+		.write_fct = write_tracing_option_file,
+	},
+};
+
+static void free_tracing_content(void)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(trace_file_list); ++i)
+		zfree(&trace_file_list[i].contents);
+}
+
+/*
+ * Return a copy of the input string.
+ * Remove a trailing newline. It will be appended in the write
+ * function when values are restored before program termination.
+ * Change "no pid" or comment sign '#' at the beginning and replace it
+ * by an empty string. This resets to the default behavior indicated
+ * by the output. Those strings are not accepted as file input.
+ */
+static char *copy_tracing_file(char *buf)
+{
+	char *c = strrchr(buf, '\n');
+
+	if (c)
+		*c = '\0';
+	if (*buf == '#' || !strncmp(buf, "no pid", 6))
+		*buf = '\0';
+	return strdup(buf);
+}
+
+static int save_tracing_files(void)
+{
+	char buf[4096];
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(trace_file_list); ++i) {
+		struct trace_file_list *tp = &trace_file_list[i];
+
+		memset(buf, 0, sizeof(buf));
+		if ((*tp->read_fct)(tp->filename, buf, sizeof(buf)) < 0)
+			goto out;
+		tp->contents = copy_tracing_file(buf);
+		if (!tp->contents)
+			goto out;
+	}
+	return 0;
+
+out:
+	free_tracing_content();
+	return -1;
+}
+
+static void restore_tracing_files(void)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(trace_file_list); ++i) {
+		struct trace_file_list *tp = &trace_file_list[i];
+
+		(*tp->write_fct)(tp->filename, tp->contents);
+	}
+	free_tracing_content();
+}
+
 static int set_tracing_pid(struct perf_ftrace *ftrace)
 {
 	int i;
@@ -1687,6 +1909,9 @@ int cmd_ftrace(int argc, const char **argv)
 	};
 	enum perf_ftrace_subcommand subcmd = PERF_FTRACE_NONE;
 
+	if (save_tracing_files())
+		return -1;
+
 	INIT_LIST_HEAD(&ftrace.filters);
 	INIT_LIST_HEAD(&ftrace.notrace);
 	INIT_LIST_HEAD(&ftrace.graph_funcs);
@@ -1839,5 +2064,6 @@ int cmd_ftrace(int argc, const char **argv)
 	delete_filter_func(&ftrace.graph_funcs);
 	delete_filter_func(&ftrace.nograph_funcs);
 
+	restore_tracing_files();
 	return ret;
 }
-- 
2.49.0


             reply	other threads:[~2025-05-15  6:34 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-15  6:34 Thomas Richter [this message]
2025-05-15 16:10 ` [PATCH] perf ftrace: Restore to original trace settings on exit Arnaldo Carvalho de Melo
2025-05-15 18:18   ` Namhyung Kim

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250515063407.3025338-1-tmricht@linux.ibm.com \
    --to=tmricht@linux.ibm.com \
    --cc=acme@kernel.org \
    --cc=agordeev@linux.ibm.com \
    --cc=egorenar@linux.ibm.com \
    --cc=gor@linux.ibm.com \
    --cc=hca@linux.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=namhyung@kernel.org \
    --cc=sumanthk@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox