All of lore.kernel.org
 help / color / mirror / Atom feed
From: Prerna Saxena <prerna@linux.vnet.ibm.com>
To: qemu-devel@nongnu.org
Cc: Maneesh Soni <maneesh@linux.vnet.ibm.com>,
	Anthony Liguori <aliguori@us.ibm.com>,
	Ananth <ananth@linux.vnet.ibm.com>,
	Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Subject: [Qemu-devel] [PATCH 2/3] Tracepoint, buffer & monitor framework
Date: Mon, 24 May 2010 21:46:51 +0530	[thread overview]
Message-ID: <4BFAA673.4050809@linux.vnet.ibm.com> (raw)
In-Reply-To: <4BFAA60D.6080308@linux.vnet.ibm.com>

[-- Attachment #1: Type: text/plain, Size: 591 bytes --]

Patch that implements tracepoint framework + trace buffer + monitor support.

tracing can be enabled at compile time using --enable-trace switch, 
which compiles tracing support(all of these).

Monitor commands introduced :
1. info trace : to see contents of trace buffer.
2. info tracepoints : to see available tracepoints and their status.
3. trace [on|off] : to enable / disable trace data collection.
4. tracepoint ABC [on|off] : to enable / disable traces from a specific 
tracepoint, eg ABC

-- 
Prerna Saxena

Linux Technology Centre,
IBM Systems and Technology Lab,
Bangalore, India

[-- Attachment #2: trace-framework.patch --]
[-- Type: text/x-diff, Size: 25690 bytes --]

Signed-off by : Prerna (prerna@linux.vnet.ibm.com)

Index: qemu/monitor.c
===================================================================
--- qemu.orig/monitor.c
+++ qemu/monitor.c
@@ -55,7 +55,9 @@
 #include "json-streamer.h"
 #include "json-parser.h"
 #include "osdep.h"
-
+#ifdef CONFIG_QEMU_TRACE
+#include "tracepoint.h"
+#endif
 //#define DEBUG
 //#define DEBUG_COMPLETION
 
@@ -145,6 +147,10 @@ struct Monitor {
 #ifdef CONFIG_DEBUG_MONITOR
     int print_calls_nr;
 #endif
+#ifdef CONFIG_QEMU_TRACE
+    struct DebugBuffer *qemu_buf_ptr;
+#endif
+
     QError *error;
     QLIST_HEAD(,mon_fd_t) fds;
     QLIST_ENTRY(Monitor) entry;
@@ -1198,6 +1204,63 @@ static void do_log(Monitor *mon, const Q
     cpu_set_log(mask);
 }
 
+#ifdef CONFIG_QEMU_TRACE
+static void do_trace(Monitor *mon, const QDict *qdict)
+{
+    const char *option = qdict_get_try_str(qdict, "option");
+    if (!option || !strncmp(option, "on", 3)) {
+	mon->qemu_buf_ptr = &qemu_buf;
+        initialize_buffer(mon->qemu_buf_ptr);
+    } else if (!strncmp(option, "off", 4)) {
+       mon->qemu_buf_ptr->enabled = 0;
+    } else {
+        monitor_printf(mon, "Invalid option %s\n", option);
+    }
+}
+
+static void do_tracepoint_status(Monitor *mon, const QDict *qdict)
+{
+    uint8_t status_num;
+    struct tracepoint *t;
+    const char *tp_name = qdict_get_str(qdict, "name");
+    const char *tp_state = qdict_get_str(qdict, "option");
+
+    if(!mon->qemu_buf_ptr || !mon->qemu_buf_ptr->enabled) {
+        monitor_printf(mon, "Tracing disabled. Use \"trace on\" before this\n");
+	return;
+    }
+    if(!strncmp(tp_state, "on", 3))
+	status_num = 1;
+    else {
+	    if(!strncmp(tp_state, "off", 4))
+		status_num = 0;
+	    else {
+        	monitor_printf(mon, "Invalid option : %s. Use [on|off]\n",
+								tp_state);
+		return;
+		 }
+	 }
+    t = find_tracepoint_by_name(tp_name);
+    if(t == NULL) {
+        monitor_printf(mon, "Tracepoint %s does not exist\n", tp_name);
+	return;
+	}
+    if(t->state == status_num) {
+        monitor_printf(mon, "State of Tracepoint %s is already %s\n",
+						 tp_name, tp_state);
+	return;
+	}
+    /* Do I need a spin_lock here ? */
+    t->state = status_num;
+    return;
+}
+#else /* CONFIG_QEMU_TRACE */
+static void do_tracepoint_status(Monitor *mon, const QDict *qdict)
+{
+    monitor_printf(mon, "Internal tracing not compiled\n");
+}
+#endif
+
 static void do_singlestep(Monitor *mon, const QDict *qdict)
 {
     const char *option = qdict_get_try_str(qdict, "option");
@@ -2170,6 +2233,42 @@ static void do_info_profile(Monitor *mon
 }
 #endif
 
+#ifdef CONFIG_QEMU_TRACE
+
+static void qemu_dump_trace(Monitor *mon, struct DebugEntry *data)
+{
+    int i;
+
+    char *iter = (char *)data;
+    for (i=0; i<SLOT_SIZE/sizeof(int); i++)
+	 monitor_printf(mon, "%c",iter[i]);
+    monitor_printf(mon, "\n");
+    return;
+}
+
+static void do_info_trace(Monitor *mon)
+{
+    struct DebugEntry data;
+    /* TODO : change def of read to have null return*/
+    if(!mon->qemu_buf_ptr || !mon->qemu_buf_ptr->enabled)
+	return;
+
+    while(1) {
+	if(!read_trace_from_buffer(mon->qemu_buf_ptr, &data))
+	    break ;
+	/* qemu_dump_trace() is a simple hex dump */
+//	 qemu_dump_trace(mon, &data);
+	print_trace(&data, mon);
+    };
+    return;
+}
+#else /* CONFIG_QEMU_TRACE */
+static void do_info_trace(Monitor *mon)
+{
+    monitor_printf(mon, "Internal tracing not compiled\n");
+}
+#endif
+
 /* Capture support */
 static QLIST_HEAD (capture_list_head, CaptureState) capture_head;
 
@@ -2779,6 +2878,20 @@ static const mon_cmd_t info_cmds[] = {
         .mhandler.info = do_info_roms,
     },
     {
+        .name       = "trace",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show contents of trace buffer",
+        .mhandler.info = do_info_trace,
+    },
+    {
+        .name       = "tracepoint",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show contents of trace buffer",
+        .mhandler.info = do_info_tracepoint,
+    },
+    {
         .name       = NULL,
     },
 };
@@ -4633,6 +4746,9 @@ void monitor_init(CharDriverState *chr, 
     QLIST_INSERT_HEAD(&mon_list, mon, entry);
     if (!default_mon || (flags & MONITOR_IS_DEFAULT))
         default_mon = mon;
+
+    /* Disable trace buffer unless enabled */
+    mon->qemu_buf_ptr = NULL;
 }
 
 static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
Index: qemu/trace-buffer.c
===================================================================
--- /dev/null
+++ qemu/trace-buffer.c
@@ -0,0 +1,111 @@
+/*
+ * Trace buffer implementation for QEMU.
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Author:
+ *  Prerna   <prerna@linux.vnet.ibm.com>
+ *
+ *  This work is licensed under the terms of the GNU GPL, version 2.  See
+ *  the COPYING file in the top-level directory.
+ *
+ */
+
+#include<string.h>
+
+#include "trace-buffer.h"
+
+#define INCREMENT_INDEX(HEAD,IDX) (HEAD->IDX++) % HEAD->buf_size
+/* TODOS :
+ * functions for computing timestamps, etc
+ */
+
+/* Trace Buffer Manipulation Functions */
+
+/* Initialise the buffer.
+ * @head	: pointer to the trace queue
+ */
+void initialize_buffer(struct DebugBuffer *head)
+{
+    if (!head)         /* Buffer doesnt exist, do nothing */
+       return ;
+
+    head->buf_size = BUFFER_SIZE;
+    head->first = head->last = 0;
+    head->enabled = 1;
+    return;
+}
+
+/* Write trace data to buffer.
+ * @trace_queue	: pointer to the trace queue.
+ * @data	: data to be written.
+ * @len         : Length of data to be written.
+ * @type       	: class of events.
+ * return      	: 0 for successful write.
+ *             	: -1 if size of data exceeds slot size.
+ */
+int write_trace_to_buffer(struct DebugBuffer *trace_queue,
+			uint32_t hash, uint8_t id, const void *data,
+				size_t len/*, EVENT_TYPE etype*/)
+{
+    int tmp;
+
+    /* Exit early if tracing is disabled */
+    if (!trace_queue || !trace_queue->enabled)
+	return -1;
+
+    /* Data not available or too large data */
+    if (!data || !len || len > EFFECTIVE_SLOT_SIZE - 5)
+       return -1;
+
+    /* NOTE : the buffer operates in overwrite mode */
+    tmp = trace_queue->last;
+    if ((trace_queue->last + 1) % trace_queue->buf_size
+					 == trace_queue->first)
+	trace_queue->first = INCREMENT_INDEX(trace_queue, first);
+    trace_queue->last  = INCREMENT_INDEX(trace_queue, last);
+
+    /* TODO: Placeholder for timestamp computation */
+
+    trace_queue->trace_buffer[tmp].metadata.write_complete = 0;
+    memcpy(trace_queue->trace_buffer[tmp].data, &hash, sizeof(hash));
+    memcpy(&trace_queue->trace_buffer[tmp].data[sizeof(hash)], &id,
+								sizeof(id));
+    memcpy(&trace_queue->trace_buffer[tmp].data[sizeof(hash)+sizeof(id)],
+								 data, len);
+    memset(&trace_queue->trace_buffer[tmp].data[len+sizeof(hash)+ sizeof(id)],
+		0, EFFECTIVE_SLOT_SIZE-len-(sizeof(hash)+sizeof(id)));
+    trace_queue->trace_buffer[tmp].metadata.write_complete = 1;
+    return 0;
+}
+
+/* Read trace data from buffer.
+ * @trace_queue	: pointer to the trace queue.
+ * @data      	: pointer to DebugEntry variable
+ *                into which data gets read.
+ * return      	: pointer to address of DebugEntry variable
+ *                into which data gets read.
+ *                NULL in case of error.
+ */
+struct DebugEntry* read_trace_from_buffer(struct DebugBuffer *trace_queue,
+						struct DebugEntry *data)
+{
+    /* Exit early if tracing is disabled */
+    if (!trace_queue->enabled)
+	return NULL;
+
+    if (!trace_queue || !data )
+	return NULL;
+
+    /* check for empty buffer OR incomplete writes*/
+    if (trace_queue->first == trace_queue->last ||
+	!trace_queue->trace_buffer[trace_queue->first].
+					metadata.write_complete)
+	return NULL;
+
+    memcpy(data, &trace_queue->trace_buffer[trace_queue->first],
+					 sizeof(struct DebugEntry));
+    trace_queue->first = INCREMENT_INDEX(trace_queue, first);
+
+    return data;
+}
Index: qemu/trace-buffer.h
===================================================================
--- /dev/null
+++ qemu/trace-buffer.h
@@ -0,0 +1,56 @@
+/*
+ * Trace buffer implementation for QEMU.
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Author:
+ *   Prerna   <prerna@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+
+#ifndef __TRACE_BUFFER_H__
+#define __TRACE_BUFFER_H__
+#include<stdint.h>
+
+#include"qemu-common.h"
+
+#define BUFFER_SIZE		128 /* Number of debug slots */
+#define SLOT_SIZE       	40 /* size of buffer slot in bytes */
+#define EFFECTIVE_SLOT_SIZE     SLOT_SIZE-9
+
+struct DebugEntry{
+    char data[EFFECTIVE_SLOT_SIZE];
+    uint64_t timestamp;
+    struct {
+	unsigned write_complete :1;
+	unsigned reserved :7;
+	} metadata;
+};
+
+struct DebugBuffer {
+	uint8_t enabled;	/* flag to test if buffer is enabled */
+				/* 1 for enabled, 0 for disabled */
+	uint16_t buf_size;	/* Size of buffer */
+	uint16_t first;		/* Index to first entry of queue
+				 * from where first 'read' occurs.
+				 */
+	uint16_t last;		/* Index to last entry of queue
+				 * at which next 'write' must occur.
+				 */
+	struct DebugEntry trace_buffer[BUFFER_SIZE];
+};
+
+struct DebugBuffer qemu_buf;
+
+/* Trace Buffer manipulation functions */
+void initialize_buffer (struct DebugBuffer *head);
+int write_trace_to_buffer(struct DebugBuffer *trace_queue,
+			uint32_t hash, uint8_t id, const void *data,
+					size_t len/*, EVENT_TYPE etype*/);
+struct DebugEntry * read_trace_from_buffer(struct DebugBuffer *trace_queue,
+						struct DebugEntry *data);
+#endif /* __TRACE_BUFFER_H__ */
Index: qemu/qemu-monitor.hx
===================================================================
--- qemu.orig/qemu-monitor.hx
+++ qemu/qemu-monitor.hx
@@ -114,6 +114,10 @@ show migration status
 show balloon information
 @item info qtree
 show device tree
+@item info trace
+show contents of trace buffer
+@item info tracepoint
+show status of all tracepoints
 @end table
 ETEXI
 
@@ -158,7 +162,7 @@ ETEXI
 
 STEXI
 @item change @var{device} @var{setting}
-@findex change
+@findex :change
 
 Change the configuration of a device.
 
@@ -235,9 +239,41 @@ STEXI
 @item log @var{item1}[,...]
 @findex log
 Activate logging of the specified items to @file{/tmp/qemu.log}.
+#ifdef CONFIG_QEMU_TRACE
 ETEXI
 
     {
+        .name       = "trace",
+        .args_type  = "option:s?",
+        .params     = "[on|off]",
+        .help       = "activate logging of the specified items ",
+        .mhandler.cmd = do_trace,
+    },
+
+STEXI
+@item trace [on|off]
+@findex trace
+If called with option on, it enables tracing.
+If called with option off, tracing is disabled.
+#endif
+ETEXI
+
+    {
+        .name       = "tracepoint",
+        .args_type  = "name:s,option:s",
+        .params     = "name on|off",
+        .help       = "activate / deactivate tracepoint ",
+        .mhandler.cmd = do_tracepoint_status,
+    },
+
+STEXI
+@item tracepoint @var [on|off]
+@findex tracepoint
+If called with option 'on', it enables tracepoint @var.
+If called with option 'off', tracepoint @var is disabled.
+ETEXI
+
+     {
         .name       = "savevm",
         .args_type  = "name:s?",
         .params     = "[tag|id]",
Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c
+++ qemu/vl.c
@@ -166,6 +166,10 @@ int main(int argc, char **argv)
 //#define DEBUG_NET
 //#define DEBUG_SLIRP
 
+#ifdef CONFIG_QEMU_TRACE
+#include "trace-entries.h"
+#endif
+
 #define DEFAULT_RAM_SIZE 128
 
 #define MAX_VIRTIO_CONSOLES 1
@@ -3653,6 +3657,11 @@ int main(int argc, char **argv, char **e
         drive_add(NULL, SD_ALIAS);
     }
 
+#ifdef CONFIG_QEMU_TRACE
+    init_tracepoint_tbl();
+    init_tracepoints();
+#endif
+
     /* open the virtual block devices */
     if (snapshot)
         qemu_opts_foreach(&qemu_drive_opts, drive_enable_snapshot, NULL, 0);
Index: qemu/configure
===================================================================
--- qemu.orig/configure
+++ qemu/configure
@@ -283,6 +283,7 @@ bsd="no"
 linux="no"
 solaris="no"
 profiler="no"
+trace="no"
 cocoa="no"
 softmmu="yes"
 linux_user="no"
@@ -575,6 +576,10 @@ for opt do
   ;;
   --enable-profiler) profiler="yes"
   ;;
+  --enable-trace) trace="yes"
+  ;;
+  --disable-trace) trace="no"
+  ;;
   --enable-cocoa)
       cocoa="yes" ;
       sdl="no" ;
