Add new functions to save error messages in a temp file.  It'll be
used by some UI front-ends to see the messages.

Signed-off-by: Namhyung Kim <namhy...@kernel.org>
---
 tools/perf/Makefile.perf |   1 +
 tools/perf/perf.c        |   5 +++
 tools/perf/util/debug.h  |  15 +++++++
 tools/perf/util/log.c    | 115 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 136 insertions(+)
 create mode 100644 tools/perf/util/log.c

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 87d7726cee2d..2b5252f09c04 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -372,6 +372,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o
 LIB_OBJS += $(OUTPUT)util/record.o
 LIB_OBJS += $(OUTPUT)util/srcline.o
 LIB_OBJS += $(OUTPUT)util/data.o
+LIB_OBJS += $(OUTPUT)util/log.o
 
 LIB_OBJS += $(OUTPUT)ui/setup.o
 LIB_OBJS += $(OUTPUT)ui/helpline.o
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 431798a4110d..f7c806d264a2 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -10,6 +10,7 @@
 
 #include "util/exec_cmd.h"
 #include "util/cache.h"
+#include "util/debug.h"
 #include "util/quote.h"
 #include "util/run-command.h"
 #include "util/parse-events.h"
@@ -524,6 +525,9 @@ int main(int argc, const char **argv)
         */
        pthread__block_sigwinch();
 
+       if (perf_log__init() < 0)
+               fprintf(stderr, "Failed to init temporary log file.. 
ignoring\n");
+
        while (1) {
                static int done_help;
                int was_alias = run_argv(&argc, &argv);
@@ -547,5 +551,6 @@ int main(int argc, const char **argv)
        fprintf(stderr, "Failed to run command '%s': %s\n",
                cmd, strerror(errno));
 out:
+       perf_log__exit();
        return 1;
 }
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 443694c36b03..2d69e9fa6499 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -19,4 +19,19 @@ int ui__warning(const char *format, ...) 
__attribute__((format(printf, 1, 2)));
 
 void pr_stat(const char *fmt, ...);
 
+struct perf_log {
+       FILE *fp;
+       off_t *linemap;
+       u32 lines;
+       u32 nr_alloc;
+       bool seen_newline;
+};
+
+extern struct perf_log perf_log;
+
+int perf_log__init(void);
+int perf_log__exit(void);
+void perf_log__add(const char *msg);
+void perf_log__addv(const char *fmt, va_list ap);
+
 #endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/log.c b/tools/perf/util/log.c
new file mode 100644
index 000000000000..cb94417da435
--- /dev/null
+++ b/tools/perf/util/log.c
@@ -0,0 +1,115 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "util/debug.h"
+
+#define LINEMAP_GROW  128
+
+struct perf_log perf_log = {
+       .seen_newline = true,
+};
+
+int perf_log__init(void)
+{
+       FILE *fp = tmpfile();
+       if (fp == NULL)
+               return -1;
+
+       perf_log.fp = fp;
+
+       return 0;
+}
+
+int perf_log__exit(void)
+{
+       FILE *fp = perf_log.fp;
+       if (fp)
+               fclose(fp);
+
+       free(perf_log.linemap);
+
+       perf_log.fp = NULL;
+       perf_log.linemap = NULL;
+       return 0;
+}
+
+static int grow_linemap(struct perf_log *log)
+{
+       off_t *newmap;
+       int newsize = log->nr_alloc + LINEMAP_GROW;
+
+       newmap = realloc(log->linemap, newsize * sizeof(*log->linemap));
+       if (newmap == NULL)
+               return -1;
+
+       log->nr_alloc = newsize;
+       log->linemap = newmap;
+       return 0;
+}
+
+static int __add_to_linemap(struct perf_log *log, off_t idx)
+{
+       if (log->lines == log->nr_alloc)
+               if (grow_linemap(log) < 0)
+                       return -1;
+
+       log->linemap[log->lines++] = idx;
+       return 0;
+}
+
+static void add_to_linemap(struct perf_log *log, const char *msg, off_t base)
+{
+       const char *pos;
+
+       if (strlen(msg) == 0)
+               return;
+
+       if (log->seen_newline) {
+               if (__add_to_linemap(log, base) < 0)
+                       return;
+       }
+
+       if ((pos = strchr(msg, '\n')) != NULL) {
+               log->seen_newline = true;
+               pos++;
+               add_to_linemap(log, pos, base + (pos - msg));
+       } else {
+               log->seen_newline = false;
+       }
+}
+
+void perf_log__add(const char *msg)
+{
+       FILE *fp = perf_log.fp;
+       off_t offset;
+       u32 saved_lines;
+       size_t msglen;
+
+       if (fp == NULL)
+               return;
+
+       pthread_mutex_lock(&ui__lock);
+
+       offset = ftello(fp);
+       saved_lines = perf_log.lines;
+       msglen = strlen(msg);
+
+       add_to_linemap(&perf_log, msg, offset);
+
+       if (fwrite(msg, 1, msglen, fp) != msglen) {
+               /* restore original offset */
+               fseeko(fp, offset, SEEK_SET);
+               perf_log.lines = saved_lines;
+       }
+       pthread_mutex_unlock(&ui__lock);
+}
+
+void perf_log__addv(const char *fmt, va_list ap)
+{
+       char buf[4096];
+
+       if (perf_log.fp == NULL)
+               return;
+
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       perf_log__add(buf);
+}
-- 
1.7.11.7

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to