[PATCH] perf tools: Add --debug-file option to redirect debug output

Yang Jihong
2023-10-31T10:57:41Z

Currently, debug messages is output to stderr, add --debug-file option to
support redirection to a specified file.

Some test scenarios:

# perf --list-opts
--help --version --exec-path --html-path --paginate --no-pager --debugfs-dir --buildid-dir --list-cmds --list-opts --debug --debug-file

# perf --debug-file
No path given for --debug-file.

Usage: perf [--version] [--help] [OPTIONS] COMMAND [ARGS]

# perf --debug-file /sys/perf.log record -v true
Open debug file '/sys/perf.log' failed: Permission denied

Usage: perf [--version] [--help] [OPTIONS] COMMAND [ARGS]

# perf --debug-file /tmp/perf.log record -v true
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.013 MB perf.data (26 samples) ]
# cat /tmp/perf.log
DEBUGINFOD_URLS=
Using CPUID GenuineIntel-6-3E-4
nr_cblocks: 0
affinity: SYS
mmap flush: 1
comp level: 0
mmap size 528384B
Control descriptor is not initialized
mmap size 528384B
Looking at the vmlinux_path (8 entries long)
Using /proc/kcore for kernel data
Using /proc/kallsyms for symbols
symbol:unmap_start file:(null) line:0 offset:0 return:0 lazy:(null)
symbol:unmap_complete file:(null) line:0 offset:0 return:0 lazy:(null)
symbol:map_start file:(null) line:0 offset:0 return:0 lazy:(null)
symbol:map_complete file:(null) line:0 offset:0 return:0 lazy:(null)
symbol:reloc_start file:(null) line:0 offset:0 return:0 lazy:(null)
symbol:reloc_complete file:(null) line:0 offset:0 return:0 lazy:(null)
symbol:init_start file:(null) line:0 offset:0 return:0 lazy:(null)
symbol:init_complete file:(null) line:0 offset:0 return:0 lazy:(null)
symbol:lll_lock_wait_private file:(null) line:0 offset:0 return:0 lazy:(null)
symbol:lll_lock_wait file:(null) line:0 offset:0 return:0 lazy:(null)
symbol:setjmp file:(null) line:0 offset:0 return:0 lazy:(null)
symbol:longjmp file:(null) line:0 offset:0 return:0 lazy:(null)
symbol:longjmp_target file:(null) line:0 offset:0 return:0 lazy:(null)
failed to write feature HYBRID_TOPOLOGY

Signed-off-by: Yang Jihong <yangjihong1@huawei.com>
---
tools/perf/Documentation/perf.txt | 3 +++
tools/perf/perf.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 33 insertions(+)

diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt
index ba3df49c169d..a7cf7bc2f968 100644
--- a/tools/perf/Documentation/perf.txt
+++ b/tools/perf/Documentation/perf.txt
@@ -64,6 +64,9 @@ OPTIONS
perf-event-open - Print perf_event_open() arguments and
return value

+--debug-file::
+ Write debug output to a specified file.
+
DESCRIPTION
-----------
Performance counters for Linux are a new kernel-based subsystem
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index d3fc8090413c..921bee0a6437 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -39,6 +39,7 @@
#include <linux/zalloc.h>

static int use_pager = -1;
+static FILE *debug_fp = NULL;

struct cmd_struct {
const char *cmd;
@@ -162,6 +163,19 @@ static void commit_pager_choice(void)
}
}

+static int set_debug_file(const char *path)
+{
+ debug_fp = fopen(path, "w");
+ if (!debug_fp) {
+ fprintf(stderr, "Open debug file '%s' failed: %s\n",
+ path, strerror(errno));
+ return -1;
+ }
+
+ debug_set_file(debug_fp);
+ return 0;
+}
+
struct option options[] = {
OPT_ARGUMENT("help", "help"),
OPT_ARGUMENT("version", "version"),
@@ -174,6 +188,7 @@ struct option options[] = {
OPT_ARGUMENT("list-cmds", "list-cmds"),
OPT_ARGUMENT("list-opts", "list-opts"),
OPT_ARGUMENT("debug", "debug"),
+ OPT_ARGUMENT("debug-file", "debug-file"),
OPT_END()
};

@@ -287,6 +302,18 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)

(*argv)++;
(*argc)--;
+ } else if (!strcmp(cmd, "--debug-file")) {
+ if (*argc < 2) {
+ fprintf(stderr, "No path given for --debug-file.\n");
+ usage(perf_usage_string);
+ }
+
+ if (set_debug_file((*argv)[1]))
+ usage(perf_usage_string);
+
+ (*argv)++;
+ (*argc)--;
+
} else {
fprintf(stderr, "Unknown option: %s\n", cmd);
usage(perf_usage_string);
@@ -547,5 +574,8 @@ int main(int argc, const char **argv)
fprintf(stderr, "Failed to run command '%s': %s\n",
cmd, str_error_r(errno, sbuf, sizeof(sbuf)));
out:
+ if (debug_fp)
+ fclose(debug_fp);
+
return 1;
}
--
2.34.1