Merge remote-tracking branch 'stefanha/tracing' into staging

# By Lluís Vilanova (7) and others
# Via Stefan Hajnoczi
* stefanha/tracing:
  vl: add runstate_set tracepoint
  .gitignore: rename trace/generated-tracers.dtrace
  .gitignore: add trace/generated-events.[ch]
  trace: rebuild generated-events.o when configuration changes
  trace: [stderr] Port to generic event information and new control interface
  trace: [simple] Port to generic event information and new control interface
  trace: [default] Port to generic event information and new control interface
  trace: [monitor] Use new event control interface
  trace: Provide a detailed event control interface
  trace: Provide a generic tracing event descriptor
  trace: [tracetool] Explicitly identify public backends
This commit is contained in:
Anthony Liguori 2013-03-28 12:57:32 -05:00
commit 837df37e88
26 changed files with 597 additions and 182 deletions

4
.gitignore vendored
View File

@ -6,7 +6,9 @@ config-target.*
trace/generated-tracers.h trace/generated-tracers.h
trace/generated-tracers.c trace/generated-tracers.c
trace/generated-tracers-dtrace.h trace/generated-tracers-dtrace.h
trace/generated-tracers-dtrace.dtrace trace/generated-tracers.dtrace
trace/generated-events.h
trace/generated-events.c
libcacard/trace/generated-tracers.c libcacard/trace/generated-tracers.c
*-timestamp *-timestamp
*-softmmu *-softmmu

View File

@ -35,6 +35,9 @@ GENERATED_HEADERS = config-host.h qemu-options.def
GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h
GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c
GENERATED_HEADERS += trace/generated-events.h
GENERATED_SOURCES += trace/generated-events.c
GENERATED_HEADERS += trace/generated-tracers.h GENERATED_HEADERS += trace/generated-tracers.h
ifeq ($(TRACE_BACKEND),dtrace) ifeq ($(TRACE_BACKEND),dtrace)
GENERATED_HEADERS += trace/generated-tracers-dtrace.h GENERATED_HEADERS += trace/generated-tracers-dtrace.h

View File

@ -100,49 +100,37 @@ respectively. This ensures portability between 32- and 64-bit platforms.
== Generic interface and monitor commands == == Generic interface and monitor commands ==
You can programmatically query and control the dynamic state of trace events You can programmatically query and control the state of trace events through a
through a backend-agnostic interface: backend-agnostic interface provided by the header "trace/control.h".
* trace_print_events Note that some of the backends do not provide an implementation for some parts
of this interface, in which case QEMU will just print a warning (please refer to
header "trace/control.h" to see which routines are backend-dependent).
* trace_event_set_state The state of events can also be queried and modified through monitor commands:
Enables or disables trace events at runtime inside QEMU.
The function returns "true" if the state of the event has been successfully
changed, or "false" otherwise:
#include "trace/control.h"
trace_event_set_state("virtio_irq", true); /* enable */
[...]
trace_event_set_state("virtio_irq", false); /* disable */
Note that some of the backends do not provide an implementation for this
interface, in which case QEMU will just print a warning.
This functionality is also provided through monitor commands:
* info trace-events * info trace-events
View available trace events and their state. State 1 means enabled, state 0 View available trace events and their state. State 1 means enabled, state 0
means disabled. means disabled.
* trace-event NAME on|off * trace-event NAME on|off
Enable/disable a given trace event or a group of events having common prefix Enable/disable a given trace event or a group of events (using wildcards).
through wildcard.
The "-trace events=<file>" command line argument can be used to enable the The "-trace events=<file>" command line argument can be used to enable the
events listed in <file> from the very beginning of the program. This file must events listed in <file> from the very beginning of the program. This file must
contain one event name per line. contain one event name per line.
A basic wildcard matching is supported in both the monitor command "trace
-event" and the events list file. That means you can enable/disable the events
having a common prefix in a batch. For example, virtio-blk trace events could
be enabled using:
trace-event virtio_blk_* on
If a line in the "-trace events=<file>" file begins with a '-', the trace event If a line in the "-trace events=<file>" file begins with a '-', the trace event
will be disabled instead of enabled. This is useful when a wildcard was used will be disabled instead of enabled. This is useful when a wildcard was used
to enable an entire family of events but one noisy event needs to be disabled. to enable an entire family of events but one noisy event needs to be disabled.
Wildcard matching is supported in both the monitor command "trace-event" and the
events list file. That means you can enable/disable the events having a common
prefix in a batch. For example, virtio-blk trace events could be enabled using
the following monitor command:
trace-event virtio_blk_* on
== Trace backends == == Trace backends ==
The "tracetool" script automates tedious trace event code generation and also The "tracetool" script automates tedious trace event code generation and also
@ -263,3 +251,7 @@ guard such computations and avoid its compilation when the event is disabled:
} }
return ptr; return ptr;
} }
You can check both if the event has been disabled and is dynamically enabled at
the same time using the 'trace_event_get_state' routine (see header
"trace/control.h" for more information).

