diff options
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | docs/tracing.txt | 44 | ||||
-rw-r--r-- | monitor.c | 13 | ||||
-rwxr-xr-x | scripts/tracetool.py | 4 | ||||
-rw-r--r-- | scripts/tracetool/backend/__init__.py | 16 | ||||
-rw-r--r-- | scripts/tracetool/backend/dtrace.py | 3 | ||||
-rw-r--r-- | scripts/tracetool/backend/events.py | 23 | ||||
-rw-r--r-- | scripts/tracetool/backend/simple.py | 22 | ||||
-rw-r--r-- | scripts/tracetool/backend/stderr.py | 28 | ||||
-rw-r--r-- | scripts/tracetool/backend/ust.py | 3 | ||||
-rw-r--r-- | scripts/tracetool/format/events_c.py | 39 | ||||
-rw-r--r-- | scripts/tracetool/format/events_h.py | 50 | ||||
-rw-r--r-- | scripts/tracetool/format/h.py | 9 | ||||
-rw-r--r-- | trace-events | 1 | ||||
-rw-r--r-- | trace/Makefile.objs | 24 | ||||
-rw-r--r-- | trace/control-internal.h | 67 | ||||
-rw-r--r-- | trace/control.c | 106 | ||||
-rw-r--r-- | trace/control.h | 190 | ||||
-rw-r--r-- | trace/default.c | 5 | ||||
-rw-r--r-- | trace/event-internal.h | 33 | ||||
-rw-r--r-- | trace/simple.c | 35 | ||||
-rw-r--r-- | trace/simple.h | 6 | ||||
-rw-r--r-- | trace/stderr.c | 34 | ||||
-rw-r--r-- | trace/stderr.h | 11 | ||||
-rw-r--r-- | vl.c | 2 |
26 files changed, 595 insertions, 180 deletions
diff --git a/.gitignore b/.gitignore index 9c234a383b..487813a5dc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,9 @@ config-target.* trace/generated-tracers.h trace/generated-tracers.c 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 *-timestamp *-softmmu @@ -35,6 +35,9 @@ GENERATED_HEADERS = config-host.h qemu-options.def GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h 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 ifeq ($(TRACE_BACKEND),dtrace) GENERATED_HEADERS += trace/generated-tracers-dtrace.h diff --git a/docs/tracing.txt b/docs/tracing.txt index 14db3bffb4..cf53c173ec 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -100,49 +100,37 @@ respectively. This ensures portability between 32- and 64-bit platforms. == Generic interface and monitor commands == -You can programmatically query and control the dynamic state of trace events -through a backend-agnostic interface: +You can programmatically query and control the state of trace events through a +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 - 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: +The state of events can also be queried and modified through monitor commands: * info trace-events View available trace events and their state. State 1 means enabled, state 0 means disabled. * trace-event NAME on|off - Enable/disable a given trace event or a group of events having common prefix - through wildcard. + Enable/disable a given trace event or a group of events (using wildcards). 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 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 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. +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 == 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; } + +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). @@ -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"); 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); } } diff --git a/scripts/tracetool.py b/scripts/tracetool.py index c003cf69ed..a79ec0f096 100755 --- a/scripts/tracetool.py +++ b/scripts/tracetool.py @@ -90,8 +90,8 @@ def main(args): arg_format = arg elif opt == "--list-backends": - backends = tracetool.backend.get_list() - out(", ".join([ b for b,_ in backends ])) + public_backends = tracetool.backend.get_list(only_public = True) + out(", ".join([ b for b,_ in public_backends ])) sys.exit(0) elif opt == "--check-backend": check_backend = True diff --git a/scripts/tracetool/backend/__init__.py b/scripts/tracetool/backend/__init__.py index be43472f7b..f0314ee376 100644 --- a/scripts/tracetool/backend/__init__.py +++ b/scripts/tracetool/backend/__init__.py @@ -17,6 +17,16 @@ considered its short description. 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 ----------------- @@ -42,7 +52,7 @@ import os import tracetool -def get_list(): +def get_list(only_public = False): """Get a list of (name, description) pairs.""" res = [("nop", "Tracing disabled.")] modnames = [] @@ -57,6 +67,10 @@ def get_list(): continue module = module[1] + public = getattr(module, "PUBLIC", False) + if only_public and not public: + continue + doc = module.__doc__ if doc is None: doc = "" diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py index ad5eb3b0ab..e31bc799f8 100644 --- a/scripts/tracetool/backend/dtrace.py +++ b/scripts/tracetool/backend/dtrace.py @@ -16,6 +16,9 @@ __email__ = "stefanha@linux.vnet.ibm.com" from tracetool import out +PUBLIC = True + + PROBEPREFIX = None def _probeprefix(): diff --git a/scripts/tracetool/backend/events.py b/scripts/tracetool/backend/events.py new file mode 100644 index 0000000000..5afce3e8da --- /dev/null +++ b/scripts/tracetool/backend/events.py @@ -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 diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py index e4b4a7f05d..37ef599324 100644 --- a/scripts/tracetool/backend/simple.py +++ b/scripts/tracetool/backend/simple.py @@ -15,6 +15,10 @@ __email__ = "stefanha@linux.vnet.ibm.com" from tracetool import out + +PUBLIC = True + + def is_string(arg): strtype = ('const char*', 'char*', 'const char *', 'char *') if arg.lstrip().startswith(strtype): @@ -24,17 +28,10 @@ def is_string(arg): def c(events): out('#include "trace.h"', + '#include "trace/control.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): out('void trace_%(name)s(%(args)s)', @@ -59,7 +56,9 @@ def c(events): 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;', ' }', '', @@ -102,6 +101,3 @@ def h(events): name = event.name, args = event.args, ) - out('') - out('#define NR_TRACE_EVENTS %d' % len(events)) - out('extern TraceEvent trace_list[NR_TRACE_EVENTS];') diff --git a/scripts/tracetool/backend/stderr.py b/scripts/tracetool/backend/stderr.py index 917fde7c15..6f93dbd1ae 100644 --- a/scripts/tracetool/backend/stderr.py +++ b/scripts/tracetool/backend/stderr.py @@ -16,41 +16,33 @@ __email__ = "stefanha@linux.vnet.ibm.com" from tracetool import out -def c(events): - out('#include "trace.h"', - '', - 'TraceEvent trace_list[] = {') +PUBLIC = True - for e in events: - out('{.tp_name = "%(name)s", .state=0},', - name = e.name, - ) - out('};') +def c(events): + pass def h(events): 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()) if len(e.args) > 0: argnames = ", " + argnames 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);', ' }', '}', name = e.name, args = e.args, - event_num = num, - fmt = e.fmt, + event_id = "TRACE_" + e.name.upper(), + fmt = e.fmt.rstrip("\n"), argnames = argnames, ) - - out('', - '#define NR_TRACE_EVENTS %d' % len(events)) diff --git a/scripts/tracetool/backend/ust.py b/scripts/tracetool/backend/ust.py index 31a2ff0404..ea36995092 100644 --- a/scripts/tracetool/backend/ust.py +++ b/scripts/tracetool/backend/ust.py @@ -16,6 +16,9 @@ __email__ = "stefanha@linux.vnet.ibm.com" from tracetool import out +PUBLIC = True + + def c(events): out('#include <ust/marker.h>', '#undef mutex_lock', diff --git a/scripts/tracetool/format/events_c.py b/scripts/tracetool/format/events_c.py new file mode 100644 index 0000000000..d670ec83d5 --- /dev/null +++ b/scripts/tracetool/format/events_c.py @@ -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('};', + '', + ) diff --git a/scripts/tracetool/format/events_h.py b/scripts/tracetool/format/events_h.py new file mode 100644 index 0000000000..d30ccea8a1 --- /dev/null +++ b/scripts/tracetool/format/events_h.py @@ -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 */', + ) diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py index 9a58de1331..93132fceaf 100644 --- a/scripts/tracetool/format/h.py +++ b/scripts/tracetool/format/h.py @@ -25,14 +25,7 @@ def begin(events): '#include "qemu-common.h"') def end(events): - 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('', - '#endif /* TRACE__GENERATED_TRACERS_H */') + out('#endif /* TRACE__GENERATED_TRACERS_H */') def nop(events): for e in events: diff --git a/trace-events b/trace-events index 5a6ef4b406..7f34112424 100644 --- a/trace-events +++ b/trace-events @@ -474,6 +474,7 @@ scsi_request_sense(int target, int lun, int tag) "target %d lun %d tag %d" # vl.c vm_state_notify(int running, int reason) "running %d reason %d" load_file(const char *name, const char *path) "name %s location %s" +runstate_set(int new_state) "new state %d" # block/qcow2.c qcow2_writev_start_req(void *co, int64_t sector, int nb_sectors) "co %p sector %" PRIx64 " nb_sectors %d" diff --git a/trace/Makefile.objs b/trace/Makefile.objs index dde9d5784e..a043072106 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -1,7 +1,29 @@ # -*- 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 @cmp -s $< $@ || cp $< $@ diff --git a/trace/control-internal.h b/trace/control-internal.h new file mode 100644 index 0000000000..cce2da47c4 --- /dev/null +++ b/trace/control-internal.h @@ -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 */ diff --git a/trace/control.c b/trace/control.c index be05efb99b..49f61e137b 100644 --- a/trace/control.c +++ b/trace/control.c @@ -1,19 +1,86 @@ /* * 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 - * the COPYING file in the top-level directory. + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. */ #include "trace/control.h" -void trace_backend_init_events(const char *fname) +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) { - int ret; + 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) +{ if (fname == NULL) { return; } @@ -32,15 +99,28 @@ void trace_backend_init_events(const char *fname) if ('#' == line_buf[0]) { /* skip commented lines */ continue; } - if ('-' == line_buf[0]) { - ret = trace_event_set_state(line_buf+1, false); + const bool enable = ('-' != line_buf[0]); + 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 { - ret = trace_event_set_state(line_buf, true); - } - if (!ret) { - fprintf(stderr, - "error: trace event '%s' does not exist\n", line_buf); - exit(1); + TraceEvent *ev = trace_event_name(line_ptr); + if (ev == NULL) { + fprintf(stderr, + "error: trace event '%s' does not exist\n", line_ptr); + 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); } } } diff --git a/trace/control.h b/trace/control.h index 2acaa4290e..cde8260a8a 100644 --- a/trace/control.h +++ b/trace/control.h @@ -1,41 +1,193 @@ /* * 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 - * the COPYING file in the top-level directory. + * 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_H -#define TRACE_CONTROL_H +#ifndef TRACE__CONTROL_H +#define TRACE__CONTROL_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); -/** Set the state of an event. +/** + * TraceEventID: + * + * Unique tracing event identifier. + * + * These are named as 'TRACE_${EVENT_NAME}'. + * + * See also: "trace/generated-events.h" + */ +enum TraceEventID; + +/** + * trace_event_id: + * @id: Event identifier. + * + * Get an event by its identifier. + * + * This routine has a constant cost, as opposed to trace_event_name and + * trace_event_pattern. + * + * 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: * - * @return Whether the state changed. + * Get the name of an event. */ -bool trace_event_set_state(const char *name, bool state); +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); -/** Initialize the tracing backend. +/** + * 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=...". * - * @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=...". - * @return Whether the backend could be successfully initialized. + * 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); -/** 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); -#endif /* TRACE_CONTROL_H */ + +#include "trace/control-internal.h" + +#endif /* TRACE__CONTROL_H */ diff --git a/trace/default.c b/trace/default.c index c9b27a289b..6e07a479d6 100644 --- a/trace/default.c +++ b/trace/default.c @@ -1,7 +1,7 @@ /* * 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 * 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"); } -bool trace_event_set_state(const char *name, bool state) +void trace_event_set_state_dynamic_backend(TraceEvent *ev, bool state) { fprintf(stderr, "warning: " "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) diff --git a/trace/event-internal.h b/trace/event-internal.h new file mode 100644 index 0000000000..b2310d9bea --- /dev/null +++ b/trace/event-internal.h @@ -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 */ diff --git a/trace/simple.c b/trace/simple.c index 375d98f70b..1e3f6914c5 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -218,6 +218,7 @@ int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasi { unsigned int idx, rec_off, old_idx, new_idx; uint32_t rec_len = sizeof(TraceRecord) + datasize; + uint64_t event_u64 = event; uint64_t timestamp_ns = get_clock(); do { @@ -235,7 +236,7 @@ int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasi idx = old_idx % TRACE_BUF_LEN; 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, ×tamp_ns, sizeof(timestamp_ns)); 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; - 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", - 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; - 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; + ev->dstate = state; } /* Helper function to create a thread with signals blocked. Use glib's diff --git a/trace/simple.h b/trace/simple.h index 2ab96a8147..5260d9aa81 100644 --- a/trace/simple.h +++ b/trace/simple.h @@ -15,12 +15,8 @@ #include <stdbool.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_set_trace_file_enabled(bool enable); diff --git a/trace/stderr.c b/trace/stderr.c index 0810d6f956..e212efd64d 100644 --- a/trace/stderr.c +++ b/trace/stderr.c @@ -4,40 +4,18 @@ 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", - 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; - 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; + ev->dstate = state; } bool trace_backend_init(const char *events, const char *file) diff --git a/trace/stderr.h b/trace/stderr.h deleted file mode 100644 index d575b613e3..0000000000 --- a/trace/stderr.h +++ /dev/null @@ -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 */ @@ -642,7 +642,7 @@ void runstate_set(RunState new_state) RunState_lookup[new_state]); abort(); } - + trace_runstate_set(new_state); current_run_state = new_state; } |