@@ -2003,6 +2008,7 @@ echo "gprof enabled     $gprof"
 echo "sparse enabled    $sparse"
 echo "strip binaries    $strip_opt"
 echo "profiler          $profiler"
+echo "trace             $trace"
 echo "static build      $static"
 echo "-Werror enabled   $werror"
 if test "$darwin" = "yes" ; then
@@ -2121,6 +2127,9 @@ fi
 if test $profiler = "yes" ; then
   echo "CONFIG_PROFILER=y" >> $config_host_mak
 fi
+if test $trace = "yes" ; then
+  echo "CONFIG_QEMU_TRACE=y" >> $config_host_mak
+fi
 if test "$slirp" = "yes" ; then
   echo "CONFIG_SLIRP=y" >> $config_host_mak
   QEMU_CFLAGS="-I\$(SRC_PATH)/slirp $QEMU_CFLAGS"
Index: qemu/Makefile.target
===================================================================
--- qemu.orig/Makefile.target
+++ qemu/Makefile.target
@@ -162,6 +162,10 @@ endif #CONFIG_BSD_USER
 ifdef CONFIG_SOFTMMU
 
 obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o
+#add option for trace-buffer to be integrated
+ifdef CONFIG_QEMU_TRACE
+obj-y += $(trace-obj-y)
+endif
 # virtio has to be here due to weird dependency between PCI and virtio-net.
 # need to fix this properly
 obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