View File

@ -761,9 +761,18 @@ static void do_trace_event_set_state(Monitor *mon, const QDict *qdict)
{ {
const char *tp_name = qdict_get_str(qdict, "name"); const char *tp_name = qdict_get_str(qdict, "name");
bool new_state = qdict_get_bool(qdict, "option"); bool new_state = qdict_get_bool(qdict, "option");
int ret = trace_event_set_state(tp_name, new_state);
if (!ret) { bool found = false;
TraceEvent *ev = NULL;
while ((ev = trace_event_pattern(tp_name, ev)) != NULL) {
found = true;
if (!trace_event_get_state_static(ev)) {
monitor_printf(mon, "event \"%s\" is not traceable\n", tp_name);
} else {
trace_event_set_state_dynamic(ev, new_state);
}
}
if (!trace_event_is_pattern(tp_name) && !found) {
monitor_printf(mon, "unknown event name \"%s\"\n", tp_name); monitor_printf(mon, "unknown event name \"%s\"\n", tp_name);
} }
} }

View File

@ -90,8 +90,8 @@ def main(args):
arg_format = arg arg_format = arg
elif opt == "--list-backends": elif opt == "--list-backends":
backends = tracetool.backend.get_list() public_backends = tracetool.backend.get_list(only_public = True)
out(", ".join([ b for b,_ in backends ])) out(", ".join([ b for b,_ in public_backends ]))
sys.exit(0) sys.exit(0)
elif opt == "--check-backend": elif opt == "--check-backend":
check_backend = True check_backend = True

View File

@ -17,6 +17,16 @@ considered its short description.
All backends must generate their contents through the 'tracetool.out' routine. All backends must generate their contents through the 'tracetool.out' routine.
Backend attributes
------------------
========= ====================================================================
Attribute Description
========= ====================================================================
PUBLIC If exists and is set to 'True', the backend is considered "public".
========= ====================================================================
Backend functions Backend functions
----------------- -----------------
@ -42,7 +52,7 @@ import os
import tracetool import tracetool
def get_list(): def get_list(only_public = False):
"""Get a list of (name, description) pairs.""" """Get a list of (name, description) pairs."""
res = [("nop", "Tracing disabled.")] res = [("nop", "Tracing disabled.")]
modnames = [] modnames = []
@ -57,6 +67,10 @@ def get_list():
continue continue
module = module[1] module = module[1]
public = getattr(module, "PUBLIC", False)
if only_public and not public:
continue
doc = module.__doc__ doc = module.__doc__
if doc is None: if doc is None:
doc = "" doc = ""

View File

@ -16,6 +16,9 @@ __email__ = "stefanha@linux.vnet.ibm.com"
from tracetool import out from tracetool import out
PUBLIC = True
PROBEPREFIX = None PROBEPREFIX = None
def _probeprefix(): def _probeprefix():

View File

