From patchwork Fri Feb 10 14:28:43 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Llu=C3=ADs_Vilanova?= X-Patchwork-Id: 140656 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 8C932B6EF3 for ; Sat, 11 Feb 2012 01:29:21 +1100 (EST) Received: from localhost ([::1]:57033 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RvrTT-00072d-Fo for incoming@patchwork.ozlabs.org; Fri, 10 Feb 2012 09:29:19 -0500 Received: from eggs.gnu.org ([140.186.70.92]:60534) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RvrTA-0006UM-3X for qemu-devel@nongnu.org; Fri, 10 Feb 2012 09:29:05 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RvrT3-0006kg-ML for qemu-devel@nongnu.org; Fri, 10 Feb 2012 09:29:00 -0500 Received: from gw.ac.upc.edu ([147.83.30.3]:51690) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RvrT3-0006kX-2h for qemu-devel@nongnu.org; Fri, 10 Feb 2012 09:28:53 -0500 Received: from localhost (unknown [10.8.0.22]) by gw.ac.upc.edu (Postfix) with ESMTP id 7409A2D0001; Fri, 10 Feb 2012 15:28:51 +0100 (CET) To: qemu-devel@nongnu.org From: =?utf-8?b?TGx1w61z?= Vilanova Date: Fri, 10 Feb 2012 15:28:43 +0100 Message-ID: <20120210142843.13518.50486.stgit@ginnungagap.bsc.es> In-Reply-To: <20120210142832.13518.22003.stgit@ginnungagap.bsc.es> References: <20120210142832.13518.22003.stgit@ginnungagap.bsc.es> User-Agent: StGit/0.15 MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 147.83.30.3 Cc: blauwirbel@gmail.com, stefanha@gmail.com Subject: [Qemu-devel] [PATCH v3 2/6] trace: Provide a detailed event control interface X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This interface decouples event obtention from interaction. Event can be obtained through three different methods: * identifier * name * simple wildcard pattern Signed-off-by: Lluís Vilanova --- docs/tracing.txt | 41 +++++-------- trace/control-internal.h | 60 +++++++++++++++++++ trace/control.c | 92 ++++++++++++++++++++++++++--- trace/control.h | 148 ++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 296 insertions(+), 45 deletions(-) create mode 100644 trace/control-internal.h diff --git a/docs/tracing.txt b/docs/tracing.txt index a92716f..17690f1 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -100,44 +100,32 @@ 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 file "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-dependant). -* 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=" command line argument can be used to enable the events listed in 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 +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 == @@ -268,3 +256,6 @@ 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. diff --git a/trace/control-internal.h b/trace/control-internal.h new file mode 100644 index 0000000..81db761 --- /dev/null +++ b/trace/control-internal.h @@ -0,0 +1,60 @@ +/* + * Interface for configuring and controlling the state of tracing events. + * + * Copyright (C) 2011, 2012 Lluís Vilanova + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + + +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); + + while (*str != '\0') { + if (*str == '*') { + return true; + } + str++; + } + return false; +} + +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; +} diff --git a/trace/control.c b/trace/control.c index 4c5527d..7fbe854 100644 --- a/trace/control.c +++ b/trace/control.c @@ -1,15 +1,84 @@ /* * Interface for configuring and controlling the state of tracing events. * - * Copyright (C) 2011 Lluís Vilanova + * Copyright (C) 2011, 2012 Lluís 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 later. + * See the COPYING file in the top-level directory. */ #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 inline bool glob(const char *pat, const char *ev) +{ + while (*pat != '\0' && *ev != '\0') { + if (*pat == *ev) { + pat++; + ev++; + } + else if (*pat == '*') { + if (glob(pat, ev+1)) { + return true; + } else if (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 (glob(pat, trace_event_get_name(res))) { + return res; + } + i++; + } + + return NULL; +} + void trace_backend_init_events(const char *fname) { if (fname == NULL) { @@ -27,10 +96,19 @@ void trace_backend_init_events(const char *fname) size_t len = strlen(line_buf); if (len > 1) { /* skip empty lines */ line_buf[len - 1] = '\0'; - if (!trace_event_set_state(line_buf, true)) { - fprintf(stderr, - "error: trace event '%s' does not exist\n", line_buf); - exit(1); + if (trace_event_is_pattern(line_buf)) { + TraceEvent *ev; + while ((ev = trace_event_pattern(line_buf, ev)) != NULL) { + trace_event_set_state_dynamic(ev, true); + } + } else { + TraceEvent *ev = trace_event_name(line_buf); + if (ev == NULL) { + fprintf(stderr, + "error: trace event '%s' does not exist\n", line_buf); + exit(1); + } + trace_event_set_state_dynamic(ev, true); } } } diff --git a/trace/control.h b/trace/control.h index 2acaa42..3b9c6f5 100644 --- a/trace/control.h +++ b/trace/control.h @@ -1,41 +1,163 @@ /* * Interface for configuring and controlling the state of tracing events. * - * Copyright (C) 2011 Lluís Vilanova + * Copyright (C) 2011, 2012 Lluís 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 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-events.h" -/** Print the state of all events. */ -void trace_print_events(FILE *stream, fprintf_function stream_printf); -/** Set the state of an event. +/** + * Opaque generic description of a tracing event. + */ +struct TraceEvent; +typedef struct TraceEvent TraceEvent; + +/** + * TraceEventID - Unique tracing event identifier. + * + * These are named as 'TRACE_${EVENT_NAME}'. + * + * See also: trace-events.h + */ + +/** + * Get an event by its identifier. + * + * @id Event identifier. + * + * @return Pointer to event. + * + * @pre The identifier is valid. + */ +static TraceEvent *trace_event_id(TraceEventID id); + +/** + * Search an event by its name. + * + * @id Event name. + * + * @return Pointer to Event or NULL if not found. + */ +TraceEvent *trace_event_name(const char *name); + +/** + * Get all events with a given name pattern. + * + * @pat Event name pattern. + * @ev Event to start searching from. + * + * @return Pointer to Event or NULL if not found. + */ +TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev); + +/** + * Whether the given string is an event name pattern. + */ +static bool trace_event_is_pattern(const char *str); + +/** + * Return the number of events. + */ +static TraceEventID trace_event_count(void); + + + +/** + * Get the identifier of an event. + */ +static TraceEventID trace_event_get_id(TraceEvent *ev); + +/** + * Get the name of an event. + */ +static const char * trace_event_get_name(TraceEvent *ev); + +/** + * Get the tracing state of an event (both static and dynamic). + * + * @id Event identifier. + * + * 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))) + +/** + * Get the static tracing state of an event. + * + * @id Event identifier. + * + * 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); + +/** + * Get the dynamic tracing state of an event. + */ +static bool trace_event_get_state_dynamic(TraceEvent *ev); + +/** + * Set the tracing state of an event. + */ +#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) + +/** + * Set the dynamic tracing state of an event. * - * @return Whether the state changed. + * @warning This function must be implemented by each tracing backend. */ -bool trace_event_set_state(const char *name, bool state); +void trace_event_set_state_dynamic(TraceEvent *ev, bool state); -/** Initialize the tracing backend. + +/** + * Print the state of all events. + * + * @warning This function must be implemented by each tracing backend. + * + * @todo Should this be moved to generic code? + */ +void trace_print_events(FILE *stream, fprintf_function stream_printf); + +/** + * Initialize the tracing backend. * * @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. + * + * @warning This function must be implemented by each tracing backend. */ bool trace_backend_init(const char *events, const char *file); -/** Generic function to initialize the state of events. +/** + * Generic function to initialize the state of events. * * @fname Name of file with events to enable; may be NULL. */ void trace_backend_init_events(const char *fname); -#endif /* TRACE_CONTROL_H */ + +#include "trace/control-internal.h" + +#endif /* TRACE__CONTROL_H */