From patchwork Fri Jan 15 16:38:37 2016 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: 8043201 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 35120BEEE5 for ; Fri, 15 Jan 2016 16:39:12 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8AD4A20459 for ; Fri, 15 Jan 2016 16:39:10 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9A9E5203F4 for ; Fri, 15 Jan 2016 16:39:08 +0000 (UTC) Received: from localhost ([::1]:47966 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aK7P1-0000dk-Vn for patchwork-qemu-devel@patchwork.kernel.org; Fri, 15 Jan 2016 11:39:08 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39730) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aK7Oj-0000Ur-Ug for qemu-devel@nongnu.org; Fri, 15 Jan 2016 11:38:52 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aK7Og-0004Xm-TA for qemu-devel@nongnu.org; Fri, 15 Jan 2016 11:38:49 -0500 Received: from roura.ac.upc.es ([147.83.33.10]:58124) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aK7Og-0004X1-8A for qemu-devel@nongnu.org; Fri, 15 Jan 2016 11:38:46 -0500 Received: from gw-3.ac.upc.es (gw-3.ac.upc.es [147.83.30.9]) by roura.ac.upc.es (8.13.8/8.13.8) with ESMTP id u0FEx3DE029659; Fri, 15 Jan 2016 15:59:03 +0100 Received: from localhost (unknown [84.88.51.85]) by gw-3.ac.upc.es (Postfix) with ESMTPSA id 734F79B9; Fri, 15 Jan 2016 17:38:37 +0100 (CET) From: =?utf-8?b?TGx1w61z?= Vilanova To: qemu-devel@nongnu.org Date: Fri, 15 Jan 2016 17:38:37 +0100 Message-Id: <145287591675.11400.12508957244344480632.stgit@localhost> X-Mailer: git-send-email 2.6.4 In-Reply-To: <145287587081.11400.4178335509020334684.stgit@localhost> References: <145287587081.11400.4178335509020334684.stgit@localhost> 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 u0FEx3DE029659 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-Received-From: 147.83.33.10 Cc: Eduardo Habkost , Peter Crosthwaite , Stefan Hajnoczi , Riku Voipio , Markus Armbruster , Luiz Capitulino , Blue Swirl , Stefan Hajnoczi , Paolo Bonzini , =?UTF-8?q?Andreas=20F=C3=A4rber?= , Richard Henderson Subject: [Qemu-devel] [PATCH v4 8/9] trace: [tcg] Add per-vCPU tracing states for events with the 'vcpu' property 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+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Each event with the 'vcpu' property gets a per-vCPU dynamic tracing state. The set of enabled events with the 'vcpu' and 'tcg' properties is used to select a per-vCPU physical TB cache. The number of events with both properties is used to select the number of physical TB caches, and a bitmap of the identifiers of such enabled events is used to select a physical TB cache. Signed-off-by: Lluís Vilanova --- Makefile.objs | 1 bsd-user/main.c | 2 include/qom/cpu.h | 10 ++ linux-user/main.c | 2 monitor.c | 4 - qapi/trace.json | 11 ++ qmp-commands.hx | 17 +++- scripts/tracetool/format/h.py | 1 scripts/tracetool/format/tcg_helper_c.py | 11 ++ trace/Makefile.objs | 2 trace/control-internal.h | 13 ++- trace/control-stub.c | 29 ++++++ trace/control-target.c | 69 +++++++++++++++ trace/control.c | 17 +++- trace/control.h | 55 ++++++++++++ trace/event-internal.h | 2 trace/qmp.c | 138 +++++++++++++++++++++++++----- translate-all.c | 1 vl.c | 1 19 files changed, 344 insertions(+), 42 deletions(-) create mode 100644 trace/control-stub.c create mode 100644 trace/control-target.c diff --git a/Makefile.objs b/Makefile.objs index dac2c02..c268acb 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -103,6 +103,7 @@ version-lobj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.lo # tracing util-obj-y += trace/ target-obj-y += trace/ +stub-obj-y += trace/ ###################################################################### # guest agent diff --git a/bsd-user/main.c b/bsd-user/main.c index 1ecaeb5..b57f9a9 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -31,6 +31,7 @@ /* For tb_lock */ #include "cpu.h" #include "tcg.h" +#include "trace/control.h" #include "qemu/timer.h" #include "qemu/envlist.h" @@ -1121,6 +1122,7 @@ int main(int argc, char **argv) gdbserver_start (gdbstub_port); gdb_handlesig(cpu, 0); } + trace_init_vcpu_events(); cpu_loop(env); /* never exits */ return 0; diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 40962e0..d1cbd7a 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -29,6 +29,7 @@ #include "qemu/queue.h" #include "qemu/thread.h" #include "qemu/typedefs.h" +#include "trace/generated-events.h" typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size, void *opaque); @@ -319,6 +320,15 @@ struct CPUState { unsigned int tb_phys_idx; unsigned int tb_phys_idx_req; + /* + * Ensure 'tb_phys_idx' can encode event states as a bitmask. + * + * This limits the number of events with the 'tcg' property and *without* + * the 'disabled' property to 'sizeof(tb_phys_idx)*8'. + */ + bool too_many_tcg_vcpu_events[ + TRACE_CPU_EVENT_COUNT > sizeof(unsigned int)*8 ? -1 : 0]; + /* TODO Move common fields from CPUArchState here. */ int cpu_index; /* used by alpha TCG */ uint32_t halted; /* used by alpha, cris, ppc TCG */ diff --git a/linux-user/main.c b/linux-user/main.c index ee12035..44f0536 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -30,6 +30,7 @@ #include "qemu-common.h" #include "cpu.h" #include "tcg.h" +#include "trace/control.h" #include "qemu/timer.h" #include "qemu/envlist.h" #include "elf.h" @@ -4654,6 +4655,7 @@ int main(int argc, char **argv, char **envp) } gdb_handlesig(cpu, 0); } + trace_init_vcpu_events(); cpu_loop(env); /* never exits */ return 0; diff --git a/monitor.c b/monitor.c index c53a453..7c42e78 100644 --- a/monitor.c +++ b/monitor.c @@ -888,7 +888,7 @@ static void hmp_trace_event(Monitor *mon, const QDict *qdict) bool new_state = qdict_get_bool(qdict, "option"); Error *local_err = NULL; - qmp_trace_event_set_state(tp_name, new_state, true, true, &local_err); + qmp_trace_event_set_state(tp_name, new_state, true, true, false, 0, &local_err); if (local_err) { error_report_err(local_err); } @@ -1047,7 +1047,7 @@ static void hmp_info_cpustats(Monitor *mon, const QDict *qdict) static void hmp_info_trace_events(Monitor *mon, const QDict *qdict) { - TraceEventInfoList *events = qmp_trace_event_get_state("*", NULL); + TraceEventInfoList *events = qmp_trace_event_get_state("*", false, 0, NULL); TraceEventInfoList *elem; for (elem = events; elem != NULL; elem = elem->next) { diff --git a/qapi/trace.json b/qapi/trace.json index 84c34dd..8708dba 100644 --- a/qapi/trace.json +++ b/qapi/trace.json @@ -42,13 +42,18 @@ # Query the state of events. # # @name: Event name pattern (case-sensitive glob). +# @vcpu: #optional The vCPU to check (any by default; since 2.6). # # Returns: a list of @TraceEventInfo for the matching events # +# For any event without the "vcpu" property: +# - If @name is a pattern and @vcpu is set, events are ignored. +# - If @name is not a pattern and @vcpu is set, an error is raised. +# # Since 2.2 ## { 'command': 'trace-event-get-state', - 'data': {'name': 'str'}, + 'data': {'name': 'str', '*vcpu': 'int'}, 'returns': ['TraceEventInfo'] } ## @@ -59,8 +64,10 @@ # @name: Event name pattern (case-sensitive glob). # @enable: Whether to enable tracing. # @ignore-unavailable: #optional Do not match unavailable events with @name. +# @vcpu: #optional The vCPU to act upon (all by default; since 2.6). # # Since 2.2 ## { 'command': 'trace-event-set-state', - 'data': {'name': 'str', 'enable': 'bool', '*ignore-unavailable': 'bool'} } + 'data': {'name': 'str', 'enable': 'bool', '*ignore-unavailable': 'bool', + '*vcpu': 'int'} } diff --git a/qmp-commands.hx b/qmp-commands.hx index db072a6..ce6a419 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -4566,7 +4566,7 @@ EQMP { .name = "trace-event-get-state", - .args_type = "name:s", + .args_type = "name:s,vcpu:i?", .mhandler.cmd_new = qmp_marshal_trace_event_get_state, }, @@ -4576,6 +4576,11 @@ trace-event-get-state Query the state of events. +Arguments: + +- "name": Event name pattern (json-string). +- "vcpu": Specific vCPU to query, any vCPU by default (json-int, optional). + Example: -> { "execute": "trace-event-get-state", "arguments": { "name": "qemu_memalign" } } @@ -4584,7 +4589,7 @@ EQMP { .name = "trace-event-set-state", - .args_type = "name:s,enable:b,ignore-unavailable:b?", + .args_type = "name:s,enable:b,ignore-unavailable:b?,vcpu:i?", .mhandler.cmd_new = qmp_marshal_trace_event_set_state, }, @@ -4594,6 +4599,13 @@ trace-event-set-state Set the state of events. +Arguments: + +- "name": Event name pattern (json-string). +- "enable": Whether to enable or disable the event (json-bool). +- "ignore-unavailable": Whether to ignore errors for events that cannot be changed (json-bool, optional). +- "vcpu": Specific vCPU to set, all vCPUs by default (json-int, optional). + Example: -> { "execute": "trace-event-set-state", "arguments": { "name": "qemu_memalign", "enable": "true" } } @@ -4662,7 +4674,6 @@ Move mouse pointer to absolute coordinates (20000, 400). { "type": "abs", "data" : { "axis": "X", "value" : 20000 } }, { "type": "abs", "data" : { "axis": "Y", "value" : 400 } } ] } } <- { "return": {} } - EQMP { diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py index 2bd68a2..f98f26b 100644 --- a/scripts/tracetool/format/h.py +++ b/scripts/tracetool/format/h.py @@ -36,6 +36,7 @@ def generate(events, backend): args=e.args) if "disable" not in e.properties: + # NOTE: See note on 'trace_event_set_cpu_state()'. backend.generate(e) out('}') diff --git a/scripts/tracetool/format/tcg_helper_c.py b/scripts/tracetool/format/tcg_helper_c.py index 96655a0..e5dd3fe 100644 --- a/scripts/tracetool/format/tcg_helper_c.py +++ b/scripts/tracetool/format/tcg_helper_c.py @@ -6,7 +6,7 @@ Generate trace/generated-helpers.c. """ __author__ = "Lluís Vilanova " -__copyright__ = "Copyright 2012-2014, Lluís Vilanova " +__copyright__ = "Copyright 2012-2016, Lluís Vilanova " __license__ = "GPL version 2 or (at your option) any later version" __maintainer__ = "Stefan Hajnoczi" @@ -36,8 +36,13 @@ def generate(events, backend): # tracetool.generate always transforms types to host e_args = e.original.args - values = ["(%s)%s" % (t, n) - for t, n in e.args.transform(TCG_2_TCG_HELPER_DEF)] + values = [] + for (t_old, n), (t_new, _) in zip( + e.args, e.args.transform(TCG_2_TCG_HELPER_DEF)): + if t_old == "CPUState *": + values.append("ENV_GET_CPU((CPUArchState*)%s)" % n) + else: + values.append("(%s)%s" % (t_new, n)) out('void %(name_tcg)s(%(args)s)', '{', diff --git a/trace/Makefile.objs b/trace/Makefile.objs index 5145b34..a179d02 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -152,4 +152,6 @@ util-obj-$(CONFIG_TRACE_SIMPLE) += simple.o generated-tracers.o util-obj-$(CONFIG_TRACE_FTRACE) += ftrace.o util-obj-$(CONFIG_TRACE_UST) += generated-ust.o util-obj-y += control.o +target-obj-y += control-target.o +stub-obj-y += control-stub.o util-obj-y += qmp.o diff --git a/trace/control-internal.h b/trace/control-internal.h index ab42396..81e757f 100644 --- a/trace/control-internal.h +++ b/trace/control-internal.h @@ -12,6 +12,9 @@ #include +#include "qemu-common.h" +#include "qom/cpu.h" + extern TraceEvent trace_events[]; @@ -60,14 +63,16 @@ static inline bool trace_event_get_state_static(TraceEvent *ev) static inline bool trace_event_get_state_dynamic(TraceEvent *ev) { assert(ev != NULL); - return ev->dstate; + /* no need to iterate over vCPUs, since the global dynamic state is always set */ + return ev->dstate > 0; } -static inline void trace_event_set_state_dynamic(TraceEvent *ev, bool state) +static inline bool trace_event_get_cpu_state_dynamic(CPUState *cpu, + TraceEvent *ev) { + assert(cpu != NULL); assert(ev != NULL); - assert(trace_event_get_state_static(ev)); - ev->dstate = state; + return cpu->tb_phys_idx & (((unsigned long)1) << ev->cpu_id); } #endif /* TRACE__CONTROL_INTERNAL_H */ diff --git a/trace/control-stub.c b/trace/control-stub.c new file mode 100644 index 0000000..784bc35 --- /dev/null +++ b/trace/control-stub.c @@ -0,0 +1,29 @@ +/* + * Interface for configuring and controlling the state of tracing events. + * + * Copyright (C) 2014-2016 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 "trace/control.h" + + +void trace_init_vcpu_tb_caches(void) +{ +} + +void trace_event_set_state_dynamic(TraceEvent *ev, bool state) +{ + assert(ev != NULL); + assert(trace_event_get_state_static(ev)); + ev->dstate = state; +} + +void trace_event_set_cpu_state_dynamic(CPUState *cpu, + TraceEvent *ev, bool state) +{ + /* should never be called on non-target binaries */ + abort(); +} diff --git a/trace/control-target.c b/trace/control-target.c new file mode 100644 index 0000000..c256f54 --- /dev/null +++ b/trace/control-target.c @@ -0,0 +1,69 @@ +/* + * Interface for configuring and controlling the state of tracing events. + * + * Copyright (C) 2014-2016 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 "trace/control.h" +#include "cpu.h" +#include "translate-all.h" + + +void trace_init_vcpu_tb_caches(void) +{ + unsigned int events = 1; + TraceEvent *ev = NULL; + while ((ev = trace_event_pattern("*", ev)) != NULL) { + if (trace_event_get_cpu_id(ev) == TRACE_CPU_EVENT_COUNT) { + continue; + } + events <<= 1; + } + tb_caches_set(events); + tb_caches_apply(); +} + +void trace_event_set_state_dynamic(TraceEvent *ev, bool state) +{ + CPUState *cpu; + assert(ev != NULL); + assert(trace_event_get_state_static(ev)); + if (trace_event_get_cpu_id(ev) != TRACE_CPU_EVENT_COUNT) { + CPU_FOREACH(cpu) { + trace_event_set_cpu_state_dynamic(cpu, ev, state); + } + } else { + ev->dstate = state; + } +} + +void trace_event_set_cpu_state_dynamic(CPUState *cpu, + TraceEvent *ev, bool state) +{ + /* + * NOTE: Does not immediately apply changes on all affected vCPUs, so + * "tcg-exec" events might be generated after being disabled (until + * the vCPU finishes a BBL and checks for event state changes). + */ + unsigned int bit; + bool state_pre; + assert(cpu != NULL); + assert(ev != NULL); + assert(trace_event_get_state_static(ev)); + assert(trace_event_get_cpu_id(ev) != TRACE_CPU_EVENT_COUNT); + bit = ((unsigned long)1) << ev->cpu_id; + /* must use the requested TB index in case it's not yet synchronized */ + state_pre = cpu->tb_phys_idx_req & bit; + if ((state_pre == 0) != (state == 0)) { + if (state) { + cpu_tb_cache_set(cpu, (cpu->tb_phys_idx_req & ~bit) | bit); + ev->dstate++; + } else { + cpu_tb_cache_set(cpu, (cpu->tb_phys_idx_req & ~bit)); + ev->dstate--; + } + } +} diff --git a/trace/control.c b/trace/control.c index 995beb3..2bd5908 100644 --- a/trace/control.c +++ b/trace/control.c @@ -1,7 +1,7 @@ /* * Interface for configuring and controlling the state of tracing events. * - * Copyright (C) 2011-2014 Lluís Vilanova + * Copyright (C) 2011-2016 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. @@ -167,3 +167,18 @@ bool trace_init_backends(const char *events, const char *file) trace_init_events(events); return true; } + +void trace_init_vcpu_events(void) +{ + TraceEvent *ev = NULL; + /* + * Set per-vCPU tracing state according to initial event state. The calls + * here affect al vCPUs in the system. + */ + while ((ev = trace_event_pattern("*", ev)) != NULL) { + if (trace_event_get_cpu_id(ev) != TRACE_CPU_EVENT_COUNT && + trace_event_get_state_dynamic(ev)) { + trace_event_set_state_dynamic(ev, true); + } + } +} diff --git a/trace/control.h b/trace/control.h index 860beed..1103a4c 100644 --- a/trace/control.h +++ b/trace/control.h @@ -115,6 +115,22 @@ static const char * trace_event_get_name(TraceEvent *ev); ((id ##_ENABLED) && trace_event_get_state_dynamic(trace_event_id(id))) /** + * trace_event_get_cpu_state: + * @id: Event identifier. + * + * 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. + * + * As a down side, you must always use an immediate #TraceEventID value. + */ +#define trace_event_get_cpu_state(cpu, id) \ + ((id ##_ENABLED) && trace_event_get_cpu_state_dynamic(cpu, \ + trace_event_id(id))) + +/** * trace_event_get_state_static: * @id: Event identifier. * @@ -129,10 +145,19 @@ static bool trace_event_get_state_static(TraceEvent *ev); * trace_event_get_state_dynamic: * * Get the dynamic tracing state of an event. + * + * If the event has the 'vcpu' property, gets the OR'ed state of all vCPUs. */ static bool trace_event_get_state_dynamic(TraceEvent *ev); /** + * trace_event_get_cpu_state_dynamic: + * + * Get the dynamic tracing state of an event for the given vCPU. + */ +static bool trace_event_get_cpu_state_dynamic(CPUState *cpu, TraceEvent *ev); + +/** * trace_event_set_state: * * Set the tracing state of an event (only if possible). @@ -146,13 +171,38 @@ static bool trace_event_get_state_dynamic(TraceEvent *ev); } while (0) /** + * trace_event_set_cpu_state: + * + * Set the tracing state of an event for the given vCPU (only if possible). + */ +#define trace_event_set_cpu_state(cpu, id, state) \ + do { \ + if ((id ##_ENABLED)) { \ + TraceEvent *_e = trace_event_id(id); \ + trace_event_set_cpu_state_dynamic(cpu, _e, state); \ + } \ + } while (0) + +/** * trace_event_set_state_dynamic: * * Set the dynamic tracing state of an event. * + * If the event has the 'vcpu' property, sets the state on all vCPUs. + * * Pre-condition: trace_event_get_state_static(ev) == true */ -static void trace_event_set_state_dynamic(TraceEvent *ev, bool state); +void trace_event_set_state_dynamic(TraceEvent *ev, bool state); + +/** + * trace_event_set_cpu_state_dynamic: + * + * Set the dynamic tracing state of an event for the given vCPU. + * + * Pre-condition: trace_event_get_cpu_state_static(ev) == true + */ +void trace_event_set_cpu_state_dynamic(CPUState *cpu, + TraceEvent *ev, bool state); @@ -169,6 +219,9 @@ static void trace_event_set_state_dynamic(TraceEvent *ev, bool state); */ bool trace_init_backends(const char *events, const char *file); +void trace_init_vcpu_tb_caches(void); +void trace_init_vcpu_events(void); + #include "trace/control-internal.h" diff --git a/trace/event-internal.h b/trace/event-internal.h index 258bcde..b785017 100644 --- a/trace/event-internal.h +++ b/trace/event-internal.h @@ -28,7 +28,7 @@ typedef struct TraceEvent { TraceEventCPUID cpu_id; const char * name; const bool sstate; - bool dstate; + size_t dstate; } TraceEvent; diff --git a/trace/qmp.c b/trace/qmp.c index be99496..8ee9b70 100644 --- a/trace/qmp.c +++ b/trace/qmp.c @@ -12,64 +12,152 @@ #include "trace/control.h" -TraceEventInfoList *qmp_trace_event_get_state(const char *name, Error **errp) +static bool get_cpu_state(bool has_index, int index, CPUState **cpu, Error **errp) +{ + if (has_index) { + *cpu = qemu_get_cpu(index); + if (*cpu == NULL) { + error_setg(errp, "invalid vCPU index %u", index); + return false; + } + } else { + *cpu = NULL; + } + return true; +} + +TraceEventInfoList *qmp_trace_event_get_state(const char *name, + bool has_vcpu, int64_t vcpu, + Error **errp) { TraceEventInfoList *events = NULL; - bool found = false; TraceEvent *ev; + bool is_pattern = trace_event_is_pattern(name); + CPUState *cpu; + + if (!get_cpu_state(has_vcpu, vcpu, &cpu, errp)) { + return NULL; + } ev = NULL; while ((ev = trace_event_pattern(name, ev)) != NULL) { - TraceEventInfoList *elem = g_new(TraceEventInfoList, 1); + TraceEventInfoList *elem; + bool is_vcpu = trace_event_get_cpu_id(ev) != TRACE_CPU_EVENT_COUNT; + if (has_vcpu && !is_vcpu) { + if (!is_pattern) { + error_setg(errp, "event \"%s\" is not vCPU-specific", name); + } + /* else: ignore */ + continue; + } + + elem = g_new(TraceEventInfoList, 1); elem->value = g_new(TraceEventInfo, 1); - elem->value->vcpu = trace_event_get_cpu_id(ev) != TRACE_CPU_EVENT_COUNT; + elem->value->vcpu = is_vcpu; elem->value->name = g_strdup(trace_event_get_name(ev)); + if (!trace_event_get_state_static(ev)) { elem->value->state = TRACE_EVENT_STATE_UNAVAILABLE; - } else if (!trace_event_get_state_dynamic(ev)) { - elem->value->state = TRACE_EVENT_STATE_DISABLED; } else { - elem->value->state = TRACE_EVENT_STATE_ENABLED; + if (has_vcpu) { + if (is_vcpu) { + if (trace_event_get_cpu_state_dynamic(cpu, ev)) { + elem->value->state = TRACE_EVENT_STATE_ENABLED; + } else { + elem->value->state = TRACE_EVENT_STATE_DISABLED; + } + } + /* else: already handled above */ + } else { + if (trace_event_get_state_dynamic(ev)) { + elem->value->state = TRACE_EVENT_STATE_ENABLED; + } else { + elem->value->state = TRACE_EVENT_STATE_DISABLED; + } + } } elem->next = events; events = elem; - found = true; } - if (!found && !trace_event_is_pattern(name)) { + if (events == NULL && !is_pattern) { error_setg(errp, "unknown event \"%s\"", name); } return events; } + +static void check_events_are_dynamic(const char *name, bool per_cpu, + bool *found, bool error_check, + bool *error_found, Error **errp) +{ + TraceEvent *ev = NULL; + *found = false; + *error_found = false; + while ((ev = trace_event_pattern(name, ev)) != NULL) { + if (per_cpu && trace_event_get_cpu_id(ev) == TRACE_CPU_EVENT_COUNT) { + if (error_check) { + Error *local_err = NULL; + error_setg(&local_err, "event \"%s\" is not vCPU-specific", + trace_event_get_name(ev)); + error_propagate(errp, local_err); + *error_found = true; + } + continue; + } + if (!trace_event_get_state_static(ev)) { + if (error_check) { + Error *local_err = NULL; + error_setg(&local_err, "cannot set dynamic tracing state for \"%s\"", + trace_event_get_name(ev)); + error_propagate(errp, local_err); + *error_found = true; + } + continue; + } + *found = true; + } +} + void qmp_trace_event_set_state(const char *name, bool enable, - bool has_ignore_unavailable, - bool ignore_unavailable, Error **errp) + bool has_ignore_unavailable, bool ignore_unavailable, + bool has_vcpu, int64_t vcpu, + Error **errp) { - bool found = false; - TraceEvent *ev; + bool error, found; + TraceEvent *ev = NULL; + CPUState *cpu; + + if (!get_cpu_state(has_vcpu, vcpu, &cpu, errp)) { + return; + } /* Check all selected events are dynamic */ - ev = NULL; - while ((ev = trace_event_pattern(name, ev)) != NULL) { - found = true; - if (!(has_ignore_unavailable && ignore_unavailable) && - !trace_event_get_state_static(ev)) { - error_setg(errp, "cannot set dynamic tracing state for \"%s\"", - trace_event_get_name(ev)); - return; - } + check_events_are_dynamic(name, has_vcpu, &found, + !(has_ignore_unavailable && ignore_unavailable), + &error, errp); + if (error) { + return; } - if (!found && !trace_event_is_pattern(name)) { - error_setg(errp, "unknown event \"%s\"", name); + if (!found) { + if (!trace_event_is_pattern(name)) { + error_setg(errp, "unknown event \"%s\"", name); + } return; } /* Apply changes */ ev = NULL; while ((ev = trace_event_pattern(name, ev)) != NULL) { - if (trace_event_get_state_static(ev)) { + if (!trace_event_get_state_static(ev) || + (has_vcpu && trace_event_get_cpu_id(ev) == TRACE_CPU_EVENT_COUNT)) { + /* if it were an error, it was catched by the check above */ + continue; + } + if (has_vcpu) { + trace_event_set_cpu_state_dynamic(cpu, ev, enable); + } else { trace_event_set_state_dynamic(ev, enable); } } diff --git a/translate-all.c b/translate-all.c index 2395977..dab44ad 100644 --- a/translate-all.c +++ b/translate-all.c @@ -179,6 +179,7 @@ void cpu_gen_init(void) tcg_ctx.tb_ctx.tb_phys_hash_size_req = 1; tcg_ctx.tb_ctx.tb_phys_hash = NULL; tb_caches_apply(); + trace_init_vcpu_tb_caches(); } /* Encode VAL as a signed leb128 sequence at P. diff --git a/vl.c b/vl.c index b7a083e..dcba749 100644 --- a/vl.c +++ b/vl.c @@ -4659,6 +4659,7 @@ int main(int argc, char **argv, char **envp) } } + trace_init_vcpu_events(); main_loop(); replay_disable_events();