From patchwork Mon Jul 24 17:26:39 2017 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: 792915 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xGSx24554z9s65 for ; Tue, 25 Jul 2017 03:27:18 +1000 (AEST) Received: from localhost ([::1]:56066 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dZh8W-0000bo-BX for incoming@patchwork.ozlabs.org; Mon, 24 Jul 2017 13:27:16 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59032) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dZh8B-0000b9-Ru for qemu-devel@nongnu.org; Mon, 24 Jul 2017 13:26:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dZh86-0000nV-Ry for qemu-devel@nongnu.org; Mon, 24 Jul 2017 13:26:55 -0400 Received: from roura.ac.upc.edu ([147.83.33.10]:55462 helo=roura.ac.upc.es) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dZh86-0000nD-6F for qemu-devel@nongnu.org; Mon, 24 Jul 2017 13:26:50 -0400 Received: from correu-1.ac.upc.es (correu-1.ac.upc.es [147.83.30.91]) by roura.ac.upc.es (8.13.8/8.13.8) with ESMTP id v6OHQkg4032570; Mon, 24 Jul 2017 19:26:46 +0200 Received: from localhost (unknown [31.210.188.120]) by correu-1.ac.upc.es (Postfix) with ESMTPSA id 6544A1770; Mon, 24 Jul 2017 19:26:40 +0200 (CEST) From: =?utf-8?b?TGx1w61z?= Vilanova To: qemu-devel@nongnu.org Date: Mon, 24 Jul 2017 20:26:39 +0300 Message-Id: <150091719881.30739.10096572040779058122.stgit@frigg.lan> X-Mailer: git-send-email 2.13.2 In-Reply-To: <150091574424.30739.4131793221953168474.stgit@frigg.lan> References: <150091574424.30739.4131793221953168474.stgit@frigg.lan> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-MIME-Autoconverted: from 8bit to quoted-printable by roura.ac.upc.es id v6OHQkg4032570 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x [fuzzy] X-Received-From: 147.83.33.10 Subject: [Qemu-devel] [PATCH 06/13] instrument: Add event control interface X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: "Emilio G. Cota" , Stefan Hajnoczi Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Adds public and internal APIs to control event instrumentation. It also adds an event object (QI_EVENT_${NAME}) and define to know if it's staically enabled (QI_EVENT_${NAME}_ENABLED). Signed-off-by: Lluís Vilanova --- Makefile | 1 configure | 4 instrument/Makefile.objs | 5 instrument/control.c | 316 ++++++++++++++++++++++++++++ instrument/control.h | 86 ++++++++ instrument/qemu-instr/control.h | 128 +++++++++++ instrument/qemu-instr/types.h | 8 + scripts/tracetool/backend/instr_dynamic.py | 14 + scripts/tracetool/format/c.py | 37 +++ scripts/tracetool/format/instr_api_h.py | 13 + trace/event-internal.h | 10 + 11 files changed, 615 insertions(+), 7 deletions(-) create mode 100644 instrument/control.c create mode 100644 instrument/control.h create mode 100644 instrument/qemu-instr/control.h diff --git a/Makefile b/Makefile index c8be326790..ee54b7e17a 100644 --- a/Makefile +++ b/Makefile @@ -688,6 +688,7 @@ ifeq ($(TRACE_INSTRUMENT_BACKEND),instr-dynamic) $(INSTALL_DIR) "$(DESTDIR)$(includedir)/qemu-instr" $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/types.h "$(DESTDIR)$(includedir)/qemu-instr/" $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/visibility-internal.h "$(DESTDIR)$(includedir)/qemu-instr/" + $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/control.h "$(DESTDIR)$(includedir)/qemu-instr/" $(INSTALL_DATA) $(BUILD_DIR)/instrument/qemu-instr/events.h "$(DESTDIR)$(includedir)/qemu-instr/" endif diff --git a/configure b/configure index ca61665874..320309e0c0 100755 --- a/configure +++ b/configure @@ -6019,10 +6019,14 @@ QEMU_INCLUDES="-I\$(SRC_PATH)/tcg $QEMU_INCLUDES" echo "TRACE_INSTRUMENT_BACKEND=instr-$trace_instrument_backend" >> $config_host_mak if test "$trace_instrument" = "yes"; then echo "CONFIG_INSTRUMENT=y" >> $config_host_mak + libs_qga="-ldl $libs_qga" + LDFLAGS="-rdynamic $LDFLAGS" fi if test -n "$instrument_events"; then echo "CONFIG_INSTRUMENT_EVENTS=$instrument_events" >> $config_host_mak fi +# code requiring it is always compiled-in +LIBS="-ldl $LIBS" ########################################## echo "TOOLS=$tools" >> $config_host_mak diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs index c2289aba85..244936aa8c 100644 --- a/instrument/Makefile.objs +++ b/instrument/Makefile.objs @@ -38,3 +38,8 @@ $(obj)/qemu-instr/events.h-timestamp: $(BUILD_DIR)/trace-events-all $(BUILD_DIR) --backend=$(TRACE_INSTRUMENT_BACKEND) \ $(TRACETOOL_INSTR_STATIC) \ $< > $@,"GEN","$(patsubst %-timestamp,%,$@)") + +###################################################################### +# Control code + +target-obj-y += control.o diff --git a/instrument/control.c b/instrument/control.c new file mode 100644 index 0000000000..309228f15d --- /dev/null +++ b/instrument/control.c @@ -0,0 +1,316 @@ +/* + * Interface for controlling dynamic trace instrumentation. + * + * Copyright (C) 2012-2017 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. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" + +#include +#include "instrument/control.h" +#include "qemu/thread.h" +#include "qemu-instr/control.h" +#include "qemu/error-report.h" + + +typedef int64_t HandleID; + +typedef struct Handle +{ + HandleID id; + void *dlhandle; + void (*init)(int, const char **); + void (*fini)(void); + QSLIST_ENTRY(Handle) list; +} Handle; + +HandleID handle_last_id; +QSLIST_HEAD(, Handle) handles = QSLIST_HEAD_INITIALIZER(handles); +static QemuMutex instr_lock; + + +static Handle *handle_get(void) +{ + Handle *res = g_malloc0(sizeof(Handle)); + res->id = handle_last_id++; + QSLIST_INSERT_HEAD(&handles, res, list); + return res; +} + +static bool handle_put(HandleID id) +{ + Handle *prev = NULL; + Handle *handle; + QSLIST_FOREACH(handle, &handles, list) { + if (handle->id == id) { + break; + } + prev = handle; + } + if (handle == NULL) { + return false; + } else { + if (prev == NULL) { + QSLIST_REMOVE_HEAD(&handles, list); + } else { + QSLIST_REMOVE_AFTER(prev, list); + } + g_free(handle); + return true; + } +} + +#if defined(CONFIG_INSTRUMENT) +static Handle *handle_find(HandleID id) +{ + Handle *handle; + QSLIST_FOREACH(handle, &handles, list) { + if (handle->id == id) { + return handle; + } + } + return NULL; +} +#endif + +static bool instr_available(void) +{ +#if defined(CONFIG_INSTRUMENT) + return true; +#else + return false; +#endif +} + +InstrLoadError instr_load(const char * path, int argc, const char ** argv, + int64_t *handle_id) +{ + InstrLoadError res; + + qemu_rec_mutex_lock(&instr_lock); + + *handle_id = -1; + if (!instr_available()) { + res = INSTR_LOAD_UNAVAILABLE; + goto out; + } + + if (!QSLIST_EMPTY(&handles) > 0) { + /* XXX: This is in fact a hard-coded limit, but there's no reason why a + * real multi-library implementation should fail with something like + * "too many open libraries". + */ + res = INSTR_LOAD_UNAVAILABLE; + goto out; + } + + Handle * handle = handle_get(); + handle->dlhandle = dlopen(path, RTLD_NOW); + if (handle->dlhandle == NULL) { + goto err; + } + + handle->init = dlsym(handle->dlhandle, "qi_init"); + if (handle->init == NULL) { + goto err; + } + handle->fini = dlsym(handle->dlhandle, "qi_fini"); + if (handle->fini == NULL) { + goto err; + } + + handle->init(argc, argv); + + *handle_id = handle->id; + res = INSTR_LOAD_OK; + goto out; + +err: + handle_put(handle->id); + res = INSTR_LOAD_ERROR; +out: + qemu_rec_mutex_unlock(&instr_lock); + return res; +} + +static inline bool instr_event_is_instrument(TraceEvent *ev) +{ +#if defined(CONFIG_INSTRUMENT) + return ev->is_instr; +#else + return false; +#endif +} + +InstrUnloadError instr_unload(int64_t handle_id) +{ + InstrLoadError res; + + qemu_rec_mutex_lock(&instr_lock); + + if (!instr_available()) { + res = INSTR_UNLOAD_UNAVAILABLE; + goto out; + } + +#if defined(CONFIG_INSTRUMENT) + Handle *handle = handle_find(handle_id); + if (handle == NULL) { + res = INSTR_UNLOAD_INVALID; + goto out; + } + + handle->fini(); + + TraceEventIter iter; + TraceEvent *ev = NULL; + trace_event_iter_init(&iter, NULL); + while ((ev = trace_event_iter_next(&iter)) != NULL) { + if (instr_event_is_instrument(ev)) { + *ev->instr_cb = ev->instr_cb_default; + } + } + + /* this should never fail */ + if (dlclose(handle->dlhandle) < 0) { + res = INSTR_UNLOAD_ERROR; + } else { + res = INSTR_UNLOAD_OK; + } + handle_put(handle->id); +#endif + +out: + qemu_rec_mutex_unlock(&instr_lock); + return res; +} + +InstrUnloadError instr_unload_all(void) +{ + InstrUnloadError res = INSTR_UNLOAD_OK; + + qemu_rec_mutex_lock(&instr_lock); + while (true) { + Handle *handle = QSLIST_FIRST(&handles); + if (handle == NULL) { + break; + } else { + res = instr_unload(handle->id); + if (res != INSTR_UNLOAD_OK) { + break; + } + } + } + qemu_rec_mutex_unlock(&instr_lock); + + return res; +} + +void qi_ctrl_event_set(QIEvent *ev, void *cb) +{ + TraceEvent *tev = (TraceEvent *)ev; + + if (unlikely(tev == NULL)) { + error_report("qi_ctrl_event_set: event is NULL"); + return; + } + +#if defined(CONFIG_INSTRUMENT) + if (unlikely(!tev->is_instr)) { + error_report("qi_ctrl_event_set: event is not instrumentable"); + return; + } + + if (cb == NULL) { + *tev->instr_cb = tev->instr_cb_default; + } else { + *tev->instr_cb = cb; + } +#else + assert(false); +#endif /* defined(CONFIG_INSTRUMENT) */ +} + +bool qi_trace_event_get_state_static(QIEvent *ev) +{ + if (unlikely(ev == NULL)) { + error_report("qi_trace_event_get_state_static: event is NULL"); + return false; + } + return trace_event_get_state_static((TraceEvent *)ev); +} + +bool qi_trace_event_get_state_dynamic(QIEvent *ev) +{ + if (unlikely(ev == NULL)) { + error_report("qi_trace_event_get_state_dynamic: event is NULL"); + return false; + } + return trace_event_get_state_dynamic((TraceEvent *)ev); +} + +bool qi_trace_event_get_vcpu_state_dynamic(QICPU *vcpu, QIEvent *ev) +{ + TraceEvent *tev = (TraceEvent *)ev; + + if (unlikely(vcpu == NULL)) { + error_report("qi_trace_event_get_vcpu_state_dynamic: vcpu is NULL"); + return false; + } + if (unlikely(tev == NULL)) { + error_report("qi_trace_event_get_vcpu_state_dynamic: event is NULL"); + return false; + } + if (unlikely(!trace_event_is_vcpu(tev))) { + error_report("qi_trace_event_get_vcpu_state_dynamic: event does not have 'vcpu' property"); + return false; + } + return trace_event_get_vcpu_state_dynamic((CPUState *)vcpu, tev); +} + +void qi_trace_event_set_state_dynamic(QIEvent *ev, bool state) +{ + TraceEvent *tev = (TraceEvent *)ev; + + if (unlikely(tev == NULL)) { + error_report("qi_trace_event_set_state_dynamic: event is NULL"); + return; + } + if (unlikely(!trace_event_get_state_static(tev))) { + error_report("qi_trace_event_set_state_dynamic: event is statically disabled"); + return; + } + trace_event_set_state_dynamic(tev, state); +} + +void qi_trace_event_set_vcpu_state_dynamic(QICPU *vcpu, QIEvent *ev, bool state) +{ + TraceEvent *tev = (TraceEvent *)ev; + + if (unlikely(vcpu == NULL)) { + error_report("qi_trace_event_set_vcpu_state_dynamic: vcpu is NULL"); + return; + } + if (unlikely(tev == NULL)) { + error_report("qi_trace_event_set_vcpu_state_dynamic: event is NULL"); + return; + } + if (unlikely(!trace_event_is_vcpu(tev))) { + error_report("qi_trace_event_set_vcpu_state_dynamic: event does not have 'vcpu' property"); + return; + } + if (unlikely(!trace_event_get_state_static(tev))) { + error_report("qi_trace_event_set_vcpu_state_dynamic: event is statically disabled"); + return; + } + trace_event_set_vcpu_state_dynamic((CPUState *)vcpu, tev, state); +} + +static void __attribute__((constructor)) instr_lock_init(void) +{ + qemu_rec_mutex_init(&instr_lock); +} diff --git a/instrument/control.h b/instrument/control.h new file mode 100644 index 0000000000..a83a350faf --- /dev/null +++ b/instrument/control.h @@ -0,0 +1,86 @@ +/* + * Interface for controlling dynamic trace instrumentation. + * + * Copyright (C) 2012-2017 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. + */ + +#ifndef INSTRUMENT__CONTROL_H +#define INSTRUMENT__CONTROL_H + +#include +#include +#include "qapi-types.h" +#include "trace/control.h" + + +/** + * InstrLoadError: + * @INSTR_LOAD_OK: Correctly loaded. + * @INSTR_LOAD_UNAVAILABLE: Service not available. + * @INSTR_LOAD_ERROR: Error with libdl (see dlerror). + * + * Error codes for instr_load(). + * + * Warning: Keep in sync with #InstrLoadCode + */ +typedef enum { + INSTR_LOAD_OK, + INSTR_LOAD_UNAVAILABLE, + INSTR_LOAD_ERROR, +} InstrLoadError; + +/** + * InstrUnloadError: + * @INSTR_UNLOAD_OK: Correctly unloaded. + * @INSTR_UNLOAD_UNAVAILABLE: Service not available. + * @INSTR_UNLOAD_INVALID: Invalid handle. + * @INSTR_UNLOAD_ERROR: Error with libdl (see dlerror). + * + * Error codes for instr_unload(). + * + * Warning: Keep in sync with #InstrUnloadCode + */ +typedef enum { + INSTR_UNLOAD_OK, + INSTR_UNLOAD_UNAVAILABLE, + INSTR_UNLOAD_INVALID, + INSTR_UNLOAD_ERROR, +} InstrUnloadError; + +/** + * instr_load: + * @path: Path to the shared library to load. + * @argc: Number of arguments passed to the initialization function of the library. + * @argv: Arguments passed to the initialization function of the library. + * @handle: Instrumentation library handle (undefined in case of error). + * + * Load a dynamic trace instrumentation library. + * + * Returns: Whether the library could be loaded. + */ +InstrLoadError instr_load(const char * path, int argc, const char ** argv, + int64_t *handle); + +/** + * instr_unload: + * @handle: Instrumentation library handle returned by instr_load(). + * + * Unload the given instrumentation library. + * + * Returns: Whether the library could be unloaded. + */ +InstrUnloadError instr_unload(int64_t handle); + +/** + * instr_unload_all: + * + * Unload all instrumentation libraries. + * + * Returns: Whether any library could not be unloaded. + */ +InstrUnloadError instr_unload_all(void); + +#endif /* INSTRUMENT__CONTROL_H */ diff --git a/instrument/qemu-instr/control.h b/instrument/qemu-instr/control.h new file mode 100644 index 0000000000..83f20d42f2 --- /dev/null +++ b/instrument/qemu-instr/control.h @@ -0,0 +1,128 @@ +/* + * Interface for controlling the state of events. + * + * Copyright (C) 2012-2017 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. + */ + +#ifndef QI__CONTROL_H +#define QI__CONTROL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + + +/** + * SECTION:control + * @section_id: qi-control + * @title: Event control API for QEMU event instrumentation + */ + +/** + * qi_ctrl_event_set: + * @ev: Event descriptor. + * @cb: Pointer to instrumentation callback. + * + * Set the instrumentation callback for the given event. + * + * @cb can also be set to #NULL to restore the default callback. + */ +QI_VPUBLIC void qi_ctrl_event_set(QIEvent *ev, void *cb); + +/** + * qi_trace_event_get_state: + * @ev: Event identifier name. + * + * 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. + */ +#define qi_trace_event_get_state(ev) \ + ((ev ##_ENABLED) && qi_trace_event_get_state_dynamic(ev)) + +/** + * qi_trace_event_get_vcpu_state: + * @vcpu: Target vCPU. + * @ev: Event identifier name. + * + * Get the tracing state of an event (both static and dynamic) for the given + * vCPU. + * + * If the event has the disabled property, the check will have no performance + * impact. + */ +#define qi_trace_event_get_vcpu_state(vcpu, ev) \ + ((ev ##_ENABLED) && \ + qi_trace_event_get_vcpu_state_dynamic(vcpu, ev)) + +/** + * qi_trace_event_get_state_static: + * @ev: Event identifier. + * + * Get the static tracing state of an event. + * + * Use the define 'QI_EVENT_${EVENT}_ENABLED' for compile-time checks (it will + * be set to 1 or 0 according to the presence of the disabled property). + */ +QI_VPUBLIC bool qi_trace_event_get_state_static(QIEvent *ev); + +/** + * qi_trace_event_get_state_dynamic: + * @ev: Event identifier. + * + * Get the dynamic tracing state of an event. + */ +QI_VPUBLIC bool qi_trace_event_get_state_dynamic(QIEvent *ev); + +/** + * qi_trace_event_get_vcpu_state_dynamic: + * @vcpu: Target vCPU. + * @ev: Event identifier. + * + * Get the dynamic tracing state of an event for the given vCPU. + */ +QI_VPUBLIC bool qi_trace_event_get_vcpu_state_dynamic(QICPU *vcpu, + QIEvent *ev); + +/** + * qi_trace_event_set_state_dynamic: + * @ev: Event identifier. + * @state: Target tracing state. + * + * Set the dynamic tracing state of an event. + * + * Pre-condition: qi_trace_event_get_state_static(ev) == true + */ +QI_VPUBLIC void qi_trace_event_set_state_dynamic(QIEvent *ev, bool state); + +/** + * qi_trace_event_set_vcpu_state_dynamic: + * @vcpu: Target vCPU. + * @ev: Event identifier. + * @state: Target tracing state. + * + * Set the dynamic tracing state of an event for the given vCPU. + * + * Pre-condition: qi_trace_event_get_state_static(ev) == true + * + * Note: Changes for execution-time events with the 'tcg' property will not be + * propagated until the next TB is executed (iff executing in TCG mode). + */ +QI_VPUBLIC void qi_trace_event_set_vcpu_state_dynamic(QICPU *vcpu, + QIEvent *ev, bool state); + +#ifdef __cplusplus +} +#endif + +#endif /* QI__CONTROL_H */ diff --git a/instrument/qemu-instr/types.h b/instrument/qemu-instr/types.h index d3d26bbf73..58a84b6d01 100644 --- a/instrument/qemu-instr/types.h +++ b/instrument/qemu-instr/types.h @@ -25,6 +25,14 @@ extern "C" { */ /** + * QIEvent: + * + * Opaque structure defining an instrumentation event. + */ +struct QIEvent; +typedef struct QIEvent QIEvent; + +/** * QICPU: * * Opaque guest CPU pointer. diff --git a/scripts/tracetool/backend/instr_dynamic.py b/scripts/tracetool/backend/instr_dynamic.py index 6f9f8e49fb..2efd4a7eb1 100644 --- a/scripts/tracetool/backend/instr_dynamic.py +++ b/scripts/tracetool/backend/instr_dynamic.py @@ -90,7 +90,8 @@ def generate_instr_tcg_c(event, group): qargs = ["(%s)%s" % (arg[0], arg[1]) for arg in iargs] - out('QI_VPUBLIC void %(nop)s(%(api_args)s)', + out('QIEvent *%(qevent)s = (QIEvent *)&%(tevent)s;', + 'QI_VPUBLIC void %(nop)s(%(api_args)s)', '{', '}', 'QI_VPUBLIC void %(trace)s(%(api_args)s)', @@ -99,7 +100,10 @@ def generate_instr_tcg_c(event, group): '}', 'QI_VPUBLIC void %(gen)s(%(api_args)s)', '{', + # does not exist when event is disabled + '#if %(teventu)s_ENABLED', ' %(b_gen)s(%(qgargs)s);', + '#endif', '}', 'QI_VPUBLIC void %(trace_gen)s(%(api_args)s)', '{', @@ -107,6 +111,9 @@ def generate_instr_tcg_c(event, group): '}', 'void *%(qi_cb)s_cb = %(trace_gen)s;', '', + qevent=event.api(event.QI_TRACE_INSTRUMENT).upper(), + tevent=event.api(event.QEMU_EVENT), + teventu=event.api(event.QEMU_TRACE).upper(), api_args=api_args, nop=event.api(event.QI_TRACE_NOP), trace=event.api(event.QI_TRACE_TRACE), @@ -133,7 +140,8 @@ def generate_instr_c(event, group): args = event.args.transform(TCG_2_QI_TCG) qargs = ["(%s)%s" % (arg[0], arg[1]) for arg in event.args] - out('QI_VPUBLIC void %(nop)s(%(args)s)', + out('QIEvent *%(qevent)s = (QIEvent *)&%(tevent)s;', + 'QI_VPUBLIC void %(nop)s(%(args)s)', '{', '}', 'QI_VPUBLIC void %(trace)s(%(args)s)', @@ -142,6 +150,8 @@ def generate_instr_c(event, group): '}', 'void *%(qi_cb)s_cb = %(qi_trace)s;', '', + qevent=event.api(event.QI_TRACE_INSTRUMENT).upper(), + tevent=event.api(event.QEMU_EVENT), args=args, nop=event.api(event.QI_TRACE_NOP), trace=event.api(event.QI_TRACE_TRACE), diff --git a/scripts/tracetool/format/c.py b/scripts/tracetool/format/c.py index 833c05a022..0b8bb98d24 100644 --- a/scripts/tracetool/format/c.py +++ b/scripts/tracetool/format/c.py @@ -6,7 +6,7 @@ trace/generated-tracers.c """ __author__ = "Lluís Vilanova " -__copyright__ = "Copyright 2012-2014, Lluís Vilanova " +__copyright__ = "Copyright 2012-2017, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -39,18 +39,49 @@ def generate(events, backend, group): vcpu_id = 0 else: vcpu_id = "TRACE_VCPU_EVENT_NONE" + + if "instrument" in e.properties: + is_instr = "true" + out('#if defined(CONFIG_INSTRUMENT)') + if "tcg-trans" in e.properties: + instr_cb = e.original.api(e.QI_TRACE_INSTRUMENT_TCG) + "_cb" + instr_cb_default = e.api(e.QI_TRACE_TRACEGEN) + out('static void *_tmp__%(name1)s;', + 'extern void *%(name1)s __attribute__((weak, alias("_tmp__%(name1)s")));', + name1=instr_cb) + else: + instr_cb = e.api(e.QI_TRACE_INSTRUMENT) + "_cb" + instr_cb_default = e.api(e.QI_TRACE_TRACE) + out('static void _tmp__%(name2)s(void) {};', + 'void %(name2)s(void) __attribute__((weak, alias("_tmp__%(name2)s")));', + '#endif', + name2=instr_cb_default) + instr_cb = "&" + instr_cb + else: + is_instr = "false" + instr_cb = "NULL" + instr_cb_default = "NULL" + out('TraceEvent %(event)s = {', ' .id = 0,', ' .vcpu_id = %(vcpu_id)s,', ' .name = \"%(name)s\",', ' .sstate = %(sstate)s,', - ' .dstate = &%(dstate)s ', + ' .dstate = &%(dstate)s,', + '#if defined(CONFIG_INSTRUMENT)', + ' .is_instr = %(is_instr)s,', + ' .instr_cb = %(instr_cb)s,', + ' .instr_cb_default = %(instr_cb_default)s,', + '#endif', '};', event = e.api(e.QEMU_EVENT), vcpu_id = vcpu_id, name = e.name, sstate = "TRACE_%s_ENABLED" % e.name.upper(), - dstate = e.api(e.QEMU_DSTATE)) + dstate = e.api(e.QEMU_DSTATE), + is_instr=is_instr, + instr_cb=instr_cb, + instr_cb_default=instr_cb_default) out('TraceEvent *%(group)s_trace_events[] = {', group = group.lower()) diff --git a/scripts/tracetool/format/instr_api_h.py b/scripts/tracetool/format/instr_api_h.py index d85f64df45..812a5d44ec 100644 --- a/scripts/tracetool/format/instr_api_h.py +++ b/scripts/tracetool/format/instr_api_h.py @@ -40,13 +40,24 @@ def generate(events, backend, group): '') for e in events: + if "disable" in e.properties: + enabled = 0 + else: + enabled = 1 + if "tcg-trans" in e.properties: args = tracetool.vcpu.transform_args("tcg_h", e.original) args = args.transform(TCG_2_QI_TCG) else: args = e.args.transform(TCG_2_QI_TCG) - out('QI_VPUBLIC void %(nop)s(%(args)s);', + + out('#define %(qeventu)s_ENABLED %(enabled)d', + 'extern QI_VPUBLIC QIEvent *%(event)s;', + 'QI_VPUBLIC void %(nop)s(%(args)s);', 'QI_VPUBLIC void %(trace)s(%(args)s);', + qeventu=e.api(e.QI_TRACE_INSTRUMENT).upper(), + enabled=enabled, + event=e.api(e.QI_TRACE_INSTRUMENT).upper(), args=args, nop=e.api(e.QI_TRACE_NOP), trace=e.api(e.QI_TRACE_TRACE)) diff --git a/trace/event-internal.h b/trace/event-internal.h index f63500b37e..b12cc110b6 100644 --- a/trace/event-internal.h +++ b/trace/event-internal.h @@ -1,7 +1,7 @@ /* * Interface for configuring and controlling the state of tracing events. * - * Copyright (C) 2012-2016 Lluís Vilanova + * Copyright (C) 2012-2017 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. @@ -23,6 +23,9 @@ * @name: Event name. * @sstate: Static tracing state. * @dstate: Dynamic tracing state + * @is_instr: Whether the event is instrumentable. + * @instr_cb: Current instrumentation callback. + * @instr_cb_default: Default instrumentation callback. * * Interpretation of @dstate depends on whether the event has the 'vcpu' * property: @@ -37,6 +40,11 @@ typedef struct TraceEvent { const char * name; const bool sstate; uint16_t *dstate; +#if defined(CONFIG_INSTRUMENT) + bool is_instr; + void **instr_cb; + void *instr_cb_default; +#endif } TraceEvent; void trace_event_set_state_dynamic_init(TraceEvent *ev, bool state);