@ -0,0 +1,23 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generic event description.
This is a dummy backend to establish appropriate frontend/backend compatibility
checks.
"""
__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
__copyright__ = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
__license__ = "GPL version 2 or (at your option) any later version"
__maintainer__ = "Stefan Hajnoczi"
__email__ = "stefanha@linux.vnet.ibm.com"
def events_h(events):
pass
def events_c(events):
pass

View File

@ -15,6 +15,10 @@ __email__ = "stefanha@linux.vnet.ibm.com"
from tracetool import out from tracetool import out
PUBLIC = True
def is_string(arg): def is_string(arg):
strtype = ('const char*', 'char*', 'const char *', 'char *') strtype = ('const char*', 'char*', 'const char *', 'char *')
if arg.lstrip().startswith(strtype): if arg.lstrip().startswith(strtype):
@ -24,17 +28,10 @@ def is_string(arg):
def c(events): def c(events):
out('#include "trace.h"', out('#include "trace.h"',
'#include "trace/control.h"',
'#include "trace/simple.h"', '#include "trace/simple.h"',
'', '',
'TraceEvent trace_list[] = {') )
for e in events:
out('{.tp_name = "%(name)s", .state=0},',
name = e.name,
)
out('};',
'')
for num, event in enumerate(events): for num, event in enumerate(events):
out('void trace_%(name)s(%(args)s)', out('void trace_%(name)s(%(args)s)',
@ -59,7 +56,9 @@ def c(events):
out('', out('',
' if (!trace_list[%(event_id)s].state) {', ' TraceEvent *eventp = trace_event_id(%(event_id)s);',
' bool _state = trace_event_get_state_dynamic(eventp);',
' if (!_state) {',
' return;', ' return;',
' }', ' }',
'', '',
@ -102,6 +101,3 @@ def h(events):
name = event.name, name = event.name,
args = event.args, args = event.args,
) )
out('')
out('#define NR_TRACE_EVENTS %d' % len(events))
out('extern TraceEvent trace_list[NR_TRACE_EVENTS];')

View File

@ -16,41 +16,33 @@ __email__ = "stefanha@linux.vnet.ibm.com"
from tracetool import out from tracetool import out
PUBLIC = True
def c(events): def c(events):
out('#include "trace.h"', pass
'',
'TraceEvent trace_list[] = {')
for e in events:
out('{.tp_name = "%(name)s", .state=0},',
name = e.name,
)
out('};')
def h(events): def h(events):
out('#include <stdio.h>', out('#include <stdio.h>',
'#include "trace/stderr.h"', '#include "trace/control.h"',
'', '',
'extern TraceEvent trace_list[];') )
for num, e in enumerate(events): for e in events:
argnames = ", ".join(e.args.names()) argnames = ", ".join(e.args.names())
if len(e.args) > 0: if len(e.args) > 0:
argnames = ", " + argnames argnames = ", " + argnames
out('static inline void trace_%(name)s(%(args)s)', out('static inline void trace_%(name)s(%(args)s)',
'{', '{',
' if (trace_list[%(event_num)s].state != 0) {', ' bool _state = trace_event_get_state(%(event_id)s);',
' if (_state) {',
' fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s);', ' fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s);',
' }', ' }',
'}', '}',
name = e.name, name = e.name,
args = e.args, args = e.args,
event_num = num, event_id = "TRACE_" + e.name.upper(),
fmt = e.fmt, fmt = e.fmt.rstrip("\n"),
argnames = argnames, argnames = argnames,
) )
out('',
'#define NR_TRACE_EVENTS %d' % len(events))

View File

@ -16,6 +16,9 @@ __email__ = "stefanha@linux.vnet.ibm.com"
from tracetool import out from tracetool import out
PUBLIC = True
def c(events): def c(events):
out('#include <ust/marker.h>', out('#include <ust/marker.h>',
'#undef mutex_lock', '#undef mutex_lock',

View File

@ -0,0 +1,39 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generate .c for event description.
"""
__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
__copyright__ = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
__license__ = "GPL version 2 or (at your option) any later version"
__maintainer__ = "Stefan Hajnoczi"
__email__ = "stefanha@linux.vnet.ibm.com"
from tracetool import out
def begin(events):
out('/* This file is autogenerated by tracetool, do not edit. */',
'',
'#include "trace.h"',
'#include "trace/generated-events.h"',
'#include "trace/control.h"',
'',
)
out('TraceEvent trace_events[TRACE_EVENT_COUNT] = {')
for e in events:
out(' { .id = %(id)s, .name = \"%(name)s\", .sstate = %(sstate)s, .dstate = 0 },',
id = "TRACE_" + e.name.upper(),
name = e.name,
sstate = "TRACE_%s_ENABLED" % e.name.upper(),
)
out('};',
'',
)

