diff mbox

[3/3] Toggle tracepoint state

Message ID 20100608123858.6d7dc770@zephyr
State New
Headers show

Commit Message

Prerna Saxena June 8, 2010, 7:08 a.m. UTC
This patch adds support for dynamically enabling/disabling of tracepoints.
Monitor commands added :
1) info tracepoints 		: to view all available tracepoints and 
				  their state.
2) tracepoint NAME on|off 	: to enable/disable data logging from a 
				  given tracepoint.
				  Eg, tracepoint paio_submit off 
				  	disables logging of data when 
					paio_submit is hit.

At present this is done with a simple comparison -- there is scope 
for optimizations that can be employed here to speed this up.

Signed-off-by: Prerna Saxena <prerna@linux.vnet.ibm.com>
---
 monitor.c       |   21 +++++++++++++++++++++
 qemu-monitor.hx |   16 ++++++++++++++++
 simpletrace.c   |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 tracetool       |   30 ++++++++++++++++++++++++++----
 vl.c            |    6 ++++++
 5 files changed, 123 insertions(+), 5 deletions(-)

Comments

Luiz Capitulino June 9, 2010, 8:43 p.m. UTC | #1
On Tue, 8 Jun 2010 12:38:58 +0530
Prerna Saxena <prerna@linux.vnet.ibm.com> wrote:

