From patchwork Wed Jun 13 19:11:07 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: 164740 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 3C527B7010 for ; Thu, 14 Jun 2012 05:11:32 +1000 (EST) Received: from localhost ([::1]:41969 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SesyY-0007r0-0q for incoming@patchwork.ozlabs.org; Wed, 13 Jun 2012 15:11:30 -0400 Received: from eggs.gnu.org ([208.118.235.92]:37286) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SesyK-0007fH-WB for qemu-devel@nongnu.org; Wed, 13 Jun 2012 15:11:19 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SesyI-0005Re-5Q for qemu-devel@nongnu.org; Wed, 13 Jun 2012 15:11:16 -0400 Received: from roura.ac.upc.es ([147.83.33.10]:42698) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SesyH-0005RI-JH for qemu-devel@nongnu.org; Wed, 13 Jun 2012 15:11:14 -0400 Received: from gw.ac.upc.edu (gw.ac.upc.es [147.83.30.3]) by roura.ac.upc.es (8.13.8/8.13.8) with ESMTP id q5DJBBQP028927; Wed, 13 Jun 2012 21:11:11 +0200 Received: from localhost (gw-1.ac.upc.es [147.83.30.7]) by gw.ac.upc.edu (Postfix) with ESMTP id 41CE32D002D; Wed, 13 Jun 2012 21:11:09 +0200 (CEST) From: =?utf-8?b?TGx1w61z?= Vilanova To: qemu-devel@nongnu.org Date: Wed, 13 Jun 2012 22:11:07 +0300 Message-Id: <20120613191107.7037.9807.stgit@fimbulvetr.bsc.es> X-Mailer: git-send-email 1.7.10 In-Reply-To: <20120613191031.7037.99289.stgit@fimbulvetr.bsc.es> References: <20120613191031.7037.99289.stgit@fimbulvetr.bsc.es> User-Agent: StGit/0.16 MIME-Version: 1.0 X-MIME-Autoconverted: from 8bit to quoted-printable by roura.ac.upc.es id q5DJBBQP028927 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 147.83.33.10 Cc: Blue Swirl , Stefan Hajnoczi Subject: [Qemu-devel] [PATCH v6 3/7] 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. Events can be obtained through three different methods: * identifier * name * simple wildcard pattern Signed-off-by: Lluís Vilanova --- docs/tracing.txt | 42 ++++------ trace/control-internal.h | 67 ++++++++++++++++ trace/control.c | 92 +++++++++++++++++++++- trace/control.h | 189 +++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 339 insertions(+), 51 deletions(-) create mode 100644 trace/control-internal.h diff --git a/docs/tracing.txt b/docs/tracing.txt index c541133..5fa2446 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-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=" 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,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). diff --git a/trace/control-internal.h b/trace/control-internal.h new file mode 100644 index 0000000..6f6fdb7 --- /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 + * + * 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; +} + +static inline void trace_event_set_state_dynamic(TraceEvent *ev, bool state) +{ + assert(ev != NULL); + assert(trace_event_get_state_static(ev)); + trace_event_set_state_dynamic_backend(ev, state); +} diff --git a/trace/control.c b/trace/control.c index 4c5527d..81088e0 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 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 = NULL; + 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..6f6a048 100644 --- a/trace/control.h +++ b/trace/control.h @@ -1,41 +1,192 @@ /* * 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. +/** + * TraceEventID: + * + * Unique tracing event identifier. + * + * These are named as 'TRACE_${EVENT_NAME}'. + * + * See also: "trace-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 Whether the state changed. + * Return the number of events. */ -bool trace_event_set_state(const char *name, bool state); +static TraceEventID trace_event_count(void); -/** Initialize the tracing backend. + +/** + * trace_event_get_id: + * + * Get the identifier of an event. + */ +static TraceEventID trace_event_get_id(TraceEvent *ev); + +/** + * trace_event_get_name: * - * @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. + * 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. + */ +#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. + */ +static void trace_event_set_state_dynamic(TraceEvent *ev, bool state); + + +/** + * trace_print_events: + * + * 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); + +/** + * 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); -/** 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 */ +/** + * 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); + + +#include "trace/control-internal.h" + +#endif /* TRACE__CONTROL_H */