[PATCH v7 2/2] perf: add support for logging debug messages to file

From: Changbin Du
Date: Tue Nov 26 2019 - 09:37:51 EST


When in TUI mode, it is impossible to show all the debug messages to
console. This make it hard to debug perf issues using debug messages.
This patch adds support for logging debug messages to file to resolve
this problem.

The usage is:
perf -debug verbose=2,file=~/perf.log COMMAND

Signed-off-by: Changbin Du <changbin.du@xxxxxxxxx>

---
v5: doc default log path.
v4: fix another segfault.
v3: fix a segfault issue.
---
tools/perf/Documentation/perf.txt | 6 ++++-
tools/perf/util/debug.c | 44 ++++++++++++++++++++++++++++---
2 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt
index dcf9d98065f2..52c6ba825552 100644
--- a/tools/perf/Documentation/perf.txt
+++ b/tools/perf/Documentation/perf.txt
@@ -16,7 +16,8 @@ OPTIONS
Setup debug variable (see list below). The range of 'level' value
is (0, 10). Use like:
--debug verbose # sets verbose = 1
- --debug verbose=2 # sets verbose = 2
+ --debug verbose=2,file=~/perf.log
+ # sets verbose = 2 and save log to file

List of debug variables allowed to set:
verbose[=level] - general debug messages
@@ -26,6 +27,9 @@ OPTIONS
in browser mode
perf-event-open - Print perf_event_open() arguments and
return value
+ file[=path] - write debug output to log file, default
+ 'perf.log' (stderr and file options are
+ exclusive)

--buildid-dir::
Setup buildid cache directory. It has higher priority than
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 929da46ece92..21bc889976bc 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -6,6 +6,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
#include <sys/wait.h>
#include <api/debug.h>
#include <linux/kernel.h>
@@ -27,7 +28,7 @@ int verbose;
int debug_peo_args;
bool dump_trace = false, quiet = false;
int debug_ordered_events;
-static bool redirect_to_stderr;
+static FILE *log_file;
int debug_data_convert;

int veprintf(int level, int var, const char *fmt, va_list args)
@@ -35,8 +36,10 @@ int veprintf(int level, int var, const char *fmt, va_list args)
int ret = 0;

if (var >= level) {
- if (use_browser >= 1 && !redirect_to_stderr)
+ if (use_browser >= 1 && !log_file)
ui_helpline__vshow(fmt, args);
+ else if (log_file)
+ ret = vfprintf(log_file, fmt, args);
else
ret = vfprintf(stderr, fmt, args);
}
@@ -198,6 +201,24 @@ static int str2loglevel(const char *vstr)
return v;
}

+static void flush_log(void)
+{
+ if (log_file)
+ fflush(log_file);
+}
+
+static void set_log_output(FILE *f)
+{
+ if (f == log_file)
+ return;
+
+ if (log_file && log_file != stderr)
+ fclose(log_file);
+
+ log_file = f;
+ atexit(flush_log);
+}
+
int perf_debug_option(const char *str)
{
char *sep, *vstr;
@@ -219,10 +240,25 @@ int perf_debug_option(const char *str)
else if (!strcmp(opt, "data-convert"))
debug_data_convert = str2loglevel(vstr);
else if (!strcmp(opt, "stderr"))
- redirect_to_stderr = true;
+ set_log_output(stderr);
else if (!strcmp(opt, "perf-event-open"))
debug_peo_args = true;
- else {
+ else if (!strcmp(opt, "file")) {
+ FILE *f;
+
+ if (!vstr)
+ vstr = (char *)"perf.log";
+
+ f = fopen(vstr, "a");
+ if (!f) {
+ pr_err("Can not create log file: %s\n",
+ strerror(errno));
+ free(dstr);
+ return -1;
+ }
+ fprintf(f, "\n===========perf log===========\n");
+ set_log_output(f);
+ } else {
fprintf(stderr, "unkown debug option '%s'\n", opt);
free(dstr);
return -1;
--
2.20.1