> This patch adds support for dynamically enabling/disabling of tracepoints.
> Monitor commands added :
> 1) info tracepoints 		: to view all available tracepoints and 
> 				  their state.
> 2) tracepoint NAME on|off 	: to enable/disable data logging from a 
> 				  given tracepoint.
> 				  Eg, tracepoint paio_submit off 
> 				  	disables logging of data when 
> 					paio_submit is hit.
> 
> At present this is done with a simple comparison -- there is scope 
> for optimizations that can be employed here to speed this up.
> 
> Signed-off-by: Prerna Saxena <prerna@linux.vnet.ibm.com>
> ---
>  monitor.c       |   21 +++++++++++++++++++++
>  qemu-monitor.hx |   16 ++++++++++++++++
>  simpletrace.c   |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  tracetool       |   30 ++++++++++++++++++++++++++----
>  vl.c            |    6 ++++++
>  5 files changed, 123 insertions(+), 5 deletions(-)
> 
> diff --git a/monitor.c b/monitor.c
> index fda29aa..1e05b38 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -547,7 +547,19 @@ static void do_commit(Monitor *mon, const QDict *qdict)
>          bdrv_commit(dinfo->bdrv);
>      }
>  }
> +#ifdef CONFIG_SIMPLE_TRACE
> +static void do_change_tracepoint_state(Monitor *mon, const QDict *qdict)
> +{
> +    const char *tp_name = qdict_get_str(qdict, "name");
> +    const char *tp_state = qdict_get_str(qdict, "option");
>  
> +    if (!strncmp(tp_state, "on", 2))
> +	change_tracepoint_state(tp_name, 1);
> +    if (!strncmp(tp_state, "off", 3))
> +	change_tracepoint_state(tp_name, 0);

 Monitor has a bool type, please take a look in do_set_link().

> +    return;

 Not needed, also true for other functions in this patch, suggest reading
CODING_STYLE for other style related issues in this series.

> +}
> +#endif
>  static void user_monitor_complete(void *opaque, QObject *ret_data)
>  {
>      MonitorCompletionData *data = (MonitorCompletionData *)opaque; 
> @@ -2783,6 +2795,15 @@ static const mon_cmd_t info_cmds[] = {
>          .help       = "show roms",
>          .mhandler.info = do_info_roms,
>      },
> +#ifdef CONFIG_SIMPLE_TRACE
> +    {
> +        .name       = "tracepoints",
> +        .args_type  = "",
> +        .params     = "",
> +        .help       = "show available tracepoints & their state",
> +        .mhandler.info = do_info_all_tracepoints,
> +    },
> +#endif
>      {
>          .name       = NULL,
>      },
> diff --git a/qemu-monitor.hx b/qemu-monitor.hx
> index c604aec..36481ea 100644
> --- a/qemu-monitor.hx
> +++ b/qemu-monitor.hx
> @@ -114,6 +114,8 @@ show migration status
>  show balloon information
>  @item info qtree
>  show device tree
> +@item info tracepoints
> +show available tracepoints and their state
>  @end table
>  ETEXI
>  
> @@ -236,6 +238,20 @@ STEXI
>  @item trace
>  @findex trace
>  show contents of trace buffer
> +ETEXI
> +
> +    {
> +        .name       = "tracepoint",
> +        .args_type  = "name:s,option:s",
> +        .params     = "name on|off",
> +        .help       = "changes status of a specific tracepoint",
> +        .mhandler.cmd = do_change_tracepoint_state,
> +    },
> +
> +STEXI
> +@item tracepoint
> +@findex tracepoint
> +changes status of a tracepoint
>  #endif
>  ETEXI
>  
> diff --git a/simpletrace.c b/simpletrace.c
> index 8f33a81..75d2fca 100644
> --- a/simpletrace.c
> +++ b/simpletrace.c
> @@ -3,6 +3,12 @@
>  #include "trace.h"
>  
>  typedef struct {
> +    char *tp_name;
> +    bool state;
> +    unsigned int hash;
> +} Tracepoint;
> +
> +typedef struct {
>      unsigned long event;
>      unsigned long x1;
>      unsigned long x2;
> @@ -18,10 +24,24 @@ enum {
>  static TraceRecord trace_buf[TRACE_BUF_LEN];
>  static unsigned int trace_idx;
>  static FILE *trace_fp;
> +static Tracepoint trace_list[NR_TRACEPOINTS];
> +
> +void init_tracepoint(const char *tname, TraceEvent tevent) {
> +    if (!tname || tevent > NR_TRACEPOINTS)
> +	return;
> +
> +    trace_list[tevent].tp_name = (char*)qemu_malloc(strlen(tname)+1);
> +    strncpy(trace_list[tevent].tp_name, tname, strlen(tname));
> +    trace_list[tevent].hash = tdb_hash(tname);
> +    trace_list[tevent].state = 1; /* Enable all by default */
> +    return;
> +}
>  
>  static void trace(TraceEvent event, unsigned long x1,
>                    unsigned long x2, unsigned long x3,
>                    unsigned long x4, unsigned long x5) {
> +    if (!trace_list[event].state)
> +	return;
>      TraceRecord *rec = &trace_buf[trace_idx];
>      rec->event = event;
>      rec->x1 = x1;
> @@ -64,7 +84,7 @@ void trace5(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long
>  }
>  
>  void do_info_trace(Monitor *mon) {
> -    static unsigned int i, max_idx;
> +    unsigned int i, max_idx;
>  
>      if (trace_idx)
>          max_idx = trace_idx;
> @@ -77,3 +97,36 @@ void do_info_trace(Monitor *mon) {
>  	trace_buf[i].x3, trace_buf[i].x4, trace_buf[i].x5);
>      return;
>  }
> +
> +void do_info_all_tracepoints(Monitor *mon) {
> +    unsigned int i;
> +    for (i=0; i<NR_TRACEPOINTS; i++)
> +	monitor_printf(mon, "%s [Event ID %u] : state %u\n",
> +		trace_list[i].tp_name, i, trace_list[i].state);
> +    return;
> +}
> +
> +static int find_tracepoint_by_name(const char *tname) {
> +    unsigned int i, name_hash;
> +
> +    if (!tname)
> +	return -1;
> +
> +    name_hash = tdb_hash(tname);
> +
> +    for (i=0; i<NR_TRACEPOINTS; i++)
> +	if (trace_list[i].hash == name_hash &&
> +		 !strncmp(trace_list[i].tp_name, tname, strlen(tname)))
> +	    return i;
> +    return -1; /* indicates end of list reached without a match */
> +}
> +
> +void change_tracepoint_state(const char *tname, bool tstate) {
> +    int i;
> +
> +    i = find_tracepoint_by_name(tname);
> +    /* TODO : This update might need to be protected by a memory barrier */
> +    if (i >= 0)
> +	trace_list[i].state = tstate;
> +    return;
> +}
> diff --git a/tracetool b/tracetool
> index 6c15154..cc2b22c 100755
> --- a/tracetool
> +++ b/tracetool
> @@ -123,14 +123,20 @@ linetoc_end_nop()
>  linetoh_begin_simple()
>  {
>      cat <<EOF
> +#include <stdbool.h>
> +
>  typedef unsigned int TraceEvent;
>  
> +void init_tracepoint_table(void);
> +void init_tracepoint(const char *tname, TraceEvent tevent);
>  void trace1(TraceEvent event, unsigned long x1);
>  void trace2(TraceEvent event, unsigned long x1, unsigned long x2);
>  void trace3(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long x3);
>  void trace4(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long x4);
>  void trace5(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long x4, unsigned long x5);
>  void do_info_trace(Monitor *mon);
> +void do_info_all_tracepoints(Monitor *mon);
> +void change_tracepoint_state(const char *tname, bool tstate);
>  EOF
>  
>      simple_event_num=0
> @@ -163,22 +169,38 @@ EOF
>  
>  linetoh_end_simple()
>  {
> -    return
> +    cat <<EOF
> +#define NR_TRACEPOINTS $simple_event_num
> +EOF
>  }
>  
>  linetoc_begin_simple()
>  {
> -    return
> +    cat <<EOF
> +#include "trace.h"
> +
> +void init_tracepoint_table(void) {
> +EOF
> +    simple_event_num=0
> +
>  }
>  
>  linetoc_simple()
>  {
> -    return
> +    local name
> +    name=$(get_name "$1")
> +    cat <<EOF
> +init_tracepoint("$name", $simple_event_num);
> +EOF
> +    simple_event_num=$((simple_event_num + 1))
>  }
>  
>  linetoc_end_simple()
>  {
> -    return
> +    cat <<EOF
> +return;
> +}
> +EOF
>  }
>  
>  linetoh_begin_ust()
> diff --git a/vl.c b/vl.c
> index 328395e..dd07904 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -163,6 +163,9 @@ int main(int argc, char **argv)
>  #include "cpus.h"
>  #include "arch_init.h"
>  
> +#ifdef CONFIG_SIMPLE_TRACE
> +#include "trace.h"
> +#endif
>  //#define DEBUG_NET
>  //#define DEBUG_SLIRP
>  
> @@ -3604,6 +3607,9 @@ int main(int argc, char **argv, char **envp)
>      if (net_init_clients() < 0) {
>          exit(1);
>      }
> +#ifdef CONFIG_SIMPLE_TRACE
> +    init_tracepoint_table();
> +#endif
>  
>      /* init the bluetooth world */
>      if (foreach_device_config(DEV_BT, bt_parse))
Prerna Saxena June 11, 2010, 10:57 a.m. UTC | #2
Hi Luiz,
Thanks for taking time to review it.

On 06/10/2010 02:13 AM, Luiz Capitulino wrote:
> On Tue, 8 Jun 2010 12:38:58 +0530
> Prerna Saxena<prerna@linux.vnet.ibm.com>  wrote:
>
>> This patch adds support for dynamically enabling/disabling of tracepoints.
>> Monitor commands added :
>> ....
>>
>
>   Monitor has a bool type, please take a look in do_set_link().
>

Thanks for the pointer. Changed in v2.

>> +    return;
>
>   Not needed, also true for other functions in this patch, suggest reading
> CODING_STYLE for other style related issues in this series.

Done.

>
>>....
>>

Hope these commands would make it easy to visualize logged traces via 
the monitor. I'd appreciate feedback on how v2 of the patches posted 
can be enhanced.
diff mbox

Patch

diff --git a/monitor.c b/monitor.c
index fda29aa..1e05b38 100644
--- a/monitor.c
+++ b/monitor.c
@@ -547,7 +547,19 @@  static void do_commit(Monitor *mon, const QDict *qdict)
         bdrv_commit(dinfo->bdrv);
     }
 }
+#ifdef CONFIG_SIMPLE_TRACE
+static void do_change_tracepoint_state(Monitor *mon, const QDict *qdict)
+{
+    const char *tp_name = qdict_get_str(qdict, "name");
+    const char *tp_state = qdict_get_str(qdict, "option");
 
+    if (!strncmp(tp_state, "on", 2))
+	change_tracepoint_state(tp_name, 1);
+    if (!strncmp(tp_state, "off", 3))
+	change_tracepoint_state(tp_name, 0);
+    return;
+}
+#endif
 static void user_monitor_complete(void *opaque, QObject *ret_data)
 {
     MonitorCompletionData *data = (MonitorCompletionData *)opaque; 
@@ -2783,6 +2795,15 @@  static const mon_cmd_t info_cmds[] = {
         .help       = "show roms",
         .mhandler.info = do_info_roms,
     },
+#ifdef CONFIG_SIMPLE_TRACE
+    {
+        .name       = "tracepoints",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show available tracepoints & their state",
+        .mhandler.info = do_info_all_tracepoints,
+    },
+#endif
     {
         .name       = NULL,
     },
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
index c604aec..36481ea 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -114,6 +114,8 @@  show migration status
 show balloon information
 @item info qtree
 show device tree
+@item info tracepoints
+show available tracepoints and their state
 @end table
 ETEXI
 
@@ -236,6 +238,20 @@  STEXI
 @item trace
 @findex trace
 show contents of trace buffer
+ETEXI
+
+    {
+        .name       = "tracepoint",
+        .args_type  = "name:s,option:s",
+        .params     = "name on|off",
+        .help       = "changes status of a specific tracepoint",
+        .mhandler.cmd = do_change_tracepoint_state,
+    },
+
+STEXI
+@item tracepoint
+@findex tracepoint
+changes status of a tracepoint
 #endif
 ETEXI
 
diff --git a/simpletrace.c b/simpletrace.c
index 8f33a81..75d2fca 100644
--- a/simpletrace.c
+++ b/simpletrace.c
@@ -3,6 +3,12 @@ 
 #include "trace.h"
 
 typedef struct {
+    char *tp_name;
+    bool state;
+    unsigned int hash;
+} Tracepoint;
+
+typedef struct {
     unsigned long event;
     unsigned long x1;
     unsigned long x2;
@@ -18,10 +24,24 @@  enum {
 static TraceRecord trace_buf[TRACE_BUF_LEN];
 static unsigned int trace_idx;
 static FILE *trace_fp;
+static Tracepoint trace_list[NR_TRACEPOINTS];
+
+void init_tracepoint(const char *tname, TraceEvent tevent) {
+    if (!tname || tevent > NR_TRACEPOINTS)
+	return;
+
+    trace_list[tevent].tp_name = (char*)qemu_malloc(strlen(tname)+1);
+    strncpy(trace_list[tevent].tp_name, tname, strlen(tname));
+    trace_list[tevent].hash = tdb_hash(tname);
+    trace_list[tevent].state = 1; /* Enable all by default */
+    return;
+}
 
 static void trace(TraceEvent event, unsigned long x1,
                   unsigned long x2, unsigned long x3,
                   unsigned long x4, unsigned long x5) {
+    if (!trace_list[event].state)
+	return;
     TraceRecord *rec = &trace_buf[trace_idx];
     rec->event = event;
     rec->x1 = x1;
@@ -64,7 +84,7 @@  void trace5(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long
 }
 
 void do_info_trace(Monitor *mon) {
-    static unsigned int i, max_idx;
+    unsigned int i, max_idx;
 
     if (trace_idx)
         max_idx = trace_idx;
@@ -77,3 +97,36 @@  void do_info_trace(Monitor *mon) {
 	trace_buf[i].x3, trace_buf[i].x4, trace_buf[i].x5);
     return;
 }
+
+void do_info_all_tracepoints(Monitor *mon) {
+    unsigned int i;
+    for (i=0; i<NR_TRACEPOINTS; i++)
+	monitor_printf(mon, "%s [Event ID %u] : state %u\n",
+		trace_list[i].tp_name, i, trace_list[i].state);
+    return;
+}
+
+static int find_tracepoint_by_name(const char *tname) {
+    unsigned int i, name_hash;
+
+    if (!tname)
+	return -1;
+
+    name_hash = tdb_hash(tname);
+
+    for (i=0; i<NR_TRACEPOINTS; i++)
+	if (trace_list[i].hash == name_hash &&
+		 !strncmp(trace_list[i].tp_name, tname, strlen(tname)))
+	    return i;
+    return -1; /* indicates end of list reached without a match */
+}
+
+void change_tracepoint_state(const char *tname, bool tstate) {
+    int i;
+
+    i = find_tracepoint_by_name(tname);
+    /* TODO : This update might need to be protected by a memory barrier */
+    if (i >= 0)
+	trace_list[i].state = tstate;
+    return;
+}
diff --git a/tracetool b/tracetool
index 6c15154..cc2b22c 100755
--- a/tracetool
+++ b/tracetool
@@ -123,14 +123,20 @@  linetoc_end_nop()
 linetoh_begin_simple()
 {
     cat <<EOF
+#include <stdbool.h>
+
 typedef unsigned int TraceEvent;
 
+void init_tracepoint_table(void);
+void init_tracepoint(const char *tname, TraceEvent tevent);
 void trace1(TraceEvent event, unsigned long x1);
 void trace2(TraceEvent event, unsigned long x1, unsigned long x2);
 void trace3(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long x3);
 void trace4(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long x4);
 void trace5(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long x4, unsigned long x5);
 void do_info_trace(Monitor *mon);
+void do_info_all_tracepoints(Monitor *mon);
+void change_tracepoint_state(const char *tname, bool tstate);
 EOF
 
     simple_event_num=0
@@ -163,22 +169,38 @@  EOF
 
 linetoh_end_simple()
 {
-    return
+    cat <<EOF
+#define NR_TRACEPOINTS $simple_event_num
+EOF
 }
 
 linetoc_begin_simple()
 {
-    return
+    cat <<EOF
+#include "trace.h"
+
+void init_tracepoint_table(void) {
+EOF
+    simple_event_num=0
+
 }
 
 linetoc_simple()
 {
-    return
+    local name
+    name=$(get_name "$1")
+    cat <<EOF
+init_tracepoint("$name", $simple_event_num);
+EOF
+    simple_event_num=$((simple_event_num + 1))
 }
 
 linetoc_end_simple()
 {
-    return
+    cat <<EOF
+return;
+}
+EOF
 }
 
 linetoh_begin_ust()
diff --git a/vl.c b/vl.c
index 328395e..dd07904 100644
--- a/vl.c
+++ b/vl.c
@@ -163,6 +163,9 @@  int main(int argc, char **argv)
 #include "cpus.h"
 #include "arch_init.h"
 
+#ifdef CONFIG_SIMPLE_TRACE
+#include "trace.h"
+#endif
 //#define DEBUG_NET
 //#define DEBUG_SLIRP
 
@@ -3604,6 +3607,9 @@  int main(int argc, char **argv, char **envp)
     if (net_init_clients() < 0) {
         exit(1);
     }
+#ifdef CONFIG_SIMPLE_TRACE
+    init_tracepoint_table();
+#endif
 
     /* init the bluetooth world */
     if (foreach_device_config(DEV_BT, bt_parse))