Patchwork [2/2,Tracing] Add trace-file command to open/close/flush trace file

login
register
mail settings
Submitter Stefan Hajnoczi
Date July 13, 2010, 8:26 a.m.
Message ID <1279009593-2562-2-git-send-email-stefanha@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/58717/
State New
Headers show

Comments

Stefan Hajnoczi - July 13, 2010, 8:26 a.m.
This patch adds the trace-file command:

  trace-file [on|off|flush]

  Open, close, or flush the trace file.  If no argument is given,
  the status of the trace file is displayed.

The trace file is turned on by default but is only written out when the
trace buffer becomes full.  The flush operation can be used to force
write out at any time.

Turning off the trace file does not change the state of trace events;
tracing will continue to the trace buffer.  When the trace file is off,
use "info trace" to display the contents of the trace buffer in memory.

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
---
 monitor.c       |   17 +++++++++++++++++
 qemu-monitor.hx |   14 ++++++++++++++
 simpletrace.c   |   45 +++++++++++++++++++++++++++++++++++++++++----
 tracetool       |    3 +++
 4 files changed, 75 insertions(+), 4 deletions(-)

Patch

diff --git a/monitor.c b/monitor.c
index 090e13c..1e35a6b 100644
--- a/monitor.c
+++ b/monitor.c
@@ -540,6 +540,23 @@  static void do_change_trace_event_state(Monitor *mon, const QDict *qdict)
     bool new_state = qdict_get_bool(qdict, "option");
     change_trace_event_state(tp_name, new_state);
 }
+
+static void do_trace_file(Monitor *mon, const QDict *qdict)
+{
+    const char *op = qdict_get_try_str(qdict, "op");
+
+    if (!op) {
+        st_print_trace_file_status((FILE *)mon, &monitor_fprintf);
+    } else if (!strcmp(op, "on")) {
+        st_set_trace_file_enabled(true);
+    } else if (!strcmp(op, "off")) {
+        st_set_trace_file_enabled(false);
+    } else if (!strcmp(op, "flush")) {
+        st_flush_trace_buffer();
+    } else {
+        monitor_printf(mon, "unexpected argument \"%s\"\n", op);
+    }
+}
 #endif
 
 static void user_monitor_complete(void *opaque, QObject *ret_data)
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
index c5ba3d2..25887bd 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -273,6 +273,20 @@  STEXI
 @findex trace-event
 changes status of a trace event
 ETEXI
+
+    {
+        .name       = "trace-file",
+        .args_type  = "op:s?",
+        .params     = "op [on|off|flush]",
+        .help       = "open, close, or flush trace file",
+        .mhandler.cmd = do_trace_file,
+    },
+
+STEXI
+@item trace-file on|off|flush
+@findex trace-file
+Open, close, or flush the trace file.  If no argument is given, the status of the trace file is displayed.
+ETEXI
 #endif
 
     {
diff --git a/simpletrace.c b/simpletrace.c
index 29fd6a9..71110b3 100644
--- a/simpletrace.c
+++ b/simpletrace.c
@@ -20,6 +20,13 @@  enum {
 static TraceRecord trace_buf[TRACE_BUF_LEN];
 static unsigned int trace_idx;
 static FILE *trace_fp;
+static bool trace_file_enabled = true;
+
+void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
+{
+    stream_printf(stream, "Trace file \"" CONFIG_TRACE_FILE "\" %s.\n",
+                  getpid(), trace_file_enabled ? "on" : "off");
+}
 
 static bool open_trace_file(void)
 {
@@ -34,22 +41,52 @@  static bool open_trace_file(void)
     return trace_fp != NULL;
 }
 
-static void flush_trace_buffer(void)
+static void flush_trace_file(void)
 {
+    /* If the trace file is not open yet, open it now */
     if (!trace_fp) {
-        if (open_trace_file()) {
-            atexit(flush_trace_buffer);
+        if (!open_trace_file()) {
+            /* Avoid repeatedly trying to open file on failure */
+            trace_file_enabled = false;
+            return;
         }
+        atexit(st_flush_trace_buffer);
     }
+
     if (trace_fp) {
         size_t unused; /* for when fwrite(3) is declared warn_unused_result */
         unused = fwrite(trace_buf, trace_idx * sizeof(trace_buf[0]), 1, trace_fp);
     }
+}
+
+void st_flush_trace_buffer(void)
+{
+    if (trace_file_enabled) {
+        flush_trace_file();
+    }
 
     /* Discard written trace records */
     trace_idx = 0;
 }
 
+void st_set_trace_file_enabled(bool enable)
+{
+    if (enable == trace_file_enabled) {
+        return; /* no change */
+    }
+
+    /* Flush/discard trace buffer */
+    st_flush_trace_buffer();
+
+    /* To disable, close trace file */
+    if (!enable) {
+        fclose(trace_fp);
+        trace_fp = NULL;
+    }
+
+    trace_file_enabled = enable;
+}
+
 static void trace(TraceEventID event, unsigned long x1,
                   unsigned long x2, unsigned long x3,
                   unsigned long x4, unsigned long x5)
@@ -76,7 +113,7 @@  static void trace(TraceEventID event, unsigned long x1,
     rec->x5 = x5;
 
     if (++trace_idx == TRACE_BUF_LEN) {
-        flush_trace_buffer();
+        st_flush_trace_buffer();
     }
 }
 
diff --git a/tracetool b/tracetool
index 8d8f27c..999ef7e 100755
--- a/tracetool
+++ b/tracetool
@@ -141,6 +141,9 @@  void trace4(TraceEventID event, unsigned long x1, unsigned long x2, unsigned lon
 void trace5(TraceEventID event, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long x4, unsigned long x5);
 void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
 void st_print_trace_events(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
+void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...));
+void st_flush_trace_buffer(void);
+void st_set_trace_file_enabled(bool enable);
 void change_trace_event_state(const char *tname, bool tstate);
 EOF