View File

@ -0,0 +1,50 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generate .h for event description.
"""
__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
__copyright__ = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
__license__ = "GPL version 2 or (at your option) any later version"
__maintainer__ = "Stefan Hajnoczi"
__email__ = "stefanha@linux.vnet.ibm.com"
from tracetool import out
def begin(events):
out('/* This file is autogenerated by tracetool, do not edit. */',
'',
'#ifndef TRACE__GENERATED_EVENTS_H',
'#define TRACE__GENERATED_EVENTS_H',
'',
'#include <stdbool.h>',
''
)
# event identifiers
out('typedef enum {')
for e in events:
out(' TRACE_%s,' % e.name.upper())
out(' TRACE_EVENT_COUNT',
'} TraceEventID;',
)
# static state
for e in events:
if 'disable' in e.properties:
enabled = 0
else:
enabled = 1
out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled))
out('#include "trace/event-internal.h"',
'',
'#endif /* TRACE__GENERATED_EVENTS_H */',
)

View File

@ -25,14 +25,7 @@ def begin(events):
'#include "qemu-common.h"') '#include "qemu-common.h"')
def end(events): def end(events):
for e in events: out('#endif /* TRACE__GENERATED_TRACERS_H */')
if "disable" in e.properties:
enabled = 0
else:
enabled = 1
out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled))
out('',
'#endif /* TRACE__GENERATED_TRACERS_H */')
def nop(events): def nop(events):
for e in events: for e in events:

View File

@ -474,6 +474,7 @@ scsi_request_sense(int target, int lun, int tag) "target %d lun %d tag %d"
# vl.c # vl.c
vm_state_notify(int running, int reason) "running %d reason %d" vm_state_notify(int running, int reason) "running %d reason %d"
load_file(const char *name, const char *path) "name %s location %s" load_file(const char *name, const char *path) "name %s location %s"
runstate_set(int new_state) "new state %d"
# block/qcow2.c # block/qcow2.c
qcow2_writev_start_req(void *co, int64_t sector, int nb_sectors) "co %p sector %" PRIx64 " nb_sectors %d" qcow2_writev_start_req(void *co, int64_t sector, int nb_sectors) "co %p sector %" PRIx64 " nb_sectors %d"

View File

@ -1,7 +1,29 @@
# -*- mode: makefile -*- # -*- mode: makefile -*-
###################################################################### ######################################################################
# Auto-generated header for tracing routines # Auto-generated event descriptions
$(obj)/generated-events.h: $(obj)/generated-events.h-timestamp
$(obj)/generated-events.h-timestamp: $(SRC_PATH)/trace-events
$(call quiet-command,$(TRACETOOL) \
--format=events-h \
--backend=events \
< $< > $@," GEN $(patsubst %-timestamp,%,$@)")
@cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@)
$(obj)/generated-events.c: $(obj)/generated-events.c-timestamp $(BUILD_DIR)/config-host.mak
$(obj)/generated-events.c-timestamp: $(SRC_PATH)/trace-events
$(call quiet-command,$(TRACETOOL) \
--format=events-c \
--backend=events \
< $< > $@," GEN $(patsubst %-timestamp,%,$@)")
@cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@)
util-obj-y += generated-events.o
######################################################################
# Auto-generated tracing routines
$(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp $(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp
@cmp -s $< $@ || cp $< $@ @cmp -s $< $@ || cp $< $@

67
trace/control-internal.h Normal file
View File

@ -0,0 +1,67 @@
/*
* Interface for configuring and controlling the state of tracing events.
*
* Copyright (C) 2011-2012 Lluís Vilanova <vilanova@ac.upc.edu>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef TRACE__CONTROL_INTERNAL_H
#define TRACE__CONTROL_INTERNAL_H
#include <string.h>
extern TraceEvent trace_events[];
static inline TraceEvent *trace_event_id(TraceEventID id)
{
assert(id < trace_event_count());
return &trace_events[id];
}
static inline TraceEventID trace_event_count(void)
{
return TRACE_EVENT_COUNT;
}
static inline bool trace_event_is_pattern(const char *str)
{
assert(str != NULL);
return strchr(str, '*') != NULL;
}
static inline TraceEventID trace_event_get_id(TraceEvent *ev)
{
assert(ev != NULL);
return ev->id;
}
static inline const char * trace_event_get_name(TraceEvent *ev)
{
assert(ev != NULL);
return ev->name;
}
static inline bool trace_event_get_state_static(TraceEvent *ev)
{
assert(ev != NULL);
return ev->sstate;
}
static inline bool trace_event_get_state_dynamic(TraceEvent *ev)
{
assert(ev != NULL);
return ev->dstate;
}
static inline void trace_event_set_state_dynamic(TraceEvent *ev, bool state)
{
assert(ev != NULL);
assert(trace_event_get_state_static(ev));
return trace_event_set_state_dynamic_backend(ev, state);
}
#endif /* TRACE__CONTROL_INTERNAL_H */

View File

@ -1,19 +1,86 @@
/* /*
* Interface for configuring and controlling the state of tracing events. * Interface for configuring and controlling the state of tracing events.
* *
* Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu> * Copyright (C) 2011-2012 Lluís Vilanova <vilanova@ac.upc.edu>
* *
* This work is licensed under the terms of the GNU GPL, version 2. See * This work is licensed under the terms of the GNU GPL, version 2 or later.
* the COPYING file in the top-level directory. * See the COPYING file in the top-level directory.
*/ */
#include "trace/control.h" #include "trace/control.h"
TraceEvent *trace_event_name(const char *name)
{
assert(name != NULL);
TraceEventID i;
for (i = 0; i < trace_event_count(); i++) {
TraceEvent *ev = trace_event_id(i);
if (strcmp(trace_event_get_name(ev), name) == 0) {
return ev;
}
}
return NULL;
}
static bool pattern_glob(const char *pat, const char *ev)
{
while (*pat != '\0' && *ev != '\0') {
if (*pat == *ev) {
pat++;
ev++;
}
else if (*pat == '*') {
if (pattern_glob(pat, ev+1)) {
return true;
} else if (pattern_glob(pat+1, ev)) {
return true;
} else {
return false;
}
} else {
return false;
}
}
while (*pat == '*') {
pat++;
}
if (*pat == '\0' && *ev == '\0') {
return true;
} else {
return false;
}
}
TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev)
{
assert(pat != NULL);
TraceEventID i;
if (ev == NULL) {
i = -1;
} else {
i = trace_event_get_id(ev);
}
i++;
while (i < trace_event_count()) {
TraceEvent *res = trace_event_id(i);
if (pattern_glob(pat, trace_event_get_name(res))) {
return res;
}
i++;
}
return NULL;
}
void trace_backend_init_events(const char *fname) void trace_backend_init_events(const char *fname)
{ {
int ret;
if (fname == NULL) { if (fname == NULL) {
return; return;
} }
@ -32,15 +99,28 @@ void trace_backend_init_events(const char *fname)
if ('#' == line_buf[0]) { /* skip commented lines */ if ('#' == line_buf[0]) { /* skip commented lines */
continue; continue;
} }
if ('-' == line_buf[0]) { const bool enable = ('-' != line_buf[0]);
ret = trace_event_set_state(line_buf+1, false); char *line_ptr = enable ? line_buf : line_buf + 1;
if (trace_event_is_pattern(line_ptr)) {
TraceEvent *ev = NULL;
while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) {
if (trace_event_get_state_static(ev)) {
trace_event_set_state_dynamic(ev, enable);
}
}
} else { } else {
ret = trace_event_set_state(line_buf, true); TraceEvent *ev = trace_event_name(line_ptr);
} if (ev == NULL) {
if (!ret) { fprintf(stderr,
fprintf(stderr, "error: trace event '%s' does not exist\n", line_ptr);
"error: trace event '%s' does not exist\n", line_buf); exit(1);
exit(1); }
if (!trace_event_get_state_static(ev)) {
fprintf(stderr,
"error: trace event '%s' is not traceable\n", line_ptr);
exit(1);
}
trace_event_set_state_dynamic(ev, enable);
} }
} }
} }

View File

@ -1,41 +1,193 @@
/* /*
* Interface for configuring and controlling the state of tracing events. * Interface for configuring and controlling the state of tracing events.
* *
* Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu> * Copyright (C) 2011-2012 Lluís Vilanova <vilanova@ac.upc.edu>
* *
* This work is licensed under the terms of the GNU GPL, version 2. See * This work is licensed under the terms of the GNU GPL, version 2 or later.
* the COPYING file in the top-level directory. * See the COPYING file in the top-level directory.
*/ */
#ifndef TRACE_CONTROL_H #ifndef TRACE__CONTROL_H
#define TRACE_CONTROL_H #define TRACE__CONTROL_H
#include "qemu-common.h" #include "qemu-common.h"
#include "trace/generated-events.h"
/** Print the state of all events. */ /**
void trace_print_events(FILE *stream, fprintf_function stream_printf); * TraceEventID:
/** Set the state of an event.
* *
* @return Whether the state changed. * Unique tracing event identifier.
*
* These are named as 'TRACE_${EVENT_NAME}'.
*
* See also: "trace/generated-events.h"
*/ */
bool trace_event_set_state(const char *name, bool state); enum TraceEventID;
/**
/** Initialize the tracing backend. * trace_event_id:
* @id: Event identifier.
* *
* @events Name of file with events to be enabled at startup; may be NULL. * Get an event by its identifier.
* Corresponds to commandline option "-trace events=...". *
* @file Name of trace output file; may be NULL. * This routine has a constant cost, as opposed to trace_event_name and
* Corresponds to commandline option "-trace file=...". * trace_event_pattern.
* @return Whether the backend could be successfully initialized. *
* Pre-conditions: The identifier is valid.
*
* Returns: pointer to #TraceEvent.
*
*/
static TraceEvent *trace_event_id(TraceEventID id);
/**
* trace_event_name:
* @id: Event name.
*
* Search an event by its name.
*
* Returns: pointer to #TraceEvent or NULL if not found.
*/
TraceEvent *trace_event_name(const char *name);
/**
* trace_event_pattern:
* @pat: Event name pattern.
* @ev: Event to start searching from (not included).
*
* Get all events with a given name pattern.
*
* Returns: pointer to #TraceEvent or NULL if not found.
*/
TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev);
/**
* trace_event_is_pattern:
*
* Whether the given string is an event name pattern.
*/
static bool trace_event_is_pattern(const char *str);
/**
* trace_event_count:
*
* Return the number of events.
*/
static TraceEventID trace_event_count(void);
/**
* trace_event_get_id:
*
* Get the identifier of an event.
*/
static TraceEventID trace_event_get_id(TraceEvent *ev);
/**
* trace_event_get_name:
*
* Get the name of an event.
*/
static const char * trace_event_get_name(TraceEvent *ev);
/**
* trace_event_get_state:
* @id: Event identifier.
*
* Get the tracing state of an event (both static and dynamic).
*
* If the event has the disabled property, the check will have no performance
* impact.
*
* As a down side, you must always use an immediate #TraceEventID value.
*/
#define trace_event_get_state(id) \
((id ##_ENABLED) && trace_event_get_state_dynamic(trace_event_id(id)))
/**
* trace_event_get_state_static:
* @id: Event identifier.
*
* Get the static tracing state of an event.
*
* Use the define 'TRACE_${EVENT_NAME}_ENABLED' for compile-time checks (it will
* be set to 1 or 0 according to the presence of the disabled property).
*/
static bool trace_event_get_state_static(TraceEvent *ev);
/**
* trace_event_get_state_dynamic:
*
* Get the dynamic tracing state of an event.
*/
static bool trace_event_get_state_dynamic(TraceEvent *ev);
/**
* trace_event_set_state:
*
* Set the tracing state of an event (only if possible).
*/
#define trace_event_set_state(id, state) \
do { \
if ((id ##_ENABLED)) { \
TraceEvent *_e = trace_event_id(id); \
trace_event_set_state_dynamic(_e, state); \
} \
} while (0)
/**
* trace_event_set_state_dynamic:
*
* Set the dynamic tracing state of an event.
*
* Pre-condition: trace_event_get_state_static(ev) == true
*/
static void trace_event_set_state_dynamic(TraceEvent *ev, bool state);
/**
* trace_event_set_state_dynamic_backend:
*
* Warning: This function must be implemented by each tracing backend.
*/
void trace_event_set_state_dynamic_backend(TraceEvent *ev, bool state);
/**
* trace_print_events:
*
* Print the state of all events.
*
* Warning: This function must be implemented by each tracing backend.
*/
void trace_print_events(FILE *stream, fprintf_function stream_printf);
/**
* trace_backend_init:
* @events: Name of file with events to be enabled at startup; may be NULL.
* Corresponds to commandline option "-trace events=...".
* @file: Name of trace output file; may be NULL.
* Corresponds to commandline option "-trace file=...".
*
* Initialize the tracing backend.
*
* Warning: This function must be implemented by each tracing backend.
*
* Returns: Whether the backend could be successfully initialized.
*/ */
bool trace_backend_init(const char *events, const char *file); bool trace_backend_init(const char *events, const char *file);
/** Generic function to initialize the state of events. /**
* trace_backend_init_events:
* @fname: Name of file with events to enable; may be NULL.
* *
* @fname Name of file with events to enable; may be NULL. * Generic function to initialize the state of events.
*/ */
void trace_backend_init_events(const char *fname); void trace_backend_init_events(const char *fname);
#endif /* TRACE_CONTROL_H */
#include "trace/control-internal.h"
#endif /* TRACE__CONTROL_H */

View File

@ -1,7 +1,7 @@
/* /*
* Default implementation for backend initialization from commandline. * Default implementation for backend initialization from commandline.
* *
* Copyright (C) 2011 Lluís Vilanova <vilanova@ac.upc.edu> * Copyright (C) 2011-2012 Lluís Vilanova <vilanova@ac.upc.edu>
* *
* This work is licensed under the terms of the GNU GPL, version 2. See * This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory. * the COPYING file in the top-level directory.
@ -18,11 +18,10 @@ void trace_print_events(FILE *stream, fprintf_function stream_printf)
"operation not supported with the current backend\n"); "operation not supported with the current backend\n");
} }
bool trace_event_set_state(const char *name, bool state) void trace_event_set_state_dynamic_backend(TraceEvent *ev, bool state)
{ {
fprintf(stderr, "warning: " fprintf(stderr, "warning: "
"cannot set the state of a trace event with the current backend\n"); "cannot set the state of a trace event with the current backend\n");
return false;
} }
bool trace_backend_init(const char *events, const char *file) bool trace_backend_init(const char *events, const char *file)

33
trace/event-internal.h Normal file
View File

@ -0,0 +1,33 @@
/*
* Interface for configuring and controlling the state of tracing events.
*
* Copyright (C) 2012 Lluís Vilanova <vilanova@ac.upc.edu>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef TRACE__EVENT_INTERNAL_H
#define TRACE__EVENT_INTERNAL_H
#include "trace/generated-events.h"
/**
* TraceEvent:
* @id: Unique event identifier.
* @name: Event name.
* @sstate: Static tracing state.
* @dstate: Dynamic tracing state.
*
* Opaque generic description of a tracing event.
*/
typedef struct TraceEvent {
TraceEventID id;
const char * name;
const bool sstate;
bool dstate;
} TraceEvent;
#endif /* TRACE__EVENT_INTERNAL_H */

View File

@ -218,6 +218,7 @@ int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasi
{ {
unsigned int idx, rec_off, old_idx, new_idx; unsigned int idx, rec_off, old_idx, new_idx;
uint32_t rec_len = sizeof(TraceRecord) + datasize; uint32_t rec_len = sizeof(TraceRecord) + datasize;
uint64_t event_u64 = event;
uint64_t timestamp_ns = get_clock(); uint64_t timestamp_ns = get_clock();
do { do {
@ -235,7 +236,7 @@ int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasi
idx = old_idx % TRACE_BUF_LEN; idx = old_idx % TRACE_BUF_LEN;
rec_off = idx; rec_off = idx;
rec_off = write_to_buffer(rec_off, &event, sizeof(event)); rec_off = write_to_buffer(rec_off, &event_u64, sizeof(event_u64));
rec_off = write_to_buffer(rec_off, &timestamp_ns, sizeof(timestamp_ns)); rec_off = write_to_buffer(rec_off, &timestamp_ns, sizeof(timestamp_ns));
rec_off = write_to_buffer(rec_off, &rec_len, sizeof(rec_len)); rec_off = write_to_buffer(rec_off, &rec_len, sizeof(rec_len));
@ -359,38 +360,16 @@ void trace_print_events(FILE *stream, fprintf_function stream_printf)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < NR_TRACE_EVENTS; i++) { for (i = 0; i < trace_event_count(); i++) {
TraceEvent *ev = trace_event_id(i);
stream_printf(stream, "%s [Event ID %u] : state %u\n", stream_printf(stream, "%s [Event ID %u] : state %u\n",
trace_list[i].tp_name, i, trace_list[i].state); trace_event_get_name(ev), i, trace_event_get_state_dynamic(ev));
} }
} }
bool trace_event_set_state(const char *name, bool state) void trace_event_set_state_dynamic_backend(TraceEvent *ev, bool state)
{ {
unsigned int i; ev->dstate = state;
unsigned int len;
bool wildcard = false;
bool matched = false;
len = strlen(name);
if (len > 0 && name[len - 1] == '*') {
wildcard = true;
len -= 1;
}
for (i = 0; i < NR_TRACE_EVENTS; i++) {
if (wildcard) {
if (!strncmp(trace_list[i].tp_name, name, len)) {
trace_list[i].state = state;
matched = true;
}
continue;
}
if (!strcmp(trace_list[i].tp_name, name)) {
trace_list[i].state = state;
return true;
}
}
return matched;
} }
/* Helper function to create a thread with signals blocked. Use glib's /* Helper function to create a thread with signals blocked. Use glib's

View File

@ -15,12 +15,8 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
typedef uint64_t TraceEventID; #include "trace/generated-events.h"
typedef struct {
const char *tp_name;
bool state;
} TraceEvent;
void st_print_trace_file_status(FILE *stream, fprintf_function stream_printf); void st_print_trace_file_status(FILE *stream, fprintf_function stream_printf);
void st_set_trace_file_enabled(bool enable); void st_set_trace_file_enabled(bool enable);

View File

@ -4,40 +4,18 @@
void trace_print_events(FILE *stream, fprintf_function stream_printf) void trace_print_events(FILE *stream, fprintf_function stream_printf)
{ {
unsigned int i; TraceEventID i;
for (i = 0; i < NR_TRACE_EVENTS; i++) { for (i = 0; i < trace_event_count(); i++) {
TraceEvent *ev = trace_event_id(i);
stream_printf(stream, "%s [Event ID %u] : state %u\n", stream_printf(stream, "%s [Event ID %u] : state %u\n",
trace_list[i].tp_name, i, trace_list[i].state); trace_event_get_name(ev), i, trace_event_get_state_dynamic(ev));
} }
} }
bool trace_event_set_state(const char *name, bool state) void trace_event_set_state_dynamic_backend(TraceEvent *ev, bool state)
{ {
unsigned int i; ev->dstate = state;
unsigned int len;
bool wildcard = false;
bool matched = false;
len = strlen(name);
if (len > 0 && name[len - 1] == '*') {
wildcard = true;
len -= 1;
}
for (i = 0; i < NR_TRACE_EVENTS; i++) {
if (wildcard) {
if (!strncmp(trace_list[i].tp_name, name, len)) {
trace_list[i].state = state;
matched = true;
}
continue;
}
if (!strcmp(trace_list[i].tp_name, name)) {
trace_list[i].state = state;
return true;
}
}
return matched;
} }
bool trace_backend_init(const char *events, const char *file) bool trace_backend_init(const char *events, const char *file)

View File

@ -1,11 +0,0 @@
#ifndef TRACE_STDERR_H
#define TRACE_STDERR_H
typedef uint64_t TraceEventID;
typedef struct {
const char *tp_name;
bool state;
} TraceEvent;
#endif /* ! TRACE_STDERR_H */

2
vl.c
View File

@ -642,7 +642,7 @@ void runstate_set(RunState new_state)
RunState_lookup[new_state]); RunState_lookup[new_state]);
abort(); abort();
} }
trace_runstate_set(new_state);
current_run_state = new_state; current_run_state = new_state;
} }