From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:49852) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ULCqO-00046I-Ns for qemu-devel@nongnu.org; Thu, 28 Mar 2013 09:26:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ULCqJ-00089Y-Iv for qemu-devel@nongnu.org; Thu, 28 Mar 2013 09:26:16 -0400 Received: from mx1.redhat.com ([209.132.183.28]:16105) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ULCqJ-00089F-7c for qemu-devel@nongnu.org; Thu, 28 Mar 2013 09:26:11 -0400 From: Stefan Hajnoczi Date: Thu, 28 Mar 2013 14:25:44 +0100 Message-Id: <1364477152-26994-4-git-send-email-stefanha@redhat.com> In-Reply-To: <1364477152-26994-1-git-send-email-stefanha@redhat.com> References: <1364477152-26994-1-git-send-email-stefanha@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH 03/11] trace: Provide a detailed event control interface List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Anthony Liguori , =?UTF-8?q?Llu=C3=ADs=20Vilanova?= , Stefan Hajnoczi From: Llu=C3=ADs Vilanova This interface decouples event obtaining from interaction. Events can be obtained through three different methods: * identifier * name * simple wildcard pattern Signed-off-by: Llu=C3=ADs Vilanova Signed-off-by: Stefan Hajnoczi --- docs/tracing.txt | 44 +++++------ trace/control-internal.h | 67 +++++++++++++++++ trace/control.c | 106 ++++++++++++++++++++++---- trace/control.h | 190 +++++++++++++++++++++++++++++++++++++++++= +----- 4 files changed, 349 insertions(+), 58 deletions(-) create mode 100644 trace/control-internal.h diff --git a/docs/tracing.txt b/docs/tracing.txt index 14db3bf..cf53c17 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -100,49 +100,37 @@ respectively. This ensures portability between 32-= and 64-bit platforms. =20 =3D=3D Generic interface and monitor commands =3D=3D =20 -You can programmatically query and control the dynamic state of trace ev= ents -through a backend-agnostic interface: +You can programmatically query and control the state of trace events thr= ough a +backend-agnostic interface provided by the header "trace/control.h". =20 -* 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). =20 -* 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 success= fully - changed, or "false" otherwise: - - #include "trace/control.h" - =20 - 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 com= mands: =20 * info trace-events View available trace events and their state. State 1 means enabled, s= tate 0 means disabled. =20 * 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 wildcar= ds). =20 The "-trace events=3D" command line argument can be used to enable= the events listed in from the very beginning of the program. This fil= e must contain one event name per line. =20 -A basic wildcard matching is supported in both the monitor command "trac= e --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=3D" file begins with a '-', the tr= ace 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 dis= abled. =20 +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 + =3D=3D Trace backends =3D=3D =20 The "tracetool" script automates tedious trace event code generation and= also @@ -263,3 +251,7 @@ guard such computations and avoid its compilation whe= n the event is disabled: } return ptr; } + +You can check both if the event has been disabled and is dynamically ena= bled at +the same time using the 'trace_event_get_state' routine (see header +"trace/control.h" for more information). diff --git a/trace/control-internal.h b/trace/control-internal.h new file mode 100644 index 0000000..cce2da4 --- /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=C3=ADs Vilanova + * + * This work is licensed under the terms of the GNU GPL, version 2 or la= ter. + * See the COPYING file in the top-level directory. + */ + +#ifndef TRACE__CONTROL_INTERNAL_H +#define TRACE__CONTROL_INTERNAL_H + +#include + + +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 !=3D NULL); + return strchr(str, '*') !=3D NULL; +} + +static inline TraceEventID trace_event_get_id(TraceEvent *ev) +{ + assert(ev !=3D NULL); + return ev->id; +} + +static inline const char * trace_event_get_name(TraceEvent *ev) +{ + assert(ev !=3D NULL); + return ev->name; +} + +static inline bool trace_event_get_state_static(TraceEvent *ev) +{ + assert(ev !=3D NULL); + return ev->sstate; +} + +static inline bool trace_event_get_state_dynamic(TraceEvent *ev) +{ + assert(ev !=3D NULL); + return ev->dstate; +} + +static inline void trace_event_set_state_dynamic(TraceEvent *ev, bool st= ate) +{ + assert(ev !=3D 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 be05efb..49f61e1 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=C3=ADs Vilanova + * Copyright (C) 2011-2012 Llu=C3=ADs Vilanova * - * 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 la= ter. + * See the COPYING file in the top-level directory. */ =20 #include "trace/control.h" =20 =20 -void trace_backend_init_events(const char *fname) +TraceEvent *trace_event_name(const char *name) +{ + assert(name !=3D NULL); + + TraceEventID i; + for (i =3D 0; i < trace_event_count(); i++) { + TraceEvent *ev =3D trace_event_id(i); + if (strcmp(trace_event_get_name(ev), name) =3D=3D 0) { + return ev; + } + } + return NULL; +} + +static bool pattern_glob(const char *pat, const char *ev) +{ + while (*pat !=3D '\0' && *ev !=3D '\0') { + if (*pat =3D=3D *ev) { + pat++; + ev++; + } + else if (*pat =3D=3D '*') { + 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 =3D=3D '*') { + pat++; + } + + if (*pat =3D=3D '\0' && *ev =3D=3D '\0') { + return true; + } else { + return false; + } +} + +TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev) { - int ret; + assert(pat !=3D NULL); =20 + TraceEventID i; + + if (ev =3D=3D NULL) { + i =3D -1; + } else { + i =3D trace_event_get_id(ev); + } + i++; + + while (i < trace_event_count()) { + TraceEvent *res =3D 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 =3D=3D NULL) { return; } @@ -32,15 +99,28 @@ void trace_backend_init_events(const char *fname) if ('#' =3D=3D line_buf[0]) { /* skip commented lines */ continue; } - if ('-' =3D=3D line_buf[0]) { - ret =3D trace_event_set_state(line_buf+1, false); + const bool enable =3D ('-' !=3D line_buf[0]); + char *line_ptr =3D enable ? line_buf : line_buf + 1; + if (trace_event_is_pattern(line_ptr)) { + TraceEvent *ev =3D NULL; + while ((ev =3D trace_event_pattern(line_ptr, ev)) !=3D N= ULL) { + if (trace_event_get_state_static(ev)) { + trace_event_set_state_dynamic(ev, enable); + } + } } else { - ret =3D 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 =3D trace_event_name(line_ptr); + if (ev =3D=3D 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 2acaa42..cde8260 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=C3=ADs Vilanova + * Copyright (C) 2011-2012 Llu=C3=ADs Vilanova * - * 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 la= ter. + * See the COPYING file in the top-level directory. */ =20 -#ifndef TRACE_CONTROL_H -#define TRACE_CONTROL_H +#ifndef TRACE__CONTROL_H +#define TRACE__CONTROL_H =20 #include "qemu-common.h" +#include "trace/generated-events.h" =20 =20 -/** 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); =20 +/** + * 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 perfor= mance + * 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 =3D 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) =3D=3D 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); =20 -/** Initialize the tracing backend. +/** + * trace_backend_init: + * @events: Name of file with events to be enabled at startup; may be NU= LL. + * Corresponds to commandline option "-trace events=3D...". + * @file: Name of trace output file; may be NULL. + * Corresponds to commandline option "-trace file=3D...". * - * @events Name of file with events to be enabled at startup; may be NUL= L. - * Corresponds to commandline option "-trace events=3D...". - * @file Name of trace output file; may be NULL. - * Corresponds to commandline option "-trace file=3D...". - * @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); =20 -/** 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); =20 -#endif /* TRACE_CONTROL_H */ + +#include "trace/control-internal.h" + +#endif /* TRACE__CONTROL_H */ --=20 1.8.1.4