From patchwork Fri Feb 3 21:19:46 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: 139472 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 00958104796 for ; Sat, 4 Feb 2012 08:20:15 +1100 (EST) Received: from localhost ([::1]:44873 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RtQYF-0008JS-Jf for incoming@patchwork.ozlabs.org; Fri, 03 Feb 2012 16:20:11 -0500 Received: from eggs.gnu.org ([140.186.70.92]:38725) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RtQY3-00083Q-T2 for qemu-devel@nongnu.org; Fri, 03 Feb 2012 16:20:03 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RtQY2-0000Kg-3e for qemu-devel@nongnu.org; Fri, 03 Feb 2012 16:19:59 -0500 Received: from gw.ac.upc.edu ([147.83.30.3]:52806) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RtQY1-0000KS-G8 for qemu-devel@nongnu.org; Fri, 03 Feb 2012 16:19:58 -0500 Received: from localhost (unknown [84.88.53.92]) by gw.ac.upc.edu (Postfix) with ESMTP id 469342D000D; Fri, 3 Feb 2012 22:19:56 +0100 (CET) To: qemu-devel@nongnu.org From: =?utf-8?b?TGx1w61z?= Vilanova Date: Fri, 03 Feb 2012 22:19:46 +0100 Message-ID: <20120203211946.339.55683.stgit@ginnungagap.bsc.es> In-Reply-To: <20120203211915.339.99432.stgit@ginnungagap.bsc.es> References: <20120203211915.339.99432.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 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 | 38 +++++--------- trace/control-internal.h | 49 ++++++++++++++++++ trace/control.c | 89 ++++++++++++++++++++++++++++++-- trace/control.h | 126 ++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 260 insertions(+), 42 deletions(-) create mode 100644 trace/control-internal.h diff --git a/docs/tracing.txt b/docs/tracing.txt index a92716f..787cabd 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 == diff --git a/trace/control-internal.h b/trace/control-internal.h new file mode 100644 index 0000000..e609ab2 --- /dev/null +++ b/trace/control-internal.h @@ -0,0 +1,49 @@ +/* + * 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) +{ + while (*str != '\0') { + if (*str == '*') { + return true; + } + str++; + } + return false; +} + +static inline TraceEventID trace_event_get_id(TraceEvent *ev) +{ + return ev->id; +} + +static inline const char * trace_event_get_name(TraceEvent *ev) +{ + return ev->name; +} + +static inline bool trace_event_get_state_dynamic(TraceEvent *ev) +{ + return ev->dstate; +} diff --git a/trace/control.c b/trace/control.c index 4c5527d..c159fab 100644 --- a/trace/control.c +++ b/trace/control.c @@ -1,15 +1,81 @@ /* * 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) +{ + 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) +{ + 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))) { + fprintf(stderr, "%s\n", trace_event_get_name(res)); + return res; + } + i++; + } + + return NULL; +} + void trace_backend_init_events(const char *fname) { if (fname == NULL) { @@ -27,10 +93,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..2ab80d3 100644 --- a/trace/control.h +++ b/trace/control.h @@ -1,41 +1,147 @@ /* * 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 #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. +/** + * Get an event by its identifier. + * + * @id Event identifier. + * + * @return Pointer to event. * - * @return Whether the state changed. + * @pre The identifier is valid. */ -bool trace_event_set_state(const char *name, bool state); +static TraceEvent *trace_event_id(TraceEventID id); +/** + * Search an event by its name. + * + * Cost: O(N) + * + * @id Event name. + * + * @return Pointer to Event or NULL if not found. + */ +TraceEvent *trace_event_name(const char *name); -/** Initialize the tracing backend. +/** + * Get all events with a given name pattern. + * + * Cost: O(N) + * + * @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. + * + * @id Event identifier. + */ +#define trace_event_get_state(id) \ + (trace_event_get_state_static(id) && \ + trace_event_get_state_dynamic(trace_event_id(id))) + +/** + * Get the static tracing state of an event. + * + * @id Event identifier. + */ +#define trace_event_get_state_static(id) \ + (id ##_ENABLED) + +/** + * 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 (trace_event_get_state_static(id)) { \ + TraceEvent *_e = trace_event_id(id); \ + trace_event_set_state_dynamic(_e, state); \ + } \ + } while (0) + +/** + * Set the dynamic tracing state of an event. + * + * @warning This function must be implemented by each tracing backend. + */ +void trace_event_set_state_dynamic(TraceEvent *ev, bool state); + + + +/** + * 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); + +#include "trace/control-internal.h" + #endif /* TRACE_CONTROL_H */