Index: qemu/tracepoint.h
===================================================================
--- /dev/null
+++ qemu/tracepoint.h
@@ -0,0 +1,95 @@
+/*
+ * Tracepoint implementation for QEMU.
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Author:
+ *  Prerna   <prerna@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef __TRACEPOINT_H__
+#define __TRACEPOINT_H__
+#include<stdarg.h>
+
+#include "qemu-queue.h"
+#include "trace-buffer.h"
+#include "monitor.h"
+#include "qdict.h"
+
+struct tracepoint {
+	char *name;			/* Tracepoint name */
+	uint8_t  trace_id;		/* numerical ID */
+	uint8_t state;			/* State. */
+	void (*print_fn)(Monitor *mon, void *ptr);
+					/* print function */
+} __attribute__((aligned(32)));
+
+#define DECLARE_TRACE(name, tproto, tstruct)			\
+	struct __trace_struct_##name {				\
+		tstruct						\
+	};							\
+	extern void trace_##name(tproto);			\
+	extern void __trace_print_##name(Monitor *mon, void *data);
+
+#define DEFINE_TRACE(name, tproto, tassign, tprint)	\
+	void trace_##name(tproto)				\
+	{ 							\
+	  unsigned int hash;					\
+	  char tpname[] = __stringify(name);			\
+	  struct tracepoint *tp;				\
+	  struct __trace_struct_##name var, *entry;		\
+								\
+	  hash = tdb_hash(tpname);		\
+	  tp = find_tracepoint_by_name(tpname);			\
+	  if (tp == NULL || !tp->state)				\
+		return;						\
+								\
+	  entry = &var;						\
+	  tassign						\
+								\
+	  write_trace_to_buffer(&qemu_buf, hash, tp->trace_id,	\
+		entry, sizeof(struct __trace_struct_##name));	\
+	}							\
+								\
+	void __trace_print_##name(Monitor *mon, void *data)	\
+	{							\
+	  struct __trace_struct_##name *entry;			\
+								\
+	  if(!entry)						\
+		return;						\
+								\
+	  entry = (struct __trace_struct_##name *)data;		\
+	  monitor_printf(mon,tprint);				\
+	  return;						\
+	}
+
+#define INIT_TRACE(name) 					\
+	register_tracepoint(__stringify_1(name), __trace_print_##name)
+
+#define DO_TRACE(name, args...)					\
+	    trace_##name(args);
+
+#define TP_PROTO(proto...)		proto
+#define TP_ARGS(args...)		args
+#define __field(type, item)            	type    item
+#define TP_STRUCT__entry(args...) 	args
+#define TP_fast_assign(args...) 	args
+
+#define __entry		 		entry
+#define __stringify_1(x...)		#x
+#define __stringify(x...)		__stringify_1(x)
+#define TP_printk(fmt, args...) 	 fmt, args
+
+
+void init_tracepoint_tbl(void);
+extern struct tracepoint* register_tracepoint(const char *name,
+			void *print_func);
+extern struct tracepoint* find_tracepoint_by_name(const char *name);
+extern struct tracepoint* find_tracepoint_by_id(uint32_t hash, uint8_t id);
+extern void print_trace(struct DebugEntry *ptr, Monitor *mon);
+void do_info_tracepoint(Monitor *mon);
+#endif /* __TRACEPOINT_H__ */
Index: qemu/tracepoint.c
===================================================================
--- /dev/null
+++ qemu/tracepoint.c
@@ -0,0 +1,216 @@
+/*
+ * Tracepoint implementation for QEMU.
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Author:
+ *  Prerna   <prerna@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "tracepoint.h"
+
+#define TRACEPOINT_HASH_BITS 6
+#define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS)
+static QLIST_HEAD(tracepoint_head, tracepoint_lib)
+			tracepoint_table[TRACEPOINT_TABLE_SIZE];
+
+/* In essence, the structure becomes :
+ * struct tracepoint_lib {
+ * 	struct tracepoint {
+ * 		char *name;
+ * 		uint8_t trace_id;
+ * 		uint8_t state;
+ * 		void (*print_fn)(Monitor *mon, void *ptr);
+ * 	}entry;
+ * 	struct {
+ * 		struct tracepoint_lib *le_next;
+ * 		struct tracepoint_lib **le_prev;
+ * 	}list_ptr;
+ *
+ */
+struct tracepoint_lib {
+	struct tracepoint entry;
+	QLIST_ENTRY(tracepoint_lib) list_ptr;
+};
+
+/*
+ * Initialize tracepoint table
+ *
+ */
+void init_tracepoint_tbl(void)
+{
+    int i=0;
+    for (i=0; i< TRACEPOINT_TABLE_SIZE; i++)
+	QLIST_INIT(&tracepoint_table[i]);
+}
+
+/*
+ * Register a given tracepoint in the global library
+ * @name : tracepoint name string
+ * @print_func : ptr to function that eventually prints logged traces.
+ * return : struct tracepoint * , NULL for error.
+ *
+ */
+struct tracepoint* register_tracepoint(const char *name, void *print_func)
+{
+    unsigned int hash;
+    uint8_t idx=0;
+    struct tracepoint_head *head;
+    struct tracepoint_lib *e, *new_entry, *prev;
+
+    if (!name || !print_func)
+	return NULL;
+
+    hash = tdb_hash(name);
+    head = &tracepoint_table[hash % TRACEPOINT_TABLE_SIZE];
+
+    e = find_tracepoint_by_name(name);
+    if (e)
+	return e;
+
+    new_entry = (struct tracepoint_lib*)
+	qemu_malloc(sizeof(struct tracepoint_lib));
+
+    if (!new_entry)
+	return NULL;	/* No memory */
+
+    new_entry->entry.name = (char*)qemu_malloc(strlen(name)+1);
+    if(!new_entry->entry.name)
+	return NULL;
+
+    strncpy(new_entry->entry.name, name, strlen(name)+1);
+    new_entry->entry.trace_id = 0; 	/* Trace ID */
+    new_entry->entry.state = 0; 	/* inactive */
+    new_entry->entry.print_fn = print_func;
+    new_entry->list_ptr.le_next = NULL;
+    new_entry->list_ptr.le_prev = NULL;
+
+    /* Add entry to tracepoint lib */
+    if (!QLIST_EMPTY(head)) {
+	prev = QLIST_FIRST(head);
+	QLIST_FOREACH(e, head, list_ptr) {
+	    idx++;
+	    prev = e;
+	    if (!strcmp(name, e->entry.name)) {
+		qemu_free(new_entry->entry.name);
+		qemu_free(new_entry);
+	        return NULL;	/* Already exists */
+	        }
+	    }
+	new_entry->entry.trace_id = idx; 	/* Trace ID */
+	QLIST_INSERT_AFTER(prev, new_entry, list_ptr);
+	}
+    else
+	QLIST_INSERT_HEAD(head, new_entry, list_ptr);
+
+    return &(new_entry->entry);
+}
+
+/*
+ * Return tracepoint* for a given name
+ * @name : name string
+ * return : struct tracepoint* in case of a successful match
+ * 	NULL otherwise.
+ *
+ */
+struct tracepoint* find_tracepoint_by_name(const char *name)
+{
+    unsigned int hash;
+    struct tracepoint_head *head;
+    struct tracepoint_lib *e;
+
+    if(name == NULL)
+	return NULL;
+
+    hash = tdb_hash(name);
+    head = &tracepoint_table[hash % TRACEPOINT_TABLE_SIZE];
+
+    if(QLIST_EMPTY(head))
+	return NULL;
+
+    QLIST_FOREACH(e, head, list_ptr) {
+	if(!strcmp(name, e->entry.name))
+	     return &(e->entry);
+	}
+
+    return NULL;
+}
+
+/*
+ * Return struct tracepoint entry corresponding to
+ * a given hash and id.
+ *
+ * @hash: hash value of tracepoint name
+ * @id	: trace_id of the tracepoint
+ *
+ */
+struct tracepoint* find_tracepoint_by_id(unsigned int hash, uint8_t id)
+{
+    struct tracepoint_head *head;
+    struct tracepoint_lib *e;
+
+    head = &tracepoint_table[hash % TRACEPOINT_TABLE_SIZE];
+
+    if(QLIST_EMPTY(head)) /* List empty */
+	return NULL;
+
+    QLIST_FOREACH(e, head, list_ptr) {
+	if(e->entry.trace_id == id)
+	     return &(e->entry);
+	}
+
+    return NULL; /* Not found */
+}
+
+/*
+ * Display data logged
+ *
+ * @ptr	: pointer to the DebugEntry in the trace buffer
+ * @mon	: pointer to Monitor
+ *
+ */
+void print_trace(struct DebugEntry *ptr, Monitor *mon)
+{
+    unsigned int hash;
+    uint8_t id;
+    struct tracepoint *tp;
+
+    if(ptr == NULL)
+	return;
+
+    memcpy(&hash, ptr->data, sizeof(hash));
+    id = ptr->data[sizeof(hash)];
+
+    tp = find_tracepoint_by_id(hash, id);
+    if (tp == NULL) {
+	monitor_printf(mon, "Not found : hash %u, id %u\n",hash, id);
+	return;
+	}
+
+//     monitor_printf(mon, "Found %s : hash %u, id %u\n",tp->name, hash, id);
+    (tp->print_fn)(mon, (void*)&ptr->data[sizeof(hash)+sizeof(id)]);
+    return;
+}
+
+/*
+ * Print all available tracepoints with their status.
+ * (Called from monitor)
+ */
+void do_info_tracepoint(Monitor *mon)
+{
+    int i;
+    struct tracepoint_head *head;
+    struct tracepoint_lib *e;
+
+    for (i=0; i< TRACEPOINT_TABLE_SIZE; i++) {
+	head = &tracepoint_table[i];
+	if(!QLIST_EMPTY(head)) {
+	    QLIST_FOREACH(e, head, list_ptr)
+		monitor_printf(mon, "%s %d\n", e->entry.name, e->entry.state);
+	}
+    }
+}
Index: qemu/trace-entries.h
===================================================================
--- /dev/null
+++ qemu/trace-entries.h
@@ -0,0 +1,33 @@
+/*
+ * Tracepoint declarations for QEMU.
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Author:
+ *  Prerna   <prerna@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef __TRACE_ENTRIES_H__
+#define __TRACE_ENTRIES_H__
+
+#include "tracepoint.h"
+
+void init_tracepoints(void);
+
+/*
+ * Add DECLARE_TRACE macros here.
+ *
+ * DECLARE_TRACE( name,
+ * 	TP_PROTO( type1 var1, type2 var2..),
+ * 	TP_STRUCT__entry(
+ * 			__field(type1, var1);
+ * 			__field(type2, var2);...
+ * 		),
+ * )
+ */
+
+#endif /*__TRACE_ENTRIES_H__ */
Index: qemu/trace-entries.c
===================================================================
--- /dev/null
+++ qemu/trace-entries.c
@@ -0,0 +1,40 @@
+/*
+ *  Tracepoint declaration(s) for QEMU.
+ *
+ *  Copyright IBM, Corp. 2010
+ *
+ *  Author:
+ *   Prerna   <prerna@linux.vnet.ibm.com>
+ *
+ *  This work is licensed under the terms of the GNU GPL, version 2.  See
+ *  the COPYING file in the top-level directory.
+ *
+ */
+#include "trace-entries.h"
+/*
+ * Initialize tracepoints
+ * Add INIT_TRACE() macro for each tracepoint you declare,
+ * inside this function.
+ *
+ */
+void init_tracepoints(void)
+{
+// INIT_TRACE(foo);
+
+   return;
+}
+
+/*
+ * Add a DEFINE_TRACE() macro for each tracepoint you declare.
+ *
+ * DEFINE_TRACE( name,
+ *     TP_PROTO( type1 var1, type2 var2..),
+ *     TP_fast_assign(
+ *                     __entry->var1 = arg1;
+ *                     __entry->var2 = arg2;...
+ *             ),
+ *     TP_printk("....", __entry->var1, __entry->var2) // No semicolon at end
+ * )
+ *
+ */
+
Index: qemu/Makefile.objs
===================================================================
--- qemu.orig/Makefile.objs
+++ qemu/Makefile.objs
@@ -5,6 +5,10 @@ qobject-obj-y += qjson.o json-lexer.o js
 qobject-obj-y += qerror.o
 
 #######################################################################
+# Trace Object
+trace-obj-y = trace-buffer.o tracepoint.o trace-entries.o $(SRC_PATH)/qdict.h
+
+#######################################################################
 # block-obj-y is code used by both qemu system emulation and qemu-img
 
 block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
Index: qemu/Makefile
===================================================================
--- qemu.orig/Makefile
+++ qemu/Makefile
@@ -1,6 +1,6 @@
 # Makefile for QEMU.
 
-GENERATED_HEADERS = config-host.h
+GENERATED_HEADERS = config-host.h trace-entries.h
 
 ifneq ($(wildcard config-host.mak),)
 # Put the all: rule here so that config-host.mak can contain dependencies.
@@ -130,16 +130,18 @@ bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS
 
 iov.o: iov.c iov.h
 
+#tracepoint.o: tracepoint.h tracepoint.c $(SRC_PATH)/qdict.h
+
 ######################################################################
 
 qemu-img.o: qemu-img-cmds.h
 qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o: $(GENERATED_HEADERS)
 
-qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y)
+qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y) $(trace-obj-y)
 
-qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y)
+qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y) $(trace-obj-y)
 
-qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y)
+qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(block-obj-y) $(qobject-obj-y) $(trace-obj-y)
 
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $@")

  reply	other threads:[~2010-05-24 16:17 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-05-24 16:05 [Qemu-devel] [RFC 0/3] Tracing framework for QEMU Prerna Saxena
2010-05-24 16:15 ` [Qemu-devel] [PATCH 1/3]make tdb_hash available Prerna Saxena
2010-05-24 16:16   ` Prerna Saxena [this message]
2010-05-25 11:40     ` [Qemu-devel] [PATCH 2/3] Tracepoint, buffer & monitor framework Stefan Hajnoczi
2010-05-25 18:20       ` Prerna Saxena
2010-05-25 20:07         ` Stefan Hajnoczi
2010-05-24 16:19   ` [Qemu-devel] [PATCH 3/3] Samples to add a tracepoint Prerna Saxena
2010-05-25 11:38     ` Stefan Hajnoczi
2010-05-25 11:43 ` [Qemu-devel] [RFC 0/3] Tracing framework for QEMU Stefan Hajnoczi
2010-06-08  8:35   ` Prerna Saxena

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4BFAA673.4050809@linux.vnet.ibm.com \
    --to=prerna@linux.vnet.ibm.com \
    --cc=aliguori@us.ibm.com \
    --cc=ananth@linux.vnet.ibm.com \
    --cc=maneesh@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.