Monitor support QEMU trace framework
cover Monitor support QEMU trace framework
This is v3 of a set of patches to enable trace visualization & control via the QEMU monitor. It is based on trace infrastructure posted by Stefan :
( http://lists.gnu.org/archive/html/qemu-devel/2010-05/msg02407.html )
This patchset adds monitor commands :
- info trace : to view current contents of the trace buffer
- info tracepoints : to view all available tracepoints and their state.
- tracepoint NAME on|off : to enable/disable the logging of data from tracepoint 'NAME' to on/off.
Changelog :
- Clean-ups from v2, particularly relating to export of tdb_hash()
Signature · 5 lines
Prerna Saxena Linux Technology Centre, IBM Systems and Technology Lab, Bangalore, India
PATCH 1/3 Export hash function
Rename tdb_hash() to qemu_hash().
Move definition from qdict.c to a new file qemu-misc.c for use by tracing infrastructure.
---
Makefile.objs | 2 +- qdict.c | 24 ++++-------------------- qemu-common.h | 3 +++ qemu-misc.c | 24 ++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 21 deletions(-) create mode 100644 qemu-misc.c
Makefile.objs +1 -1
@@ -1,6 +1,6 @@ ####################################################################### # QObject -qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o +qobject-obj-y = qint.o qstring.o qdict.o qemu-misc.o qlist.o qfloat.o qbool.o qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o qobject-obj-y += qerror.o
qdict.c +4 -20
@@ -53,22 +53,6 @@ QDict *qobject_to_qdict(const QObject *obj) }/** -* tdb_hash(): based on the hash agorithm from gdbm, via tdb -* (from module-init-tools) -*/ -static unsigned int tdb_hash (const char *name) -{ -unsigned value;/* Used to compute the hash value. */ -unsigned i;/* Used to cycle through random values. */ - -/* Set the initial value from the key size. */ -for (value =0x238F13AF *strlen (name), i=0 ; name[i]; i++) - value = (value + (((const unsigned char *)name)[i] << (i*5 %24 ))); - -return (1103515243 * value +12345 ); -} - -/** * alloc_entry(): allocate a new QDictEntry */ static QDictEntry *alloc_entry (const char *key,QObject *value)
@@ -113,7 +97,7 @@ void qdict_put_obj(QDict *qdict, const char *key, QObject *value)unsigned int hash;QDictEntry *entry; - hash =tdb_hash (key) %QDICT_HASH_SIZE ; + hash =qemu_hash (key) %QDICT_HASH_SIZE ; entry =qdict_find (qdict, key, hash);if (entry) {/* replace key's value */
@@ -137,7 +121,7 @@ QObject *qdict_get(const QDict *qdict, const char *key) {QDictEntry *entry; - entry =qdict_find (qdict, key,tdb_hash (key) %QDICT_HASH_SIZE ); + entry =qdict_find (qdict, key,qemu_hash (key) %QDICT_HASH_SIZE );return (entry ==NULL ?NULL : entry->value); }
@@ -148,7 +132,7 @@ QObject *qdict_get(const QDict *qdict, const char *key)*/ int qdict_haskey (const QDict *qdict,const char *key) { -unsigned int hash =tdb_hash (key) %QDICT_HASH_SIZE ; +unsigned int hash =qemu_hash (key) %QDICT_HASH_SIZE ;return (qdict_find (qdict, key, hash) ==NULL ?0 :1 ); }
@@ -347,7 +331,7 @@ void qdict_del(QDict *qdict, const char *key) {QDictEntry *entry; - entry =qdict_find (qdict, key,tdb_hash (key) %QDICT_HASH_SIZE ); + entry =qdict_find (qdict, key,qemu_hash (key) %QDICT_HASH_SIZE );if (entry) {QLIST_REMOVE (entry, next);qentry_destroy (entry);
qemu-common.h +3 -0
@@ -17,6 +17,9 @@ typedef struct QEMUTimer QEMUTimer;typedef struct QEMUFile QEMUFile ;typedef struct QEMUBH QEMUBH ; +/* Hash function definition */ +unsigned int qemu_hash (const char *name); +/* Hack around the mess dyngen-exec.h causes: We need QEMU_NORETURN in files that cannot include the following headers without conflicts. This condition has to be removed once dyngen is gone. */
qemu-misc.c new file +24 -0
@@ -0,0 +1,24 @@ +/* +* Definition of tdb_hash() moved here, from qdict.c. Renamed to qemu_hash() +* +* This work is licensed under the terms of the GNU LGPL, version 2.1 or later. +* See the COPYING.LIB file in the top-level directory. +* +*/ +#include "qemu-common.h" + +/** +* tdb_hash(): based on the hash agorithm from gdbm, via tdb +* (from module-init-tools). Renamed to qemu_hash(). +*/ +unsigned int qemu_hash (const char *name) +{ +unsigned value;/* Used to compute the hash value. */ +unsigned i;/* Used to cycle through random values. */ + +/* Set the initial value from the key size. */ +for (value =0x238F13AF *strlen (name), i=0 ; name[i]; i++) + value = (value + (((const unsigned char *)name)[i] << (i*5 %24 ))); + +return (1103515243 * value +12345 ); +}
Signature · 5 lines
Prerna Saxena Linux Technology Centre, IBM Systems and Technology Lab, Bangalore, India
PATCH 2/3 Monitor command 'info trace'
In reply to Prerna SaxenaMonitor command 'info trace' to display contents of trace buffer
---
configure | 3 +++ monitor.c | 12 ++++++++++++ qemu-monitor.hx | 4 ++++ simpletrace.c | 13 +++++++++++++ tracetool | 2 ++ 5 files changed, 34 insertions(+), 0 deletions(-)
configure +3 -0
@@ -2302,6 +2302,9 @@ bsd) esac echo "TRACE_BACKEND=$trace_backend" >> $config_host_mak +if test "$trace_backend" = "simple"; then + echo "CONFIG_SIMPLE_TRACE=y" >> $config_host_mak +fi if test "$trace_backend" = "ust"; then LIBS="-lust $LIBS" fi
monitor.c +12 -0
@@ -55,6 +55,9 @@#include "json-streamer.h" #include "json-parser.h" #include "osdep.h" +#ifdef CONFIG_SIMPLE_TRACE +#include "trace.h" +#endif //#define DEBUG //#define DEBUG_COMPLETION
@@ -2780,6 +2783,15 @@ static const mon_cmd_t info_cmds[] = { .help = "show roms", .mhandler.info = do_info_roms, }, +#if defined(CONFIG_SIMPLE_TRACE) + { + .name = "trace", + .args_type = "", + .params = "", + .help = "show current contents of trace buffer", + .mhandler.info = do_info_trace, + }, +#endif { .name = NULL, },
qemu-monitor.hx +4 -0
@@ -114,6 +114,10 @@ show migration status show balloon information @item info qtree show device tree +#ifdef CONFIG_SIMPLE_TRACE +@item info trace +show contents of trace buffer +#endif @end table ETEXI
simpletrace.c +13 -0
@@ -62,3 +62,16 @@ void trace4(TraceEvent event, unsigned long x1, unsigned long x2, unsigned longvoid trace5 (TraceEvent event,unsigned long x1,unsigned long x2,unsigned long x3,unsigned long x4,unsigned long x5) {trace (event, x1, x2, x3, x4, x5); } + +void do_info_trace (Monitor *mon) +{ +unsigned int i, max_idx; + + max_idx = trace_idx ? trace_idx :TRACE_BUF_LEN ; + +for (i=0 ; i<max_idx ;i++) { +monitor_printf (mon,"Event %ld : %ld %ld %ld %ld %ld\n" , + trace_buf[i].event, trace_buf[i].x1, trace_buf[i].x2, + trace_buf[i].x3, trace_buf[i].x4, trace_buf[i].x5); + } +}
tracetool +2 -0
@@ -130,6 +130,7 @@ 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); EOF simple_event_num=0
@@ -289,6 +290,7 @@ tracetoh() #define TRACE_H #include "qemu-common.h" +#include "monitor.h" EOF convert h echo "#endif /* TRACE_H */"
Signature · 5 lines
Prerna Saxena Linux Technology Centre, IBM Systems and Technology Lab, Bangalore, India
Re: [PATCH 2/3] Monitor command 'info trace'
Quoted 5 lines · Prerna Saxena
simpletrace.c +0
-0
simpletrace.c void trace4(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long · line 70
Quoted 9 lines
simpletrace.c +6
-0@@ -62,3 +62,16 @@ void trace4(TraceEvent event, unsigned long x1, unsigned long x2, unsigned longvoid trace5 (TraceEvent event,unsigned long x1,unsigned long x2,unsigned long x3,unsigned long x4,unsigned long x5) {trace (event, x1, x2, x3, x4, x5); } + +void do_info_trace (Monitor *mon) +{ +unsigned int i, max_idx; + + max_idx = trace_idx ? trace_idx :TRACE_BUF_LEN ;
trace_idx is always in the range [0, TRACE_BUF_LEN). There is no need to perform this test.
simpletrace.c void trace4(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long · line 72
Quoted 2 lines
simpletrace.c +2
-0+ +for (i=0 ; i<max_idx ;i++) {
Whitespace "i=0; i<max_idx ;i++". "i = 0; i < max_idx; i++" is pretty common across QEMU.
simpletrace.c void trace4(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long · line 75
Quoted 3 lines
simpletrace.c +3
-0+monitor_printf (mon,"Event %ld : %ld %ld %ld %ld %ld\n" , + trace_buf[i].event, trace_buf[i].x1, trace_buf[i].x2, + trace_buf[i].x3, trace_buf[i].x4, trace_buf[i].x5);
Getting only numeric output is the limitation of a binary trace. It would probably be possible to pretty-print without much additional code by using the format strings from the trace-events file.
I think the numeric dump is good for now though. Hex is more compact than decimal and would make pointers easier to spot. Want to change this?
Quoted 15 lines
simpletrace.c +2
-0+ } +}tracetool +1
-0@@ -130,6 +130,7 @@ 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); EOF simple_event_num=0
tracetool tracetoh() · line 293
Quoted 4 lines
tracetool +1
-0@@ -289,6 +290,7 @@ tracetoh() #define TRACE_H #include "qemu-common.h" +#include "monitor.h"
qemu-common.h forward-declares Monitor, I don't think you need monitor.h.
Stefan
Re: [PATCH 2/3] Monitor command 'info trace'
Hi Stefan, Jan,
Thanks for taking a look.
Quoted 10 lines · Stefan Hajnoczi
Quoted 9 lines · Prerna Saxena
simpletrace.c +1
-0@@ -62,3 +62,16 @@ void trace4(TraceEvent event, unsigned long x1, unsigned long x2, unsigned longvoid trace5 (TraceEvent event,unsigned long x1,unsigned long x2,unsigned long x3,unsigned long x4,unsigned long x5) {trace (event, x1, x2, x3, x4, x5); } +
Quoted 8 lines
simpletrace.c void trace4(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long · line 70
Quoted 5 lines
simpletrace.c +5
-0+void do_info_trace (Monitor *mon) +{ +unsigned int i, max_idx; + + max_idx = trace_idx ? trace_idx :TRACE_BUF_LEN ;
trace_idxis always in the range [0,TRACE_BUF_LEN). There is no need to perform this test.
I only display the logged contents in the trace buffer (till trace_idx) , and not the entire trace buffer. Only when the index is full that the entire buffer is displayed.
Quoted 7 lines
simpletrace.c void trace4(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long · line 72
Quoted 3 lines
simpletrace.c +2
-0+ +for (i=0 ; i<max_idx ;i++) {Whitespace "i=0; i<max_idx ;i++". "i = 0; i<
max_idx; i++" is pretty common across QEMU.
I'll fix this.
Quoted 4 lines
simpletrace.c void trace4(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long · line 75
Quoted 3 lines
simpletrace.c +3
-0+monitor_printf (mon,"Event %ld : %ld %ld %ld %ld %ld\n" , + trace_buf[i].event, trace_buf[i].x1, trace_buf[i].x2, + trace_buf[i].x3, trace_buf[i].x4, trace_buf[i].x5);
Quoted 8 lines
Getting only numeric output is the limitation of a binary trace. It would probably be possible to pretty-print without much additional code by using the format strings from the trace-events file.
I think the numeric dump is good for now though. Hex is more compact than decimal and would make pointers easier to spot. Want to change this?
I agree, but we can let this be a todo till after the first prototype goes upstream ?
Quoted 17 lines
Quoted 17 lines
simpletrace.c +2
-0+ } +}tracetool +1
-0@@ -130,6 +130,7 @@ 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); EOF simple_event_num=0@@ -289,6 +290,7 @@ tracetoh() #define TRACE_H
Quoted 6 lines
tracetool tracetoh() · line 293
Quoted 2 lines
tracetool +1
-0#include "qemu-common.h" +#include "monitor.h"
qemu-common.hforward-declares Monitor, I don't think you needmonitor.h.
Right.
Quoted 1 line
Stefan
I'll post patches by Monday that addresses your suggestions, and try to get it integrated with QMP.
Signature · 5 lines
Prerna Saxena Linux Technology Centre, IBM Systems and Technology Lab, Bangalore, India
Re: [PATCH 2/3] Monitor command 'info trace'
Quoted 27 lines · Prerna Saxena
Hi Stefan, Jan,
Thanks for taking a look.Quoted 14 lines · Stefan Hajnoczi
Quoted 12 lines · Prerna Saxena
simpletrace.c +0
-0@@ -62,3 +62,16 @@ void trace4(TraceEvent event, unsigned long x1,unsigned long x2, unsigned long
void trace5(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long x4, unsigned long x5) {trace(event, x1, x2, x3, x4, x5);
}
+Quoted 8 lines
simpletrace.c void trace4(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long · line 70
Quoted 5 lines
simpletrace.c +5
-0+void do_info_trace (Monitor *mon) +{ + unsigned int i, max_idx; + + max_idx = trace_idx ? trace_idx : TRACE_BUF_LEN;
trace_idxis always in the range [0,TRACE_BUF_LEN). There is no need to perform this test.
Quoted 3 lines
I only display the logged contents in the trace buffer (till
trace_idx) , and not the entire trace buffer. Only when the index is full that the entire buffer is displayed.
Thanks for explaining, I understand what you are doing now. Due to this special case, the code will dump out the empty trace buffer if used before anything has been traced (trace_idx=0).
Quoted 10 lines
Quoted 10 lines
Quoted 5 lines
+ monitor_printf(mon, "Event %ld : %ld %ld %ld %ld %ld\n",
+ trace_buf[i].event, trace_buf[i].x1, trace_buf[i].x2,
+ trace_buf[i].x3, trace_buf[i].x4, trace_buf[i].x5);Getting only numeric output is the limitation of a binary trace. It would probably be possible to pretty-print without much additional code by using the format strings from the trace-events file.
Quoted 7 lines
Quoted 4 lines
I think the numeric dump is good for now though. Hex is more compact than decimal and would make pointers easier to spot. Want to change this?
I agree, but we can let this be a todo till after the first prototype goes upstream ?
I still vote for hex instead of decimal :). Since you're already spinning a new patch it would be nice to put that change in, but no worries.
Quoted 2 lines
I'll post patches by Monday that addresses your suggestions, and try to get it integrated with QMP.
Excellent, thanks. I'd like to put your patches onto my tracing branch soon and test out the overall workflow of tracing QEMU.
Stefan
PATCH 3/3 Toggle tracepoint state
In reply to Prerna SaxenaThis patch adds support for dynamically enabling/disabling of tracepoints. This is done by internally maintaining each tracepoint's state, and permitting logging of data from a tracepoint only if it is in an 'active' state.
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.
---
monitor.c | 16 ++++++++++++++ qemu-monitor.hx | 18 ++++++++++++++++ simpletrace.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tracetool | 30 +++++++++++++++++++++++--- vl.c | 6 +++++ 5 files changed, 129 insertions(+), 4 deletions(-)
monitor.c +16 -0
@@ -548,6 +548,15 @@ static void do_commit(Monitor *mon, const QDict *qdict) } } +#ifdef CONFIG_SIMPLE_TRACE +static void do_change_tracepoint_state (Monitor *mon,const QDict *qdict) +{ +const char *tp_name =qdict_get_str (qdict,"name" ); +bool new_state =qdict_get_bool (qdict,"option" ); +change_tracepoint_state (tp_name, new_state); +} +#endif +static void user_monitor_complete (void *opaque,QObject *ret_data) {MonitorCompletionData *data = (MonitorCompletionData *)opaque;
@@ -2791,6 +2800,13 @@ static const mon_cmd_t info_cmds[] = { .help = "show current contents of trace buffer", .mhandler.info = do_info_trace, }, + { + .name = "tracepoints", + .args_type = "", + .params = "", + .help = "show available tracepoints & their state", + .mhandler.info = do_info_all_tracepoints, + },#endif { .name = NULL,
qemu-monitor.hx +18 -0
@@ -117,6 +117,8 @@ show device tree #ifdef CONFIG_SIMPLE_TRACE @item info trace show contents of trace buffer +@item info tracepoints +show available tracepoints and their state #endif @end table ETEXI
@@ -225,6 +227,22 @@ STEXI @item logfile @var{filename} @findex logfile Output logs to @var{filename}. +#ifdef CONFIG_SIMPLE_TRACE +ETEXI + + { + .name = "tracepoint", + .args_type = "name:s,option:b", + .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 {
simpletrace.c +63 -0
83 lines not on this page · raw message
tracetool +26 -4
@@ -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()
vl.c +6 -0
@@ -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))
Signature · 5 lines
Prerna Saxena Linux Technology Centre, IBM Systems and Technology Lab, Bangalore, India
Re: [PATCH 3/3] Toggle tracepoint state
Quoted 100 lines · Prerna Saxena
This patch adds support for dynamically enabling/disabling of tracepoints. This is done by internally maintaining each tracepoint's state, and permitting logging of data from a tracepoint only if it is in an 'active' state.
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, tracepointpaio_submitoff
disables logging of data whenpaio_submitis hit.Signed-off-by Prerna Saxena <[email protected]>---
monitor.c | 16 ++++++++++++++ qemu-monitor.hx | 18 ++++++++++++++++ simpletrace.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tracetool | 30 +++++++++++++++++++++++--- vl.c | 6 +++++ 5 files changed, 129 insertions(+), 4 deletions(-)monitor.c +16
-0@@ -548,6 +548,15 @@ static void do_commit(Monitor *mon, const QDict *qdict) } } +#ifdef CONFIG_SIMPLE_TRACE +static void do_change_tracepoint_state (Monitor *mon,const QDict *qdict) +{ +const char *tp_name =qdict_get_str (qdict,"name" ); +bool new_state =qdict_get_bool (qdict,"option" ); +change_tracepoint_state (tp_name, new_state); +} +#endif +static void user_monitor_complete (void *opaque,QObject *ret_data) {MonitorCompletionData *data = (MonitorCompletionData *)opaque;@@ -2791,6 +2800,13 @@ static const mon_cmd_t info_cmds[] = { .help = "show current contents of trace buffer", .mhandler.info = do_info_trace, }, + { + .name = "tracepoints", + .args_type = "", + .params = "", + .help = "show available tracepoints & their state", + .mhandler.info = do_info_all_tracepoints, + },#endif { .name = NULL,qemu-monitor.hx +18
-0@@ -117,6 +117,8 @@ show device tree #ifdef CONFIG_SIMPLE_TRACE @item info trace show contents of trace buffer +@item info tracepoints +show available tracepoints and their state #endif @end table ETEXI@@ -225,6 +227,22 @@ STEXI @item logfile @var{filename} @findex logfile Output logs to @var{filename}. +#ifdef CONFIG_SIMPLE_TRACE +ETEXI + + { + .name = "tracepoint", + .args_type = "name:s,option:b", + .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 {simpletrace.c +0
-0
simpletrace.c line 9
Quoted 7 lines
simpletrace.c +4
-0@@ -3,6 +3,12 @@#include "trace.h" typedef struct { +char *tp_name; +bool state; +unsigned int hash; +}Tracepoint ;
The tracing infrastructure avoids using the name 'tracepoint'. It calls them trace events. I didn't deliberately choose that name, but was unaware at the time that Linux tracing calls them tracepoints. Given that 'trace event' is currently used, it would be nice to remain consistent/reduce confusion.
How about:
typedef struct {
const char *name;
bool enabled;
unsigned int hash;
} TraceEventState;Or a nicer overall change might be to rename enum TraceEvent to TraceEventID and Tracepoint to TraceEvent.
Quoted 6 lines
simpletrace.c +2
-0+ +typedef struct { unsigned long event; unsigned long x1; unsigned long x2;
simpletrace.c enum { · line 33
Quoted 10 lines
simpletrace.c +7
-0@@ -18,11 +24,29 @@ 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 ; + }
I'd drop this check because only trace.c should use init_tracepoint() and you have ensured it uses correct arguments. Just a coding style suggestion; having redundant checks makes the code more verbose, may lead the reader to assume that this function really is called with junk arguments, and silently returning will not help make the issue visible.
simpletrace.c enum { · line 36
Quoted 2 lines
simpletrace.c +2
-0+ trace_list[tevent].tp_name = (char *)qemu_malloc (strlen (tname)+1 ); +strncpy (trace_list[tevent].tp_name, tname,strlen (tname));
Or use qemmu_strdup() but we don't really need to allocate memory at all here. Just hold the const char* to a string literal since the trace event is a static object that is built into the binary.
Quoted 19 lines
simpletrace.c +8
-0+ trace_list[tevent].hash =qemu_hash (tname); + trace_list[tevent].state =1 ;/* Enable all by default */ +}static void trace (TraceEvent event,unsigned long x1,unsigned long x2,unsigned long x3,unsigned long x4,unsigned long x5) {TraceRecord *rec = &trace_buf[trace_idx]; + +if (!trace_list[event].state) { +return ; + } + rec->event = event; rec->x1 = x1; rec->x2 = x2;@@ -75,3 +99,42 @@ void do_info_trace(Monitor *mon) trace_buf[i].x3, trace_buf[i].x4, trace_buf[i].x5); }
simpletrace.c void do_info_trace(Monitor *mon) · line 110
Quoted 10 lines
simpletrace.c +9
-0} + +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); + }
Whitespace and indentation.
Quoted 9 lines
simpletrace.c +9
-0+} + +static Tracepoint *find_tracepoint_by_name (const char *tname) +{ +unsigned int i, name_hash; + +if (!tname) { +return NULL ; + }
simpletrace.c void do_info_trace(Monitor *mon) · line 129
Quoted 10 lines
simpletrace.c +10
-0+ + name_hash =qemu_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 &trace_list[i]; + } + } +return NULL ;/* indicates end of list reached without a match */
I don't see the need for hashing. We don't actually have a hash table and are doing a linear search. There will be a smallish constant number of trace events and only change_tracepoint_by_name() needs to do a lookup. There's no need to optimize that.
Is strncmp() used so looking up "foo" is like searching for foo*? The strlen(tname) should be outside the loop. I think that could be useful but we should document it or just use strcmp().
Quoted 44 lines
simpletrace.c +11
-0+} + +void change_tracepoint_state (const char *tname,bool tstate) +{ +Tracepoint *tp; + + tp =find_tracepoint_by_name (tname); +if (tp) { + tp->state = tstate; + } +}tracetool +9
-1@@ -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
tracetool EOF · line 183
Quoted 10 lines
tracetool +5
-1} linetoc_begin_simple() { - return + cat <<EOF +#include "trace.h" + +void init_tracepoint_table(void) { +EOF
Have you looked at module.h? Perhaps that provides a good solution for initializing trace events. It would allow the vl.c changes to be done without an #ifdef.
Quoted 10 lines
tracetool +5
-1+ simple_event_num=0 + } linetoc_simple() { - return + local name + name=$(get_name "$1") + cat <<EOF
tracetool EOF · line 201
Quoted 10 lines
tracetool +5
-1+init_tracepoint("$name", $simple_event_num); +EOF + simple_event_num=$((simple_event_num + 1)) } linetoc_end_simple() { - return + cat <<EOF +return;
Please don't use return at the end of a void function. Coding style.
Quoted 38 lines
tracetool +2
-0+} +EOF } linetoh_begin_ust()vl.c +6
-0@@ -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))Signature · 6 lines
-- Prerna Saxena Linux Technology Centre, IBM Systems and Technology Lab, Bangalore, India
Re: [Qemu-devel] Re: [PATCH 3/3] Toggle tracepoint state
Quoted 20 lines · Stefan Hajnoczi
simpletrace.c line 9
Quoted 11 lines · Prerna Saxena
This patch adds support for dynamically enabling/disabling of tracepoints. This is done by internally maintaining each tracepoint's state, and permitting logging of data from a tracepoint only if it is in an 'active' state.
....
....
typedef struct {simpletrace.c +4
-0+char *tp_name; +bool state; +unsigned int hash; +} Tracepoint;The tracing infrastructure avoids using the name 'tracepoint'. It calls them trace events. I didn't deliberately choose that name, but was unaware at the time that Linux tracing calls them tracepoints. Given that 'trace event' is currently used, it would be nice to remain consistent/reduce confusion.
How about:
Quoted 9 lines
typedef struct { const char *name; bool enabled; unsigned int hash; } TraceEventState;Or a nicer overall change might be to rename enum TraceEvent to TraceEventID and Tracepoint to TraceEvent.
I'll change that !
Quoted 14 lines
Quoted 14 lines
simpletrace.c +7
-0+ +typedef struct { unsigned long event; unsigned long x1; unsigned long x2;@@ -18,11 +24,29 @@ 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 ) {
Quoted 8 lines
Review enum { · line 33
Quoted 2 lines
(quoted diff) +2
-0+ return; + }I'd drop this check because only
trace.cshould useinit_tracepoint()and you have ensured it uses correct arguments. Just a coding style suggestion; having redundant checks makes the code more verbose, may lead the reader to assume that this function really is called with junk arguments, and silently returning will not help make the issue visible.
Ok.
Quoted 8 lines
simpletrace.c enum { · line 36
Quoted 3 lines
simpletrace.c +2
-0+ trace_list[tevent].tp_name = (char *)qemu_malloc (strlen (tname)+1 ); +strncpy (trace_list[tevent].tp_name, tname,strlen (tname));Or use
qemmu_strdup()but we don't really need to allocate memory at all here. Just hold the const char* to a string literal since the trace event is a static object that is built into the binary.
Ok
Quoted 6 lines
Quoted 6 lines
simpletrace.c +5
-0+ trace_list[tevent].hash =qemu_hash (tname); + trace_list[tevent].state =1 ;/* Enable all by default */ +} +void do_info_all_tracepoints (Monitor *mon) +{
Quoted 9 lines
simpletrace.c void do_info_trace(Monitor *mon) · line 110
Quoted 6 lines
simpletrace.c +6
-0+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); + }Whitespace and indentation.
Will fix.
Quoted 16 lines
Quoted 16 lines
simpletrace.c +16
-0+} + +static Tracepoint *find_tracepoint_by_name (const char *tname) +{ +unsigned int i, name_hash; + +if (!tname) { +return NULL ; + } + + name_hash =qemu_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 &trace_list[i];
Quoted 9 lines
simpletrace.c void do_info_trace(Monitor *mon) · line 129
Quoted 3 lines
simpletrace.c +3
-0+ } + } +return NULL ;/* indicates end of list reached without a match */ I don't see the need for hashing. We don't actually have a hash table and are doing a linear search. There will be a smallish constant number of trace events and only
change_tracepoint_by_name()needs to do a lookup. There's no need to optimize that.
I was only optimising lookups. Instead of doing a strlen()-size comparison for each tracepoint, we end up doing a constant int-size comparison till there is possibility of hash collision. Strlen()-size lookups isnt really an issure right now, but will be more glaring if qemu ends up having a much larger number of tracepoints.
Quoted 4 lines
Is
strncmp()used so looking up "foo" is like searching for foo*? The strlen(tname) should be outside the loop. I think that could be useful but we should document it or just usestrcmp().
The hash would take care of most such cases. But this might be an issue in the rare event of a hash collision happening when foo_1 and foo_2 match as well. I'll fix this.
Quoted 46 lines
Quoted 46 lines
simpletrace.c +11
-0+} + +void change_tracepoint_state (const char *tname,bool tstate) +{ +Tracepoint *tp; + + tp =find_tracepoint_by_name (tname); +if (tp) { + tp->state = tstate; + } +}tracetool +9
-1@@ -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 }
Quoted 12 lines
tracetool EOF · line 183
Quoted 8 lines
tracetool +5
-1linetoc_begin_simple() { - return + cat<<EOF +#include "trace.h" + +void init_tracepoint_table(void) { +EOFHave you looked at
module.h? Perhaps that provides a good solution for initializing trace events. It would allow thevl.cchanges to be done without an #ifdef.
Thanks for the tip, I'll check.
Quoted 16 lines
Quoted 16 lines
tracetool +8
-1+ 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)) }
Quoted 8 lines
tracetool EOF · line 201
Quoted 5 lines
tracetool +2
-1linetoc_end_simple() { - return + cat<<EOF +return;Please don't use return at the end of a void function. Coding style.
Ok.
Quoted 4 lines
Quoted 4 lines
tracetool +2
-0+} +EOF
Signature · 5 lines
Prerna Saxena Linux Technology Centre, IBM Systems and Technology Lab, Bangalore, India
Re: [Qemu-devel] Re: [PATCH 3/3] Toggle tracepoint state
Quoted 28 lines · Prerna Saxena
Quoted 17 lines · Stefan Hajnoczi
Quoted 17 lines
simpletrace.c +15
-0+} + +static Tracepoint* find_tracepoint_by_name(const char *tname) +{ + unsigned int i, name_hash; + + if (!tname) { + return NULL; + } + + name_hash = qemu_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&trace_list[i];Quoted 9 lines
Quoted 3 lines
+ }
+ }
+ return NULL; /* indicates end of list reached without a match */I don't see the need for hashing. We don't actually have a hash table and are doing a linear search. There will be a smallish constant number of trace events and only
change_tracepoint_by_name()needs to do a lookup. There's no need to optimize that.
Quoted 5 lines
I was only optimising lookups. Instead of doing a strlen()-size comparison for each tracepoint, we end up doing a constant int-size comparison till there is possibility of hash collision. Strlen()-size lookups isnt really an issure right now, but will be more glaring if qemu ends up having a much larger number of tracepoints.
The thing is we only need to do lookups when tracepoints are enabled/disabled. That is a very rare operation, not critical path.
This feels like premature optimization. If there is a performance bottleneck down the road we can switch to a data structure that has better time complexity than an array. This is an easy change to make later because it will not affect the user interface.
In the meantime linear strcmp() over an array keeps the code simple. We can drop the tdb_hash() patch and remove some lines from this patch.
Quoted 51 lines
Quoted 38 lines
Quoted 38 lines
tracetool +0
-0@@ -123,14 +123,20 @@ linetoc_end_nop() linetoh_begin_simple() {cat<<EOF
tracetool +2
-0+#include<stdbool.h> +typedef unsigned int TraceEvent;
tracetool +2
-0+void init_tracepoint_table(void); +void init_tracepoint(const char *tname, TraceEvent tevent);void
trace1(TraceEvent event, unsigned long x1);
voidtrace2(TraceEvent event, unsigned long x1, unsigned long x2); voidtrace3(TraceEvent event, unsigned long x1, unsigned long x2, unsigned long x3);
voidtrace4(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); voiddo_info_trace(Monitor *mon);tracetool +2
-0+void do_info_all_tracepoints(Monitor *mon); +void change_tracepoint_state(const char *tname, bool tstate);EOF
simple_event_num=0
tracetool +3
-1@@ -163,22 +169,38 @@ EOF linetoh_end_simple() { - return + cat<<EOF +#define NR_TRACEPOINTS $simple_event_num +EOF }Quoted 12 lines
tracetool EOF · line 183
Quoted 8 lines
tracetool +5
-1linetoc_begin_simple() { - return + cat<<EOF +#include "trace.h" + +void init_tracepoint_table(void) { +EOFHave you looked at
module.h? Perhaps that provides a good solution for initializing trace events. It would allow thevl.cchanges to be done without an #ifdef.
Quoted 1 line
Thanks for the tip, I'll check.
I also wonder if it's possible to statically initialize the TraceEvent array in the generated trace.c. That way we need no vl.c startup magic and tracing is available even in the very early stages of QEMU startup. What do you think?
Stefan
Quoted 6 lines · Prerna Saxena
This is v3 of a set of patches to enable trace visualization & control via the QEMU monitor. It is based on trace infrastructure posted by Stefan :
( http://lists.gnu.org/archive/html/qemu-devel/2010-05/msg02407.html )
Quoted 9 lines
This patchset adds monitor commands :
- info trace : to view current contents of the trace buffer
- info tracepoints : to view all available tracepoints and their state.
- tracepoint NAME on|off : to enable/disable the logging of data from tracepoint 'NAME' to on/off.Changelog :
- Clean-ups from v2, particularly relating to export oftdb_hash()
But it's still using the legacy monitor command interface. See [1]+[2] for a mechanism that allows you to convert to the new interface without automatically exposing your commands via QMP.
Jan
[1] http://thread.gmane.org/gmane.comp.emulators.qemu/74356
[2] http://thread.gmane.org/gmane.comp.emulators.qemu/74372
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux