提交 22890ab5 编写于 作者: P Prerna Saxena 提交者: Anthony Liguori

trace: Support for dynamically enabling/disabling trace events

This patch adds support for dynamically enabling/disabling of trace events.
This is done by internally maintaining each trace event's state, and
permitting logging of data from a trace event only if it is in an
'active' state.

Monitor commands added :
1) info trace-events 		: to view all available trace events and
				  their state.
2) trace-event NAME on|off 	: to enable/disable data logging from a
				  given trace event.
				  Eg, trace-event paio_submit off
				  	disables logging of data when
					paio_submit is hit.

By default, all trace-events are disabled. One can enable desired trace-events
via the monitor.
Signed-off-by: NPrerna Saxena <prerna@linux.vnet.ibm.com>
Signed-off-by: NStefan Hajnoczi <stefanha@linux.vnet.ibm.com>

trace: Monitor command 'info trace'

Monitor command 'info trace' to display contents of trace buffer
Signed-off-by: NPrerna Saxena <prerna@linux.vnet.ibm.com>
Signed-off-by: NStefan Hajnoczi <stefanha@linux.vnet.ibm.com>

trace: Remove monitor.h dependency from simpletrace

User-mode targets don't have a monitor so the simple trace backend
currently does not build on those targets.  This patch abstracts the
monitor printing interface so there is no direct coupling between
simpletrace and the monitor.
Signed-off-by: NStefan Hajnoczi <stefanha@linux.vnet.ibm.com>
上级 26f7227b
......@@ -2468,6 +2468,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
echo "TOOLS=$tools" >> $config_host_mak
echo "ROMS=$roms" >> $config_host_mak
echo "MAKE=$make" >> $config_host_mak
......
......@@ -56,6 +56,9 @@
#include "json-parser.h"
#include "osdep.h"
#include "exec-all.h"
#ifdef CONFIG_SIMPLE_TRACE
#include "trace.h"
#endif
//#define DEBUG
//#define DEBUG_COMPLETION
......@@ -539,6 +542,15 @@ static void do_help_cmd(Monitor *mon, const QDict *qdict)
help_cmd(mon, qdict_get_try_str(qdict, "name"));
}
#ifdef CONFIG_SIMPLE_TRACE
static void do_change_trace_event_state(Monitor *mon, const QDict *qdict)
{
const char *tp_name = qdict_get_str(qdict, "name");
bool new_state = qdict_get_bool(qdict, "option");
st_change_trace_event_state(tp_name, new_state);
}
#endif
static void user_monitor_complete(void *opaque, QObject *ret_data)
{
MonitorCompletionData *data = (MonitorCompletionData *)opaque;
......@@ -938,6 +950,18 @@ static void do_info_cpu_stats(Monitor *mon)
}
#endif
#if defined(CONFIG_SIMPLE_TRACE)
static void do_info_trace(Monitor *mon)
{
st_print_trace((FILE *)mon, &monitor_fprintf);
}
static void do_info_trace_events(Monitor *mon)
{
st_print_trace_events((FILE *)mon, &monitor_fprintf);
}
#endif
/**
* do_quit(): Quit QEMU execution
*/
......@@ -2594,6 +2618,22 @@ 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,
},
{
.name = "trace-events",
.args_type = "",
.params = "",
.help = "show available trace-events & their state",
.mhandler.info = do_info_trace_events,
},
#endif
{
.name = NULL,
},
......
......@@ -281,6 +281,22 @@ STEXI
Output logs to @var{filename}.
ETEXI
#ifdef CONFIG_SIMPLE_TRACE
{
.name = "trace-event",
.args_type = "name:s,option:b",
.params = "name on|off",
.help = "changes status of a specific trace event",
.mhandler.cmd = do_change_trace_event_state,
},
STEXI
@item trace-event
@findex trace-event
changes status of a trace event
ETEXI
#endif
{
.name = "log",
.args_type = "items:s",
......@@ -2529,6 +2545,15 @@ show roms
@end table
ETEXI
#ifdef CONFIG_SIMPLE_TRACE
STEXI
@item info trace
show contents of trace buffer
@item info trace-events
show available trace events and their state
ETEXI
#endif
HXCOMM DO NOT add new commands after 'info', move your addition before it!
STEXI
......
......@@ -101,6 +101,10 @@ static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
*/
clock_gettime(CLOCK_MONOTONIC, &ts);
if (!trace_list[event].state) {
return;
}
rec->event = event;
rec->timestamp_ns = ts.tv_sec * 1000000000LL + ts.tv_nsec;
rec->x1 = x1;
......@@ -157,3 +161,50 @@ static void __attribute__((constructor)) st_init(void)
{
atexit(st_flush_trace_buffer);
}
void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
{
unsigned int i;
for (i = 0; i < trace_idx; i++) {
stream_printf(stream, "Event %lu : %lx %lx %lx %lx %lx\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);
}
}
void st_print_trace_events(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
{
unsigned int i;
for (i = 0; i < NR_TRACE_EVENTS; i++) {
stream_printf(stream, "%s [Event ID %u] : state %u\n",
trace_list[i].tp_name, i, trace_list[i].state);
}
}
static TraceEvent* find_trace_event_by_name(const char *tname)
{
unsigned int i;
if (!tname) {
return NULL;
}
for (i = 0; i < NR_TRACE_EVENTS; i++) {
if (!strcmp(trace_list[i].tp_name, tname)) {
return &trace_list[i];
}
}
return NULL; /* indicates end of list reached without a match */
}
void st_change_trace_event_state(const char *tname, bool tstate)
{
TraceEvent *tp;
tp = find_trace_event_by_name(tname);
if (tp) {
tp->state = tstate;
}
}
......@@ -12,9 +12,16 @@
#define SIMPLETRACE_H
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
typedef uint64_t TraceEventID;
typedef struct {
const char *tp_name;
bool state;
} TraceEvent;
void trace0(TraceEventID event);
void trace1(TraceEventID event, uint64_t x1);
void trace2(TraceEventID event, uint64_t x1, uint64_t x2);
......@@ -22,5 +29,8 @@ void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3);
void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4);
void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5);
void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6);
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_change_trace_event_state(const char *tname, bool tstate);
#endif /* SIMPLETRACE_H */
......@@ -169,22 +169,38 @@ EOF
linetoh_end_simple()
{
return
cat <<EOF
#define NR_TRACE_EVENTS $simple_event_num
extern TraceEvent trace_list[NR_TRACE_EVENTS];
EOF
}
linetoc_begin_simple()
{
return
cat <<EOF
#include "trace.h"
TraceEvent trace_list[] = {
EOF
simple_event_num=0
}
linetoc_simple()
{
return
local name
name=$(get_name "$1")
cat <<EOF
{.tp_name = "$name", .state=0},
EOF
simple_event_num=$((simple_event_num + 1))
}
linetoc_end_simple()
{
return
cat <<EOF
};
EOF
}
# Process stdin by calling begin, line, and end functions for the backend
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册