From patchwork Tue Mar 26 14:00:27 2013 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: 231209 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 0574F2C007E for ; Wed, 27 Mar 2013 01:02:53 +1100 (EST) Received: from localhost ([::1]:55999 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UKUSe-0000JX-Pq for incoming@patchwork.ozlabs.org; Tue, 26 Mar 2013 10:02:48 -0400 Received: from eggs.gnu.org ([208.118.235.92]:36186) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UKUQU-000696-PA for qemu-devel@nongnu.org; Tue, 26 Mar 2013 10:00:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UKUQO-0007fJ-RB for qemu-devel@nongnu.org; Tue, 26 Mar 2013 10:00:34 -0400 Received: from roura.ac.upc.es ([147.83.33.10]:37413) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UKUQO-0007ey-87 for qemu-devel@nongnu.org; Tue, 26 Mar 2013 10:00:28 -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 r2QE0RnP005043 for ; Tue, 26 Mar 2013 15:00:27 +0100 Received: from localhost (unknown [84.88.51.85]) by gw.ac.upc.edu (Postfix) with ESMTP id 0E5B76B01C4 for ; Tue, 26 Mar 2013 15:00:27 +0100 (CET) From: =?utf-8?b?TGx1w61z?= Vilanova To: qemu-devel@nongnu.org Date: Tue, 26 Mar 2013 15:00:27 +0100 Message-Id: <20130326140027.4471.31454.stgit@fimbulvetr.bsc.es> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <20130326140021.4471.99597.stgit@fimbulvetr.bsc.es> References: <20130326140021.4471.99597.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 r2QE0RnP005043 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-Received-From: 147.83.33.10 Subject: [Qemu-devel] [PATCH 01/22] instrument: Add documentation 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 Signed-off-by: LluĂ­s Vilanova --- docs/instrumentation.txt | 481 ++++++++++++++++++++++++++++++++++++++++++++++ docs/tracing.txt | 9 + 2 files changed, 490 insertions(+) create mode 100644 docs/instrumentation.txt diff --git a/docs/instrumentation.txt b/docs/instrumentation.txt new file mode 100644 index 0000000..2f5ec3b --- /dev/null +++ b/docs/instrumentation.txt @@ -0,0 +1,481 @@ += Trace instrumentation = + +== Introduction == + +This document describes how the events provided by the tracing infrastructure +(described in the document "tracing.txt") can be extended with user-provided +code. + +Instrumentation comes in two (three) flavours; dynamic and static (and none at +all). Both provide means for you to associate code to specific tracing events +that have the "instrument" property in the "trace-events" file. + +As opposed to using tracing backends that can dynamically load user-defined code +into the tracing events (e.g., "dtrace"), trace instrumentation provides a +well-defined API for the user-provided code to interact with QEMU. + +In the case of dynamic instrumentation, you can load and unload a shared object +(a dynamic library) to establish your instrumentation callbacks. This mechanism +provides a trade-off between performance and the simplicity of reusing the same +QEMU binary for different instrumentation scenarios. + +In the case of static instrumentation, you must provide a static library that is +compiled directly into QEMU. This mechanism can provide better performance, at +the expense of having to recompile QEMU for each different instrumentation +scenario. + + + +== Selecting the events to instrument == + +You must declare which events to instrument before compiling QEMU. + +This can be done by adding the "instrument" property (and removing the "disable" +property, if any) in the events listed in the "trace-events" file. + +In order to avoid modifying the QEMU sources, you can simply create a new +trace-events file with your modifications: + + cp /path/to/qemu-source/trace-events /tmp/trace-events + sed -i -e "s/qemu_vmalloc(/instrument qemu_vmalloc(/g" /tmp/trace-events + +Note: You must remove the "disable" property (if any) if you want to add the +"instrument" property of an event, as these are mutually exclusive. + + +== Pre-defined instrumentation callbacks == + +If you are using dynamic auto-instrumentation (see 'QI_CTRL_INSTR_AUTO' below) +or static instrumentation, your callbacks must follow a specific naming scheme: +'qi_event_${event}'. + +Two other default callbacks are provided by QEMU: + +* 'qi_event_${event}_nop' + + Does nothing. + + This is the default callback for all instrumentable events when using dynamic + instrumentation. + +* 'qi_event_${event}_trace' + + Call QEMU's tracing backend. That is, trace the event using whatever tracing + backend QEMU has been configured with. + + See document "tracing.txt" to learn more about tracing events with QEMU (e.g., + write events into a file or print them on the screen). + +All these callbacks are declared in the "qemu-instr/events.h" header. + + +== Dynamic instrumentation == + +Dynamic instrumentation is based on dynamically loadable libraries that can be +loaded and unloaded from QEMU at any point in time. This also includes an API to +dynamically set the per-event tracing instrumentation callback at any point in +time. + +Being able to load and unload an instrumentation library provides a comfortable +mechanism to test multiple instrumentation approaches without having to +recompile or restart QEMU between instrumentation tests. + +Note: By default, events are set to use the 'qi_event_${event}_nop' callback. + + +=== Example === + +1. Select the events to instrument in file "trace-events" (see above). + +2. Build QEMU with dynamic trace intrumentation: + + mkdir -p /tmp/qemu-build + cd /tmp/qemu-build + /path/to/qemu-source/configure \ + --with-trace-events=/tmp/trace-events \ + --with-trace-instrument=dynamic \ + --enable-trace-backend=stderr \ + --prefix=/tmp/qemu-install + make + make install + +3. Create the "Makefile" to build the instrumentation library: + + mkdir -p /tmp/my-dinstrument + + cat > /tmp/my-dinstrument/Makefile < /tmp/my-dinstrument/instrument.c < + #include + + /* get event declarations */ + #include + + /* enumerate events and manipulate their instrumentation callbacks */ + #include + + /* manipulate the dynamic tracing state of events */ + #include + + /* define instrumentation callbacks during event execution: + * qi_event_${event} + */ + + /* called every time QEMU traces event 'qemu_vmalloc' */ + void qi_event_qemu_vmalloc(size_t size, void *ptr) + { + fprintf(stderr, "qemu_vmalloc! [instrument]\n"); + + /* call the original tracing routine */ + qi_event_qemu_vmalloc_trace(size, ptr); + + /* disable instrumentation and tracing after 10 calls */ + static int c = 0; + if (c++ > 10) { + QIEvent *ev = qi_ctrl_event_id(QI_EVENT_QEMU_VMALLOC); + qi_ctrl_event_set(ev, QI_CTRL_INSTR_NOP); + qi_trace_event_set_state_dynamic(ev, false); + } + } + + + + /* mandatory initialization callback */ + void qi_init(const char *args) + { + fprintf(stderr, "init!\n"); + fprintf(stderr, " args :: %s\n", args); + + /* iterate on all trace events */ + QIEvent *ev = NULL; + while ((ev = qi_ctrl_event_pattern("*", ev)) != NULL) { + + /* auto-instrument all events instrumentable at execution time */ + if (qi_ctrl_event_is_available(ev)) { + + printf("[exec] instrumenting '%s'\n", + qi_ctrl_event_get_name(ev)); + + /* auto-detect instrumentation routines */ + bool instrumented = qi_ctrl_event_set(ev, QI_CTRL_INSTR_AUTO); + assert(instrumented); + + /* activate tracing for that event + * (otherwise qi_event_${event}_trace does nothing when using + * the 'stderr' backend) + */ + qi_trace_event_set_state_dynamic(ev, true); + } + } + } + + /* mandatory finalization callback */ + void qi_fini(void) + { + fprintf(stderr, "fini!\n"); + + /* ensure all tracing is disabled */ + QIEvent *ev = NULL; + while ((ev = qi_ctrl_event_pattern("*", ev)) != NULL) { + qi_trace_event_set_state_dynamic(ev, false); + } + + /* instrumentation callbacks are automatically reset by QEMU */ + } + EOF + +5. Compile the instrumentation library: + + make -C /tmp/my-dinstrument + +6. Start QEMU with the instrumentation library: + + /tmp/qemu-install/bin/qemu-system-x86_64 \ + -instr file=/tmp/my-dinstrument/.libs/libtrace-instrument.so + + +Alternatively, you can explicitly set which events and with which callback you +want to instrument them: + + /* ... */ + void qi_init(void) + { + fprintf(stderr, "init!\n"); + fprintf(stderr, " args :: %s\n", args); + + QIEvent *ev; + bool instrumented; + + /* NOTE: the callbacks can be pointers to arbitrary routines; + * there's no need to follow the 'qi_event_${event}' naming + * scheme if you're not using QI_CTRL_INSTR_AUTO. + */ + + ev = qi_ctrl_event_id(QI_EVENT_QEMU_VMALLOC); + assert(ev); + printf("[exec] instrumenting '%s'\n", + qi_ctrl_event_get_name(ev)); + instrumented = qi_ctrl_event_set(ev, execute_qemu_vmalloc); + assert(instrumented); + qi_trace_event_set_state_dynamic(ev, true); + } + /* ... */ + + + +== Static instrumentation == + +Static instrumentation relies on you providing a directory that QEMU will +compile on to produce a static library. The instrumentation library is compiled +during the compilation of QEMU's target-dependant code, and the directory you +provided will be present on the include path. This static library will then be +linked into QEMU itself. + +This mechanism allows you to inline your own instrumentation code into the QEMU +tracing routines. This requires the (partial) recompilation of QEMU whenever the +instrumentation analysis code changes, and is thus intended for +performance-critical event instrumentation analysis. + +For this reason, you can prototype your analysis using dynamic instrumentation +before moving to static instrumentation. + + +=== Example === + +1. Select the events to instrument in file "trace-events" (see above). + +2. Create the "Makefile" to build the instrumentation library: + + mkdir -p /tmp/my-sinstrument + + cat > /tmp/my-sinstrument/Makefile < + + // file residing in "/tmp/my-sinstrument/my-header.h", + // which declares 'my_trace_qemu_vmalloc_slow' + #include "my-header.h" + + + // requires "#define QI_EVENT_QEMU_VMALLOC_INLINE 1" in "events-pre.h" + static inline void qi_event_qemu_vmalloc(size_t size, void *ptr) + { + if (/* ... performance-critical condition ... */) { + /* ... performance-critical code ... */ + } else { + my_trace_qemu_vmalloc_slow(size, ptr); + } + } + + #endif /* EVENTS_POST_H */ + +Note: All these headers are completely optional, and will only be used if they +exist at compile time. + + + +== Loading and unloading instrumentation libraries == + +QEMU starts with all instrumentation callbacks set to their default value, which +corresponds to a call to 'qi_event_${event}_nop'. + +To load a dynamic instrumentation library, the user can either use the "-instr" +command line argument, or the "instr-load" command available in the QEMU +monitor, QAPI and QMP. + +Once loaded, QEMU will call the 'qi_init' routine in the instrumentation library. + +To unload a dynamic instrumentation library, the user can use the "instr-unload" +command. + +When unloading, QEMU will call the 'qi_fini' routine in the instrumentation +library, and immediately after restore all the instrumentation callbacks to +their default value. + +In the case of static instrumentation, the commands "instr-load" and +"instr-unload" are not available, and thus the instrumentation library is +already loaded when QEMU starts, and is unloaded when QEMU exits. + + + +== Instrumentation API == + +Both dynamic and static trace instrumentation libraries can interact with QEMU +using the API provided in the headers found under the "qemu-instr" directory +(installed alongside QEMU). + + +=== Event enumeration === + +Events can be obtained either by identifier or by name. Identifiers are values +of the enumeration 'QIEventID' and follow the naming scheme 'QI_EVENT_${EVENT}' +(e.g., 'QI_EVENT_QEMU_VMALLOC' for the "qemu_vmalloc" event). + +Identifiers, together with defines indicating if an event is enabled at +compile-time ('QI_EVENT_${EVENT}_ENABLED') are located in the +"qemu-instr/events-list.h" header. + +The interface to obtain and enumerate these events is located in the +"qemu-instr/control.h" header. + + +=== Event tracing === + +You can interact with the state of QEMU's event tracing backend (see document +"tracing.txt") through the API in the "qemu-instr/trace.h" header. + + +=== Event instrumentation === + +You can control the instrumentation callbacks of events through the API in the +"qemu-instr/control.h" header. + + +=== Instrumentation type discrimination === + +The same source code for an instrumentation library can result in different code +depending on the current instrumentation type (either dynamic or static): + +* "qemu-instr/config.h" + + The define QI_TYPE_STATIC (QI_TYPE_DYNAMIC) will be available and set to 1 if + QEMU has been compiled with static (dynamic) instrumentation. + +* "qemu-instr/control.h" + + Routine 'qi_ctrl_dynamic' can be used to discriminate if dynamic + instrumentation is available. + + Similarly, routine 'qi_ctrl_event_is_available' indicates whether the given + event is available for instrumentation (both static and dynamic). + +With this, you can ensure the same code will work under both instrumentation +types. + +Example initialization: + + #if defined(QI_TYPE_DYNAMIC) + #include "events-post.h" + #endif + + void qi_init(void) + { + QIEvent *ev = NULL; + while ((ev = qi_ctrl_event_pattern("*", ev)) != NULL) { + + if (qi_ctrl_event_is_available(ev)) { + + /* changing the callback will fail during static instrumentation */ + if (qi_ctrl_dynamic()) { + bool instrumented = qi_ctrl_event_set(ev, QI_CTRL_INSTR_AUTO); + assert(instrumented); + } + + qi_trace_event_set_state_dynamic(ev, true); + } + } + } + +Example "events-post.h": + + #if defined(QI_TYPE_STATIC) + static inline + #endif + void qi_event_qemu_vmalloc(size_t size, void *ptr) + { + /* ... */ + } diff --git a/docs/tracing.txt b/docs/tracing.txt index cf53c17..d33717b 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -255,3 +255,12 @@ guard such computations and avoid its compilation when the event is disabled: 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). + +=== "instrument" === + +When compiling QEMU with trace instrumentation enabled, the "instrument" +property lets you provide your own implementation for that trace event. This +implementation can override and/or wrap the backend-specific tracing code +(regardless of the tracing backend). + +See the document "instrumentation.txt" for more information.